From 47ae60742c5d40e2180cfbb769634e77c80fcd1c Mon Sep 17 00:00:00 2001 From: "A. Wilcox" Date: Mon, 28 Oct 2024 03:47:38 -0500 Subject: system/easy-kernel: Update to 6.6.58-mc2 Includes oldconfigs for all arches, but only tested on ppc64 so far. --- system/easy-kernel/0000-README | 40 +- system/easy-kernel/0100-linux-6.6.58.patch | 506489 ++++++++++++++++++ system/easy-kernel/0100-linux-6.6.6.patch | 64421 --- system/easy-kernel/0120-XATTR_USER_PREFIX.patch | 31 - .../0204-amd-deserialised-MSR-access.patch | 134 - system/easy-kernel/0204-sparc-warray-fix.patch | 17 + system/easy-kernel/0208-gcc14-objtool-fix.patch | 41 + .../easy-kernel/0210-fix-powerbook6-5-audio.patch | 48 - .../easy-kernel/0250-expose-per-process-ksm.patch | 4 + .../easy-kernel/0252-rectify-ksm-inheritance.patch | 1059 + .../0300-correct-max98388-includes.patch | 39 + .../easy-kernel/0300-tmp513-regression-fix.patch | 30 - system/easy-kernel/0302-i915-gcc14-fix.patch | 37 + system/easy-kernel/0302-iwlwifi-rfkill-fix.patch | 170 - .../easy-kernel/0304-fix-powerbook6-5-audio.patch | 48 + system/easy-kernel/0502-gcc9-kcflags.patch | 68 +- .../easy-kernel/0504-update-zstd-to-v1_5_5.patch | 13822 - .../easy-kernel/0504-update-zstd-to-v1_5_6.patch | 18713 + system/easy-kernel/1000-version.patch | 6 +- system/easy-kernel/APKBUILD | 58 +- system/easy-kernel/config-aarch64 | 73 +- system/easy-kernel/config-armv7 | 44 +- system/easy-kernel/config-m68k | 40 +- system/easy-kernel/config-pmmx | 60 +- system/easy-kernel/config-ppc | 44 +- system/easy-kernel/config-ppc64 | 49 +- system/easy-kernel/config-sparc64 | 43 +- system/easy-kernel/config-x86_64 | 66 +- system/easy-kernel/no-require-gnu-tar.patch | 4 +- 29 files changed, 526812 insertions(+), 78886 deletions(-) create mode 100644 system/easy-kernel/0100-linux-6.6.58.patch delete mode 100644 system/easy-kernel/0100-linux-6.6.6.patch delete mode 100644 system/easy-kernel/0120-XATTR_USER_PREFIX.patch delete mode 100644 system/easy-kernel/0204-amd-deserialised-MSR-access.patch create mode 100644 system/easy-kernel/0204-sparc-warray-fix.patch create mode 100644 system/easy-kernel/0208-gcc14-objtool-fix.patch delete mode 100644 system/easy-kernel/0210-fix-powerbook6-5-audio.patch create mode 100644 system/easy-kernel/0252-rectify-ksm-inheritance.patch create mode 100644 system/easy-kernel/0300-correct-max98388-includes.patch delete mode 100644 system/easy-kernel/0300-tmp513-regression-fix.patch create mode 100644 system/easy-kernel/0302-i915-gcc14-fix.patch delete mode 100644 system/easy-kernel/0302-iwlwifi-rfkill-fix.patch create mode 100644 system/easy-kernel/0304-fix-powerbook6-5-audio.patch delete mode 100644 system/easy-kernel/0504-update-zstd-to-v1_5_5.patch create mode 100644 system/easy-kernel/0504-update-zstd-to-v1_5_6.patch diff --git a/system/easy-kernel/0000-README b/system/easy-kernel/0000-README index ba2ebb04d..67d75ca60 100644 --- a/system/easy-kernel/0000-README +++ b/system/easy-kernel/0000-README @@ -28,10 +28,6 @@ Patchset Sequence Individual Patch Descriptions (0120-1000): -------------------------------------------------------------------------- -File: 0120-XATTR_USER_PREFIX.patch -From: Anthony G. Basile -Desc: Support for namespace user.pax.* on tmpfs. - File: 0122-link-security-restrictions.patch From: Ben Hutchings Desc: Enable link security restrictions by default. @@ -52,18 +48,22 @@ File: 0202-parisc-disable-prctl.patch From: Helge Deller Desc: Disables prctl on PA-RISC/HPPA due to this platform needing executable stacks. -File: 0204-amd-deserialised-MSR-access.patch -From: Borislav Petkov -Desc: Reduces performance penalty on AMD64 processors (Opteron, K8, Athlon64, Sempron) by removing unnecessary synchronisation barrier. +File: 0204-sparc-warray-fix.patch +From: Gustavo A. R. Silva +Desc: Fixes issues with SPARC compilation due to -Warray-bounds -File: 0210-fix-powerbook-6-5-audio.patch -From: Horst Burkhardt -Desc: Enables audio in PowerBook6,4 and PowerBook6,5 iBooks on PowerPC. +File: 0208-gcc14-objtool-fix.patch +From: Sam James +Desc: Fixes to calloc to make gcc14 not chuck a -Walloc hissy fit. File: 0250-expose-per-process-ksm.patch From: Oleksandr Natalenko Desc: Provides a non-prctl interface for per-process KSM to support uksmd. +File: 0252-rectify-ksm-inheritance.patch +From: Stefan Roesch +Desc: Extends prctl interface for per-process KSM to allow proper inheritance of KSM state. + File: 0260-reduce-swappiness.patch From: Horst Burkhardt - originally from -ck patchset by Con Kolivas Desc: Reduces the proclivity of the kernel to page out memory contents to disk. @@ -72,13 +72,17 @@ File: 0262-boot-order.patch From: Peter Jung Desc: Changes graphics bringup to occur after ATA initialisation, saving some time at boot. -File: 0300-tmp513-regression-fix.patch -From: Mike Pagano -Desc: Fix to regression in Kconfig from kernel 5.5.6 to enable tmp513 hardware monitoring module to build. +File: 0300-correct-max98388-includes.patch +From: Linus Walleij +Desc: Fixes includes in MAX98388 ASoC ALSA driver. + +File: 0302-i915-gcc14-fix.patch +From: Sam James +Desc: Adjusts alloc size in drm/i915 to prevent gcc14 hissy fit. -File: 0302-iwlwifi-rfkill-fix.patch -From: Johannes Berg -Desc: Fix issue where rfkill results in kernel lock-up. +File: 0304-fix-powerbook-6-5-audio.patch +From: Horst Burkhardt +Desc: Enables audio in PowerBook6,4 and PowerBook6,5 iBooks on PowerPC. File: 0400-reduce-pageblock-size-nonhugetlb.patch From: Sultan Alsawaf @@ -100,9 +104,9 @@ File: 0502-gcc9-kcflags.patch From: graysky Desc: Enables gcc >=9.1 optimizations for the very latest x86_64 CPUs. -File: 0504-update-zstd-to-v1_5_5.patch +File: 0504-update-zstd-to-v1_5_6.patch From: Piotr Gorski -Desc: Updates kernel Zstandard compression code to upstream 1.5.5 from Meta. +Desc: Updates kernel Zstandard compression code to upstream 1.5.6 from Meta. File: 1000-version.patch From: Horst Burkhardt diff --git a/system/easy-kernel/0100-linux-6.6.58.patch b/system/easy-kernel/0100-linux-6.6.58.patch new file mode 100644 index 000000000..83409c5f7 --- /dev/null +++ b/system/easy-kernel/0100-linux-6.6.58.patch @@ -0,0 +1,506489 @@ +diff --git a/.gitignore b/.gitignore +index 0bbae167bf93e9..d1a8ab3f98aaf1 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -135,7 +135,6 @@ GTAGS + # id-utils files + ID + +-*.orig + *~ + \#*# + +diff --git a/Documentation/ABI/stable/sysfs-block b/Documentation/ABI/stable/sysfs-block +index 1fe9a553c37b71..f0025d1c3d5acd 100644 +--- a/Documentation/ABI/stable/sysfs-block ++++ b/Documentation/ABI/stable/sysfs-block +@@ -101,6 +101,16 @@ Description: + devices that support receiving integrity metadata. + + ++What: /sys/block//partscan ++Date: May 2024 ++Contact: Christoph Hellwig ++Description: ++ The /sys/block//partscan files reports if partition ++ scanning is enabled for the disk. It returns "1" if partition ++ scanning is enabled, or "0" if not. The value type is a 32-bit ++ unsigned integer, but only "0" and "1" are valid values. ++ ++ + What: /sys/block///alignment_offset + Date: April 2009 + Contact: Martin K. Petersen +diff --git a/Documentation/ABI/testing/sysfs-bus-iio-filter-admv8818 b/Documentation/ABI/testing/sysfs-bus-iio-filter-admv8818 +index 31dbb390573ff2..c431f0a13cf502 100644 +--- a/Documentation/ABI/testing/sysfs-bus-iio-filter-admv8818 ++++ b/Documentation/ABI/testing/sysfs-bus-iio-filter-admv8818 +@@ -3,7 +3,7 @@ KernelVersion: + Contact: linux-iio@vger.kernel.org + Description: + Reading this returns the valid values that can be written to the +- on_altvoltage0_mode attribute: ++ filter_mode attribute: + + - auto -> Adjust bandpass filter to track changes in input clock rate. + - manual -> disable/unregister the clock rate notifier / input clock tracking. +diff --git a/Documentation/ABI/testing/sysfs-bus-optee-devices b/Documentation/ABI/testing/sysfs-bus-optee-devices +index 0f58701367b66a..af31e5a22d89fc 100644 +--- a/Documentation/ABI/testing/sysfs-bus-optee-devices ++++ b/Documentation/ABI/testing/sysfs-bus-optee-devices +@@ -6,3 +6,12 @@ Description: + OP-TEE bus provides reference to registered drivers under this directory. The + matches Trusted Application (TA) driver and corresponding TA in secure OS. Drivers + are free to create needed API under optee-ta- directory. ++ ++What: /sys/bus/tee/devices/optee-ta-/need_supplicant ++Date: November 2023 ++KernelVersion: 6.7 ++Contact: op-tee@lists.trustedfirmware.org ++Description: ++ Allows to distinguish whether an OP-TEE based TA/device requires user-space ++ tee-supplicant to function properly or not. This attribute will be present for ++ devices which depend on tee-supplicant to be running. +diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq +index 5e6b74f304062a..1e7e0bb4c14ecb 100644 +--- a/Documentation/ABI/testing/sysfs-class-devfreq ++++ b/Documentation/ABI/testing/sysfs-class-devfreq +@@ -52,6 +52,9 @@ Description: + + echo 0 > /sys/class/devfreq/.../trans_stat + ++ If the transition table is bigger than PAGE_SIZE, reading ++ this will return an -EFBIG error. ++ + What: /sys/class/devfreq/.../available_frequencies + Date: October 2012 + Contact: Nishanth Menon +diff --git a/Documentation/ABI/testing/sysfs-class-led b/Documentation/ABI/testing/sysfs-class-led +index b2ff0012c0f2b8..2e24ac3bd7efa4 100644 +--- a/Documentation/ABI/testing/sysfs-class-led ++++ b/Documentation/ABI/testing/sysfs-class-led +@@ -59,15 +59,6 @@ Description: + brightness. Reading this file when no hw brightness change + event has happened will return an ENODATA error. + +-What: /sys/class/leds//color +-Date: June 2023 +-KernelVersion: 6.5 +-Description: +- Color of the LED. +- +- This is a read-only file. Reading this file returns the color +- of the LED as a string (e.g: "red", "green", "multicolor"). +- + What: /sys/class/leds//trigger + Date: March 2006 + KernelVersion: 2.6.17 +diff --git a/Documentation/ABI/testing/sysfs-class-net-queues b/Documentation/ABI/testing/sysfs-class-net-queues +index 906ff3ca928ac1..5bff64d256c207 100644 +--- a/Documentation/ABI/testing/sysfs-class-net-queues ++++ b/Documentation/ABI/testing/sysfs-class-net-queues +@@ -1,4 +1,4 @@ +-What: /sys/class//queues/rx-/rps_cpus ++What: /sys/class/net//queues/rx-/rps_cpus + Date: March 2010 + KernelVersion: 2.6.35 + Contact: netdev@vger.kernel.org +@@ -8,7 +8,7 @@ Description: + network device queue. Possible values depend on the number + of available CPU(s) in the system. + +-What: /sys/class//queues/rx-/rps_flow_cnt ++What: /sys/class/net//queues/rx-/rps_flow_cnt + Date: April 2010 + KernelVersion: 2.6.35 + Contact: netdev@vger.kernel.org +@@ -16,7 +16,7 @@ Description: + Number of Receive Packet Steering flows being currently + processed by this particular network device receive queue. + +-What: /sys/class//queues/tx-/tx_timeout ++What: /sys/class/net//queues/tx-/tx_timeout + Date: November 2011 + KernelVersion: 3.3 + Contact: netdev@vger.kernel.org +@@ -24,7 +24,7 @@ Description: + Indicates the number of transmit timeout events seen by this + network interface transmit queue. + +-What: /sys/class//queues/tx-/tx_maxrate ++What: /sys/class/net//queues/tx-/tx_maxrate + Date: March 2015 + KernelVersion: 4.1 + Contact: netdev@vger.kernel.org +@@ -32,7 +32,7 @@ Description: + A Mbps max-rate set for the queue, a value of zero means disabled, + default is disabled. + +-What: /sys/class//queues/tx-/xps_cpus ++What: /sys/class/net//queues/tx-/xps_cpus + Date: November 2010 + KernelVersion: 2.6.38 + Contact: netdev@vger.kernel.org +@@ -42,7 +42,7 @@ Description: + network device transmit queue. Possible values depend on the + number of available CPU(s) in the system. + +-What: /sys/class//queues/tx-/xps_rxqs ++What: /sys/class/net//queues/tx-/xps_rxqs + Date: June 2018 + KernelVersion: 4.18.0 + Contact: netdev@vger.kernel.org +@@ -53,7 +53,7 @@ Description: + number of available receive queue(s) in the network device. + Default is disabled. + +-What: /sys/class//queues/tx-/byte_queue_limits/hold_time ++What: /sys/class/net//queues/tx-/byte_queue_limits/hold_time + Date: November 2011 + KernelVersion: 3.3 + Contact: netdev@vger.kernel.org +@@ -62,7 +62,7 @@ Description: + of this particular network device transmit queue. + Default value is 1000. + +-What: /sys/class//queues/tx-/byte_queue_limits/inflight ++What: /sys/class/net//queues/tx-/byte_queue_limits/inflight + Date: November 2011 + KernelVersion: 3.3 + Contact: netdev@vger.kernel.org +@@ -70,7 +70,7 @@ Description: + Indicates the number of bytes (objects) in flight on this + network device transmit queue. + +-What: /sys/class//queues/tx-/byte_queue_limits/limit ++What: /sys/class/net//queues/tx-/byte_queue_limits/limit + Date: November 2011 + KernelVersion: 3.3 + Contact: netdev@vger.kernel.org +@@ -79,7 +79,7 @@ Description: + on this network device transmit queue. This value is clamped + to be within the bounds defined by limit_max and limit_min. + +-What: /sys/class//queues/tx-/byte_queue_limits/limit_max ++What: /sys/class/net//queues/tx-/byte_queue_limits/limit_max + Date: November 2011 + KernelVersion: 3.3 + Contact: netdev@vger.kernel.org +@@ -88,7 +88,7 @@ Description: + queued on this network device transmit queue. See + include/linux/dynamic_queue_limits.h for the default value. + +-What: /sys/class//queues/tx-/byte_queue_limits/limit_min ++What: /sys/class/net//queues/tx-/byte_queue_limits/limit_min + Date: November 2011 + KernelVersion: 3.3 + Contact: netdev@vger.kernel.org +diff --git a/Documentation/ABI/testing/sysfs-class-net-statistics b/Documentation/ABI/testing/sysfs-class-net-statistics +index 55db27815361b2..53e508c6936a51 100644 +--- a/Documentation/ABI/testing/sysfs-class-net-statistics ++++ b/Documentation/ABI/testing/sysfs-class-net-statistics +@@ -1,4 +1,4 @@ +-What: /sys/class//statistics/collisions ++What: /sys/class/net//statistics/collisions + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -6,7 +6,7 @@ Description: + Indicates the number of collisions seen by this network device. + This value might not be relevant with all MAC layers. + +-What: /sys/class//statistics/multicast ++What: /sys/class/net//statistics/multicast + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -14,7 +14,7 @@ Description: + Indicates the number of multicast packets received by this + network device. + +-What: /sys/class//statistics/rx_bytes ++What: /sys/class/net//statistics/rx_bytes + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -23,7 +23,7 @@ Description: + See the network driver for the exact meaning of when this + value is incremented. + +-What: /sys/class//statistics/rx_compressed ++What: /sys/class/net//statistics/rx_compressed + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -32,7 +32,7 @@ Description: + network device. This value might only be relevant for interfaces + that support packet compression (e.g: PPP). + +-What: /sys/class//statistics/rx_crc_errors ++What: /sys/class/net//statistics/rx_crc_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -41,7 +41,7 @@ Description: + by this network device. Note that the specific meaning might + depend on the MAC layer used by the interface. + +-What: /sys/class//statistics/rx_dropped ++What: /sys/class/net//statistics/rx_dropped + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -51,7 +51,7 @@ Description: + packet processing. See the network driver for the exact + meaning of this value. + +-What: /sys/class//statistics/rx_errors ++What: /sys/class/net//statistics/rx_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -59,7 +59,7 @@ Description: + Indicates the number of receive errors on this network device. + See the network driver for the exact meaning of this value. + +-What: /sys/class//statistics/rx_fifo_errors ++What: /sys/class/net//statistics/rx_fifo_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -68,7 +68,7 @@ Description: + network device. See the network driver for the exact + meaning of this value. + +-What: /sys/class//statistics/rx_frame_errors ++What: /sys/class/net//statistics/rx_frame_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -78,7 +78,7 @@ Description: + on the MAC layer protocol used. See the network driver for + the exact meaning of this value. + +-What: /sys/class//statistics/rx_length_errors ++What: /sys/class/net//statistics/rx_length_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -87,7 +87,7 @@ Description: + error, oversized or undersized. See the network driver for the + exact meaning of this value. + +-What: /sys/class//statistics/rx_missed_errors ++What: /sys/class/net//statistics/rx_missed_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -96,7 +96,7 @@ Description: + due to lack of capacity in the receive side. See the network + driver for the exact meaning of this value. + +-What: /sys/class//statistics/rx_nohandler ++What: /sys/class/net//statistics/rx_nohandler + Date: February 2016 + KernelVersion: 4.6 + Contact: netdev@vger.kernel.org +@@ -104,7 +104,7 @@ Description: + Indicates the number of received packets that were dropped on + an inactive device by the network core. + +-What: /sys/class//statistics/rx_over_errors ++What: /sys/class/net//statistics/rx_over_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -114,7 +114,7 @@ Description: + (e.g: larger than MTU). See the network driver for the exact + meaning of this value. + +-What: /sys/class//statistics/rx_packets ++What: /sys/class/net//statistics/rx_packets + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -122,7 +122,7 @@ Description: + Indicates the total number of good packets received by this + network device. + +-What: /sys/class//statistics/tx_aborted_errors ++What: /sys/class/net//statistics/tx_aborted_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -132,7 +132,7 @@ Description: + a medium collision). See the network driver for the exact + meaning of this value. + +-What: /sys/class//statistics/tx_bytes ++What: /sys/class/net//statistics/tx_bytes + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -143,7 +143,7 @@ Description: + transmitted packets or all packets that have been queued for + transmission. + +-What: /sys/class//statistics/tx_carrier_errors ++What: /sys/class/net//statistics/tx_carrier_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -152,7 +152,7 @@ Description: + because of carrier errors (e.g: physical link down). See the + network driver for the exact meaning of this value. + +-What: /sys/class//statistics/tx_compressed ++What: /sys/class/net//statistics/tx_compressed + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -161,7 +161,7 @@ Description: + this might only be relevant for devices that support + compression (e.g: PPP). + +-What: /sys/class//statistics/tx_dropped ++What: /sys/class/net//statistics/tx_dropped + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -170,7 +170,7 @@ Description: + See the driver for the exact reasons as to why the packets were + dropped. + +-What: /sys/class//statistics/tx_errors ++What: /sys/class/net//statistics/tx_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -179,7 +179,7 @@ Description: + a network device. See the driver for the exact reasons as to + why the packets were dropped. + +-What: /sys/class//statistics/tx_fifo_errors ++What: /sys/class/net//statistics/tx_fifo_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -188,7 +188,7 @@ Description: + FIFO error. See the driver for the exact reasons as to why the + packets were dropped. + +-What: /sys/class//statistics/tx_heartbeat_errors ++What: /sys/class/net//statistics/tx_heartbeat_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -197,7 +197,7 @@ Description: + reported as heartbeat errors. See the driver for the exact + reasons as to why the packets were dropped. + +-What: /sys/class//statistics/tx_packets ++What: /sys/class/net//statistics/tx_packets + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +@@ -206,7 +206,7 @@ Description: + device. See the driver for whether this reports the number of all + attempted or successful transmissions. + +-What: /sys/class//statistics/tx_window_errors ++What: /sys/class/net//statistics/tx_window_errors + Date: April 2005 + KernelVersion: 2.6.12 + Contact: netdev@vger.kernel.org +diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu +index 7ecd5c8161a610..657bdee28d845a 100644 +--- a/Documentation/ABI/testing/sysfs-devices-system-cpu ++++ b/Documentation/ABI/testing/sysfs-devices-system-cpu +@@ -519,6 +519,7 @@ What: /sys/devices/system/cpu/vulnerabilities + /sys/devices/system/cpu/vulnerabilities/mds + /sys/devices/system/cpu/vulnerabilities/meltdown + /sys/devices/system/cpu/vulnerabilities/mmio_stale_data ++ /sys/devices/system/cpu/vulnerabilities/reg_file_data_sampling + /sys/devices/system/cpu/vulnerabilities/retbleed + /sys/devices/system/cpu/vulnerabilities/spec_store_bypass + /sys/devices/system/cpu/vulnerabilities/spectre_v1 +@@ -564,7 +565,8 @@ Description: Control Symmetric Multi Threading (SMT) + ================ ========================================= + + If control status is "forceoff" or "notsupported" writes +- are rejected. ++ are rejected. Note that enabling SMT on PowerPC skips ++ offline cores. + + What: /sys/devices/system/cpu/cpuX/power/energy_perf_bias + Date: March 2019 +diff --git a/Documentation/ABI/testing/sysfs-driver-qat b/Documentation/ABI/testing/sysfs-driver-qat +index ef6d6c57105efb..96834d103a09e2 100644 +--- a/Documentation/ABI/testing/sysfs-driver-qat ++++ b/Documentation/ABI/testing/sysfs-driver-qat +@@ -29,6 +29,8 @@ Description: (RW) Reports the current configuration of the QAT device. + services + * asym;sym: identical to sym;asym + * dc: the device is configured for running compression services ++ * dcc: identical to dc but enables the dc chaining feature, ++ hash then compression. If this is not required chose dc + * sym: the device is configured for running symmetric crypto + services + * asym: the device is configured for running asymmetric crypto +diff --git a/Documentation/admin-guide/abi-obsolete.rst b/Documentation/admin-guide/abi-obsolete.rst +index d095867899c59a..594e697aa1b2f4 100644 +--- a/Documentation/admin-guide/abi-obsolete.rst ++++ b/Documentation/admin-guide/abi-obsolete.rst +@@ -7,5 +7,5 @@ marked to be removed at some later point in time. + The description of the interface will document the reason why it is + obsolete and when it can be expected to be removed. + +-.. kernel-abi:: $srctree/Documentation/ABI/obsolete ++.. kernel-abi:: ABI/obsolete + :rst: +diff --git a/Documentation/admin-guide/abi-removed.rst b/Documentation/admin-guide/abi-removed.rst +index f7e9e43023c136..f9e000c81828e5 100644 +--- a/Documentation/admin-guide/abi-removed.rst ++++ b/Documentation/admin-guide/abi-removed.rst +@@ -1,5 +1,5 @@ + ABI removed symbols + =================== + +-.. kernel-abi:: $srctree/Documentation/ABI/removed ++.. kernel-abi:: ABI/removed + :rst: +diff --git a/Documentation/admin-guide/abi-stable.rst b/Documentation/admin-guide/abi-stable.rst +index 70490736e0d301..fc3361d847b123 100644 +--- a/Documentation/admin-guide/abi-stable.rst ++++ b/Documentation/admin-guide/abi-stable.rst +@@ -10,5 +10,5 @@ for at least 2 years. + Most interfaces (like syscalls) are expected to never change and always + be available. + +-.. kernel-abi:: $srctree/Documentation/ABI/stable ++.. kernel-abi:: ABI/stable + :rst: +diff --git a/Documentation/admin-guide/abi-testing.rst b/Documentation/admin-guide/abi-testing.rst +index b205b16a72d08a..19767926b34407 100644 +--- a/Documentation/admin-guide/abi-testing.rst ++++ b/Documentation/admin-guide/abi-testing.rst +@@ -16,5 +16,5 @@ Programs that use these interfaces are strongly encouraged to add their + name to the description of these interfaces, so that the kernel + developers can easily notify them if any changes occur. + +-.. kernel-abi:: $srctree/Documentation/ABI/testing ++.. kernel-abi:: ABI/testing + :rst: +diff --git a/Documentation/admin-guide/cifs/usage.rst b/Documentation/admin-guide/cifs/usage.rst +index 5f936b4b601881..3de599cf0779a9 100644 +--- a/Documentation/admin-guide/cifs/usage.rst ++++ b/Documentation/admin-guide/cifs/usage.rst +@@ -722,40 +722,26 @@ Configuration pseudo-files: + ======================= ======================================================= + SecurityFlags Flags which control security negotiation and + also packet signing. Authentication (may/must) +- flags (e.g. for NTLM and/or NTLMv2) may be combined with ++ flags (e.g. for NTLMv2) may be combined with + the signing flags. Specifying two different password + hashing mechanisms (as "must use") on the other hand + does not make much sense. Default flags are:: + +- 0x07007 +- +- (NTLM, NTLMv2 and packet signing allowed). The maximum +- allowable flags if you want to allow mounts to servers +- using weaker password hashes is 0x37037 (lanman, +- plaintext, ntlm, ntlmv2, signing allowed). Some +- SecurityFlags require the corresponding menuconfig +- options to be enabled. Enabling plaintext +- authentication currently requires also enabling +- lanman authentication in the security flags +- because the cifs module only supports sending +- laintext passwords using the older lanman dialect +- form of the session setup SMB. (e.g. for authentication +- using plain text passwords, set the SecurityFlags +- to 0x30030):: ++ 0x00C5 ++ ++ (NTLMv2 and packet signing allowed). Some SecurityFlags ++ may require enabling a corresponding menuconfig option. + + may use packet signing 0x00001 + must use packet signing 0x01001 +- may use NTLM (most common password hash) 0x00002 +- must use NTLM 0x02002 + may use NTLMv2 0x00004 + must use NTLMv2 0x04004 +- may use Kerberos security 0x00008 +- must use Kerberos 0x08008 +- may use lanman (weak) password hash 0x00010 +- must use lanman password hash 0x10010 +- may use plaintext passwords 0x00020 +- must use plaintext passwords 0x20020 +- (reserved for future packet encryption) 0x00040 ++ may use Kerberos security (krb5) 0x00008 ++ must use Kerberos 0x08008 ++ may use NTLMSSP 0x00080 ++ must use NTLMSSP 0x80080 ++ seal (packet encryption) 0x00040 ++ must seal 0x40040 + + cifsFYI If set to non-zero value, additional debug information + will be logged to the system error log. This field +diff --git a/Documentation/admin-guide/features.rst b/Documentation/admin-guide/features.rst +index 8c167082a84f9e..7651eca38227d0 100644 +--- a/Documentation/admin-guide/features.rst ++++ b/Documentation/admin-guide/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features ++.. kernel-feat:: features +diff --git a/Documentation/admin-guide/hw-vuln/core-scheduling.rst b/Documentation/admin-guide/hw-vuln/core-scheduling.rst +index cf1eeefdfc32f3..a92e10ec402e7d 100644 +--- a/Documentation/admin-guide/hw-vuln/core-scheduling.rst ++++ b/Documentation/admin-guide/hw-vuln/core-scheduling.rst +@@ -67,8 +67,8 @@ arg4: + will be performed for all tasks in the task group of ``pid``. + + arg5: +- userspace pointer to an unsigned long for storing the cookie returned by +- ``PR_SCHED_CORE_GET`` command. Should be 0 for all other commands. ++ userspace pointer to an unsigned long long for storing the cookie returned ++ by ``PR_SCHED_CORE_GET`` command. Should be 0 for all other commands. + + In order for a process to push a cookie to, or pull a cookie from a process, it + is required to have the ptrace access mode: `PTRACE_MODE_READ_REALCREDS` to the +diff --git a/Documentation/admin-guide/hw-vuln/index.rst b/Documentation/admin-guide/hw-vuln/index.rst +index de99caabf65a3f..ff0b440ef2dc90 100644 +--- a/Documentation/admin-guide/hw-vuln/index.rst ++++ b/Documentation/admin-guide/hw-vuln/index.rst +@@ -21,3 +21,4 @@ are configurable at compile, boot or run time. + cross-thread-rsb + srso + gather_data_sampling ++ reg-file-data-sampling +diff --git a/Documentation/admin-guide/hw-vuln/reg-file-data-sampling.rst b/Documentation/admin-guide/hw-vuln/reg-file-data-sampling.rst +new file mode 100644 +index 00000000000000..0585d02b9a6cbc +--- /dev/null ++++ b/Documentation/admin-guide/hw-vuln/reg-file-data-sampling.rst +@@ -0,0 +1,104 @@ ++================================== ++Register File Data Sampling (RFDS) ++================================== ++ ++Register File Data Sampling (RFDS) is a microarchitectural vulnerability that ++only affects Intel Atom parts(also branded as E-cores). RFDS may allow ++a malicious actor to infer data values previously used in floating point ++registers, vector registers, or integer registers. RFDS does not provide the ++ability to choose which data is inferred. CVE-2023-28746 is assigned to RFDS. ++ ++Affected Processors ++=================== ++Below is the list of affected Intel processors [#f1]_: ++ ++ =================== ============ ++ Common name Family_Model ++ =================== ============ ++ ATOM_GOLDMONT 06_5CH ++ ATOM_GOLDMONT_D 06_5FH ++ ATOM_GOLDMONT_PLUS 06_7AH ++ ATOM_TREMONT_D 06_86H ++ ATOM_TREMONT 06_96H ++ ALDERLAKE 06_97H ++ ALDERLAKE_L 06_9AH ++ ATOM_TREMONT_L 06_9CH ++ RAPTORLAKE 06_B7H ++ RAPTORLAKE_P 06_BAH ++ ATOM_GRACEMONT 06_BEH ++ RAPTORLAKE_S 06_BFH ++ =================== ============ ++ ++As an exception to this table, Intel Xeon E family parts ALDERLAKE(06_97H) and ++RAPTORLAKE(06_B7H) codenamed Catlow are not affected. They are reported as ++vulnerable in Linux because they share the same family/model with an affected ++part. Unlike their affected counterparts, they do not enumerate RFDS_CLEAR or ++CPUID.HYBRID. This information could be used to distinguish between the ++affected and unaffected parts, but it is deemed not worth adding complexity as ++the reporting is fixed automatically when these parts enumerate RFDS_NO. ++ ++Mitigation ++========== ++Intel released a microcode update that enables software to clear sensitive ++information using the VERW instruction. Like MDS, RFDS deploys the same ++mitigation strategy to force the CPU to clear the affected buffers before an ++attacker can extract the secrets. This is achieved by using the otherwise ++unused and obsolete VERW instruction in combination with a microcode update. ++The microcode clears the affected CPU buffers when the VERW instruction is ++executed. ++ ++Mitigation points ++----------------- ++VERW is executed by the kernel before returning to user space, and by KVM ++before VMentry. None of the affected cores support SMT, so VERW is not required ++at C-state transitions. ++ ++New bits in IA32_ARCH_CAPABILITIES ++---------------------------------- ++Newer processors and microcode update on existing affected processors added new ++bits to IA32_ARCH_CAPABILITIES MSR. These bits can be used to enumerate ++vulnerability and mitigation capability: ++ ++- Bit 27 - RFDS_NO - When set, processor is not affected by RFDS. ++- Bit 28 - RFDS_CLEAR - When set, processor is affected by RFDS, and has the ++ microcode that clears the affected buffers on VERW execution. ++ ++Mitigation control on the kernel command line ++--------------------------------------------- ++The kernel command line allows to control RFDS mitigation at boot time with the ++parameter "reg_file_data_sampling=". The valid arguments are: ++ ++ ========== ================================================================= ++ on If the CPU is vulnerable, enable mitigation; CPU buffer clearing ++ on exit to userspace and before entering a VM. ++ off Disables mitigation. ++ ========== ================================================================= ++ ++Mitigation default is selected by CONFIG_MITIGATION_RFDS. ++ ++Mitigation status information ++----------------------------- ++The Linux kernel provides a sysfs interface to enumerate the current ++vulnerability status of the system: whether the system is vulnerable, and ++which mitigations are active. The relevant sysfs file is: ++ ++ /sys/devices/system/cpu/vulnerabilities/reg_file_data_sampling ++ ++The possible values in this file are: ++ ++ .. list-table:: ++ ++ * - 'Not affected' ++ - The processor is not vulnerable ++ * - 'Vulnerable' ++ - The processor is vulnerable, but no mitigation enabled ++ * - 'Vulnerable: No microcode' ++ - The processor is vulnerable but microcode is not updated. ++ * - 'Mitigation: Clear Register File' ++ - The processor is vulnerable and the CPU buffer clearing mitigation is ++ enabled. ++ ++References ++---------- ++.. [#f1] Affected Processors ++ https://www.intel.com/content/www/us/en/developer/topic-technology/software-security-guidance/processors-affected-consolidated-product-cpu-model.html +diff --git a/Documentation/admin-guide/hw-vuln/spectre.rst b/Documentation/admin-guide/hw-vuln/spectre.rst +index 32a8893e561776..e0a1be97fa7598 100644 +--- a/Documentation/admin-guide/hw-vuln/spectre.rst ++++ b/Documentation/admin-guide/hw-vuln/spectre.rst +@@ -138,11 +138,10 @@ associated with the source address of the indirect branch. Specifically, + the BHB might be shared across privilege levels even in the presence of + Enhanced IBRS. + +-Currently the only known real-world BHB attack vector is via +-unprivileged eBPF. Therefore, it's highly recommended to not enable +-unprivileged eBPF, especially when eIBRS is used (without retpolines). +-For a full mitigation against BHB attacks, it's recommended to use +-retpolines (or eIBRS combined with retpolines). ++Previously the only known real-world BHB attack vector was via unprivileged ++eBPF. Further research has found attacks that don't require unprivileged eBPF. ++For a full mitigation against BHB attacks it is recommended to set BHI_DIS_S or ++use the BHB clearing sequence. + + Attack scenarios + ---------------- +@@ -430,6 +429,23 @@ The possible values in this file are: + 'PBRSB-eIBRS: Not affected' CPU is not affected by PBRSB + =========================== ======================================================= + ++ - Branch History Injection (BHI) protection status: ++ ++.. list-table:: ++ ++ * - BHI: Not affected ++ - System is not affected ++ * - BHI: Retpoline ++ - System is protected by retpoline ++ * - BHI: BHI_DIS_S ++ - System is protected by BHI_DIS_S ++ * - BHI: SW loop, KVM SW loop ++ - System is protected by software clearing sequence ++ * - BHI: Vulnerable ++ - System is vulnerable to BHI ++ * - BHI: Vulnerable, KVM: SW loop ++ - System is vulnerable; KVM is protected by software clearing sequence ++ + Full mitigation might require a microcode update from the CPU + vendor. When the necessary microcode is not available, the kernel will + report vulnerability. +@@ -484,7 +500,11 @@ Spectre variant 2 + + Systems which support enhanced IBRS (eIBRS) enable IBRS protection once at + boot, by setting the IBRS bit, and they're automatically protected against +- Spectre v2 variant attacks. ++ some Spectre v2 variant attacks. The BHB can still influence the choice of ++ indirect branch predictor entry, and although branch predictor entries are ++ isolated between modes when eIBRS is enabled, the BHB itself is not isolated ++ between modes. Systems which support BHI_DIS_S will set it to protect against ++ BHI attacks. + + On Intel's enhanced IBRS systems, this includes cross-thread branch target + injections on SMT systems (STIBP). In other words, Intel eIBRS enables +@@ -638,6 +658,18 @@ kernel command line. + spectre_v2=off. Spectre variant 1 mitigations + cannot be disabled. + ++ spectre_bhi= ++ ++ [X86] Control mitigation of Branch History Injection ++ (BHI) vulnerability. This setting affects the deployment ++ of the HW BHI control and the SW BHB clearing sequence. ++ ++ on ++ (default) Enable the HW or SW mitigation as ++ needed. ++ off ++ Disable the mitigation. ++ + For spectre_v2_user see Documentation/admin-guide/kernel-parameters.txt + + Mitigation selection guide +diff --git a/Documentation/admin-guide/hw-vuln/srso.rst b/Documentation/admin-guide/hw-vuln/srso.rst +index b6cfb51cb0b469..e715bfc09879a7 100644 +--- a/Documentation/admin-guide/hw-vuln/srso.rst ++++ b/Documentation/admin-guide/hw-vuln/srso.rst +@@ -46,12 +46,22 @@ The possible values in this file are: + + The processor is not vulnerable + +- * 'Vulnerable: no microcode': ++* 'Vulnerable': ++ ++ The processor is vulnerable and no mitigations have been applied. ++ ++ * 'Vulnerable: No microcode': + + The processor is vulnerable, no microcode extending IBPB + functionality to address the vulnerability has been applied. + +- * 'Mitigation: microcode': ++ * 'Vulnerable: Safe RET, no microcode': ++ ++ The "Safe RET" mitigation (see below) has been applied to protect the ++ kernel, but the IBPB-extending microcode has not been applied. User ++ space tasks may still be vulnerable. ++ ++ * 'Vulnerable: Microcode, no safe RET': + + Extended IBPB functionality microcode patch has been applied. It does + not address User->Kernel and Guest->Host transitions protection but it +@@ -72,11 +82,11 @@ The possible values in this file are: + + (spec_rstack_overflow=microcode) + +- * 'Mitigation: safe RET': ++ * 'Mitigation: Safe RET': + +- Software-only mitigation. It complements the extended IBPB microcode +- patch functionality by addressing User->Kernel and Guest->Host +- transitions protection. ++ Combined microcode/software mitigation. It complements the ++ extended IBPB microcode patch functionality by addressing ++ User->Kernel and Guest->Host transitions protection. + + Selected by default or by spec_rstack_overflow=safe-ret + +@@ -129,7 +139,7 @@ an indrect branch prediction barrier after having applied the required + microcode patch for one's system. This mitigation comes also at + a performance cost. + +-Mitigation: safe RET ++Mitigation: Safe RET + -------------------- + + The mitigation works by ensuring all RET instructions speculate to +diff --git a/Documentation/admin-guide/kdump/vmcoreinfo.rst b/Documentation/admin-guide/kdump/vmcoreinfo.rst +index 599e8d3bcbc318..9235cf4fbabff0 100644 +--- a/Documentation/admin-guide/kdump/vmcoreinfo.rst ++++ b/Documentation/admin-guide/kdump/vmcoreinfo.rst +@@ -172,7 +172,7 @@ variables. + Offset of the free_list's member. This value is used to compute the number + of free pages. + +-Each zone has a free_area structure array called free_area[MAX_ORDER + 1]. ++Each zone has a free_area structure array called free_area[NR_PAGE_ORDERS]. + The free_list represents a linked list of free page blocks. + + (list_head, next|prev) +@@ -189,8 +189,8 @@ Offsets of the vmap_area's members. They carry vmalloc-specific + information. Makedumpfile gets the start address of the vmalloc region + from this. + +-(zone.free_area, MAX_ORDER + 1) +-------------------------------- ++(zone.free_area, NR_PAGE_ORDERS) ++-------------------------------- + + Free areas descriptor. User-space tools use this value to iterate the + free_area ranges. MAX_ORDER is used by the zone buddy allocator. +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index 0a1731a0f0ef37..d83a3f47e20074 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -664,12 +664,6 @@ + loops can be debugged more effectively on production + systems. + +- clocksource.max_cswd_read_retries= [KNL] +- Number of clocksource_watchdog() retries due to +- external delays before the clock will be marked +- unstable. Defaults to two retries, that is, +- three attempts to read the clock under test. +- + clocksource.verify_n_cpus= [KNL] + Limit the number of CPUs checked for clocksources + marked with CLOCK_SOURCE_VERIFY_PERCPU that +@@ -1133,6 +1127,26 @@ + The filter can be disabled or changed to another + driver later using sysfs. + ++ reg_file_data_sampling= ++ [X86] Controls mitigation for Register File Data ++ Sampling (RFDS) vulnerability. RFDS is a CPU ++ vulnerability which may allow userspace to infer ++ kernel data values previously stored in floating point ++ registers, vector registers, or integer registers. ++ RFDS only affects Intel Atom processors. ++ ++ on: Turns ON the mitigation. ++ off: Turns OFF the mitigation. ++ ++ This parameter overrides the compile time default set ++ by CONFIG_MITIGATION_RFDS. Mitigation cannot be ++ disabled when other VERW based mitigations (like MDS) ++ are enabled. In order to disable RFDS mitigation all ++ VERW based mitigations need to be disabled. ++ ++ For details see: ++ Documentation/admin-guide/hw-vuln/reg-file-data-sampling.rst ++ + driver_async_probe= [KNL] + List of driver names to be probed asynchronously. * + matches with all driver names. If * is specified, the +@@ -3249,9 +3263,7 @@ + + mem_encrypt= [X86-64] AMD Secure Memory Encryption (SME) control + Valid arguments: on, off +- Default (depends on kernel configuration option): +- on (CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT=y) +- off (CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT=n) ++ Default: off + mem_encrypt=on: Activate SME + mem_encrypt=off: Do not activate SME + +@@ -3305,6 +3317,9 @@ + arch-independent options, each of which is an + aggregation of existing arch-specific options. + ++ Note, "mitigations" is supported if and only if the ++ kernel was built with CPU_MITIGATIONS=y. ++ + off + Disable all optional CPU mitigations. This + improves system performance, but it may also +@@ -3322,8 +3337,10 @@ + nospectre_bhb [ARM64] + nospectre_v1 [X86,PPC] + nospectre_v2 [X86,PPC,S390,ARM64] ++ reg_file_data_sampling=off [X86] + retbleed=off [X86] + spec_store_bypass_disable=off [X86,PPC] ++ spectre_bhi=off [X86] + spectre_v2_user=off [X86] + srbds=off [X86,INTEL] + ssbd=force-off [ARM64] +@@ -4622,6 +4639,16 @@ + printk.time= Show timing data prefixed to each printk message line + Format: (1/Y/y=enable, 0/N/n=disable) + ++ proc_mem.force_override= [KNL] ++ Format: {always | ptrace | never} ++ Traditionally /proc/pid/mem allows memory permissions to be ++ overridden without restrictions. This option may be set to ++ restrict that. Can be one of: ++ - 'always': traditional behavior always allows mem overrides. ++ - 'ptrace': only allow mem overrides for active ptracers. ++ - 'never': never allow mem overrides. ++ If not specified, default is the CONFIG_PROC_MEM_* choice. ++ + processor.max_cstate= [HW,ACPI] + Limit processor to maximum C-state + max_cstate=9 overrides any DMI blacklist limit. +@@ -4632,11 +4659,9 @@ + + profile= [KNL] Enable kernel profiling via /proc/profile + Format: [,] +- Param: : "schedule", "sleep", or "kvm" ++ Param: : "schedule" or "kvm" + [defaults to kernel profiling] + Param: "schedule" - profile schedule points. +- Param: "sleep" - profile D-state sleeping (millisecs). +- Requires CONFIG_SCHEDSTATS + Param: "kvm" - profile VM exits. + Param: - step/bucket size as a power of 2 for + statistical time based profiling. +@@ -5858,6 +5883,13 @@ + This feature may be more efficiently disabled + using the csdlock_debug- kernel parameter. + ++ smp.panic_on_ipistall= [KNL] ++ If a csd_lock_timeout extends for more than ++ the specified number of milliseconds, panic the ++ system. By default, let CSD-lock acquisition ++ take as long as they take. Specifying 300,000 ++ for this value provides a 5-minute timeout. ++ + smsc-ircc2.nopnp [HW] Don't use PNP to discover SMC devices + smsc-ircc2.ircc_cfg= [HW] Device configuration I/O port + smsc-ircc2.ircc_sir= [HW] SIR base I/O port +@@ -5894,6 +5926,15 @@ + sonypi.*= [HW] Sony Programmable I/O Control Device driver + See Documentation/admin-guide/laptops/sonypi.rst + ++ spectre_bhi= [X86] Control mitigation of Branch History Injection ++ (BHI) vulnerability. This setting affects the ++ deployment of the HW BHI control and the SW BHB ++ clearing sequence. ++ ++ on - (default) Enable the HW or SW mitigation ++ as needed. ++ off - Disable the mitigation. ++ + spectre_v2= [X86] Control mitigation of Spectre variant 2 + (indirect branch speculation) vulnerability. + The default operation protects the kernel from +@@ -6817,6 +6858,9 @@ + pause after every control message); + o = USB_QUIRK_HUB_SLOW_RESET (Hub needs extra + delay after resetting its port); ++ p = USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT ++ (Reduce timeout of the SET_ADDRESS ++ request from 5000 ms to 500 ms); + Example: quirks=0781:5580:bk,0a5c:5834:gij + + usbhid.mousepoll= +diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst +index 8da1b728182733..9285f69f4f7355 100644 +--- a/Documentation/admin-guide/mm/damon/usage.rst ++++ b/Documentation/admin-guide/mm/damon/usage.rst +@@ -389,7 +389,7 @@ pages of all memory cgroups except ``/having_care_already``.:: + # # further filter out all cgroups except one at '/having_care_already' + echo memcg > 1/type + echo /having_care_already > 1/memcg_path +- echo N > 1/matching ++ echo Y > 1/matching + + Note that ``anon`` and ``memcg`` filters are currently supported only when + ``paddr`` `implementation ` is being used. +diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin-guide/sysctl/net.rst +index 4877563241f3bd..5f1748f33d9a20 100644 +--- a/Documentation/admin-guide/sysctl/net.rst ++++ b/Documentation/admin-guide/sysctl/net.rst +@@ -205,6 +205,11 @@ Will increase power usage. + + Default: 0 (off) + ++mem_pcpu_rsv ++------------ ++ ++Per-cpu reserved forward alloc cache size in page units. Default 1MB per CPU. ++ + rmem_default + ------------ + +diff --git a/Documentation/arch/arc/features.rst b/Documentation/arch/arc/features.rst +index b793583d688a46..49ff446ff744cc 100644 +--- a/Documentation/arch/arc/features.rst ++++ b/Documentation/arch/arc/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features arc ++.. kernel-feat:: features arc +diff --git a/Documentation/arch/arm/features.rst b/Documentation/arch/arm/features.rst +index 7414ec03dd157c..0e76aaf68ecab2 100644 +--- a/Documentation/arch/arm/features.rst ++++ b/Documentation/arch/arm/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features arm ++.. kernel-feat:: features arm +diff --git a/Documentation/arch/arm64/features.rst b/Documentation/arch/arm64/features.rst +index dfa4cb3cd3efa5..03321f4309d0be 100644 +--- a/Documentation/arch/arm64/features.rst ++++ b/Documentation/arch/arm64/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features arm64 ++.. kernel-feat:: features arm64 +diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst +index f47f63bcf67c91..3cf806733083c7 100644 +--- a/Documentation/arch/arm64/silicon-errata.rst ++++ b/Documentation/arch/arm64/silicon-errata.rst +@@ -54,6 +54,8 @@ stable kernels. + +----------------+-----------------+-----------------+-----------------------------+ + | Ampere | AmpereOne | AC03_CPU_38 | AMPERE_ERRATUM_AC03_CPU_38 | + +----------------+-----------------+-----------------+-----------------------------+ ++| Ampere | AmpereOne AC04 | AC04_CPU_10 | AMPERE_ERRATUM_AC03_CPU_38 | +++----------------+-----------------+-----------------+-----------------------------+ + +----------------+-----------------+-----------------+-----------------------------+ + | ARM | Cortex-A510 | #2457168 | ARM64_ERRATUM_2457168 | + +----------------+-----------------+-----------------+-----------------------------+ +@@ -71,6 +73,8 @@ stable kernels. + +----------------+-----------------+-----------------+-----------------------------+ + | ARM | Cortex-A510 | #2658417 | ARM64_ERRATUM_2658417 | + +----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Cortex-A510 | #3117295 | ARM64_ERRATUM_3117295 | +++----------------+-----------------+-----------------+-----------------------------+ + | ARM | Cortex-A520 | #2966298 | ARM64_ERRATUM_2966298 | + +----------------+-----------------+-----------------+-----------------------------+ + | ARM | Cortex-A53 | #826319 | ARM64_ERRATUM_826319 | +@@ -117,32 +121,72 @@ stable kernels. + +----------------+-----------------+-----------------+-----------------------------+ + | ARM | Cortex-A76 | #1463225 | ARM64_ERRATUM_1463225 | + +----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Cortex-A76 | #3324349 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ + | ARM | Cortex-A77 | #1508412 | ARM64_ERRATUM_1508412 | + +----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Cortex-A77 | #3324348 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Cortex-A78 | #3324344 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Cortex-A78C | #3324346,3324347| ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ + | ARM | Cortex-A710 | #2119858 | ARM64_ERRATUM_2119858 | + +----------------+-----------------+-----------------+-----------------------------+ + | ARM | Cortex-A710 | #2054223 | ARM64_ERRATUM_2054223 | + +----------------+-----------------+-----------------+-----------------------------+ + | ARM | Cortex-A710 | #2224489 | ARM64_ERRATUM_2224489 | + +----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Cortex-A710 | #3324338 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ + | ARM | Cortex-A715 | #2645198 | ARM64_ERRATUM_2645198 | + +----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Cortex-A715 | #3456084 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Cortex-A720 | #3456091 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Cortex-A725 | #3456106 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Cortex-X1 | #3324344 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Cortex-X1C | #3324346 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ + | ARM | Cortex-X2 | #2119858 | ARM64_ERRATUM_2119858 | + +----------------+-----------------+-----------------+-----------------------------+ + | ARM | Cortex-X2 | #2224489 | ARM64_ERRATUM_2224489 | + +----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Cortex-X2 | #3324338 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Cortex-X3 | #3324335 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Cortex-X4 | #3194386 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Cortex-X925 | #3324334 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ + | ARM | Neoverse-N1 | #1188873,1418040| ARM64_ERRATUM_1418040 | + +----------------+-----------------+-----------------+-----------------------------+ + | ARM | Neoverse-N1 | #1349291 | N/A | + +----------------+-----------------+-----------------+-----------------------------+ + | ARM | Neoverse-N1 | #1542419 | ARM64_ERRATUM_1542419 | + +----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Neoverse-N1 | #3324349 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ + | ARM | Neoverse-N2 | #2139208 | ARM64_ERRATUM_2139208 | + +----------------+-----------------+-----------------+-----------------------------+ + | ARM | Neoverse-N2 | #2067961 | ARM64_ERRATUM_2067961 | + +----------------+-----------------+-----------------+-----------------------------+ + | ARM | Neoverse-N2 | #2253138 | ARM64_ERRATUM_2253138 | + +----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Neoverse-N2 | #3324339 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Neoverse-N3 | #3456111 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Neoverse-V1 | #3324341 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Neoverse-V2 | #3324336 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ ++| ARM | Neoverse-V3 | #3312417 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ + | ARM | MMU-500 | #841119,826419 | N/A | + +----------------+-----------------+-----------------+-----------------------------+ + | ARM | MMU-600 | #1076982,1209401| N/A | +@@ -233,3 +277,12 @@ stable kernels. + +----------------+-----------------+-----------------+-----------------------------+ + | ASR | ASR8601 | #8601001 | N/A | + +----------------+-----------------+-----------------+-----------------------------+ +++----------------+-----------------+-----------------+-----------------------------+ ++| Microsoft | Azure Cobalt 100| #2139208 | ARM64_ERRATUM_2139208 | +++----------------+-----------------+-----------------+-----------------------------+ ++| Microsoft | Azure Cobalt 100| #2067961 | ARM64_ERRATUM_2067961 | +++----------------+-----------------+-----------------+-----------------------------+ ++| Microsoft | Azure Cobalt 100| #2253138 | ARM64_ERRATUM_2253138 | +++----------------+-----------------+-----------------+-----------------------------+ ++| Microsoft | Azure Cobalt 100| #3324339 | ARM64_ERRATUM_3194386 | +++----------------+-----------------+-----------------+-----------------------------+ +diff --git a/Documentation/arch/ia64/features.rst b/Documentation/arch/ia64/features.rst +index d7226fdcf5f8c0..056838d2ab55c5 100644 +--- a/Documentation/arch/ia64/features.rst ++++ b/Documentation/arch/ia64/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features ia64 ++.. kernel-feat:: features ia64 +diff --git a/Documentation/arch/loongarch/features.rst b/Documentation/arch/loongarch/features.rst +index ebacade3ea454e..009f44c7951f8a 100644 +--- a/Documentation/arch/loongarch/features.rst ++++ b/Documentation/arch/loongarch/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features loongarch ++.. kernel-feat:: features loongarch +diff --git a/Documentation/arch/m68k/features.rst b/Documentation/arch/m68k/features.rst +index 5107a21194724e..de7f0ccf7fc8ed 100644 +--- a/Documentation/arch/m68k/features.rst ++++ b/Documentation/arch/m68k/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features m68k ++.. kernel-feat:: features m68k +diff --git a/Documentation/arch/mips/features.rst b/Documentation/arch/mips/features.rst +index 1973d729b29a98..6e0ffe3e735400 100644 +--- a/Documentation/arch/mips/features.rst ++++ b/Documentation/arch/mips/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features mips ++.. kernel-feat:: features mips +diff --git a/Documentation/arch/nios2/features.rst b/Documentation/arch/nios2/features.rst +index 8449e63f69b2b4..89913810ccb5a0 100644 +--- a/Documentation/arch/nios2/features.rst ++++ b/Documentation/arch/nios2/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features nios2 ++.. kernel-feat:: features nios2 +diff --git a/Documentation/arch/openrisc/features.rst b/Documentation/arch/openrisc/features.rst +index 3f7c40d219f2cc..bae2e25adfd642 100644 +--- a/Documentation/arch/openrisc/features.rst ++++ b/Documentation/arch/openrisc/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features openrisc ++.. kernel-feat:: features openrisc +diff --git a/Documentation/arch/parisc/features.rst b/Documentation/arch/parisc/features.rst +index 501d7c45003790..b3aa4d243b9362 100644 +--- a/Documentation/arch/parisc/features.rst ++++ b/Documentation/arch/parisc/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features parisc ++.. kernel-feat:: features parisc +diff --git a/Documentation/arch/s390/features.rst b/Documentation/arch/s390/features.rst +index 57c296a9d8f30d..2883dc95068173 100644 +--- a/Documentation/arch/s390/features.rst ++++ b/Documentation/arch/s390/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features s390 ++.. kernel-feat:: features s390 +diff --git a/Documentation/arch/sh/features.rst b/Documentation/arch/sh/features.rst +index f722af3b6c9934..fae48fe81e9bd0 100644 +--- a/Documentation/arch/sh/features.rst ++++ b/Documentation/arch/sh/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features sh ++.. kernel-feat:: features sh +diff --git a/Documentation/arch/sparc/features.rst b/Documentation/arch/sparc/features.rst +index c0c92468b0fe90..96835b6d598a1a 100644 +--- a/Documentation/arch/sparc/features.rst ++++ b/Documentation/arch/sparc/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features sparc ++.. kernel-feat:: features sparc +diff --git a/Documentation/arch/x86/amd-memory-encryption.rst b/Documentation/arch/x86/amd-memory-encryption.rst +index 934310ce725829..bace87cc9ca2ce 100644 +--- a/Documentation/arch/x86/amd-memory-encryption.rst ++++ b/Documentation/arch/x86/amd-memory-encryption.rst +@@ -87,14 +87,14 @@ The state of SME in the Linux kernel can be documented as follows: + kernel is non-zero). + + SME can also be enabled and activated in the BIOS. If SME is enabled and +-activated in the BIOS, then all memory accesses will be encrypted and it will +-not be necessary to activate the Linux memory encryption support. If the BIOS +-merely enables SME (sets bit 23 of the MSR_AMD64_SYSCFG), then Linux can activate +-memory encryption by default (CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT=y) or +-by supplying mem_encrypt=on on the kernel command line. However, if BIOS does +-not enable SME, then Linux will not be able to activate memory encryption, even +-if configured to do so by default or the mem_encrypt=on command line parameter +-is specified. ++activated in the BIOS, then all memory accesses will be encrypted and it ++will not be necessary to activate the Linux memory encryption support. ++ ++If the BIOS merely enables SME (sets bit 23 of the MSR_AMD64_SYSCFG), ++then memory encryption can be enabled by supplying mem_encrypt=on on the ++kernel command line. However, if BIOS does not enable SME, then Linux ++will not be able to activate memory encryption, even if configured to do ++so by default or the mem_encrypt=on command line parameter is specified. + + Secure Nested Paging (SNP) + ========================== +diff --git a/Documentation/arch/x86/features.rst b/Documentation/arch/x86/features.rst +index b663f15053ce85..a33616346a388c 100644 +--- a/Documentation/arch/x86/features.rst ++++ b/Documentation/arch/x86/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features x86 ++.. kernel-feat:: features x86 +diff --git a/Documentation/arch/x86/mds.rst b/Documentation/arch/x86/mds.rst +index e73fdff62c0aa1..c58c72362911cd 100644 +--- a/Documentation/arch/x86/mds.rst ++++ b/Documentation/arch/x86/mds.rst +@@ -95,6 +95,9 @@ The kernel provides a function to invoke the buffer clearing: + + mds_clear_cpu_buffers() + ++Also macro CLEAR_CPU_BUFFERS can be used in ASM late in exit-to-user path. ++Other than CFLAGS.ZF, this macro doesn't clobber any registers. ++ + The mitigation is invoked on kernel/userspace, hypervisor/guest and C-state + (idle) transitions. + +@@ -138,17 +141,30 @@ Mitigation points + + When transitioning from kernel to user space the CPU buffers are flushed + on affected CPUs when the mitigation is not disabled on the kernel +- command line. The migitation is enabled through the static key +- mds_user_clear. +- +- The mitigation is invoked in prepare_exit_to_usermode() which covers +- all but one of the kernel to user space transitions. The exception +- is when we return from a Non Maskable Interrupt (NMI), which is +- handled directly in do_nmi(). +- +- (The reason that NMI is special is that prepare_exit_to_usermode() can +- enable IRQs. In NMI context, NMIs are blocked, and we don't want to +- enable IRQs with NMIs blocked.) ++ command line. The mitigation is enabled through the feature flag ++ X86_FEATURE_CLEAR_CPU_BUF. ++ ++ The mitigation is invoked just before transitioning to userspace after ++ user registers are restored. This is done to minimize the window in ++ which kernel data could be accessed after VERW e.g. via an NMI after ++ VERW. ++ ++ **Corner case not handled** ++ Interrupts returning to kernel don't clear CPUs buffers since the ++ exit-to-user path is expected to do that anyways. But, there could be ++ a case when an NMI is generated in kernel after the exit-to-user path ++ has cleared the buffers. This case is not handled and NMI returning to ++ kernel don't clear CPU buffers because: ++ ++ 1. It is rare to get an NMI after VERW, but before returning to userspace. ++ 2. For an unprivileged user, there is no known way to make that NMI ++ less rare or target it. ++ 3. It would take a large number of these precisely-timed NMIs to mount ++ an actual attack. There's presumably not enough bandwidth. ++ 4. The NMI in question occurs after a VERW, i.e. when user state is ++ restored and most interesting data is already scrubbed. Whats left ++ is only the data that NMI touches, and that may or may not be of ++ any interest. + + + 2. C-State transition +diff --git a/Documentation/arch/xtensa/features.rst b/Documentation/arch/xtensa/features.rst +index 6b92c7bfa19daa..28dcce1759be4b 100644 +--- a/Documentation/arch/xtensa/features.rst ++++ b/Documentation/arch/xtensa/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features xtensa ++.. kernel-feat:: features xtensa +diff --git a/Documentation/bpf/map_lpm_trie.rst b/Documentation/bpf/map_lpm_trie.rst +index 74d64a30f50073..f9cd579496c9ce 100644 +--- a/Documentation/bpf/map_lpm_trie.rst ++++ b/Documentation/bpf/map_lpm_trie.rst +@@ -17,7 +17,7 @@ significant byte. + + LPM tries may be created with a maximum prefix length that is a multiple + of 8, in the range from 8 to 2048. The key used for lookup and update +-operations is a ``struct bpf_lpm_trie_key``, extended by ++operations is a ``struct bpf_lpm_trie_key_u8``, extended by + ``max_prefixlen/8`` bytes. + + - For IPv4 addresses the data length is 4 bytes +diff --git a/Documentation/cdrom/cdrom-standard.rst b/Documentation/cdrom/cdrom-standard.rst +index 7964fe134277b8..6c1303cff159e1 100644 +--- a/Documentation/cdrom/cdrom-standard.rst ++++ b/Documentation/cdrom/cdrom-standard.rst +@@ -217,7 +217,7 @@ current *struct* is:: + int (*media_changed)(struct cdrom_device_info *, int); + int (*tray_move)(struct cdrom_device_info *, int); + int (*lock_door)(struct cdrom_device_info *, int); +- int (*select_speed)(struct cdrom_device_info *, int); ++ int (*select_speed)(struct cdrom_device_info *, unsigned long); + int (*get_last_session) (struct cdrom_device_info *, + struct cdrom_multisession *); + int (*get_mcn)(struct cdrom_device_info *, struct cdrom_mcn *); +@@ -396,7 +396,7 @@ action need be taken, and the return value should be 0. + + :: + +- int select_speed(struct cdrom_device_info *cdi, int speed) ++ int select_speed(struct cdrom_device_info *cdi, unsigned long speed) + + Some CD-ROM drives are capable of changing their head-speed. There + are several reasons for changing the speed of a CD-ROM drive. Badly +diff --git a/Documentation/conf.py b/Documentation/conf.py +index d4fdf6a3875a83..e385e24fe9e72e 100644 +--- a/Documentation/conf.py ++++ b/Documentation/conf.py +@@ -345,9 +345,9 @@ sys.stderr.write("Using %s theme\n" % html_theme) + html_static_path = ['sphinx-static'] + + # If true, Docutils "smart quotes" will be used to convert quotes and dashes +-# to typographically correct entities. This will convert "--" to "—", +-# which is not always what we want, so disable it. +-smartquotes = False ++# to typographically correct entities. However, conversion of "--" to "—" ++# is not always what we want, so enable only quotes. ++smartquotes_action = 'q' + + # Custom sidebar templates, maps document names to template names. + # Note that the RTD theme ignores this +@@ -383,6 +383,12 @@ latex_elements = { + verbatimhintsturnover=false, + ''', + ++ # ++ # Some of our authors are fond of deep nesting; tell latex to ++ # cope. ++ # ++ 'maxlistdepth': '10', ++ + # For CJK One-half spacing, need to be in front of hyperref + 'extrapackages': r'\usepackage{setspace}', + +diff --git a/Documentation/dev-tools/kselftest.rst b/Documentation/dev-tools/kselftest.rst +index deede972f25479..3ae1b3677d7f3a 100644 +--- a/Documentation/dev-tools/kselftest.rst ++++ b/Documentation/dev-tools/kselftest.rst +@@ -255,9 +255,21 @@ Contributing new tests (details) + + TEST_PROGS_EXTENDED, TEST_GEN_PROGS_EXTENDED mean it is the + executable which is not tested by default. ++ + TEST_FILES, TEST_GEN_FILES mean it is the file which is used by + test. + ++ TEST_INCLUDES is similar to TEST_FILES, it lists files which should be ++ included when exporting or installing the tests, with the following ++ differences: ++ ++ * symlinks to files in other directories are preserved ++ * the part of paths below tools/testing/selftests/ is preserved when ++ copying the files to the output directory ++ ++ TEST_INCLUDES is meant to list dependencies located in other directories of ++ the selftests hierarchy. ++ + * First use the headers inside the kernel source and/or git repo, and then the + system headers. Headers for the kernel release as opposed to headers + installed by the distro on the system should be the primary focus to be able +diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml +index adbfaea3234354..90f31beb80c224 100644 +--- a/Documentation/devicetree/bindings/arm/qcom.yaml ++++ b/Documentation/devicetree/bindings/arm/qcom.yaml +@@ -136,7 +136,7 @@ description: | + There are many devices in the list below that run the standard ChromeOS + bootloader setup and use the open source depthcharge bootloader to boot the + OS. These devices do not use the scheme described above. For details, see: +- https://docs.kernel.org/arm/google/chromebook-boot-flow.html ++ https://docs.kernel.org/arch/arm/google/chromebook-boot-flow.html + + properties: + $nodename: +diff --git a/Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml +index 0999ea07f47bb6..e4576546bf0dbb 100644 +--- a/Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml ++++ b/Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml +@@ -127,6 +127,7 @@ patternProperties: + - qcom,dsi-phy-20nm + - qcom,dsi-phy-28nm-8226 + - qcom,dsi-phy-28nm-hpm ++ - qcom,dsi-phy-28nm-hpm-fam-b + - qcom,dsi-phy-28nm-lp + - qcom,hdmi-phy-8084 + - qcom,hdmi-phy-8660 +diff --git a/Documentation/devicetree/bindings/dma/fsl,edma.yaml b/Documentation/devicetree/bindings/dma/fsl,edma.yaml +index 437db0c62339fa..e1b4b910044b0e 100644 +--- a/Documentation/devicetree/bindings/dma/fsl,edma.yaml ++++ b/Documentation/devicetree/bindings/dma/fsl,edma.yaml +@@ -47,8 +47,8 @@ properties: + - 3 + + dma-channels: +- minItems: 1 +- maxItems: 64 ++ minimum: 1 ++ maximum: 64 + + clocks: + minItems: 1 +diff --git a/Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml b/Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml +index c1060e5fcef3a9..d3d8a2e143ed25 100644 +--- a/Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml ++++ b/Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml +@@ -126,7 +126,7 @@ examples: + - | + #include + +- gpio@e000a000 { ++ gpio@a0020000 { + compatible = "xlnx,xps-gpio-1.00.a"; + reg = <0xa0020000 0x10000>; + #gpio-cells = <2>; +diff --git a/Documentation/devicetree/bindings/i2c/atmel,at91sam-i2c.yaml b/Documentation/devicetree/bindings/i2c/atmel,at91sam-i2c.yaml +index 6adedd3ec399b9..c22e459c175abf 100644 +--- a/Documentation/devicetree/bindings/i2c/atmel,at91sam-i2c.yaml ++++ b/Documentation/devicetree/bindings/i2c/atmel,at91sam-i2c.yaml +@@ -75,7 +75,7 @@ required: + - clocks + + allOf: +- - $ref: i2c-controller.yaml ++ - $ref: /schemas/i2c/i2c-controller.yaml# + - if: + properties: + compatible: +diff --git a/Documentation/devicetree/bindings/i2c/google,cros-ec-i2c-tunnel.yaml b/Documentation/devicetree/bindings/i2c/google,cros-ec-i2c-tunnel.yaml +index ab151c9db21913..580003cdfff59e 100644 +--- a/Documentation/devicetree/bindings/i2c/google,cros-ec-i2c-tunnel.yaml ++++ b/Documentation/devicetree/bindings/i2c/google,cros-ec-i2c-tunnel.yaml +@@ -21,7 +21,7 @@ description: | + google,cros-ec-spi or google,cros-ec-i2c. + + allOf: +- - $ref: i2c-controller.yaml# ++ - $ref: /schemas/i2c/i2c-controller.yaml# + + properties: + compatible: +diff --git a/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml b/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml +index 9996dd93f84b29..e1f450b80db278 100644 +--- a/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml ++++ b/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml +@@ -28,6 +28,9 @@ properties: + reg: + maxItems: 1 + ++ clocks: ++ maxItems: 1 ++ + dmas: + maxItems: 1 + +@@ -39,12 +42,16 @@ properties: + $ref: /schemas/types.yaml#/definitions/phandle + description: + A reference to a the actual ADC to which this FPGA ADC interfaces to. ++ deprecated: true ++ ++ '#io-backend-cells': ++ const: 0 + + required: + - compatible + - dmas + - reg +- - adi,adc-dev ++ - clocks + + additionalProperties: false + +@@ -55,7 +62,7 @@ examples: + reg = <0x44a00000 0x10000>; + dmas = <&rx_dma 0>; + dma-names = "rx"; +- +- adi,adc-dev = <&spi_adc>; ++ clocks = <&axi_clk>; ++ #io-backend-cells = <0>; + }; + ... +diff --git a/Documentation/devicetree/bindings/iio/health/maxim,max30102.yaml b/Documentation/devicetree/bindings/iio/health/maxim,max30102.yaml +index c13c10c8d65da2..eed0df9d3a2322 100644 +--- a/Documentation/devicetree/bindings/iio/health/maxim,max30102.yaml ++++ b/Documentation/devicetree/bindings/iio/health/maxim,max30102.yaml +@@ -42,7 +42,7 @@ allOf: + properties: + compatible: + contains: +- const: maxim,max30100 ++ const: maxim,max30102 + then: + properties: + maxim,green-led-current-microamp: false +diff --git a/Documentation/devicetree/bindings/iio/magnetometer/asahi-kasei,ak8975.yaml b/Documentation/devicetree/bindings/iio/magnetometer/asahi-kasei,ak8975.yaml +index 9790f75fc669ef..fe5145d3b73cf2 100644 +--- a/Documentation/devicetree/bindings/iio/magnetometer/asahi-kasei,ak8975.yaml ++++ b/Documentation/devicetree/bindings/iio/magnetometer/asahi-kasei,ak8975.yaml +@@ -23,7 +23,6 @@ properties: + - ak8963 + - ak09911 + - ak09912 +- - ak09916 + deprecated: true + + reg: +diff --git a/Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.yaml b/Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.yaml +index 509d20c091af82..6a206111d4e0f0 100644 +--- a/Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.yaml ++++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.yaml +@@ -62,6 +62,9 @@ properties: + - description: MPM pin number + - description: GIC SPI number for the MPM pin + ++ '#power-domain-cells': ++ const: 0 ++ + required: + - compatible + - reg +@@ -93,4 +96,5 @@ examples: + <86 183>, + <90 260>, + <91 260>; ++ #power-domain-cells = <0>; + }; +diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml +index cf456f8d9ddcb8..c87677f5e2a250 100644 +--- a/Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml ++++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml +@@ -37,15 +37,15 @@ properties: + active low. + maxItems: 1 + +- dovdd-supply: ++ DOVDD-supply: + description: + Definition of the regulator used as interface power supply. + +- avdd-supply: ++ AVDD-supply: + description: + Definition of the regulator used as analog power supply. + +- dvdd-supply: ++ DVDD-supply: + description: + Definition of the regulator used as digital power supply. + +@@ -59,9 +59,9 @@ required: + - reg + - clocks + - clock-names +- - dovdd-supply +- - avdd-supply +- - dvdd-supply ++ - DOVDD-supply ++ - AVDD-supply ++ - DVDD-supply + - reset-gpios + - port + +@@ -82,9 +82,9 @@ examples: + clock-names = "xvclk"; + reset-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>; + +- dovdd-supply = <&sw2_reg>; +- dvdd-supply = <&sw2_reg>; +- avdd-supply = <®_peri_3p15v>; ++ DOVDD-supply = <&sw2_reg>; ++ DVDD-supply = <&sw2_reg>; ++ AVDD-supply = <®_peri_3p15v>; + + port { + ov2680_to_mipi: endpoint { +diff --git a/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml b/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml +index 7032c7e1503900..3e128733ef535b 100644 +--- a/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml ++++ b/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml +@@ -61,6 +61,9 @@ properties: + - description: used for 1st data pipe from RDMA + - description: used for 2nd data pipe from RDMA + ++ '#dma-cells': ++ const: 1 ++ + required: + - compatible + - reg +@@ -70,6 +73,7 @@ required: + - clocks + - iommus + - mboxes ++ - '#dma-cells' + + additionalProperties: false + +@@ -80,16 +84,17 @@ examples: + #include + #include + +- mdp3_rdma0: mdp3-rdma0@14001000 { +- compatible = "mediatek,mt8183-mdp3-rdma"; +- reg = <0x14001000 0x1000>; +- mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x1000 0x1000>; +- mediatek,gce-events = , +- ; +- power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; +- clocks = <&mmsys CLK_MM_MDP_RDMA0>, +- <&mmsys CLK_MM_MDP_RSZ1>; +- iommus = <&iommu>; +- mboxes = <&gce 20 CMDQ_THR_PRIO_LOWEST>, +- <&gce 21 CMDQ_THR_PRIO_LOWEST>; ++ dma-controller@14001000 { ++ compatible = "mediatek,mt8183-mdp3-rdma"; ++ reg = <0x14001000 0x1000>; ++ mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x1000 0x1000>; ++ mediatek,gce-events = , ++ ; ++ power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; ++ clocks = <&mmsys CLK_MM_MDP_RDMA0>, ++ <&mmsys CLK_MM_MDP_RSZ1>; ++ iommus = <&iommu>; ++ mboxes = <&gce 20 CMDQ_THR_PRIO_LOWEST>, ++ <&gce 21 CMDQ_THR_PRIO_LOWEST>; ++ #dma-cells = <1>; + }; +diff --git a/Documentation/devicetree/bindings/media/mediatek,mdp3-wrot.yaml b/Documentation/devicetree/bindings/media/mediatek,mdp3-wrot.yaml +index 0baa77198fa217..64ea98aa05928e 100644 +--- a/Documentation/devicetree/bindings/media/mediatek,mdp3-wrot.yaml ++++ b/Documentation/devicetree/bindings/media/mediatek,mdp3-wrot.yaml +@@ -50,6 +50,9 @@ properties: + iommus: + maxItems: 1 + ++ '#dma-cells': ++ const: 1 ++ + required: + - compatible + - reg +@@ -58,6 +61,7 @@ required: + - power-domains + - clocks + - iommus ++ - '#dma-cells' + + additionalProperties: false + +@@ -68,13 +72,14 @@ examples: + #include + #include + +- mdp3_wrot0: mdp3-wrot0@14005000 { +- compatible = "mediatek,mt8183-mdp3-wrot"; +- reg = <0x14005000 0x1000>; +- mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x5000 0x1000>; +- mediatek,gce-events = , +- ; +- power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; +- clocks = <&mmsys CLK_MM_MDP_WROT0>; +- iommus = <&iommu>; ++ dma-controller@14005000 { ++ compatible = "mediatek,mt8183-mdp3-wrot"; ++ reg = <0x14005000 0x1000>; ++ mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x5000 0x1000>; ++ mediatek,gce-events = , ++ ; ++ power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; ++ clocks = <&mmsys CLK_MM_MDP_WROT0>; ++ iommus = <&iommu>; ++ #dma-cells = <1>; + }; +diff --git a/Documentation/devicetree/bindings/media/rockchip-isp1.yaml b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml +index e466dff8286d2b..afcaa427d48b09 100644 +--- a/Documentation/devicetree/bindings/media/rockchip-isp1.yaml ++++ b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml +@@ -90,15 +90,16 @@ properties: + description: connection point for input on the parallel interface + + properties: +- bus-type: +- enum: [5, 6] +- + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + +- required: +- - bus-type ++ properties: ++ bus-type: ++ enum: [5, 6] ++ ++ required: ++ - bus-type + + anyOf: + - required: +diff --git a/Documentation/devicetree/bindings/mfd/mt6397.txt b/Documentation/devicetree/bindings/mfd/mt6397.txt +index 294693a8906cf5..10540aa7afa1af 100644 +--- a/Documentation/devicetree/bindings/mfd/mt6397.txt ++++ b/Documentation/devicetree/bindings/mfd/mt6397.txt +@@ -22,8 +22,9 @@ compatible: + "mediatek,mt6323" for PMIC MT6323 + "mediatek,mt6331" for PMIC MT6331 and MT6332 + "mediatek,mt6357" for PMIC MT6357 +- "mediatek,mt6358" for PMIC MT6358 and MT6366 ++ "mediatek,mt6358" for PMIC MT6358 + "mediatek,mt6359" for PMIC MT6359 ++ "mediatek,mt6366", "mediatek,mt6358" for PMIC MT6366 + "mediatek,mt6397" for PMIC MT6397 + + Optional subnodes: +@@ -40,6 +41,7 @@ Optional subnodes: + - compatible: "mediatek,mt6323-regulator" + see ../regulator/mt6323-regulator.txt + - compatible: "mediatek,mt6358-regulator" ++ - compatible: "mediatek,mt6366-regulator", "mediatek-mt6358-regulator" + see ../regulator/mt6358-regulator.txt + - compatible: "mediatek,mt6397-regulator" + see ../regulator/mt6397-regulator.txt +diff --git a/Documentation/devicetree/bindings/net/mediatek,net.yaml b/Documentation/devicetree/bindings/net/mediatek,net.yaml +index e74502a0afe867..3202dc7967c5b6 100644 +--- a/Documentation/devicetree/bindings/net/mediatek,net.yaml ++++ b/Documentation/devicetree/bindings/net/mediatek,net.yaml +@@ -337,8 +337,8 @@ allOf: + minItems: 4 + + clocks: +- minItems: 34 +- maxItems: 34 ++ minItems: 24 ++ maxItems: 24 + + clock-names: + items: +@@ -351,18 +351,6 @@ allOf: + - const: ethwarp_wocpu1 + - const: ethwarp_wocpu0 + - const: esw +- - const: netsys0 +- - const: netsys1 +- - const: sgmii_tx250m +- - const: sgmii_rx250m +- - const: sgmii2_tx250m +- - const: sgmii2_rx250m +- - const: top_usxgmii0_sel +- - const: top_usxgmii1_sel +- - const: top_sgm0_sel +- - const: top_sgm1_sel +- - const: top_xfi_phy0_xtal_sel +- - const: top_xfi_phy1_xtal_sel + - const: top_eth_gmii_sel + - const: top_eth_refck_50m_sel + - const: top_eth_sys_200m_sel +@@ -375,16 +363,10 @@ allOf: + - const: top_netsys_sync_250m_sel + - const: top_netsys_ppefb_250m_sel + - const: top_netsys_warp_sel +- - const: wocpu1 +- - const: wocpu0 + - const: xgp1 + - const: xgp2 + - const: xgp3 + +- mediatek,sgmiisys: +- minItems: 2 +- maxItems: 2 +- + patternProperties: + "^mac@[0-1]$": + type: object +diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml +index ddf9522a5dc230..5c2769dc689af7 100644 +--- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml ++++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml +@@ -394,6 +394,11 @@ properties: + When a PFC frame is received with priorities matching the bitmask, + the queue is blocked from transmitting for the pause time specified + in the PFC frame. ++ ++ snps,coe-unsupported: ++ type: boolean ++ description: TX checksum offload is unsupported by the TX queue. ++ + allOf: + - if: + required: +diff --git a/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml b/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml +index 1d33d80af11c3c..652d696bc9e90b 100644 +--- a/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml ++++ b/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml +@@ -34,6 +34,7 @@ properties: + and length of the AXI DMA controller IO space, unless + axistream-connected is specified, in which case the reg + attribute of the node referenced by it is used. ++ minItems: 1 + maxItems: 2 + + interrupts: +@@ -165,7 +166,7 @@ examples: + clock-names = "s_axi_lite_clk", "axis_clk", "ref_clk", "mgt_clk"; + clocks = <&axi_clk>, <&axi_clk>, <&pl_enet_ref_clk>, <&mgt_clk>; + phy-mode = "mii"; +- reg = <0x00 0x40000000 0x00 0x40000>; ++ reg = <0x40000000 0x40000>; + xlnx,rxcsum = <0x2>; + xlnx,rxmem = <0x800>; + xlnx,txcsum = <0x2>; +diff --git a/Documentation/devicetree/bindings/nvmem/mxs-ocotp.yaml b/Documentation/devicetree/bindings/nvmem/mxs-ocotp.yaml +index a9b822aeaa7edb..e436650f0faf7d 100644 +--- a/Documentation/devicetree/bindings/nvmem/mxs-ocotp.yaml ++++ b/Documentation/devicetree/bindings/nvmem/mxs-ocotp.yaml +@@ -14,9 +14,11 @@ allOf: + + properties: + compatible: +- enum: +- - fsl,imx23-ocotp +- - fsl,imx28-ocotp ++ items: ++ - enum: ++ - fsl,imx23-ocotp ++ - fsl,imx28-ocotp ++ - const: fsl,ocotp + + reg: + maxItems: 1 +@@ -34,7 +36,7 @@ unevaluatedProperties: false + examples: + - | + ocotp: efuse@8002c000 { +- compatible = "fsl,imx28-ocotp"; ++ compatible = "fsl,imx28-ocotp", "fsl,ocotp"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x8002c000 0x2000>; +diff --git a/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml b/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml +index 8fdfbc763d7045..835b6db00c2796 100644 +--- a/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml ++++ b/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml +@@ -68,6 +68,18 @@ properties: + phy-names: + const: pcie + ++ vpcie1v5-supply: ++ description: The 1.5v regulator to use for PCIe. ++ ++ vpcie3v3-supply: ++ description: The 3.3v regulator to use for PCIe. ++ ++ vpcie12v-supply: ++ description: The 12v regulator to use for PCIe. ++ ++ iommu-map: true ++ iommu-map-mask: true ++ + required: + - compatible + - reg +@@ -121,5 +133,7 @@ examples: + clock-names = "pcie", "pcie_bus"; + power-domains = <&sysc R8A7791_PD_ALWAYS_ON>; + resets = <&cpg 319>; ++ vpcie3v3-supply = <&pcie_3v3>; ++ vpcie12v-supply = <&pcie_12v>; + }; + }; +diff --git a/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml b/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml +index 531008f0b6ac32..002b728cbc7184 100644 +--- a/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml ++++ b/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml +@@ -37,6 +37,7 @@ properties: + description: This property is needed if using 24MHz OSC for RC's PHY. + + ep-gpios: ++ maxItems: 1 + description: pre-reset GPIO + + vpcie12v-supply: +diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml +index d981d77e82e40a..a6244c33faf614 100644 +--- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml ++++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml +@@ -71,7 +71,6 @@ required: + - reg + - clocks + - clock-names +- - power-domains + - resets + - reset-names + - vdda-phy-supply +@@ -130,6 +129,21 @@ allOf: + clock-names: + maxItems: 1 + ++ - if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - qcom,msm8996-qmp-ufs-phy ++ - qcom,msm8998-qmp-ufs-phy ++ then: ++ properties: ++ power-domains: ++ false ++ else: ++ required: ++ - power-domains ++ + additionalProperties: false + + examples: +diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml +index 9af203dc8793f3..fa7408eb74895b 100644 +--- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml ++++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml +@@ -62,12 +62,12 @@ properties: + "#clock-cells": + const: 1 + description: +- See include/dt-bindings/dt-bindings/phy/phy-qcom-qmp.h ++ See include/dt-bindings/phy/phy-qcom-qmp.h + + "#phy-cells": + const: 1 + description: +- See include/dt-bindings/dt-bindings/phy/phy-qcom-qmp.h ++ See include/dt-bindings/phy/phy-qcom-qmp.h + + orientation-switch: + description: +diff --git a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml +index 029569d5fcf35f..24c733c10e0e92 100644 +--- a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml ++++ b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml +@@ -32,6 +32,27 @@ properties: + + vdd3-supply: true + ++ qcom,tune-usb2-disc-thres: ++ $ref: /schemas/types.yaml#/definitions/uint8 ++ description: High-Speed disconnect threshold ++ minimum: 0 ++ maximum: 7 ++ default: 0 ++ ++ qcom,tune-usb2-amplitude: ++ $ref: /schemas/types.yaml#/definitions/uint8 ++ description: High-Speed trasmit amplitude ++ minimum: 0 ++ maximum: 15 ++ default: 8 ++ ++ qcom,tune-usb2-preem: ++ $ref: /schemas/types.yaml#/definitions/uint8 ++ description: High-Speed TX pre-emphasis tuning ++ minimum: 0 ++ maximum: 7 ++ default: 5 ++ + required: + - compatible + - reg +diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml b/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml +index 0f200e3f97a9a3..fce7f8a19e9c0a 100644 +--- a/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml ++++ b/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml +@@ -15,9 +15,6 @@ description: | + properties: + compatible: + oneOf: +- - enum: +- - qcom,sc8180x-usb-hs-phy +- - qcom,usb-snps-femto-v2-phy + - items: + - enum: + - qcom,sa8775p-usb-hs-phy +@@ -26,6 +23,7 @@ properties: + - items: + - enum: + - qcom,sc7280-usb-hs-phy ++ - qcom,sc8180x-usb-hs-phy + - qcom,sdx55-usb-hs-phy + - qcom,sdx65-usb-hs-phy + - qcom,sm6375-usb-hs-phy +diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt7622-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt7622-pinctrl.yaml +index bd72a326e6e069..60f30a59f3853e 100644 +--- a/Documentation/devicetree/bindings/pinctrl/mediatek,mt7622-pinctrl.yaml ++++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt7622-pinctrl.yaml +@@ -97,7 +97,8 @@ patternProperties: + then: + properties: + groups: +- enum: [emmc, emmc_rst] ++ items: ++ enum: [emmc, emmc_rst] + - if: + properties: + function: +@@ -105,8 +106,9 @@ patternProperties: + then: + properties: + groups: +- enum: [esw, esw_p0_p1, esw_p2_p3_p4, rgmii_via_esw, +- rgmii_via_gmac1, rgmii_via_gmac2, mdc_mdio] ++ items: ++ enum: [esw, esw_p0_p1, esw_p2_p3_p4, rgmii_via_esw, ++ rgmii_via_gmac1, rgmii_via_gmac2, mdc_mdio] + - if: + properties: + function: +@@ -123,10 +125,11 @@ patternProperties: + then: + properties: + groups: +- enum: [i2s_in_mclk_bclk_ws, i2s1_in_data, i2s2_in_data, +- i2s3_in_data, i2s4_in_data, i2s_out_mclk_bclk_ws, +- i2s1_out_data, i2s2_out_data, i2s3_out_data, +- i2s4_out_data] ++ items: ++ enum: [i2s_in_mclk_bclk_ws, i2s1_in_data, i2s2_in_data, ++ i2s3_in_data, i2s4_in_data, i2s_out_mclk_bclk_ws, ++ i2s1_out_data, i2s2_out_data, i2s3_out_data, ++ i2s4_out_data] + - if: + properties: + function: +@@ -159,10 +162,11 @@ patternProperties: + then: + properties: + groups: +- enum: [pcie0_0_waken, pcie0_1_waken, pcie1_0_waken, +- pcie0_0_clkreq, pcie0_1_clkreq, pcie1_0_clkreq, +- pcie0_pad_perst, pcie1_pad_perst, pcie_pereset, +- pcie_wake, pcie_clkreq] ++ items: ++ enum: [pcie0_0_waken, pcie0_1_waken, pcie1_0_waken, ++ pcie0_0_clkreq, pcie0_1_clkreq, pcie1_0_clkreq, ++ pcie0_pad_perst, pcie1_pad_perst, pcie_pereset, ++ pcie_wake, pcie_clkreq] + - if: + properties: + function: +@@ -178,11 +182,12 @@ patternProperties: + then: + properties: + groups: +- enum: [pwm_ch1_0, pwm_ch1_1, pwm_ch1_2, pwm_ch2_0, pwm_ch2_1, +- pwm_ch2_2, pwm_ch3_0, pwm_ch3_1, pwm_ch3_2, pwm_ch4_0, +- pwm_ch4_1, pwm_ch4_2, pwm_ch4_3, pwm_ch5_0, pwm_ch5_1, +- pwm_ch5_2, pwm_ch6_0, pwm_ch6_1, pwm_ch6_2, pwm_ch6_3, +- pwm_ch7_0, pwm_0, pwm_1] ++ items: ++ enum: [pwm_ch1_0, pwm_ch1_1, pwm_ch1_2, pwm_ch2_0, pwm_ch2_1, ++ pwm_ch2_2, pwm_ch3_0, pwm_ch3_1, pwm_ch3_2, pwm_ch4_0, ++ pwm_ch4_1, pwm_ch4_2, pwm_ch4_3, pwm_ch5_0, pwm_ch5_1, ++ pwm_ch5_2, pwm_ch6_0, pwm_ch6_1, pwm_ch6_2, pwm_ch6_3, ++ pwm_ch7_0, pwm_0, pwm_1] + - if: + properties: + function: +@@ -260,33 +265,34 @@ patternProperties: + pins: + description: + An array of strings. Each string contains the name of a pin. +- enum: [GPIO_A, I2S1_IN, I2S1_OUT, I2S_BCLK, I2S_WS, I2S_MCLK, TXD0, +- RXD0, SPI_WP, SPI_HOLD, SPI_CLK, SPI_MOSI, SPI_MISO, SPI_CS, +- I2C_SDA, I2C_SCL, I2S2_IN, I2S3_IN, I2S4_IN, I2S2_OUT, +- I2S3_OUT, I2S4_OUT, GPIO_B, MDC, MDIO, G2_TXD0, G2_TXD1, +- G2_TXD2, G2_TXD3, G2_TXEN, G2_TXC, G2_RXD0, G2_RXD1, G2_RXD2, +- G2_RXD3, G2_RXDV, G2_RXC, NCEB, NWEB, NREB, NDL4, NDL5, NDL6, +- NDL7, NRB, NCLE, NALE, NDL0, NDL1, NDL2, NDL3, MDI_TP_P0, +- MDI_TN_P0, MDI_RP_P0, MDI_RN_P0, MDI_TP_P1, MDI_TN_P1, +- MDI_RP_P1, MDI_RN_P1, MDI_RP_P2, MDI_RN_P2, MDI_TP_P2, +- MDI_TN_P2, MDI_TP_P3, MDI_TN_P3, MDI_RP_P3, MDI_RN_P3, +- MDI_RP_P4, MDI_RN_P4, MDI_TP_P4, MDI_TN_P4, PMIC_SCL, +- PMIC_SDA, SPIC1_CLK, SPIC1_MOSI, SPIC1_MISO, SPIC1_CS, +- GPIO_D, WATCHDOG, RTS3_N, CTS3_N, TXD3, RXD3, PERST0_N, +- PERST1_N, WLED_N, EPHY_LED0_N, AUXIN0, AUXIN1, AUXIN2, +- AUXIN3, TXD4, RXD4, RTS4_N, CST4_N, PWM1, PWM2, PWM3, PWM4, +- PWM5, PWM6, PWM7, GPIO_E, TOP_5G_CLK, TOP_5G_DATA, +- WF0_5G_HB0, WF0_5G_HB1, WF0_5G_HB2, WF0_5G_HB3, WF0_5G_HB4, +- WF0_5G_HB5, WF0_5G_HB6, XO_REQ, TOP_RST_N, SYS_WATCHDOG, +- EPHY_LED0_N_JTDO, EPHY_LED1_N_JTDI, EPHY_LED2_N_JTMS, +- EPHY_LED3_N_JTCLK, EPHY_LED4_N_JTRST_N, WF2G_LED_N, +- WF5G_LED_N, GPIO_9, GPIO_10, GPIO_11, GPIO_12, UART1_TXD, +- UART1_RXD, UART1_CTS, UART1_RTS, UART2_TXD, UART2_RXD, +- UART2_CTS, UART2_RTS, SMI_MDC, SMI_MDIO, PCIE_PERESET_N, +- PWM_0, GPIO_0, GPIO_1, GPIO_2, GPIO_3, GPIO_4, GPIO_5, +- GPIO_6, GPIO_7, GPIO_8, UART0_TXD, UART0_RXD, TOP_2G_CLK, +- TOP_2G_DATA, WF0_2G_HB0, WF0_2G_HB1, WF0_2G_HB2, WF0_2G_HB3, +- WF0_2G_HB4, WF0_2G_HB5, WF0_2G_HB6] ++ items: ++ enum: [GPIO_A, I2S1_IN, I2S1_OUT, I2S_BCLK, I2S_WS, I2S_MCLK, TXD0, ++ RXD0, SPI_WP, SPI_HOLD, SPI_CLK, SPI_MOSI, SPI_MISO, SPI_CS, ++ I2C_SDA, I2C_SCL, I2S2_IN, I2S3_IN, I2S4_IN, I2S2_OUT, ++ I2S3_OUT, I2S4_OUT, GPIO_B, MDC, MDIO, G2_TXD0, G2_TXD1, ++ G2_TXD2, G2_TXD3, G2_TXEN, G2_TXC, G2_RXD0, G2_RXD1, G2_RXD2, ++ G2_RXD3, G2_RXDV, G2_RXC, NCEB, NWEB, NREB, NDL4, NDL5, NDL6, ++ NDL7, NRB, NCLE, NALE, NDL0, NDL1, NDL2, NDL3, MDI_TP_P0, ++ MDI_TN_P0, MDI_RP_P0, MDI_RN_P0, MDI_TP_P1, MDI_TN_P1, ++ MDI_RP_P1, MDI_RN_P1, MDI_RP_P2, MDI_RN_P2, MDI_TP_P2, ++ MDI_TN_P2, MDI_TP_P3, MDI_TN_P3, MDI_RP_P3, MDI_RN_P3, ++ MDI_RP_P4, MDI_RN_P4, MDI_TP_P4, MDI_TN_P4, PMIC_SCL, ++ PMIC_SDA, SPIC1_CLK, SPIC1_MOSI, SPIC1_MISO, SPIC1_CS, ++ GPIO_D, WATCHDOG, RTS3_N, CTS3_N, TXD3, RXD3, PERST0_N, ++ PERST1_N, WLED_N, EPHY_LED0_N, AUXIN0, AUXIN1, AUXIN2, ++ AUXIN3, TXD4, RXD4, RTS4_N, CST4_N, PWM1, PWM2, PWM3, PWM4, ++ PWM5, PWM6, PWM7, GPIO_E, TOP_5G_CLK, TOP_5G_DATA, ++ WF0_5G_HB0, WF0_5G_HB1, WF0_5G_HB2, WF0_5G_HB3, WF0_5G_HB4, ++ WF0_5G_HB5, WF0_5G_HB6, XO_REQ, TOP_RST_N, SYS_WATCHDOG, ++ EPHY_LED0_N_JTDO, EPHY_LED1_N_JTDI, EPHY_LED2_N_JTMS, ++ EPHY_LED3_N_JTCLK, EPHY_LED4_N_JTRST_N, WF2G_LED_N, ++ WF5G_LED_N, GPIO_9, GPIO_10, GPIO_11, GPIO_12, UART1_TXD, ++ UART1_RXD, UART1_CTS, UART1_RTS, UART2_TXD, UART2_RXD, ++ UART2_CTS, UART2_RTS, SMI_MDC, SMI_MDIO, PCIE_PERESET_N, ++ PWM_0, GPIO_0, GPIO_1, GPIO_2, GPIO_3, GPIO_4, GPIO_5, ++ GPIO_6, GPIO_7, GPIO_8, UART0_TXD, UART0_RXD, TOP_2G_CLK, ++ TOP_2G_DATA, WF0_2G_HB0, WF0_2G_HB1, WF0_2G_HB2, WF0_2G_HB3, ++ WF0_2G_HB4, WF0_2G_HB5, WF0_2G_HB6] + + bias-disable: true + +diff --git a/Documentation/devicetree/bindings/serial/rs485.yaml b/Documentation/devicetree/bindings/serial/rs485.yaml +index 303a443d9e29b2..9418fd66a8e95a 100644 +--- a/Documentation/devicetree/bindings/serial/rs485.yaml ++++ b/Documentation/devicetree/bindings/serial/rs485.yaml +@@ -29,6 +29,10 @@ properties: + default: 0 + maximum: 100 + ++ rs485-rts-active-high: ++ description: drive RTS high when sending (this is the default). ++ $ref: /schemas/types.yaml#/definitions/flag ++ + rs485-rts-active-low: + description: drive RTS low when sending (default is high). + $ref: /schemas/types.yaml#/definitions/flag +diff --git a/Documentation/devicetree/bindings/serial/serial.yaml b/Documentation/devicetree/bindings/serial/serial.yaml +index ea277560a59664..5727bd549deca4 100644 +--- a/Documentation/devicetree/bindings/serial/serial.yaml ++++ b/Documentation/devicetree/bindings/serial/serial.yaml +@@ -96,7 +96,7 @@ then: + rts-gpios: false + + patternProperties: +- "^bluetooth|gnss|gps|mcu$": ++ "^(bluetooth|gnss|gps|mcu)$": + if: + type: object + then: +diff --git a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml +index e4fa6a07b4fa2c..be6ffec2b07497 100644 +--- a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml ++++ b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml +@@ -163,6 +163,7 @@ allOf: + unevaluatedProperties: false + + pcie-phy: ++ type: object + description: + Documentation/devicetree/bindings/phy/rockchip-pcie-phy.txt + +diff --git a/Documentation/devicetree/bindings/sound/rt5645.txt b/Documentation/devicetree/bindings/sound/rt5645.txt +index 41a62fd2ae1ffb..c1fa379f5f3ea1 100644 +--- a/Documentation/devicetree/bindings/sound/rt5645.txt ++++ b/Documentation/devicetree/bindings/sound/rt5645.txt +@@ -20,6 +20,11 @@ Optional properties: + a GPIO spec for the external headphone detect pin. If jd-mode = 0, + we will get the JD status by getting the value of hp-detect-gpios. + ++- cbj-sleeve-gpios: ++ a GPIO spec to control the external combo jack circuit to tie the sleeve/ring2 ++ contacts to the ground or floating. It could avoid some electric noise from the ++ active speaker jacks. ++ + - realtek,in2-differential + Boolean. Indicate MIC2 input are differential, rather than single-ended. + +@@ -68,6 +73,7 @@ codec: rt5650@1a { + compatible = "realtek,rt5650"; + reg = <0x1a>; + hp-detect-gpios = <&gpio 19 0>; ++ cbj-sleeve-gpios = <&gpio 20 0>; + interrupt-parent = <&gpio>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + realtek,dmic-en = "true"; +diff --git a/Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml b/Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml +index 7fd59114548001..902db92da83207 100644 +--- a/Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml ++++ b/Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml +@@ -15,12 +15,19 @@ allOf: + + properties: + compatible: +- enum: +- - nxp,imx8dxl-fspi +- - nxp,imx8mm-fspi +- - nxp,imx8mp-fspi +- - nxp,imx8qxp-fspi +- - nxp,lx2160a-fspi ++ oneOf: ++ - enum: ++ - nxp,imx8dxl-fspi ++ - nxp,imx8mm-fspi ++ - nxp,imx8mp-fspi ++ - nxp,imx8qxp-fspi ++ - nxp,imx8ulp-fspi ++ - nxp,lx2160a-fspi ++ - items: ++ - enum: ++ - nxp,imx93-fspi ++ - nxp,imx95-fspi ++ - const: nxp,imx8mm-fspi + + reg: + items: +diff --git a/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml +index f882903769f954..eee7c8d4cf4a29 100644 +--- a/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml ++++ b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml +@@ -14,7 +14,7 @@ description: | + It is a MIPI System Power Management (SPMI) controller. + + The PMIC part is provided by +- ./Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml. ++ Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml. + + allOf: + - $ref: spmi.yaml# +@@ -48,7 +48,7 @@ patternProperties: + PMIC properties, which are specific to the used SPMI PMIC device(s). + When used in combination with HiSilicon 6421v600, the properties + are documented at +- drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml. ++ Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml + + unevaluatedProperties: false + +diff --git a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml +index 7538469997f9e1..ca81c8afba79c6 100644 +--- a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml ++++ b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml +@@ -10,28 +10,55 @@ maintainers: + - zhanghongchen + - Yinbo Zhu + ++allOf: ++ - $ref: /schemas/thermal/thermal-sensor.yaml# ++ + properties: + compatible: + oneOf: + - enum: + - loongson,ls2k1000-thermal ++ - loongson,ls2k2000-thermal + - items: + - enum: +- - loongson,ls2k2000-thermal ++ - loongson,ls2k0500-thermal + - const: loongson,ls2k1000-thermal + + reg: +- maxItems: 1 ++ minItems: 1 ++ maxItems: 2 + + interrupts: + maxItems: 1 + ++ '#thermal-sensor-cells': ++ const: 1 ++ + required: + - compatible + - reg + - interrupts ++ - '#thermal-sensor-cells' ++ ++if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - loongson,ls2k2000-thermal ++ ++then: ++ properties: ++ reg: ++ minItems: 2 ++ maxItems: 2 ++ ++else: ++ properties: ++ reg: ++ maxItems: 1 + +-additionalProperties: false ++unevaluatedProperties: false + + examples: + - | +@@ -41,4 +68,5 @@ examples: + reg = <0x1fe01500 0x30>; + interrupt-parent = <&liointc0>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; ++ #thermal-sensor-cells = <1>; + }; +diff --git a/Documentation/devicetree/bindings/thermal/thermal-zones.yaml b/Documentation/devicetree/bindings/thermal/thermal-zones.yaml +index 4f3acdc4dec0ef..98cdd98212c495 100644 +--- a/Documentation/devicetree/bindings/thermal/thermal-zones.yaml ++++ b/Documentation/devicetree/bindings/thermal/thermal-zones.yaml +@@ -49,7 +49,10 @@ properties: + to take when the temperature crosses those thresholds. + + patternProperties: +- "^[a-zA-Z][a-zA-Z0-9\\-]{1,12}-thermal$": ++ # Node name is limited in size due to Linux kernel requirements - 19 ++ # characters in total (see THERMAL_NAME_LENGTH, including terminating NUL ++ # byte): ++ "^[a-zA-Z][a-zA-Z0-9\\-]{1,10}-thermal$": + type: object + description: + Each thermal zone node contains information about how frequently it +diff --git a/Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml b/Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml +index bffdab0b01859b..fbac40b958ddea 100644 +--- a/Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml ++++ b/Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml +@@ -169,27 +169,27 @@ properties: + - const: tgib0 + - const: tgic0 + - const: tgid0 +- - const: tgiv0 ++ - const: tciv0 + - const: tgie0 + - const: tgif0 + - const: tgia1 + - const: tgib1 +- - const: tgiv1 +- - const: tgiu1 ++ - const: tciv1 ++ - const: tciu1 + - const: tgia2 + - const: tgib2 +- - const: tgiv2 +- - const: tgiu2 ++ - const: tciv2 ++ - const: tciu2 + - const: tgia3 + - const: tgib3 + - const: tgic3 + - const: tgid3 +- - const: tgiv3 ++ - const: tciv3 + - const: tgia4 + - const: tgib4 + - const: tgic4 + - const: tgid4 +- - const: tgiv4 ++ - const: tciv4 + - const: tgiu5 + - const: tgiv5 + - const: tgiw5 +@@ -197,18 +197,18 @@ properties: + - const: tgib6 + - const: tgic6 + - const: tgid6 +- - const: tgiv6 ++ - const: tciv6 + - const: tgia7 + - const: tgib7 + - const: tgic7 + - const: tgid7 +- - const: tgiv7 ++ - const: tciv7 + - const: tgia8 + - const: tgib8 + - const: tgic8 + - const: tgid8 +- - const: tgiv8 +- - const: tgiu8 ++ - const: tciv8 ++ - const: tciu8 + + clocks: + maxItems: 1 +@@ -285,16 +285,16 @@ examples: + , + , + ; +- interrupt-names = "tgia0", "tgib0", "tgic0", "tgid0", "tgiv0", "tgie0", ++ interrupt-names = "tgia0", "tgib0", "tgic0", "tgid0", "tciv0", "tgie0", + "tgif0", +- "tgia1", "tgib1", "tgiv1", "tgiu1", +- "tgia2", "tgib2", "tgiv2", "tgiu2", +- "tgia3", "tgib3", "tgic3", "tgid3", "tgiv3", +- "tgia4", "tgib4", "tgic4", "tgid4", "tgiv4", ++ "tgia1", "tgib1", "tciv1", "tciu1", ++ "tgia2", "tgib2", "tciv2", "tciu2", ++ "tgia3", "tgib3", "tgic3", "tgid3", "tciv3", ++ "tgia4", "tgib4", "tgic4", "tgid4", "tciv4", + "tgiu5", "tgiv5", "tgiw5", +- "tgia6", "tgib6", "tgic6", "tgid6", "tgiv6", +- "tgia7", "tgib7", "tgic7", "tgid7", "tgiv7", +- "tgia8", "tgib8", "tgic8", "tgid8", "tgiv8", "tgiu8"; ++ "tgia6", "tgib6", "tgic6", "tgid6", "tciv6", ++ "tgia7", "tgib7", "tgic7", "tgid7", "tciv7", ++ "tgia8", "tgib8", "tgic8", "tgid8", "tciv8", "tciu8"; + clocks = <&cpg CPG_MOD R9A07G044_MTU_X_MCK_MTU3>; + power-domains = <&cpg>; + resets = <&cpg R9A07G044_MTU_X_PRESET_MTU3>; +diff --git a/Documentation/devicetree/bindings/usb/microchip,usb5744.yaml b/Documentation/devicetree/bindings/usb/microchip,usb5744.yaml +index ff3a1707ef570f..6d4cfd943f5847 100644 +--- a/Documentation/devicetree/bindings/usb/microchip,usb5744.yaml ++++ b/Documentation/devicetree/bindings/usb/microchip,usb5744.yaml +@@ -36,7 +36,11 @@ properties: + + vdd-supply: + description: +- VDD power supply to the hub ++ 3V3 power supply to the hub ++ ++ vdd2-supply: ++ description: ++ 1V2 power supply to the hub + + peer-hub: + $ref: /schemas/types.yaml#/definitions/phandle +@@ -62,6 +66,7 @@ allOf: + properties: + reset-gpios: false + vdd-supply: false ++ vdd2-supply: false + peer-hub: false + i2c-bus: false + else: +diff --git a/Documentation/driver-api/fpga/fpga-bridge.rst b/Documentation/driver-api/fpga/fpga-bridge.rst +index 60420853409533..833f68fb070089 100644 +--- a/Documentation/driver-api/fpga/fpga-bridge.rst ++++ b/Documentation/driver-api/fpga/fpga-bridge.rst +@@ -6,9 +6,12 @@ API to implement a new FPGA bridge + + * struct fpga_bridge - The FPGA Bridge structure + * struct fpga_bridge_ops - Low level Bridge driver ops +-* fpga_bridge_register() - Create and register a bridge ++* __fpga_bridge_register() - Create and register a bridge + * fpga_bridge_unregister() - Unregister a bridge + ++The helper macro ``fpga_bridge_register()`` automatically sets ++the module that registers the FPGA bridge as the owner. ++ + .. kernel-doc:: include/linux/fpga/fpga-bridge.h + :functions: fpga_bridge + +@@ -16,7 +19,7 @@ API to implement a new FPGA bridge + :functions: fpga_bridge_ops + + .. kernel-doc:: drivers/fpga/fpga-bridge.c +- :functions: fpga_bridge_register ++ :functions: __fpga_bridge_register + + .. kernel-doc:: drivers/fpga/fpga-bridge.c + :functions: fpga_bridge_unregister +diff --git a/Documentation/driver-api/fpga/fpga-mgr.rst b/Documentation/driver-api/fpga/fpga-mgr.rst +index 49c0a951265320..8d2b79f696c1fb 100644 +--- a/Documentation/driver-api/fpga/fpga-mgr.rst ++++ b/Documentation/driver-api/fpga/fpga-mgr.rst +@@ -24,7 +24,8 @@ How to support a new FPGA device + -------------------------------- + + To add another FPGA manager, write a driver that implements a set of ops. The +-probe function calls fpga_mgr_register() or fpga_mgr_register_full(), such as:: ++probe function calls ``fpga_mgr_register()`` or ``fpga_mgr_register_full()``, ++such as:: + + static const struct fpga_manager_ops socfpga_fpga_ops = { + .write_init = socfpga_fpga_ops_configure_init, +@@ -69,10 +70,11 @@ probe function calls fpga_mgr_register() or fpga_mgr_register_full(), such as:: + } + + Alternatively, the probe function could call one of the resource managed +-register functions, devm_fpga_mgr_register() or devm_fpga_mgr_register_full(). +-When these functions are used, the parameter syntax is the same, but the call +-to fpga_mgr_unregister() should be removed. In the above example, the +-socfpga_fpga_remove() function would not be required. ++register functions, ``devm_fpga_mgr_register()`` or ++``devm_fpga_mgr_register_full()``. When these functions are used, the ++parameter syntax is the same, but the call to ``fpga_mgr_unregister()`` should be ++removed. In the above example, the ``socfpga_fpga_remove()`` function would not be ++required. + + The ops will implement whatever device specific register writes are needed to + do the programming sequence for this particular FPGA. These ops return 0 for +@@ -125,15 +127,19 @@ API for implementing a new FPGA Manager driver + * struct fpga_manager - the FPGA manager struct + * struct fpga_manager_ops - Low level FPGA manager driver ops + * struct fpga_manager_info - Parameter structure for fpga_mgr_register_full() +-* fpga_mgr_register_full() - Create and register an FPGA manager using the ++* __fpga_mgr_register_full() - Create and register an FPGA manager using the + fpga_mgr_info structure to provide the full flexibility of options +-* fpga_mgr_register() - Create and register an FPGA manager using standard ++* __fpga_mgr_register() - Create and register an FPGA manager using standard + arguments +-* devm_fpga_mgr_register_full() - Resource managed version of +- fpga_mgr_register_full() +-* devm_fpga_mgr_register() - Resource managed version of fpga_mgr_register() ++* __devm_fpga_mgr_register_full() - Resource managed version of ++ __fpga_mgr_register_full() ++* __devm_fpga_mgr_register() - Resource managed version of __fpga_mgr_register() + * fpga_mgr_unregister() - Unregister an FPGA manager + ++Helper macros ``fpga_mgr_register_full()``, ``fpga_mgr_register()``, ++``devm_fpga_mgr_register_full()``, and ``devm_fpga_mgr_register()`` are available ++to ease the registration. ++ + .. kernel-doc:: include/linux/fpga/fpga-mgr.h + :functions: fpga_mgr_states + +@@ -147,16 +153,16 @@ API for implementing a new FPGA Manager driver + :functions: fpga_manager_info + + .. kernel-doc:: drivers/fpga/fpga-mgr.c +- :functions: fpga_mgr_register_full ++ :functions: __fpga_mgr_register_full + + .. kernel-doc:: drivers/fpga/fpga-mgr.c +- :functions: fpga_mgr_register ++ :functions: __fpga_mgr_register + + .. kernel-doc:: drivers/fpga/fpga-mgr.c +- :functions: devm_fpga_mgr_register_full ++ :functions: __devm_fpga_mgr_register_full + + .. kernel-doc:: drivers/fpga/fpga-mgr.c +- :functions: devm_fpga_mgr_register ++ :functions: __devm_fpga_mgr_register + + .. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_mgr_unregister +diff --git a/Documentation/driver-api/fpga/fpga-region.rst b/Documentation/driver-api/fpga/fpga-region.rst +index dc55d60a0b4a51..2d03b5fb765755 100644 +--- a/Documentation/driver-api/fpga/fpga-region.rst ++++ b/Documentation/driver-api/fpga/fpga-region.rst +@@ -46,13 +46,16 @@ API to add a new FPGA region + ---------------------------- + + * struct fpga_region - The FPGA region struct +-* struct fpga_region_info - Parameter structure for fpga_region_register_full() +-* fpga_region_register_full() - Create and register an FPGA region using the ++* struct fpga_region_info - Parameter structure for __fpga_region_register_full() ++* __fpga_region_register_full() - Create and register an FPGA region using the + fpga_region_info structure to provide the full flexibility of options +-* fpga_region_register() - Create and register an FPGA region using standard ++* __fpga_region_register() - Create and register an FPGA region using standard + arguments + * fpga_region_unregister() - Unregister an FPGA region + ++Helper macros ``fpga_region_register()`` and ``fpga_region_register_full()`` ++automatically set the module that registers the FPGA region as the owner. ++ + The FPGA region's probe function will need to get a reference to the FPGA + Manager it will be using to do the programming. This usually would happen + during the region's probe function. +@@ -82,10 +85,10 @@ following APIs to handle building or tearing down that list. + :functions: fpga_region_info + + .. kernel-doc:: drivers/fpga/fpga-region.c +- :functions: fpga_region_register_full ++ :functions: __fpga_region_register_full + + .. kernel-doc:: drivers/fpga/fpga-region.c +- :functions: fpga_region_register ++ :functions: __fpga_region_register + + .. kernel-doc:: drivers/fpga/fpga-region.c + :functions: fpga_region_unregister +diff --git a/Documentation/driver-api/ipmi.rst b/Documentation/driver-api/ipmi.rst +index e224e47b6b0944..dfa021eacd63c4 100644 +--- a/Documentation/driver-api/ipmi.rst ++++ b/Documentation/driver-api/ipmi.rst +@@ -540,7 +540,7 @@ at module load time (for a module) with:: + alerts_broken + + The addresses are normal I2C addresses. The adapter is the string +-name of the adapter, as shown in /sys/class/i2c-adapter/i2c-/name. ++name of the adapter, as shown in /sys/bus/i2c/devices/i2c-/name. + It is *NOT* i2c- itself. Also, the comparison is done ignoring + spaces, so if the name is "This is an I2C chip" you can say + adapter_name=ThisisanI2cchip. This is because it's hard to pass in +diff --git a/Documentation/driver-api/pci/p2pdma.rst b/Documentation/driver-api/pci/p2pdma.rst +index 44deb52beeb476..d0b241628cf13d 100644 +--- a/Documentation/driver-api/pci/p2pdma.rst ++++ b/Documentation/driver-api/pci/p2pdma.rst +@@ -83,19 +83,9 @@ this to include other types of resources like doorbells. + Client Drivers + -------------- + +-A client driver typically only has to conditionally change its DMA map +-routine to use the mapping function :c:func:`pci_p2pdma_map_sg()` instead +-of the usual :c:func:`dma_map_sg()` function. Memory mapped in this +-way does not need to be unmapped. +- +-The client may also, optionally, make use of +-:c:func:`is_pci_p2pdma_page()` to determine when to use the P2P mapping +-functions and when to use the regular mapping functions. In some +-situations, it may be more appropriate to use a flag to indicate a +-given request is P2P memory and map appropriately. It is important to +-ensure that struct pages that back P2P memory stay out of code that +-does not have support for them as other code may treat the pages as +-regular memory which may not be appropriate. ++A client driver only has to use the mapping API :c:func:`dma_map_sg()` ++and :c:func:`dma_unmap_sg()` functions as usual, and the implementation ++will do the right thing for the P2P capable memory. + + + Orchestrator Drivers +diff --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst +index 3fdc95f7a1d159..ed5ec98165381f 100644 +--- a/Documentation/driver-api/pwm.rst ++++ b/Documentation/driver-api/pwm.rst +@@ -41,7 +41,7 @@ the getter, devm_pwm_get() and devm_fwnode_pwm_get(), also exist. + + After being requested, a PWM has to be configured using:: + +- int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state); ++ int pwm_apply_might_sleep(struct pwm_device *pwm, struct pwm_state *state); + + This API controls both the PWM period/duty_cycle config and the + enable/disable state. +@@ -57,13 +57,13 @@ If supported by the driver, the signal can be optimized, for example to improve + EMI by phase shifting the individual channels of a chip. + + The pwm_config(), pwm_enable() and pwm_disable() functions are just wrappers +-around pwm_apply_state() and should not be used if the user wants to change ++around pwm_apply_might_sleep() and should not be used if the user wants to change + several parameter at once. For example, if you see pwm_config() and + pwm_{enable,disable}() calls in the same function, this probably means you +-should switch to pwm_apply_state(). ++should switch to pwm_apply_might_sleep(). + + The PWM user API also allows one to query the PWM state that was passed to the +-last invocation of pwm_apply_state() using pwm_get_state(). Note this is ++last invocation of pwm_apply_might_sleep() using pwm_get_state(). Note this is + different to what the driver has actually implemented if the request cannot be + satisfied exactly with the hardware in use. There is currently no way for + consumers to get the actually implemented settings. +diff --git a/Documentation/filesystems/directory-locking.rst b/Documentation/filesystems/directory-locking.rst +index dccd61c7c5c3be..193c22687851a7 100644 +--- a/Documentation/filesystems/directory-locking.rst ++++ b/Documentation/filesystems/directory-locking.rst +@@ -22,13 +22,16 @@ exclusive. + 3) object removal. Locking rules: caller locks parent, finds victim, + locks victim and calls the method. Locks are exclusive. + +-4) rename() that is _not_ cross-directory. Locking rules: caller locks the +-parent and finds source and target. We lock both (provided they exist). If we +-need to lock two inodes of different type (dir vs non-dir), we lock directory +-first. If we need to lock two inodes of the same type, lock them in inode +-pointer order. Then call the method. All locks are exclusive. +-NB: we might get away with locking the source (and target in exchange +-case) shared. ++4) rename() that is _not_ cross-directory. Locking rules: caller locks ++the parent and finds source and target. Then we decide which of the ++source and target need to be locked. Source needs to be locked if it's a ++non-directory; target - if it's a non-directory or about to be removed. ++Take the locks that need to be taken, in inode pointer order if need ++to take both (that can happen only when both source and target are ++non-directories - the source because it wouldn't be locked otherwise ++and the target because mixing directory and non-directory is allowed ++only with RENAME_EXCHANGE, and that won't be removing the target). ++After the locks had been taken, call the method. All locks are exclusive. + + 5) link creation. Locking rules: + +@@ -44,20 +47,17 @@ rules: + + * lock the filesystem + * lock parents in "ancestors first" order. If one is not ancestor of +- the other, lock them in inode pointer order. ++ the other, lock the parent of source first. + * find source and target. + * if old parent is equal to or is a descendent of target + fail with -ENOTEMPTY + * if new parent is equal to or is a descendent of source + fail with -ELOOP +- * Lock both the source and the target provided they exist. If we +- need to lock two inodes of different type (dir vs non-dir), we lock +- the directory first. If we need to lock two inodes of the same type, +- lock them in inode pointer order. ++ * Lock subdirectories involved (source before target). ++ * Lock non-directories involved, in inode pointer order. + * call the method. + +-All ->i_rwsem are taken exclusive. Again, we might get away with locking +-the source (and target in exchange case) shared. ++All ->i_rwsem are taken exclusive. + + The rules above obviously guarantee that all directories that are going to be + read, modified or removed by method will be locked by caller. +@@ -67,6 +67,7 @@ If no directory is its own ancestor, the scheme above is deadlock-free. + + Proof: + ++[XXX: will be updated once we are done massaging the lock_rename()] + First of all, at any moment we have a linear ordering of the + objects - A < B iff (A is an ancestor of B) or (B is not an ancestor + of A and ptr(A) < ptr(B)). +diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst +index d32c6209685d64..dbfbbe9ab28b12 100644 +--- a/Documentation/filesystems/f2fs.rst ++++ b/Documentation/filesystems/f2fs.rst +@@ -126,9 +126,7 @@ norecovery Disable the roll-forward recovery routine, mounted read- + discard/nodiscard Enable/disable real-time discard in f2fs, if discard is + enabled, f2fs will issue discard/TRIM commands when a + segment is cleaned. +-no_heap Disable heap-style segment allocation which finds free +- segments for data from the beginning of main area, while +- for node from the end of main area. ++heap/no_heap Deprecated. + nouser_xattr Disable Extended User Attributes. Note: xattr is enabled + by default if CONFIG_F2FS_FS_XATTR is selected. + noacl Disable POSIX Access Control List. Note: acl is enabled +@@ -228,8 +226,6 @@ mode=%s Control block allocation mode which supports "adaptive" + option for more randomness. + Please, use these options for your experiments and we strongly + recommend to re-format the filesystem after using these options. +-io_bits=%u Set the bit size of write IO requests. It should be set +- with "mode=lfs". + usrquota Enable plain user disk quota accounting. + grpquota Enable plain group disk quota accounting. + prjquota Enable plain project quota accounting. +diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst +index 7be2900806c853..bd12f2f850ad3a 100644 +--- a/Documentation/filesystems/locking.rst ++++ b/Documentation/filesystems/locking.rst +@@ -101,7 +101,7 @@ symlink: exclusive + mkdir: exclusive + unlink: exclusive (both) + rmdir: exclusive (both)(see below) +-rename: exclusive (all) (see below) ++rename: exclusive (both parents, some children) (see below) + readlink: no + get_link: no + setattr: exclusive +@@ -123,6 +123,9 @@ get_offset_ctx no + Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_rwsem + exclusive on victim. + cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem. ++ ->unlink() and ->rename() have ->i_rwsem exclusive on all non-directories ++ involved. ++ ->rename() has ->i_rwsem exclusive on any subdirectory that changes parent. + + See Documentation/filesystems/directory-locking.rst for more detailed discussion + of the locking scheme for directory operations. +diff --git a/Documentation/filesystems/overlayfs.rst b/Documentation/filesystems/overlayfs.rst +index 5b93268e400f4c..56a5ad7a4fbd20 100644 +--- a/Documentation/filesystems/overlayfs.rst ++++ b/Documentation/filesystems/overlayfs.rst +@@ -344,10 +344,11 @@ escaping the colons with a single backslash. For example: + + mount -t overlay overlay -olowerdir=/a\:lower\:\:dir /merged + +-Since kernel version v6.5, directory names containing colons can also +-be provided as lower layer using the fsconfig syscall from new mount api: ++Since kernel version v6.8, directory names containing colons can also ++be configured as lower layer using the "lowerdir+" mount options and the ++fsconfig syscall from new mount api. For example: + +- fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir", "/a:lower::dir", 0); ++ fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir+", "/a:lower::dir", 0); + + In the latter case, colons in lower layer directory names will be escaped + as an octal characters (\072) when displayed in /proc/self/mountinfo. +@@ -416,6 +417,16 @@ Only the data of the files in the "data-only" lower layers may be visible + when a "metacopy" file in one of the lower layers above it, has a "redirect" + to the absolute path of the "lower data" file in the "data-only" lower layer. + ++Since kernel version v6.8, "data-only" lower layers can also be added using ++the "datadir+" mount options and the fsconfig syscall from new mount api. ++For example: ++ ++ fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir+", "/l1", 0); ++ fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir+", "/l2", 0); ++ fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir+", "/l3", 0); ++ fsconfig(fs_fd, FSCONFIG_SET_STRING, "datadir+", "/do1", 0); ++ fsconfig(fs_fd, FSCONFIG_SET_STRING, "datadir+", "/do2", 0); ++ + + fs-verity support + ---------------------- +diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst +index 4d05b9862451ea..41d964b48e6578 100644 +--- a/Documentation/filesystems/porting.rst ++++ b/Documentation/filesystems/porting.rst +@@ -1045,3 +1045,21 @@ filesystem type is now moved to a later point when the devices are closed: + As this is a VFS level change it has no practical consequences for filesystems + other than that all of them must use one of the provided kill_litter_super(), + kill_anon_super(), or kill_block_super() helpers. ++ ++--- ++ ++**mandatory** ++ ++If ->rename() update of .. on cross-directory move needs an exclusion with ++directory modifications, do *not* lock the subdirectory in question in your ++->rename() - it's done by the caller now [that item should've been added in ++28eceeda130f "fs: Lock moved directories"]. ++ ++--- ++ ++**mandatory** ++ ++On same-directory ->rename() the (tautological) update of .. is not protected ++by any locks; just don't do it if the old parent is the same as the new one. ++We really can't lock two subdirectories in same-directory rename - not without ++deadlocks. +diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst +index a0c83fc481264e..690d2ffe720eff 100644 +--- a/Documentation/gpu/drm-kms.rst ++++ b/Documentation/gpu/drm-kms.rst +@@ -546,6 +546,8 @@ Plane Composition Properties + .. kernel-doc:: drivers/gpu/drm/drm_blend.c + :doc: overview + ++.. _damage_tracking_properties: ++ + Damage Tracking Properties + -------------------------- + +diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst +index 03fe5d1247be28..85bbe05436098a 100644 +--- a/Documentation/gpu/todo.rst ++++ b/Documentation/gpu/todo.rst +@@ -337,8 +337,8 @@ connector register/unregister fixes + + Level: Intermediate + +-Remove load/unload callbacks from all non-DRIVER_LEGACY drivers +---------------------------------------------------------------- ++Remove load/unload callbacks ++---------------------------- + + The load/unload callbacks in struct &drm_driver are very much midlayers, plus + for historical reasons they get the ordering wrong (and we can't fix that) +@@ -347,8 +347,7 @@ between setting up the &drm_driver structure and calling drm_dev_register(). + - Rework drivers to no longer use the load/unload callbacks, directly coding the + load/unload sequence into the driver's probe function. + +-- Once all non-DRIVER_LEGACY drivers are converted, disallow the load/unload +- callbacks for all modern drivers. ++- Once all drivers are converted, remove the load/unload callbacks. + + Contact: Daniel Vetter + +diff --git a/Documentation/hwmon/corsair-psu.rst b/Documentation/hwmon/corsair-psu.rst +index 16db34d464dd6b..7ed794087f8489 100644 +--- a/Documentation/hwmon/corsair-psu.rst ++++ b/Documentation/hwmon/corsair-psu.rst +@@ -15,11 +15,11 @@ Supported devices: + + Corsair HX850i + +- Corsair HX1000i (Series 2022 and 2023) ++ Corsair HX1000i (Legacy and Series 2023) + +- Corsair HX1200i ++ Corsair HX1200i (Legacy and Series 2023) + +- Corsair HX1500i (Series 2022 and 2023) ++ Corsair HX1500i (Legacy and Series 2023) + + Corsair RM550i + +diff --git a/Documentation/i2c/busses/i2c-i801.rst b/Documentation/i2c/busses/i2c-i801.rst +index e76e68ccf7182c..10eced6c2e4625 100644 +--- a/Documentation/i2c/busses/i2c-i801.rst ++++ b/Documentation/i2c/busses/i2c-i801.rst +@@ -47,6 +47,7 @@ Supported adapters: + * Intel Alder Lake (PCH) + * Intel Raptor Lake (PCH) + * Intel Meteor Lake (SOC and PCH) ++ * Intel Birch Stream (SOC) + + Datasheets: Publicly available at the Intel website + +diff --git a/Documentation/kbuild/modules.rst b/Documentation/kbuild/modules.rst +index a1f3eb7a43e235..131863142cbb35 100644 +--- a/Documentation/kbuild/modules.rst ++++ b/Documentation/kbuild/modules.rst +@@ -128,7 +128,7 @@ executed to make module versioning work. + + modules_install + Install the external module(s). The default location is +- /lib/modules//extra/, but a prefix may ++ /lib/modules//updates/, but a prefix may + be added with INSTALL_MOD_PATH (discussed in section 5). + + clean +@@ -417,7 +417,7 @@ directory: + + And external modules are installed in: + +- /lib/modules/$(KERNELRELEASE)/extra/ ++ /lib/modules/$(KERNELRELEASE)/updates/ + + 5.1 INSTALL_MOD_PATH + -------------------- +@@ -438,10 +438,10 @@ And external modules are installed in: + ------------------- + + External modules are by default installed to a directory under +- /lib/modules/$(KERNELRELEASE)/extra/, but you may wish to ++ /lib/modules/$(KERNELRELEASE)/updates/, but you may wish to + locate modules for a specific functionality in a separate + directory. For this purpose, use INSTALL_MOD_DIR to specify an +- alternative name to "extra.":: ++ alternative name to "updates.":: + + $ make INSTALL_MOD_DIR=gandalf -C $KDIR \ + M=$PWD modules_install +diff --git a/Documentation/locking/hwspinlock.rst b/Documentation/locking/hwspinlock.rst +index 6f03713b700390..2ffaa3cbd63f16 100644 +--- a/Documentation/locking/hwspinlock.rst ++++ b/Documentation/locking/hwspinlock.rst +@@ -85,6 +85,17 @@ is already free). + + Should be called from a process context (might sleep). + ++:: ++ ++ int hwspin_lock_bust(struct hwspinlock *hwlock, unsigned int id); ++ ++After verifying the owner of the hwspinlock, release a previously acquired ++hwspinlock; returns 0 on success, or an appropriate error code on failure ++(e.g. -EOPNOTSUPP if the bust operation is not defined for the specific ++hwspinlock). ++ ++Should be called from a process context (might sleep). ++ + :: + + int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int timeout); +diff --git a/Documentation/mm/arch_pgtable_helpers.rst b/Documentation/mm/arch_pgtable_helpers.rst +index c82e3ee20e51ee..8c71249e7c4d05 100644 +--- a/Documentation/mm/arch_pgtable_helpers.rst ++++ b/Documentation/mm/arch_pgtable_helpers.rst +@@ -142,7 +142,8 @@ PMD Page Table Helpers + +---------------------------+--------------------------------------------------+ + | pmd_swp_clear_soft_dirty | Clears a soft dirty swapped PMD | + +---------------------------+--------------------------------------------------+ +-| pmd_mkinvalid | Invalidates a mapped PMD [1] | ++| pmd_mkinvalid | Invalidates a present PMD; do not call for | ++| | non-present PMD [1] | + +---------------------------+--------------------------------------------------+ + | pmd_set_huge | Creates a PMD huge mapping | + +---------------------------+--------------------------------------------------+ +@@ -198,7 +199,8 @@ PUD Page Table Helpers + +---------------------------+--------------------------------------------------+ + | pud_mkdevmap | Creates a ZONE_DEVICE mapped PUD | + +---------------------------+--------------------------------------------------+ +-| pud_mkinvalid | Invalidates a mapped PUD [1] | ++| pud_mkinvalid | Invalidates a present PUD; do not call for | ++| | non-present PUD [1] | + +---------------------------+--------------------------------------------------+ + | pud_set_huge | Creates a PUD huge mapping | + +---------------------------+--------------------------------------------------+ +diff --git a/Documentation/mm/page_table_check.rst b/Documentation/mm/page_table_check.rst +index c12838ce6b8de2..c59f22eb6a0f9a 100644 +--- a/Documentation/mm/page_table_check.rst ++++ b/Documentation/mm/page_table_check.rst +@@ -14,7 +14,7 @@ Page table check performs extra verifications at the time when new pages become + accessible from the userspace by getting their page table entries (PTEs PMDs + etc.) added into the table. + +-In case of detected corruption, the kernel is crashed. There is a small ++In case of most detected corruption, the kernel is crashed. There is a small + performance and memory overhead associated with the page table check. Therefore, + it is disabled by default, but can be optionally enabled on systems where the + extra hardening outweighs the performance costs. Also, because page table check +@@ -22,6 +22,13 @@ is synchronous, it can help with debugging double map memory corruption issues, + by crashing kernel at the time wrong mapping occurs instead of later which is + often the case with memory corruptions bugs. + ++It can also be used to do page table entry checks over various flags, dump ++warnings when illegal combinations of entry flags are detected. Currently, ++userfaultfd is the only user of such to sanity check wr-protect bit against ++any writable flags. Illegal flag combinations will not directly cause data ++corruption in this case immediately, but that will cause read-only data to ++be writable, leading to corrupt when the page content is later modified. ++ + Double mapping detection logic + ============================== + +diff --git a/Documentation/networking/device_drivers/ethernet/amazon/ena.rst b/Documentation/networking/device_drivers/ethernet/amazon/ena.rst +index 5eaa3ab6c73e7f..b842bcb14255b5 100644 +--- a/Documentation/networking/device_drivers/ethernet/amazon/ena.rst ++++ b/Documentation/networking/device_drivers/ethernet/amazon/ena.rst +@@ -54,6 +54,7 @@ ena_common_defs.h Common definitions for ena_com layer. + ena_regs_defs.h Definition of ENA PCI memory-mapped (MMIO) registers. + ena_netdev.[ch] Main Linux kernel driver. + ena_ethtool.c ethtool callbacks. ++ena_xdp.[ch] XDP files + ena_pci_id_tbl.h Supported device IDs. + ================= ====================================================== + +diff --git a/Documentation/networking/devlink/devlink-port.rst b/Documentation/networking/devlink/devlink-port.rst +index e33ad2401ad70c..562f46b4127449 100644 +--- a/Documentation/networking/devlink/devlink-port.rst ++++ b/Documentation/networking/devlink/devlink-port.rst +@@ -126,7 +126,7 @@ Users may also set the RoCE capability of the function using + `devlink port function set roce` command. + + Users may also set the function as migratable using +-'devlink port function set migratable' command. ++`devlink port function set migratable` command. + + Users may also set the IPsec crypto capability of the function using + `devlink port function set ipsec_crypto` command. +diff --git a/Documentation/powerpc/features.rst b/Documentation/powerpc/features.rst +index aeae73df86b0c5..ee4b95e04202d3 100644 +--- a/Documentation/powerpc/features.rst ++++ b/Documentation/powerpc/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features powerpc ++.. kernel-feat:: features powerpc +diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst +index b48da698d6f253..bb96ca0f774b9a 100644 +--- a/Documentation/process/changes.rst ++++ b/Documentation/process/changes.rst +@@ -31,7 +31,7 @@ you probably needn't concern yourself with pcmciautils. + ====================== =============== ======================================== + GNU C 5.1 gcc --version + Clang/LLVM (optional) 11.0.0 clang --version +-Rust (optional) 1.71.1 rustc --version ++Rust (optional) 1.73.0 rustc --version + bindgen (optional) 0.65.1 bindgen --version + GNU make 3.82 make --version + bash 4.2 bash --version +diff --git a/Documentation/riscv/features.rst b/Documentation/riscv/features.rst +index c70ef6ac2368c9..36e90144adabd1 100644 +--- a/Documentation/riscv/features.rst ++++ b/Documentation/riscv/features.rst +@@ -1,3 +1,3 @@ + .. SPDX-License-Identifier: GPL-2.0 + +-.. kernel-feat:: $srctree/Documentation/features riscv ++.. kernel-feat:: features riscv +diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst +index 8e44107933abf5..c3154ce6e1b273 100644 +--- a/Documentation/sound/soc/dapm.rst ++++ b/Documentation/sound/soc/dapm.rst +@@ -234,7 +234,7 @@ corresponding soft power control. In this case it is necessary to create + a virtual widget - a widget with no control bits e.g. + :: + +- SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0), ++ SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), + + This can be used to merge to signal paths together in software. + +diff --git a/Documentation/sphinx/cdomain.py b/Documentation/sphinx/cdomain.py +index a99716bf44b553..de5d132d94c595 100644 +--- a/Documentation/sphinx/cdomain.py ++++ b/Documentation/sphinx/cdomain.py +@@ -93,7 +93,7 @@ def markup_ctype_refs(match): + # + RE_expr = re.compile(r':c:(expr|texpr):`([^\`]+)`') + def markup_c_expr(match): +- return '\ ``' + match.group(2) + '``\ ' ++ return '\\ ``' + match.group(2) + '``\\ ' + + # + # Parse Sphinx 3.x C markups, replacing them by backward-compatible ones +diff --git a/Documentation/sphinx/kernel_abi.py b/Documentation/sphinx/kernel_abi.py +index b5feb5b1d90548..5911bd0d796571 100644 +--- a/Documentation/sphinx/kernel_abi.py ++++ b/Documentation/sphinx/kernel_abi.py +@@ -39,8 +39,6 @@ import sys + import re + import kernellog + +-from os import path +- + from docutils import nodes, statemachine + from docutils.statemachine import ViewList + from docutils.parsers.rst import directives, Directive +@@ -73,60 +71,26 @@ class KernelCmd(Directive): + } + + def run(self): +- + doc = self.state.document + if not doc.settings.file_insertion_enabled: + raise self.warning("docutils: file insertion disabled") + +- env = doc.settings.env +- cwd = path.dirname(doc.current_source) +- cmd = "get_abi.pl rest --enable-lineno --dir " +- cmd += self.arguments[0] +- +- if 'rst' in self.options: +- cmd += " --rst-source" ++ srctree = os.path.abspath(os.environ["srctree"]) + +- srctree = path.abspath(os.environ["srctree"]) ++ args = [ ++ os.path.join(srctree, 'scripts/get_abi.pl'), ++ 'rest', ++ '--enable-lineno', ++ '--dir', os.path.join(srctree, 'Documentation', self.arguments[0]), ++ ] + +- fname = cmd +- +- # extend PATH with $(srctree)/scripts +- path_env = os.pathsep.join([ +- srctree + os.sep + "scripts", +- os.environ["PATH"] +- ]) +- shell_env = os.environ.copy() +- shell_env["PATH"] = path_env +- shell_env["srctree"] = srctree ++ if 'rst' in self.options: ++ args.append('--rst-source') + +- lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env) ++ lines = subprocess.check_output(args, cwd=os.path.dirname(doc.current_source)).decode('utf-8') + nodeList = self.nestedParse(lines, self.arguments[0]) + return nodeList + +- def runCmd(self, cmd, **kwargs): +- u"""Run command ``cmd`` and return its stdout as unicode.""" +- +- try: +- proc = subprocess.Popen( +- cmd +- , stdout = subprocess.PIPE +- , stderr = subprocess.PIPE +- , **kwargs +- ) +- out, err = proc.communicate() +- +- out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8') +- +- if proc.returncode != 0: +- raise self.severe( +- u"command '%s' failed with return code %d" +- % (cmd, proc.returncode) +- ) +- except OSError as exc: +- raise self.severe(u"problems with '%s' directive: %s." +- % (self.name, ErrorString(exc))) +- return out +- + def nestedParse(self, lines, fname): + env = self.state.document.settings.env + content = ViewList() +@@ -138,7 +102,7 @@ class KernelCmd(Directive): + code_block += "\n " + l + lines = code_block + "\n\n" + +- line_regex = re.compile("^\.\. LINENO (\S+)\#([0-9]+)$") ++ line_regex = re.compile(r"^\.\. LINENO (\S+)\#([0-9]+)$") + ln = 0 + n = 0 + f = fname +diff --git a/Documentation/sphinx/kernel_feat.py b/Documentation/sphinx/kernel_feat.py +index 27b701ed3681ed..03ace5f01b5c02 100644 +--- a/Documentation/sphinx/kernel_feat.py ++++ b/Documentation/sphinx/kernel_feat.py +@@ -37,8 +37,6 @@ import re + import subprocess + import sys + +-from os import path +- + from docutils import nodes, statemachine + from docutils.statemachine import ViewList + from docutils.parsers.rst import directives, Directive +@@ -76,35 +74,28 @@ class KernelFeat(Directive): + self.state.document.settings.env.app.warn(message, prefix="") + + def run(self): +- + doc = self.state.document + if not doc.settings.file_insertion_enabled: + raise self.warning("docutils: file insertion disabled") + + env = doc.settings.env +- cwd = path.dirname(doc.current_source) +- cmd = "get_feat.pl rest --enable-fname --dir " +- cmd += self.arguments[0] +- +- if len(self.arguments) > 1: +- cmd += " --arch " + self.arguments[1] + +- srctree = path.abspath(os.environ["srctree"]) ++ srctree = os.path.abspath(os.environ["srctree"]) + +- fname = cmd ++ args = [ ++ os.path.join(srctree, 'scripts/get_feat.pl'), ++ 'rest', ++ '--enable-fname', ++ '--dir', ++ os.path.join(srctree, 'Documentation', self.arguments[0]), ++ ] + +- # extend PATH with $(srctree)/scripts +- path_env = os.pathsep.join([ +- srctree + os.sep + "scripts", +- os.environ["PATH"] +- ]) +- shell_env = os.environ.copy() +- shell_env["PATH"] = path_env +- shell_env["srctree"] = srctree ++ if len(self.arguments) > 1: ++ args.extend(['--arch', self.arguments[1]]) + +- lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env) ++ lines = subprocess.check_output(args, cwd=os.path.dirname(doc.current_source)).decode('utf-8') + +- line_regex = re.compile("^\.\. FILE (\S+)$") ++ line_regex = re.compile(r"^\.\. FILE (\S+)$") + + out_lines = "" + +@@ -118,33 +109,9 @@ class KernelFeat(Directive): + else: + out_lines += line + "\n" + +- nodeList = self.nestedParse(out_lines, fname) ++ nodeList = self.nestedParse(out_lines, self.arguments[0]) + return nodeList + +- def runCmd(self, cmd, **kwargs): +- u"""Run command ``cmd`` and return its stdout as unicode.""" +- +- try: +- proc = subprocess.Popen( +- cmd +- , stdout = subprocess.PIPE +- , stderr = subprocess.PIPE +- , **kwargs +- ) +- out, err = proc.communicate() +- +- out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8') +- +- if proc.returncode != 0: +- raise self.severe( +- u"command '%s' failed with return code %d" +- % (cmd, proc.returncode) +- ) +- except OSError as exc: +- raise self.severe(u"problems with '%s' directive: %s." +- % (self.name, ErrorString(exc))) +- return out +- + def nestedParse(self, lines, fname): + content = ViewList() + node = nodes.section() +diff --git a/Documentation/sphinx/kernel_include.py b/Documentation/sphinx/kernel_include.py +index abe7680883771d..6387624423363d 100755 +--- a/Documentation/sphinx/kernel_include.py ++++ b/Documentation/sphinx/kernel_include.py +@@ -97,7 +97,6 @@ class KernelInclude(Include): + # HINT: this is the only line I had to change / commented out: + #path = utils.relative_path(None, path) + +- path = nodes.reprunicode(path) + encoding = self.options.get( + 'encoding', self.state.document.settings.input_encoding) + e_handler=self.state.document.settings.input_encoding_error_handler +diff --git a/Documentation/sphinx/kerneldoc.py b/Documentation/sphinx/kerneldoc.py +index 9395892c7ba38b..8dc134904b9077 100644 +--- a/Documentation/sphinx/kerneldoc.py ++++ b/Documentation/sphinx/kerneldoc.py +@@ -130,7 +130,7 @@ class KernelDocDirective(Directive): + result = ViewList() + + lineoffset = 0; +- line_regex = re.compile("^\.\. LINENO ([0-9]+)$") ++ line_regex = re.compile(r"^\.\. LINENO ([0-9]+)$") + for line in lines: + match = line_regex.search(line) + if match: +diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py +index 328b3631a585cd..dcad0fff4723ee 100755 +--- a/Documentation/sphinx/maintainers_include.py ++++ b/Documentation/sphinx/maintainers_include.py +@@ -77,7 +77,7 @@ class MaintainersInclude(Include): + line = line.rstrip() + + # Linkify all non-wildcard refs to ReST files in Documentation/. +- pat = '(Documentation/([^\s\?\*]*)\.rst)' ++ pat = r'(Documentation/([^\s\?\*]*)\.rst)' + m = re.search(pat, line) + if m: + # maintainers.rst is in a subdirectory, so include "../". +@@ -90,11 +90,11 @@ class MaintainersInclude(Include): + output = "| %s" % (line.replace("\\", "\\\\")) + # Look for and record field letter to field name mappings: + # R: Designated *reviewer*: FullName +- m = re.search("\s(\S):\s", line) ++ m = re.search(r"\s(\S):\s", line) + if m: + field_letter = m.group(1) + if field_letter and not field_letter in fields: +- m = re.search("\*([^\*]+)\*", line) ++ m = re.search(r"\*([^\*]+)\*", line) + if m: + fields[field_letter] = m.group(1) + elif subsystems: +@@ -112,7 +112,7 @@ class MaintainersInclude(Include): + field_content = "" + + # Collapse whitespace in subsystem name. +- heading = re.sub("\s+", " ", line) ++ heading = re.sub(r"\s+", " ", line) + output = output + "%s\n%s" % (heading, "~" * len(heading)) + field_prev = "" + else: +diff --git a/Documentation/translations/zh_CN/arch/loongarch/features.rst b/Documentation/translations/zh_CN/arch/loongarch/features.rst +index 82bfac180bdc04..cec38dda8298c1 100644 +--- a/Documentation/translations/zh_CN/arch/loongarch/features.rst ++++ b/Documentation/translations/zh_CN/arch/loongarch/features.rst +@@ -5,4 +5,4 @@ + :Original: Documentation/arch/loongarch/features.rst + :Translator: Huacai Chen + +-.. kernel-feat:: $srctree/Documentation/features loongarch ++.. kernel-feat:: features loongarch +diff --git a/Documentation/translations/zh_CN/arch/mips/features.rst b/Documentation/translations/zh_CN/arch/mips/features.rst +index da1b956e4a40f6..0d6df97db069bb 100644 +--- a/Documentation/translations/zh_CN/arch/mips/features.rst ++++ b/Documentation/translations/zh_CN/arch/mips/features.rst +@@ -10,4 +10,4 @@ + + .. _cn_features: + +-.. kernel-feat:: $srctree/Documentation/features mips ++.. kernel-feat:: features mips +diff --git a/Documentation/translations/zh_TW/dev-tools/index.rst b/Documentation/translations/zh_TW/dev-tools/index.rst +new file mode 100644 +index 00000000000000..8f101db5a07fff +--- /dev/null ++++ b/Documentation/translations/zh_TW/dev-tools/index.rst +@@ -0,0 +1,40 @@ ++.. include:: ../disclaimer-zh_TW.rst ++ ++:Original: Documentation/dev-tools/index.rst ++:Translator: Min-Hua Chen ++ ++============ ++內核開發工具 ++============ ++ ++本文檔是有關內核開發工具文檔的合集。 ++目前這些文檔已經整理在一起,不需要再花費額外的精力。 ++歡迎任何補丁。 ++ ++有關測試專用工具的簡要概述,參見 ++Documentation/dev-tools/testing-overview.rst ++ ++.. class:: toc-title ++ ++ 目錄 ++ ++.. toctree:: ++ :maxdepth: 2 ++ ++ sparse ++ ++Todolist: ++ ++ - coccinelle ++ - kcov ++ - ubsan ++ - kmemleak ++ - kcsan ++ - kfence ++ - kgdb ++ - kselftest ++ - kunit/index ++ - testing-overview ++ - gcov ++ - kasan ++ - gdb-kernel-debugging +diff --git a/Documentation/translations/zh_TW/dev-tools/sparse.txt b/Documentation/translations/zh_TW/dev-tools/sparse.txt +new file mode 100644 +index 00000000000000..35d3d1d748e6f1 +--- /dev/null ++++ b/Documentation/translations/zh_TW/dev-tools/sparse.txt +@@ -0,0 +1,91 @@ ++Chinese translated version of Documentation/dev-tools/sparse.rst ++ ++If you have any comment or update to the content, please contact the ++original document maintainer directly. However, if you have a problem ++communicating in English you can also ask the Chinese maintainer for ++help. Contact the Chinese maintainer if this translation is outdated ++or if there is a problem with the translation. ++ ++Traditional Chinese maintainer: Hu Haowen ++--------------------------------------------------------------------- ++Documentation/dev-tools/sparse.rst 的繁體中文翻譯 ++ ++如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文 ++交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或 ++者翻譯存在問題,請聯繫繁體中文版維護者。 ++ ++繁體中文版維護者: 胡皓文 Hu Haowen ++繁體中文版翻譯者: 胡皓文 Hu Haowen ++ ++以下爲正文 ++--------------------------------------------------------------------- ++ ++Copyright 2004 Linus Torvalds ++Copyright 2004 Pavel Machek ++Copyright 2006 Bob Copeland ++ ++使用 sparse 工具做類型檢查 ++~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ ++"__bitwise" 是一種類型屬性,所以你應該這樣使用它: ++ ++ typedef int __bitwise pm_request_t; ++ ++ enum pm_request { ++ PM_SUSPEND = (__force pm_request_t) 1, ++ PM_RESUME = (__force pm_request_t) 2 ++ }; ++ ++這樣會使 PM_SUSPEND 和 PM_RESUME 成爲位方式(bitwise)整數(使用"__force" ++是因爲 sparse 會抱怨改變位方式的類型轉換,但是這裡我們確實需要強制進行轉 ++換)。而且因爲所有枚舉值都使用了相同的類型,這裡的"enum pm_request"也將 ++會使用那個類型做爲底層實現。 ++ ++而且使用 gcc 編譯的時候,所有的 __bitwise/__force 都會消失,最後在 gcc ++看來它們只不過是普通的整數。 ++ ++坦白來說,你並不需要使用枚舉類型。上面那些實際都可以濃縮成一個特殊的"int ++__bitwise"類型。 ++ ++所以更簡單的辦法只要這樣做: ++ ++ typedef int __bitwise pm_request_t; ++ ++ #define PM_SUSPEND ((__force pm_request_t) 1) ++ #define PM_RESUME ((__force pm_request_t) 2) ++ ++現在你就有了嚴格的類型檢查所需要的所有基礎架構。 ++ ++一個小提醒:常數整數"0"是特殊的。你可以直接把常數零當作位方式整數使用而 ++不用擔心 sparse 會抱怨。這是因爲"bitwise"(恰如其名)是用來確保不同位方 ++式類型不會被弄混(小尾模式,大尾模式,cpu尾模式,或者其他),對他們來說 ++常數"0"確實是特殊的。 ++ ++獲取 sparse 工具 ++~~~~~~~~~~~~~~~~ ++ ++你可以從 Sparse 的主頁獲取最新的發布版本: ++ ++ https://www.kernel.org/pub/software/devel/sparse/dist/ ++ ++或者,你也可以使用 git 克隆最新的 sparse 開發版本: ++ ++ git://git.kernel.org/pub/scm/devel/sparse/sparse.git ++ ++一旦你下載了源碼,只要以普通用戶身份運行: ++ ++ make ++ make install ++ ++它將會被自動安裝到你的 ~/bin 目錄下。 ++ ++使用 sparse 工具 ++~~~~~~~~~~~~~~~~ ++ ++用"make C=1"命令來編譯內核,會對所有重新編譯的 C 文件使用 sparse 工具。 ++或者使用"make C=2"命令,無論文件是否被重新編譯都會對其使用 sparse 工具。 ++如果你已經編譯了內核,用後一種方式可以很快地檢查整個源碼樹。 ++ ++make 的可選變量 CHECKFLAGS 可以用來向 sparse 工具傳遞參數。編譯系統會自 ++動向 sparse 工具傳遞 -Wbitwise 參數。 ++ +diff --git a/Documentation/translations/zh_TW/index.rst b/Documentation/translations/zh_TW/index.rst +index d1cf0b4d8e46d9..ffcaf3272fe70a 100644 +--- a/Documentation/translations/zh_TW/index.rst ++++ b/Documentation/translations/zh_TW/index.rst +@@ -55,11 +55,11 @@ TODOList: + :maxdepth: 1 + + process/license-rules ++ dev-tools/index + + TODOList: + + * doc-guide/index +-* dev-tools/index + * dev-tools/testing-overview + * kernel-hacking/index + * rust/index +diff --git a/Documentation/translations/zh_TW/sparse.txt b/Documentation/translations/zh_TW/sparse.txt +deleted file mode 100644 +index 35d3d1d748e6f1..00000000000000 +--- a/Documentation/translations/zh_TW/sparse.txt ++++ /dev/null +@@ -1,91 +0,0 @@ +-Chinese translated version of Documentation/dev-tools/sparse.rst +- +-If you have any comment or update to the content, please contact the +-original document maintainer directly. However, if you have a problem +-communicating in English you can also ask the Chinese maintainer for +-help. Contact the Chinese maintainer if this translation is outdated +-or if there is a problem with the translation. +- +-Traditional Chinese maintainer: Hu Haowen +---------------------------------------------------------------------- +-Documentation/dev-tools/sparse.rst 的繁體中文翻譯 +- +-如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文 +-交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或 +-者翻譯存在問題,請聯繫繁體中文版維護者。 +- +-繁體中文版維護者: 胡皓文 Hu Haowen +-繁體中文版翻譯者: 胡皓文 Hu Haowen +- +-以下爲正文 +---------------------------------------------------------------------- +- +-Copyright 2004 Linus Torvalds +-Copyright 2004 Pavel Machek +-Copyright 2006 Bob Copeland +- +-使用 sparse 工具做類型檢查 +-~~~~~~~~~~~~~~~~~~~~~~~~~~ +- +-"__bitwise" 是一種類型屬性,所以你應該這樣使用它: +- +- typedef int __bitwise pm_request_t; +- +- enum pm_request { +- PM_SUSPEND = (__force pm_request_t) 1, +- PM_RESUME = (__force pm_request_t) 2 +- }; +- +-這樣會使 PM_SUSPEND 和 PM_RESUME 成爲位方式(bitwise)整數(使用"__force" +-是因爲 sparse 會抱怨改變位方式的類型轉換,但是這裡我們確實需要強制進行轉 +-換)。而且因爲所有枚舉值都使用了相同的類型,這裡的"enum pm_request"也將 +-會使用那個類型做爲底層實現。 +- +-而且使用 gcc 編譯的時候,所有的 __bitwise/__force 都會消失,最後在 gcc +-看來它們只不過是普通的整數。 +- +-坦白來說,你並不需要使用枚舉類型。上面那些實際都可以濃縮成一個特殊的"int +-__bitwise"類型。 +- +-所以更簡單的辦法只要這樣做: +- +- typedef int __bitwise pm_request_t; +- +- #define PM_SUSPEND ((__force pm_request_t) 1) +- #define PM_RESUME ((__force pm_request_t) 2) +- +-現在你就有了嚴格的類型檢查所需要的所有基礎架構。 +- +-一個小提醒:常數整數"0"是特殊的。你可以直接把常數零當作位方式整數使用而 +-不用擔心 sparse 會抱怨。這是因爲"bitwise"(恰如其名)是用來確保不同位方 +-式類型不會被弄混(小尾模式,大尾模式,cpu尾模式,或者其他),對他們來說 +-常數"0"確實是特殊的。 +- +-獲取 sparse 工具 +-~~~~~~~~~~~~~~~~ +- +-你可以從 Sparse 的主頁獲取最新的發布版本: +- +- https://www.kernel.org/pub/software/devel/sparse/dist/ +- +-或者,你也可以使用 git 克隆最新的 sparse 開發版本: +- +- git://git.kernel.org/pub/scm/devel/sparse/sparse.git +- +-一旦你下載了源碼,只要以普通用戶身份運行: +- +- make +- make install +- +-它將會被自動安裝到你的 ~/bin 目錄下。 +- +-使用 sparse 工具 +-~~~~~~~~~~~~~~~~ +- +-用"make C=1"命令來編譯內核,會對所有重新編譯的 C 文件使用 sparse 工具。 +-或者使用"make C=2"命令,無論文件是否被重新編譯都會對其使用 sparse 工具。 +-如果你已經編譯了內核,用後一種方式可以很快地檢查整個源碼樹。 +- +-make 的可選變量 CHECKFLAGS 可以用來向 sparse 工具傳遞參數。編譯系統會自 +-動向 sparse 工具傳遞 -Wbitwise 參數。 +- +diff --git a/Documentation/userspace-api/media/mediactl/media-types.rst b/Documentation/userspace-api/media/mediactl/media-types.rst +index 0ffeece1e0c8e9..6332e8395263b0 100644 +--- a/Documentation/userspace-api/media/mediactl/media-types.rst ++++ b/Documentation/userspace-api/media/mediactl/media-types.rst +@@ -375,12 +375,11 @@ Types and flags used to represent the media graph elements + are origins of links. + + * - ``MEDIA_PAD_FL_MUST_CONNECT`` +- - If this flag is set and the pad is linked to any other pad, then +- at least one of those links must be enabled for the entity to be +- able to stream. There could be temporary reasons (e.g. device +- configuration dependent) for the pad to need enabled links even +- when this flag isn't set; the absence of the flag doesn't imply +- there is none. ++ - If this flag is set, then for this pad to be able to stream, it must ++ be connected by at least one enabled link. There could be temporary ++ reasons (e.g. device configuration dependent) for the pad to need ++ enabled links even when this flag isn't set; the absence of the flag ++ doesn't imply there is none. + + + One and only one of ``MEDIA_PAD_FL_SINK`` and ``MEDIA_PAD_FL_SOURCE`` +diff --git a/Documentation/virt/kvm/locking.rst b/Documentation/virt/kvm/locking.rst +index 3a034db5e55f89..887d9d2fed492b 100644 +--- a/Documentation/virt/kvm/locking.rst ++++ b/Documentation/virt/kvm/locking.rst +@@ -9,7 +9,7 @@ KVM Lock Overview + + The acquisition orders for mutexes are as follows: + +-- cpus_read_lock() is taken outside kvm_lock ++- cpus_read_lock() is taken outside kvm_lock and kvm_usage_lock + + - kvm->lock is taken outside vcpu->mutex + +@@ -24,6 +24,13 @@ The acquisition orders for mutexes are as follows: + are taken on the waiting side when modifying memslots, so MMU notifiers + must not take either kvm->slots_lock or kvm->slots_arch_lock. + ++cpus_read_lock() vs kvm_lock: ++ ++- Taking cpus_read_lock() outside of kvm_lock is problematic, despite that ++ being the official ordering, as it is quite easy to unknowingly trigger ++ cpus_read_lock() while holding kvm_lock. Use caution when walking vm_list, ++ e.g. avoid complex operations when possible. ++ + For SRCU: + + - ``synchronize_srcu(&kvm->srcu)`` is called inside critical sections +@@ -228,10 +235,17 @@ time it will be set using the Dirty tracking mechanism described above. + :Type: mutex + :Arch: any + :Protects: - vm_list +- - kvm_usage_count ++ ++``kvm_usage_lock`` ++^^^^^^^^^^^^^^^^^^ ++ ++:Type: mutex ++:Arch: any ++:Protects: - kvm_usage_count + - hardware virtualization enable/disable +-:Comment: KVM also disables CPU hotplug via cpus_read_lock() during +- enable/disable. ++:Comment: Exists because using kvm_lock leads to deadlock (see earlier comment ++ on cpus_read_lock() vs kvm_lock). Note, KVM also disables CPU hotplug via ++ cpus_read_lock() when enabling/disabling virtualization. + + ``kvm->mn_invalidate_lock`` + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +@@ -291,11 +305,12 @@ time it will be set using the Dirty tracking mechanism described above. + wakeup. + + ``vendor_module_lock`` +-^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++^^^^^^^^^^^^^^^^^^^^^^ + :Type: mutex + :Arch: x86 + :Protects: loading a vendor module (kvm_amd or kvm_intel) +-:Comment: Exists because using kvm_lock leads to deadlock. cpu_hotplug_lock is +- taken outside of kvm_lock, e.g. in KVM's CPU online/offline callbacks, and +- many operations need to take cpu_hotplug_lock when loading a vendor module, +- e.g. updating static calls. ++:Comment: Exists because using kvm_lock leads to deadlock. kvm_lock is taken ++ in notifiers, e.g. __kvmclock_cpufreq_notifier(), that may be invoked while ++ cpu_hotplug_lock is held, e.g. from cpufreq_boost_trigger_state(), and many ++ operations need to take cpu_hotplug_lock when loading a vendor module, e.g. ++ updating static calls. +diff --git a/MAINTAINERS b/MAINTAINERS +index dd5de540ec0b52..ae4c0cec507360 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -8142,7 +8142,7 @@ M: Geoffrey D. Bennett + L: alsa-devel@alsa-project.org (moderated for non-subscribers) + S: Maintained + T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git +-F: sound/usb/mixer_scarlett_gen2.c ++F: sound/usb/mixer_scarlett2.c + + FORCEDETH GIGABIT ETHERNET DRIVER + M: Rain River +@@ -10157,6 +10157,14 @@ L: linux-media@vger.kernel.org + S: Maintained + F: drivers/media/rc/iguanair.c + ++IIO BACKEND FRAMEWORK ++M: Nuno Sa ++R: Olivier Moysan ++L: linux-iio@vger.kernel.org ++S: Maintained ++F: drivers/iio/industrialio-backend.c ++F: include/linux/iio/backend.h ++ + IIO DIGITAL POTENTIOMETER DAC + M: Peter Rosin + L: linux-iio@vger.kernel.org +@@ -13694,7 +13702,7 @@ M: Mathieu Desnoyers + M: "Paul E. McKenney" + L: linux-kernel@vger.kernel.org + S: Supported +-F: arch/powerpc/include/asm/membarrier.h ++F: arch/*/include/asm/membarrier.h + F: include/uapi/linux/membarrier.h + F: kernel/sched/membarrier.c + +@@ -17380,7 +17388,7 @@ F: drivers/video/backlight/pwm_bl.c + F: include/dt-bindings/pwm/ + F: include/linux/pwm.h + F: include/linux/pwm_backlight.h +-K: pwm_(config|apply_state|ops) ++K: pwm_(config|apply_might_sleep|ops) + + PXA GPIO DRIVER + M: Robert Jarzmik +@@ -23630,6 +23638,7 @@ F: include/xen/arm/swiotlb-xen.h + F: include/xen/swiotlb-xen.h + + XFS FILESYSTEM ++M: Catherine Hoang + M: Chandan Babu R + R: Darrick J. Wong + L: linux-xfs@vger.kernel.org +diff --git a/Makefile b/Makefile +index 5c418efbe89b6c..f80e78c7cf2006 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,9 +1,9 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 0 ++SUBLEVEL = 58 + EXTRAVERSION = +-NAME = Hurr durr I'ma ninja sloth ++NAME = Pinguïn Aangedreven + + # *DOCUMENTATION* + # To see a list of typical targets execute "make help" +@@ -951,7 +951,6 @@ endif + ifdef CONFIG_LTO_CLANG + ifdef CONFIG_LTO_CLANG_THIN + CC_FLAGS_LTO := -flto=thin -fsplit-lto-unit +-KBUILD_LDFLAGS += --thinlto-cache-dir=$(extmod_prefix).thinlto-cache + else + CC_FLAGS_LTO := -flto + endif +@@ -1317,6 +1316,14 @@ scripts_unifdef: scripts_basic + quiet_cmd_install = INSTALL $(INSTALL_PATH) + cmd_install = unset sub_make_done; $(srctree)/scripts/install.sh + ++# --------------------------------------------------------------------------- ++# vDSO install ++ ++PHONY += vdso_install ++vdso_install: export INSTALL_FILES = $(vdso-install-y) ++vdso_install: ++ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.vdsoinst ++ + # --------------------------------------------------------------------------- + # Tools + +@@ -1474,7 +1481,7 @@ endif # CONFIG_MODULES + # Directories & files removed with 'make clean' + CLEAN_FILES += vmlinux.symvers modules-only.symvers \ + modules.builtin modules.builtin.modinfo modules.nsdeps \ +- compile_commands.json .thinlto-cache rust/test \ ++ compile_commands.json rust/test \ + rust-project.json .vmlinux.objs .vmlinux.export.c + + # Directories & files removed with 'make mrproper' +@@ -1560,6 +1567,7 @@ help: + @echo '* vmlinux - Build the bare kernel' + @echo '* modules - Build all modules' + @echo ' modules_install - Install all modules to INSTALL_MOD_PATH (default: /)' ++ @echo ' vdso_install - Install unstripped vdso to INSTALL_MOD_PATH (default: /)' + @echo ' dir/ - Build all files in dir and below' + @echo ' dir/file.[ois] - Build specified target only' + @echo ' dir/file.ll - Build the LLVM assembly file' +@@ -1777,7 +1785,7 @@ PHONY += compile_commands.json + + clean-dirs := $(KBUILD_EXTMOD) + clean: rm-files := $(KBUILD_EXTMOD)/Module.symvers $(KBUILD_EXTMOD)/modules.nsdeps \ +- $(KBUILD_EXTMOD)/compile_commands.json $(KBUILD_EXTMOD)/.thinlto-cache ++ $(KBUILD_EXTMOD)/compile_commands.json + + PHONY += prepare + # now expand this into a simple variable to reduce the cost of shell evaluations +diff --git a/arch/Kconfig b/arch/Kconfig +index 12d51495caec18..09603e0bc2cc16 100644 +--- a/arch/Kconfig ++++ b/arch/Kconfig +@@ -9,6 +9,14 @@ + # + source "arch/$(SRCARCH)/Kconfig" + ++config ARCH_CONFIGURES_CPU_MITIGATIONS ++ bool ++ ++if !ARCH_CONFIGURES_CPU_MITIGATIONS ++config CPU_MITIGATIONS ++ def_bool y ++endif ++ + menu "General architecture-dependent options" + + config ARCH_HAS_SUBPAGE_FAULTS +@@ -681,6 +689,7 @@ config SHADOW_CALL_STACK + bool "Shadow Call Stack" + depends on ARCH_SUPPORTS_SHADOW_CALL_STACK + depends on DYNAMIC_FTRACE_WITH_ARGS || DYNAMIC_FTRACE_WITH_REGS || !FUNCTION_GRAPH_TRACER ++ depends on MMU + help + This option enables the compiler's Shadow Call Stack, which + uses a shadow stack to protect function return addresses from +diff --git a/arch/alpha/kernel/rtc.c b/arch/alpha/kernel/rtc.c +index fb3025396ac964..cfdf90bc8b3f86 100644 +--- a/arch/alpha/kernel/rtc.c ++++ b/arch/alpha/kernel/rtc.c +@@ -80,7 +80,7 @@ init_rtc_epoch(void) + static int + alpha_rtc_read_time(struct device *dev, struct rtc_time *tm) + { +- int ret = mc146818_get_time(tm); ++ int ret = mc146818_get_time(tm, 10); + + if (ret < 0) { + dev_err_ratelimited(dev, "unable to read current time\n"); +diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c +index c80258ec332ffe..85a679ce061c25 100644 +--- a/arch/alpha/kernel/setup.c ++++ b/arch/alpha/kernel/setup.c +@@ -131,6 +131,7 @@ static void determine_cpu_caches (unsigned int); + + static char __initdata command_line[COMMAND_LINE_SIZE]; + ++#ifdef CONFIG_VGA_CONSOLE + /* + * The format of "screen_info" is strange, and due to early + * i386-setup code. This is just enough to make the console +@@ -147,6 +148,7 @@ struct screen_info screen_info = { + }; + + EXPORT_SYMBOL(screen_info); ++#endif + + /* + * The direct map I/O window, if any. This should be the same +diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c +index 7c420d8dac53d9..7de8a5d2d20667 100644 +--- a/arch/alpha/kernel/sys_sio.c ++++ b/arch/alpha/kernel/sys_sio.c +@@ -57,11 +57,13 @@ sio_init_irq(void) + static inline void __init + alphabook1_init_arch(void) + { ++#ifdef CONFIG_VGA_CONSOLE + /* The AlphaBook1 has LCD video fixed at 800x600, + 37 rows and 100 cols. */ + screen_info.orig_y = 37; + screen_info.orig_video_cols = 100; + screen_info.orig_video_lines = 37; ++#endif + + lca_init_arch(); + } +diff --git a/arch/arc/boot/dts/hsdk.dts b/arch/arc/boot/dts/hsdk.dts +index 6691f425507788..41b980df862b14 100644 +--- a/arch/arc/boot/dts/hsdk.dts ++++ b/arch/arc/boot/dts/hsdk.dts +@@ -205,7 +205,6 @@ dmac_cfg_clk: dmac-gpu-cfg-clk { + }; + + gmac: ethernet@8000 { +- #interrupt-cells = <1>; + compatible = "snps,dwmac"; + reg = <0x8000 0x2000>; + interrupts = <10>; +diff --git a/arch/arc/include/asm/cacheflush.h b/arch/arc/include/asm/cacheflush.h +index bd5b1a9a054402..6fc74500a9f52a 100644 +--- a/arch/arc/include/asm/cacheflush.h ++++ b/arch/arc/include/asm/cacheflush.h +@@ -40,6 +40,7 @@ void dma_cache_wback(phys_addr_t start, unsigned long sz); + + /* TBD: optimize this */ + #define flush_cache_vmap(start, end) flush_cache_all() ++#define flush_cache_vmap_early(start, end) do { } while (0) + #define flush_cache_vunmap(start, end) flush_cache_all() + + #define flush_cache_dup_mm(mm) /* called on fork (VIVT only) */ +diff --git a/arch/arc/include/asm/jump_label.h b/arch/arc/include/asm/jump_label.h +index 9d96180797396b..a339223d9e052b 100644 +--- a/arch/arc/include/asm/jump_label.h ++++ b/arch/arc/include/asm/jump_label.h +@@ -31,7 +31,7 @@ + static __always_inline bool arch_static_branch(struct static_key *key, + bool branch) + { +- asm_volatile_goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)" \n" ++ asm goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)" \n" + "1: \n" + "nop \n" + ".pushsection __jump_table, \"aw\" \n" +@@ -47,7 +47,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, + static __always_inline bool arch_static_branch_jump(struct static_key *key, + bool branch) + { +- asm_volatile_goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)" \n" ++ asm goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)" \n" + "1: \n" + "b %l[l_yes] \n" + ".pushsection __jump_table, \"aw\" \n" +diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c +index 4dcf8589b708ac..d08a5092c2b4d4 100644 +--- a/arch/arc/kernel/setup.c ++++ b/arch/arc/kernel/setup.c +@@ -153,7 +153,7 @@ static int arcv2_mumbojumbo(int c, struct cpuinfo_arc *info, char *buf, int len) + { + int n = 0; + #ifdef CONFIG_ISA_ARCV2 +- const char *release, *cpu_nm, *isa_nm = "ARCv2"; ++ const char *release = "", *cpu_nm = "HS38", *isa_nm = "ARCv2"; + int dual_issue = 0, dual_enb = 0, mpy_opt, present; + int bpu_full, bpu_cache, bpu_pred, bpu_ret_stk; + char mpy_nm[16], lpb_nm[32]; +@@ -172,8 +172,6 @@ static int arcv2_mumbojumbo(int c, struct cpuinfo_arc *info, char *buf, int len) + * releases only update it. + */ + +- cpu_nm = "HS38"; +- + if (info->arcver > 0x50 && info->arcver <= 0x53) { + release = arc_hs_rel[info->arcver - 0x51].str; + } else { +diff --git a/arch/arc/kernel/signal.c b/arch/arc/kernel/signal.c +index 0b3bb529d24632..8f6f4a5429646f 100644 +--- a/arch/arc/kernel/signal.c ++++ b/arch/arc/kernel/signal.c +@@ -62,7 +62,7 @@ struct rt_sigframe { + unsigned int sigret_magic; + }; + +-static int save_arcv2_regs(struct sigcontext *mctx, struct pt_regs *regs) ++static int save_arcv2_regs(struct sigcontext __user *mctx, struct pt_regs *regs) + { + int err = 0; + #ifndef CONFIG_ISA_ARCOMPACT +@@ -75,12 +75,12 @@ static int save_arcv2_regs(struct sigcontext *mctx, struct pt_regs *regs) + #else + v2abi.r58 = v2abi.r59 = 0; + #endif +- err = __copy_to_user(&mctx->v2abi, &v2abi, sizeof(v2abi)); ++ err = __copy_to_user(&mctx->v2abi, (void const *)&v2abi, sizeof(v2abi)); + #endif + return err; + } + +-static int restore_arcv2_regs(struct sigcontext *mctx, struct pt_regs *regs) ++static int restore_arcv2_regs(struct sigcontext __user *mctx, struct pt_regs *regs) + { + int err = 0; + #ifndef CONFIG_ISA_ARCOMPACT +diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig +index 9557808e8937b1..57c0448d017a13 100644 +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -589,8 +589,8 @@ source "arch/arm/mm/Kconfig" + + config IWMMXT + bool "Enable iWMMXt support" +- depends on CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_PJ4 || CPU_PJ4B +- default y if PXA27x || PXA3xx || ARCH_MMP || CPU_PJ4 || CPU_PJ4B ++ depends on CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK ++ default y if PXA27x || PXA3xx || ARCH_MMP + help + Enable support for iWMMXt context switching at run time if + running on a CPU that supports it. +diff --git a/arch/arm/Makefile b/arch/arm/Makefile +index 547e5856eaa0d3..5ba42f69f8ce0c 100644 +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -304,11 +304,7 @@ $(INSTALL_TARGETS): KBUILD_IMAGE = $(boot)/$(patsubst %install,%Image,$@) + $(INSTALL_TARGETS): + $(call cmd,install) + +-PHONY += vdso_install +-vdso_install: +-ifeq ($(CONFIG_VDSO),y) +- $(Q)$(MAKE) $(build)=arch/arm/vdso $@ +-endif ++vdso-install-$(CONFIG_VDSO) += arch/arm/vdso/vdso.so.dbg + + # My testing targets (bypasses dependencies) + bp:; $(Q)$(MAKE) $(build)=$(boot) $(boot)/bootpImage +@@ -331,7 +327,6 @@ define archhelp + echo ' Install using (your) ~/bin/$(INSTALLKERNEL) or' + echo ' (distribution) /sbin/$(INSTALLKERNEL) or' + echo ' install to $$(INSTALL_PATH) and run lilo' +- echo ' vdso_install - Install unstripped vdso.so to $$(INSTALL_MOD_PATH)/vdso' + echo + echo ' multi_v7_lpae_defconfig - multi_v7_defconfig with CONFIG_ARM_LPAE enabled' + endef +diff --git a/arch/arm/boot/dts/allwinner/Makefile b/arch/arm/boot/dts/allwinner/Makefile +index eebb5a0c873ad4..296be33ec93465 100644 +--- a/arch/arm/boot/dts/allwinner/Makefile ++++ b/arch/arm/boot/dts/allwinner/Makefile +@@ -259,68 +259,6 @@ dtb-$(CONFIG_MACH_SUN8I) += \ + sun8i-v3s-licheepi-zero.dtb \ + sun8i-v3s-licheepi-zero-dock.dtb \ + sun8i-v40-bananapi-m2-berry.dtb +-dtb-$(CONFIG_MACH_SUN8I) += \ +- sun8i-a23-evb.dtb \ +- sun8i-a23-gt90h-v4.dtb \ +- sun8i-a23-inet86dz.dtb \ +- sun8i-a23-ippo-q8h-v5.dtb \ +- sun8i-a23-ippo-q8h-v1.2.dtb \ +- sun8i-a23-polaroid-mid2407pxe03.dtb \ +- sun8i-a23-polaroid-mid2809pxe04.dtb \ +- sun8i-a23-q8-tablet.dtb \ +- sun8i-a33-et-q8-v1.6.dtb \ +- sun8i-a33-ga10h-v1.1.dtb \ +- sun8i-a33-inet-d978-rev2.dtb \ +- sun8i-a33-ippo-q8h-v1.2.dtb \ +- sun8i-a33-olinuxino.dtb \ +- sun8i-a33-q8-tablet.dtb \ +- sun8i-a33-sinlinx-sina33.dtb \ +- sun8i-a83t-allwinner-h8homlet-v2.dtb \ +- sun8i-a83t-bananapi-m3.dtb \ +- sun8i-a83t-cubietruck-plus.dtb \ +- sun8i-a83t-tbs-a711.dtb \ +- sun8i-h2-plus-bananapi-m2-zero.dtb \ +- sun8i-h2-plus-libretech-all-h3-cc.dtb \ +- sun8i-h2-plus-orangepi-r1.dtb \ +- sun8i-h2-plus-orangepi-zero.dtb \ +- sun8i-h3-bananapi-m2-plus.dtb \ +- sun8i-h3-bananapi-m2-plus-v1.2.dtb \ +- sun8i-h3-beelink-x2.dtb \ +- sun8i-h3-libretech-all-h3-cc.dtb \ +- sun8i-h3-mapleboard-mp130.dtb \ +- sun8i-h3-nanopi-duo2.dtb \ +- sun8i-h3-nanopi-m1.dtb\ +- \ +- sun8i-h3-nanopi-m1-plus.dtb \ +- sun8i-h3-nanopi-neo.dtb \ +- sun8i-h3-nanopi-neo-air.dtb \ +- sun8i-h3-nanopi-r1.dtb \ +- sun8i-h3-orangepi-2.dtb \ +- sun8i-h3-orangepi-lite.dtb \ +- sun8i-h3-orangepi-one.dtb \ +- sun8i-h3-orangepi-pc.dtb \ +- sun8i-h3-orangepi-pc-plus.dtb \ +- sun8i-h3-orangepi-plus.dtb \ +- sun8i-h3-orangepi-plus2e.dtb \ +- sun8i-h3-orangepi-zero-plus2.dtb \ +- sun8i-h3-rervision-dvk.dtb \ +- sun8i-h3-zeropi.dtb \ +- sun8i-h3-emlid-neutis-n5h3-devboard.dtb \ +- sun8i-r16-bananapi-m2m.dtb \ +- sun8i-r16-nintendo-nes-classic.dtb \ +- sun8i-r16-nintendo-super-nes-classic.dtb \ +- sun8i-r16-parrot.dtb \ +- sun8i-r40-bananapi-m2-ultra.dtb \ +- sun8i-r40-oka40i-c.dtb \ +- sun8i-s3-elimo-initium.dtb \ +- sun8i-s3-lichee-zero-plus.dtb \ +- sun8i-s3-pinecube.dtb \ +- sun8i-t113s-mangopi-mq-r-t113.dtb \ +- sun8i-t3-cqa3t-bv3.dtb \ +- sun8i-v3-sl631-imx179.dtb \ +- sun8i-v3s-licheepi-zero.dtb \ +- sun8i-v3s-licheepi-zero-dock.dtb \ +- sun8i-v40-bananapi-m2-berry.dtb + dtb-$(CONFIG_MACH_SUN9I) += \ + sun9i-a80-optimus.dtb \ + sun9i-a80-cubieboard4.dtb +diff --git a/arch/arm/boot/dts/amazon/alpine.dtsi b/arch/arm/boot/dts/amazon/alpine.dtsi +index ff68dfb4eb7874..90bd12feac0101 100644 +--- a/arch/arm/boot/dts/amazon/alpine.dtsi ++++ b/arch/arm/boot/dts/amazon/alpine.dtsi +@@ -167,7 +167,6 @@ pcie@fbc00000 { + msix: msix@fbe00000 { + compatible = "al,alpine-msix"; + reg = <0x0 0xfbe00000 0x0 0x100000>; +- interrupt-controller; + msi-controller; + al,msi-base-spi = <96>; + al,msi-num-spis = <64>; +diff --git a/arch/arm/boot/dts/arm/arm-realview-pb1176.dts b/arch/arm/boot/dts/arm/arm-realview-pb1176.dts +index efed325af88d20..d99bac02232b37 100644 +--- a/arch/arm/boot/dts/arm/arm-realview-pb1176.dts ++++ b/arch/arm/boot/dts/arm/arm-realview-pb1176.dts +@@ -451,7 +451,7 @@ pb1176_serial3: serial@1010f000 { + + /* Direct-mapped development chip ROM */ + pb1176_rom@10200000 { +- compatible = "direct-mapped"; ++ compatible = "mtd-rom"; + reg = <0x10200000 0x4000>; + bank-width = <1>; + }; +diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts +index e899de681f4752..5be0e8fd2633c2 100644 +--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts ++++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts +@@ -45,8 +45,8 @@ spi1_gpio: spi1-gpio { + num-chipselects = <1>; + cs-gpios = <&gpio0 ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>; + +- tpmdev@0 { +- compatible = "tcg,tpm_tis-spi"; ++ tpm@0 { ++ compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + spi-max-frequency = <33000000>; + reg = <0>; + }; +diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts +index a677c827e758fe..5a8169bbda8792 100644 +--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts ++++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts +@@ -80,8 +80,8 @@ spi_gpio: spi { + gpio-miso = <&gpio ASPEED_GPIO(R, 5) GPIO_ACTIVE_HIGH>; + num-chipselects = <1>; + +- tpmdev@0 { +- compatible = "tcg,tpm_tis-spi"; ++ tpm@0 { ++ compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + spi-max-frequency = <33000000>; + reg = <0>; + }; +diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-tacoma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-tacoma.dts +index 3f6010ef2b86f2..213023bc5aec41 100644 +--- a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-tacoma.dts ++++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-tacoma.dts +@@ -456,7 +456,7 @@ &i2c1 { + status = "okay"; + + tpm: tpm@2e { +- compatible = "tcg,tpm-tis-i2c"; ++ compatible = "nuvoton,npct75x", "tcg,tpm-tis-i2c"; + reg = <0x2e>; + }; + }; +diff --git a/arch/arm/boot/dts/aspeed/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g4.dtsi +index 530491ae5eb260..857cb26ed6d7e8 100644 +--- a/arch/arm/boot/dts/aspeed/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed/aspeed-g4.dtsi +@@ -466,7 +466,6 @@ i2c_ic: interrupt-controller@0 { + i2c0: i2c-bus@40 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x40 0x40>; + compatible = "aspeed,ast2400-i2c-bus"; +@@ -482,7 +481,6 @@ i2c0: i2c-bus@40 { + i2c1: i2c-bus@80 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x80 0x40>; + compatible = "aspeed,ast2400-i2c-bus"; +@@ -498,7 +496,6 @@ i2c1: i2c-bus@80 { + i2c2: i2c-bus@c0 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0xc0 0x40>; + compatible = "aspeed,ast2400-i2c-bus"; +@@ -515,7 +512,6 @@ i2c2: i2c-bus@c0 { + i2c3: i2c-bus@100 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x100 0x40>; + compatible = "aspeed,ast2400-i2c-bus"; +@@ -532,7 +528,6 @@ i2c3: i2c-bus@100 { + i2c4: i2c-bus@140 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x140 0x40>; + compatible = "aspeed,ast2400-i2c-bus"; +@@ -549,7 +544,6 @@ i2c4: i2c-bus@140 { + i2c5: i2c-bus@180 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x180 0x40>; + compatible = "aspeed,ast2400-i2c-bus"; +@@ -566,7 +560,6 @@ i2c5: i2c-bus@180 { + i2c6: i2c-bus@1c0 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x1c0 0x40>; + compatible = "aspeed,ast2400-i2c-bus"; +@@ -583,7 +576,6 @@ i2c6: i2c-bus@1c0 { + i2c7: i2c-bus@300 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x300 0x40>; + compatible = "aspeed,ast2400-i2c-bus"; +@@ -600,7 +592,6 @@ i2c7: i2c-bus@300 { + i2c8: i2c-bus@340 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x340 0x40>; + compatible = "aspeed,ast2400-i2c-bus"; +@@ -617,7 +608,6 @@ i2c8: i2c-bus@340 { + i2c9: i2c-bus@380 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x380 0x40>; + compatible = "aspeed,ast2400-i2c-bus"; +@@ -634,7 +624,6 @@ i2c9: i2c-bus@380 { + i2c10: i2c-bus@3c0 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x3c0 0x40>; + compatible = "aspeed,ast2400-i2c-bus"; +@@ -651,7 +640,6 @@ i2c10: i2c-bus@3c0 { + i2c11: i2c-bus@400 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x400 0x40>; + compatible = "aspeed,ast2400-i2c-bus"; +@@ -668,7 +656,6 @@ i2c11: i2c-bus@400 { + i2c12: i2c-bus@440 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x440 0x40>; + compatible = "aspeed,ast2400-i2c-bus"; +@@ -685,7 +672,6 @@ i2c12: i2c-bus@440 { + i2c13: i2c-bus@480 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x480 0x40>; + compatible = "aspeed,ast2400-i2c-bus"; +diff --git a/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi +index 04f98d1dbb97c8..e6f3cf3c721e57 100644 +--- a/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed/aspeed-g5.dtsi +@@ -363,6 +363,7 @@ sgpio: sgpio@1e780200 { + interrupts = <40>; + reg = <0x1e780200 0x0100>; + clocks = <&syscon ASPEED_CLK_APB>; ++ #interrupt-cells = <2>; + interrupt-controller; + bus-frequency = <12000000>; + pinctrl-names = "default"; +@@ -594,7 +595,6 @@ i2c_ic: interrupt-controller@0 { + i2c0: i2c-bus@40 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x40 0x40>; + compatible = "aspeed,ast2500-i2c-bus"; +@@ -610,7 +610,6 @@ i2c0: i2c-bus@40 { + i2c1: i2c-bus@80 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x80 0x40>; + compatible = "aspeed,ast2500-i2c-bus"; +@@ -626,7 +625,6 @@ i2c1: i2c-bus@80 { + i2c2: i2c-bus@c0 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0xc0 0x40>; + compatible = "aspeed,ast2500-i2c-bus"; +@@ -643,7 +641,6 @@ i2c2: i2c-bus@c0 { + i2c3: i2c-bus@100 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x100 0x40>; + compatible = "aspeed,ast2500-i2c-bus"; +@@ -660,7 +657,6 @@ i2c3: i2c-bus@100 { + i2c4: i2c-bus@140 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x140 0x40>; + compatible = "aspeed,ast2500-i2c-bus"; +@@ -677,7 +673,6 @@ i2c4: i2c-bus@140 { + i2c5: i2c-bus@180 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x180 0x40>; + compatible = "aspeed,ast2500-i2c-bus"; +@@ -694,7 +689,6 @@ i2c5: i2c-bus@180 { + i2c6: i2c-bus@1c0 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x1c0 0x40>; + compatible = "aspeed,ast2500-i2c-bus"; +@@ -711,7 +705,6 @@ i2c6: i2c-bus@1c0 { + i2c7: i2c-bus@300 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x300 0x40>; + compatible = "aspeed,ast2500-i2c-bus"; +@@ -728,7 +721,6 @@ i2c7: i2c-bus@300 { + i2c8: i2c-bus@340 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x340 0x40>; + compatible = "aspeed,ast2500-i2c-bus"; +@@ -745,7 +737,6 @@ i2c8: i2c-bus@340 { + i2c9: i2c-bus@380 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x380 0x40>; + compatible = "aspeed,ast2500-i2c-bus"; +@@ -762,7 +753,6 @@ i2c9: i2c-bus@380 { + i2c10: i2c-bus@3c0 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x3c0 0x40>; + compatible = "aspeed,ast2500-i2c-bus"; +@@ -779,7 +769,6 @@ i2c10: i2c-bus@3c0 { + i2c11: i2c-bus@400 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x400 0x40>; + compatible = "aspeed,ast2500-i2c-bus"; +@@ -796,7 +785,6 @@ i2c11: i2c-bus@400 { + i2c12: i2c-bus@440 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x440 0x40>; + compatible = "aspeed,ast2500-i2c-bus"; +@@ -813,7 +801,6 @@ i2c12: i2c-bus@440 { + i2c13: i2c-bus@480 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + + reg = <0x480 0x40>; + compatible = "aspeed,ast2500-i2c-bus"; +diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi +index c4d1faade8be33..29f94696d8b189 100644 +--- a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi ++++ b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi +@@ -474,6 +474,7 @@ sgpiom0: sgpiom@1e780500 { + reg = <0x1e780500 0x100>; + interrupts = ; + clocks = <&syscon ASPEED_CLK_APB2>; ++ #interrupt-cells = <2>; + interrupt-controller; + bus-frequency = <12000000>; + pinctrl-names = "default"; +@@ -488,6 +489,7 @@ sgpiom1: sgpiom@1e780600 { + reg = <0x1e780600 0x100>; + interrupts = ; + clocks = <&syscon ASPEED_CLK_APB2>; ++ #interrupt-cells = <2>; + interrupt-controller; + bus-frequency = <12000000>; + pinctrl-names = "default"; +@@ -902,7 +904,6 @@ &i2c { + i2c0: i2c-bus@80 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x80 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +@@ -917,7 +918,6 @@ i2c0: i2c-bus@80 { + i2c1: i2c-bus@100 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x100 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +@@ -932,7 +932,6 @@ i2c1: i2c-bus@100 { + i2c2: i2c-bus@180 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x180 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +@@ -947,7 +946,6 @@ i2c2: i2c-bus@180 { + i2c3: i2c-bus@200 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x200 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +@@ -962,7 +960,6 @@ i2c3: i2c-bus@200 { + i2c4: i2c-bus@280 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x280 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +@@ -977,7 +974,6 @@ i2c4: i2c-bus@280 { + i2c5: i2c-bus@300 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x300 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +@@ -992,7 +988,6 @@ i2c5: i2c-bus@300 { + i2c6: i2c-bus@380 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x380 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +@@ -1007,7 +1002,6 @@ i2c6: i2c-bus@380 { + i2c7: i2c-bus@400 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x400 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +@@ -1022,7 +1016,6 @@ i2c7: i2c-bus@400 { + i2c8: i2c-bus@480 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x480 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +@@ -1037,7 +1030,6 @@ i2c8: i2c-bus@480 { + i2c9: i2c-bus@500 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x500 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +@@ -1052,7 +1044,6 @@ i2c9: i2c-bus@500 { + i2c10: i2c-bus@580 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x580 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +@@ -1067,7 +1058,6 @@ i2c10: i2c-bus@580 { + i2c11: i2c-bus@600 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x600 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +@@ -1082,7 +1072,6 @@ i2c11: i2c-bus@600 { + i2c12: i2c-bus@680 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x680 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +@@ -1097,7 +1086,6 @@ i2c12: i2c-bus@680 { + i2c13: i2c-bus@700 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x700 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +@@ -1112,7 +1100,6 @@ i2c13: i2c-bus@700 { + i2c14: i2c-bus@780 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x780 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +@@ -1127,7 +1114,6 @@ i2c14: i2c-bus@780 { + i2c15: i2c-bus@800 { + #address-cells = <1>; + #size-cells = <0>; +- #interrupt-cells = <1>; + reg = <0x800 0x80>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; +diff --git a/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi b/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi +index 31590d3186a2e0..00e5887c926f18 100644 +--- a/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi ++++ b/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi +@@ -35,8 +35,8 @@ spi_gpio: spi { + gpio-mosi = <&gpio0 ASPEED_GPIO(X, 4) GPIO_ACTIVE_HIGH>; + gpio-miso = <&gpio0 ASPEED_GPIO(X, 5) GPIO_ACTIVE_HIGH>; + +- tpmdev@0 { +- compatible = "tcg,tpm_tis-spi"; ++ tpm@0 { ++ compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + spi-max-frequency = <33000000>; + reg = <0>; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm-cygnus.dtsi b/arch/arm/boot/dts/broadcom/bcm-cygnus.dtsi +index f9f79ed825181b..07ca0d993c9fdb 100644 +--- a/arch/arm/boot/dts/broadcom/bcm-cygnus.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm-cygnus.dtsi +@@ -167,6 +167,7 @@ gpio_crmu: gpio@3024800 { + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; ++ #interrupt-cells = <2>; + interrupt-parent = <&mailbox>; + interrupts = <0>; + }; +@@ -247,6 +248,7 @@ gpio_ccm: gpio@1800a000 { + gpio-controller; + interrupts = ; + interrupt-controller; ++ #interrupt-cells = <2>; + }; + + i2c1: i2c@1800b000 { +@@ -518,6 +520,7 @@ gpio_asiu: gpio@180a5000 { + gpio-controller; + + interrupt-controller; ++ #interrupt-cells = <2>; + interrupts = ; + gpio-ranges = <&pinctrl 0 42 1>, + <&pinctrl 1 44 3>, +diff --git a/arch/arm/boot/dts/broadcom/bcm-hr2.dtsi b/arch/arm/boot/dts/broadcom/bcm-hr2.dtsi +index 788a6806191a33..75545b10ef2fa6 100644 +--- a/arch/arm/boot/dts/broadcom/bcm-hr2.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm-hr2.dtsi +@@ -200,6 +200,7 @@ gpiob: gpio@30000 { + gpio-controller; + ngpios = <4>; + interrupt-controller; ++ #interrupt-cells = <2>; + interrupts = ; + }; + +diff --git a/arch/arm/boot/dts/broadcom/bcm-nsp.dtsi b/arch/arm/boot/dts/broadcom/bcm-nsp.dtsi +index 9d20ba3b1ffb13..6a4482c9316741 100644 +--- a/arch/arm/boot/dts/broadcom/bcm-nsp.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm-nsp.dtsi +@@ -180,6 +180,7 @@ gpioa: gpio@20 { + gpio-controller; + ngpios = <32>; + interrupt-controller; ++ #interrupt-cells = <2>; + interrupts = ; + gpio-ranges = <&pinctrl 0 0 32>; + }; +@@ -352,6 +353,7 @@ gpiob: gpio@30000 { + gpio-controller; + ngpios = <4>; + interrupt-controller; ++ #interrupt-cells = <2>; + interrupts = ; + }; + +diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi-400.dts b/arch/arm/boot/dts/broadcom/bcm2711-rpi-400.dts +index 1ab8184302db44..5a2869a18bd555 100644 +--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-400.dts ++++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-400.dts +@@ -36,9 +36,7 @@ &led_pwr { + gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; + }; + +-&leds { +- /delete-node/ led_act; +-}; ++/delete-node/ &led_act; + + &pm { + /delete-property/ system-power-controller; +diff --git a/arch/arm/boot/dts/broadcom/bcm4708-buffalo-wzr-1166dhp-common.dtsi b/arch/arm/boot/dts/broadcom/bcm4708-buffalo-wzr-1166dhp-common.dtsi +index 42bcbf10957c40..9f9084269ef58b 100644 +--- a/arch/arm/boot/dts/broadcom/bcm4708-buffalo-wzr-1166dhp-common.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm4708-buffalo-wzr-1166dhp-common.dtsi +@@ -181,5 +181,13 @@ port@4 { + port@5 { + label = "cpu"; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm4708-luxul-xap-1510.dts b/arch/arm/boot/dts/broadcom/bcm4708-luxul-xap-1510.dts +index e04d2e5ea51aa4..72e960c888ac86 100644 +--- a/arch/arm/boot/dts/broadcom/bcm4708-luxul-xap-1510.dts ++++ b/arch/arm/boot/dts/broadcom/bcm4708-luxul-xap-1510.dts +@@ -85,5 +85,13 @@ port@4 { + port@5 { + label = "cpu"; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm4708-luxul-xwc-1000.dts b/arch/arm/boot/dts/broadcom/bcm4708-luxul-xwc-1000.dts +index a399800139d9ce..750e17482371cf 100644 +--- a/arch/arm/boot/dts/broadcom/bcm4708-luxul-xwc-1000.dts ++++ b/arch/arm/boot/dts/broadcom/bcm4708-luxul-xwc-1000.dts +@@ -88,5 +88,13 @@ port@4 { + port@5 { + label = "cpu"; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm4708-netgear-r6250.dts b/arch/arm/boot/dts/broadcom/bcm4708-netgear-r6250.dts +index fad3473810a2e5..2bdbc7d18b0eb1 100644 +--- a/arch/arm/boot/dts/broadcom/bcm4708-netgear-r6250.dts ++++ b/arch/arm/boot/dts/broadcom/bcm4708-netgear-r6250.dts +@@ -122,5 +122,13 @@ port@4 { + port@5 { + label = "cpu"; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm4708-smartrg-sr400ac.dts b/arch/arm/boot/dts/broadcom/bcm4708-smartrg-sr400ac.dts +index 5b2b7b8b3b123f..b226bef3369cf7 100644 +--- a/arch/arm/boot/dts/broadcom/bcm4708-smartrg-sr400ac.dts ++++ b/arch/arm/boot/dts/broadcom/bcm4708-smartrg-sr400ac.dts +@@ -145,6 +145,14 @@ port@4 { + port@5 { + label = "cpu"; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; + +diff --git a/arch/arm/boot/dts/broadcom/bcm47081-buffalo-wzr-600dhp2.dts b/arch/arm/boot/dts/broadcom/bcm47081-buffalo-wzr-600dhp2.dts +index d0a26b643b82fe..192b8db5a89c39 100644 +--- a/arch/arm/boot/dts/broadcom/bcm47081-buffalo-wzr-600dhp2.dts ++++ b/arch/arm/boot/dts/broadcom/bcm47081-buffalo-wzr-600dhp2.dts +@@ -145,5 +145,13 @@ port@4 { + port@5 { + label = "cpu"; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm47081-luxul-xap-1410.dts b/arch/arm/boot/dts/broadcom/bcm47081-luxul-xap-1410.dts +index 9f21d6d6d35b75..0198b5f9e4a750 100644 +--- a/arch/arm/boot/dts/broadcom/bcm47081-luxul-xap-1410.dts ++++ b/arch/arm/boot/dts/broadcom/bcm47081-luxul-xap-1410.dts +@@ -81,5 +81,13 @@ port@4 { + port@5 { + label = "cpu"; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm47081-luxul-xwr-1200.dts b/arch/arm/boot/dts/broadcom/bcm47081-luxul-xwr-1200.dts +index 2561072917021c..73ff1694a4a0b3 100644 +--- a/arch/arm/boot/dts/broadcom/bcm47081-luxul-xwr-1200.dts ++++ b/arch/arm/boot/dts/broadcom/bcm47081-luxul-xwr-1200.dts +@@ -148,5 +148,13 @@ port@4 { + port@5 { + label = "cpu"; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm4709-netgear-r8000.dts b/arch/arm/boot/dts/broadcom/bcm4709-netgear-r8000.dts +index 707c561703ed81..55fc9f44cbc7f5 100644 +--- a/arch/arm/boot/dts/broadcom/bcm4709-netgear-r8000.dts ++++ b/arch/arm/boot/dts/broadcom/bcm4709-netgear-r8000.dts +@@ -227,6 +227,14 @@ port@4 { + label = "wan"; + }; + ++ port@5 { ++ status = "disabled"; ++ }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ + port@8 { + label = "cpu"; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm47094-dlink-dir-885l.dts b/arch/arm/boot/dts/broadcom/bcm47094-dlink-dir-885l.dts +index c914569ddd5ecc..e6d26987865d02 100644 +--- a/arch/arm/boot/dts/broadcom/bcm47094-dlink-dir-885l.dts ++++ b/arch/arm/boot/dts/broadcom/bcm47094-dlink-dir-885l.dts +@@ -144,6 +144,14 @@ port@4 { + label = "wan"; + }; + ++ port@5 { ++ status = "disabled"; ++ }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ + port@8 { + label = "cpu"; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm47094-dlink-dir-890l.dts b/arch/arm/boot/dts/broadcom/bcm47094-dlink-dir-890l.dts +index f050acbea0b207..3124dfd01b9447 100644 +--- a/arch/arm/boot/dts/broadcom/bcm47094-dlink-dir-890l.dts ++++ b/arch/arm/boot/dts/broadcom/bcm47094-dlink-dir-890l.dts +@@ -192,6 +192,14 @@ port@4 { + label = "wan"; + }; + ++ port@5 { ++ status = "disabled"; ++ }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ + port@8 { + label = "cpu"; + phy-mode = "rgmii"; +diff --git a/arch/arm/boot/dts/broadcom/bcm47094-luxul-abr-4500.dts b/arch/arm/boot/dts/broadcom/bcm47094-luxul-abr-4500.dts +index e8991d4e248ce2..e374062eb5b762 100644 +--- a/arch/arm/boot/dts/broadcom/bcm47094-luxul-abr-4500.dts ++++ b/arch/arm/boot/dts/broadcom/bcm47094-luxul-abr-4500.dts +@@ -107,5 +107,13 @@ port@4 { + port@5 { + label = "cpu"; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm47094-luxul-xap-1610.dts b/arch/arm/boot/dts/broadcom/bcm47094-luxul-xap-1610.dts +index afc635c8cdebbc..badafa024d24c5 100644 +--- a/arch/arm/boot/dts/broadcom/bcm47094-luxul-xap-1610.dts ++++ b/arch/arm/boot/dts/broadcom/bcm47094-luxul-xap-1610.dts +@@ -120,5 +120,13 @@ port@1 { + port@5 { + label = "cpu"; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm47094-luxul-xbr-4500.dts b/arch/arm/boot/dts/broadcom/bcm47094-luxul-xbr-4500.dts +index 7cfa4607ef311f..cf95af9db1e66d 100644 +--- a/arch/arm/boot/dts/broadcom/bcm47094-luxul-xbr-4500.dts ++++ b/arch/arm/boot/dts/broadcom/bcm47094-luxul-xbr-4500.dts +@@ -107,5 +107,13 @@ port@4 { + port@5 { + label = "cpu"; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm47094-luxul-xwc-2000.dts b/arch/arm/boot/dts/broadcom/bcm47094-luxul-xwc-2000.dts +index d55e10095eae79..992c19e1cfa173 100644 +--- a/arch/arm/boot/dts/broadcom/bcm47094-luxul-xwc-2000.dts ++++ b/arch/arm/boot/dts/broadcom/bcm47094-luxul-xwc-2000.dts +@@ -75,5 +75,13 @@ port@0 { + port@5 { + label = "cpu"; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm47094-luxul-xwr-3100.dts b/arch/arm/boot/dts/broadcom/bcm47094-luxul-xwr-3100.dts +index ccf031c0e276d6..4d0ba315a2049e 100644 +--- a/arch/arm/boot/dts/broadcom/bcm47094-luxul-xwr-3100.dts ++++ b/arch/arm/boot/dts/broadcom/bcm47094-luxul-xwr-3100.dts +@@ -147,5 +147,13 @@ port@4 { + port@5 { + label = "cpu"; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm47094-luxul-xwr-3150-v1.dts b/arch/arm/boot/dts/broadcom/bcm47094-luxul-xwr-3150-v1.dts +index e28f7a3501179f..83c429afc2974d 100644 +--- a/arch/arm/boot/dts/broadcom/bcm47094-luxul-xwr-3150-v1.dts ++++ b/arch/arm/boot/dts/broadcom/bcm47094-luxul-xwr-3150-v1.dts +@@ -158,5 +158,13 @@ port@4 { + port@5 { + label = "cpu"; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; +diff --git a/arch/arm/boot/dts/broadcom/bcm53015-meraki-mr26.dts b/arch/arm/boot/dts/broadcom/bcm53015-meraki-mr26.dts +index 03ad614e6b7214..0bf5106f7012c9 100644 +--- a/arch/arm/boot/dts/broadcom/bcm53015-meraki-mr26.dts ++++ b/arch/arm/boot/dts/broadcom/bcm53015-meraki-mr26.dts +@@ -124,6 +124,14 @@ fixed-link { + full-duplex; + }; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; + +diff --git a/arch/arm/boot/dts/broadcom/bcm53016-meraki-mr32.dts b/arch/arm/boot/dts/broadcom/bcm53016-meraki-mr32.dts +index 26c12bfb0bdd4a..25eeacf6a2484c 100644 +--- a/arch/arm/boot/dts/broadcom/bcm53016-meraki-mr32.dts ++++ b/arch/arm/boot/dts/broadcom/bcm53016-meraki-mr32.dts +@@ -185,6 +185,14 @@ fixed-link { + full-duplex; + }; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; + +diff --git a/arch/arm/boot/dts/broadcom/bcm953012er.dts b/arch/arm/boot/dts/broadcom/bcm953012er.dts +index 4fe3b365337670..d939ec9f4a9e79 100644 +--- a/arch/arm/boot/dts/broadcom/bcm953012er.dts ++++ b/arch/arm/boot/dts/broadcom/bcm953012er.dts +@@ -84,6 +84,14 @@ port@5 { + label = "cpu"; + ethernet = <&gmac0>; + }; ++ ++ port@7 { ++ status = "disabled"; ++ }; ++ ++ port@8 { ++ status = "disabled"; ++ }; + }; + }; + +diff --git a/arch/arm/boot/dts/intel/ixp/intel-ixp42x-gateway-7001.dts b/arch/arm/boot/dts/intel/ixp/intel-ixp42x-gateway-7001.dts +index 4d70f6afd13ab5..6d5e69035f94dc 100644 +--- a/arch/arm/boot/dts/intel/ixp/intel-ixp42x-gateway-7001.dts ++++ b/arch/arm/boot/dts/intel/ixp/intel-ixp42x-gateway-7001.dts +@@ -60,6 +60,8 @@ pci@c0000000 { + * We have slots (IDSEL) 1 and 2 with one assigned IRQ + * each handling all IRQs. + */ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = + /* IDSEL 1 */ + <0x0800 0 0 1 &gpio0 11 IRQ_TYPE_LEVEL_LOW>, /* INT A on slot 1 is irq 11 */ +diff --git a/arch/arm/boot/dts/intel/ixp/intel-ixp42x-goramo-multilink.dts b/arch/arm/boot/dts/intel/ixp/intel-ixp42x-goramo-multilink.dts +index 9ec0169bacf8c2..5f4c849915db71 100644 +--- a/arch/arm/boot/dts/intel/ixp/intel-ixp42x-goramo-multilink.dts ++++ b/arch/arm/boot/dts/intel/ixp/intel-ixp42x-goramo-multilink.dts +@@ -89,6 +89,8 @@ pci@c0000000 { + * The slots have Ethernet, Ethernet, NEC and MPCI. + * The IDSELs are 11, 12, 13, 14. + */ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = + /* IDSEL 11 - Ethernet A */ + <0x5800 0 0 1 &gpio0 4 IRQ_TYPE_LEVEL_LOW>, /* INT A on slot 11 is irq 4 */ +diff --git a/arch/arm/boot/dts/marvell/kirkwood-l-50.dts b/arch/arm/boot/dts/marvell/kirkwood-l-50.dts +index dffb9f84e67c50..c841eb8e7fb1d0 100644 +--- a/arch/arm/boot/dts/marvell/kirkwood-l-50.dts ++++ b/arch/arm/boot/dts/marvell/kirkwood-l-50.dts +@@ -65,6 +65,7 @@ i2c@11000 { + gpio2: gpio-expander@20 { + #gpio-cells = <2>; + #interrupt-cells = <2>; ++ interrupt-controller; + compatible = "semtech,sx1505q"; + reg = <0x20>; + +@@ -79,6 +80,7 @@ gpio2: gpio-expander@20 { + gpio3: gpio-expander@21 { + #gpio-cells = <2>; + #interrupt-cells = <2>; ++ interrupt-controller; + compatible = "semtech,sx1505q"; + reg = <0x21>; + +diff --git a/arch/arm/boot/dts/marvell/mmp2-brownstone.dts b/arch/arm/boot/dts/marvell/mmp2-brownstone.dts +index 04f1ae1382e7a3..bc64348b821851 100644 +--- a/arch/arm/boot/dts/marvell/mmp2-brownstone.dts ++++ b/arch/arm/boot/dts/marvell/mmp2-brownstone.dts +@@ -28,7 +28,7 @@ &uart3 { + &twsi1 { + status = "okay"; + pmic: max8925@3c { +- compatible = "maxium,max8925"; ++ compatible = "maxim,max8925"; + reg = <0x3c>; + interrupts = <1>; + interrupt-parent = <&intcmux4>; +diff --git a/arch/arm/boot/dts/microchip/at91-sama7g5ek.dts b/arch/arm/boot/dts/microchip/at91-sama7g5ek.dts +index 217e9b96c61e5d..20b2497657ae48 100644 +--- a/arch/arm/boot/dts/microchip/at91-sama7g5ek.dts ++++ b/arch/arm/boot/dts/microchip/at91-sama7g5ek.dts +@@ -293,7 +293,7 @@ vddcore: VDD_CORE { + + regulator-state-standby { + regulator-on-in-suspend; +- regulator-suspend-voltage = <1150000>; ++ regulator-suspend-microvolt = <1150000>; + regulator-mode = <4>; + }; + +@@ -314,7 +314,7 @@ vddcpu: VDD_OTHER { + + regulator-state-standby { + regulator-on-in-suspend; +- regulator-suspend-voltage = <1050000>; ++ regulator-suspend-microvolt = <1050000>; + regulator-mode = <4>; + }; + +@@ -331,7 +331,7 @@ vldo1: LDO1 { + regulator-always-on; + + regulator-state-standby { +- regulator-suspend-voltage = <1800000>; ++ regulator-suspend-microvolt = <1800000>; + regulator-on-in-suspend; + }; + +@@ -346,7 +346,7 @@ vldo2: LDO2 { + regulator-max-microvolt = <3700000>; + + regulator-state-standby { +- regulator-suspend-voltage = <1800000>; ++ regulator-suspend-microvolt = <1800000>; + regulator-on-in-suspend; + }; + +diff --git a/arch/arm/boot/dts/microchip/sam9x60.dtsi b/arch/arm/boot/dts/microchip/sam9x60.dtsi +index 73d570a172690c..1705c96f4221e8 100644 +--- a/arch/arm/boot/dts/microchip/sam9x60.dtsi ++++ b/arch/arm/boot/dts/microchip/sam9x60.dtsi +@@ -1312,7 +1312,7 @@ rtt: rtc@fffffe20 { + compatible = "microchip,sam9x60-rtt", "atmel,at91sam9260-rtt"; + reg = <0xfffffe20 0x20>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; +- clocks = <&clk32k 0>; ++ clocks = <&clk32k 1>; + }; + + pit: timer@fffffe40 { +@@ -1338,7 +1338,7 @@ rtc: rtc@fffffea8 { + compatible = "microchip,sam9x60-rtc", "atmel,at91sam9x5-rtc"; + reg = <0xfffffea8 0x100>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; +- clocks = <&clk32k 0>; ++ clocks = <&clk32k 1>; + }; + + watchdog: watchdog@ffffff80 { +diff --git a/arch/arm/boot/dts/microchip/sama7g5.dtsi b/arch/arm/boot/dts/microchip/sama7g5.dtsi +index 269e0a3ca269cd..7a95464bb78d83 100644 +--- a/arch/arm/boot/dts/microchip/sama7g5.dtsi ++++ b/arch/arm/boot/dts/microchip/sama7g5.dtsi +@@ -272,7 +272,7 @@ rtt: rtc@e001d020 { + compatible = "microchip,sama7g5-rtt", "microchip,sam9x60-rtt", "atmel,at91sam9260-rtt"; + reg = <0xe001d020 0x30>; + interrupts = ; +- clocks = <&clk32k 0>; ++ clocks = <&clk32k 1>; + }; + + clk32k: clock-controller@e001d050 { +diff --git a/arch/arm/boot/dts/nuvoton/nuvoton-wpcm450.dtsi b/arch/arm/boot/dts/nuvoton/nuvoton-wpcm450.dtsi +index fd671c7a1e5d64..6e1f0f164cb4f5 100644 +--- a/arch/arm/boot/dts/nuvoton/nuvoton-wpcm450.dtsi ++++ b/arch/arm/boot/dts/nuvoton/nuvoton-wpcm450.dtsi +@@ -120,6 +120,7 @@ gpio0: gpio@0 { + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>, + <3 IRQ_TYPE_LEVEL_HIGH>, + <4 IRQ_TYPE_LEVEL_HIGH>; ++ #interrupt-cells = <2>; + interrupt-controller; + }; + +@@ -128,6 +129,7 @@ gpio1: gpio@1 { + gpio-controller; + #gpio-cells = <2>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; ++ #interrupt-cells = <2>; + interrupt-controller; + }; + +diff --git a/arch/arm/boot/dts/nvidia/tegra30-apalis-v1.1.dtsi b/arch/arm/boot/dts/nvidia/tegra30-apalis-v1.1.dtsi +index 1640763fd4af22..ff0d684622f74d 100644 +--- a/arch/arm/boot/dts/nvidia/tegra30-apalis-v1.1.dtsi ++++ b/arch/arm/boot/dts/nvidia/tegra30-apalis-v1.1.dtsi +@@ -997,7 +997,6 @@ touchscreen@41 { + compatible = "st,stmpe811"; + reg = <0x41>; + irq-gpio = <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_LOW>; +- interrupt-controller; + id = <0>; + blocks = <0x5>; + irq-trigger = <0x1>; +diff --git a/arch/arm/boot/dts/nvidia/tegra30-apalis.dtsi b/arch/arm/boot/dts/nvidia/tegra30-apalis.dtsi +index 3b6fad273cabf1..d38f1dd38a9068 100644 +--- a/arch/arm/boot/dts/nvidia/tegra30-apalis.dtsi ++++ b/arch/arm/boot/dts/nvidia/tegra30-apalis.dtsi +@@ -980,7 +980,6 @@ touchscreen@41 { + compatible = "st,stmpe811"; + reg = <0x41>; + irq-gpio = <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_LOW>; +- interrupt-controller; + id = <0>; + blocks = <0x5>; + irq-trigger = <0x1>; +diff --git a/arch/arm/boot/dts/nvidia/tegra30-colibri.dtsi b/arch/arm/boot/dts/nvidia/tegra30-colibri.dtsi +index 4eb526fe9c5588..81c8a5fd92ccea 100644 +--- a/arch/arm/boot/dts/nvidia/tegra30-colibri.dtsi ++++ b/arch/arm/boot/dts/nvidia/tegra30-colibri.dtsi +@@ -861,7 +861,6 @@ touchscreen@41 { + compatible = "st,stmpe811"; + reg = <0x41>; + irq-gpio = <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_LOW>; +- interrupt-controller; + id = <0>; + blocks = <0x5>; + irq-trigger = <0x1>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx1-ads.dts b/arch/arm/boot/dts/nxp/imx/imx1-ads.dts +index 5833fb6f15d88a..2c817c4a4c68f8 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx1-ads.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx1-ads.dts +@@ -65,7 +65,7 @@ &weim { + pinctrl-0 = <&pinctrl_weim>; + status = "okay"; + +- nor: nor@0,0 { ++ nor: flash@0,0 { + compatible = "cfi-flash"; + reg = <0 0x00000000 0x02000000>; + bank-width = <4>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx1-apf9328.dts b/arch/arm/boot/dts/nxp/imx/imx1-apf9328.dts +index 1f11e9542a72de..e66eef87a7a4fd 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx1-apf9328.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx1-apf9328.dts +@@ -45,7 +45,7 @@ &weim { + pinctrl-0 = <&pinctrl_weim>; + status = "okay"; + +- nor: nor@0,0 { ++ nor: flash@0,0 { + compatible = "cfi-flash"; + reg = <0 0x00000000 0x02000000>; + bank-width = <2>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx1.dtsi b/arch/arm/boot/dts/nxp/imx/imx1.dtsi +index e312f1e74e2fe6..4aeb74479f44e9 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx1.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx1.dtsi +@@ -268,9 +268,12 @@ weim: weim@220000 { + status = "disabled"; + }; + +- esram: esram@300000 { ++ esram: sram@300000 { + compatible = "mmio-sram"; + reg = <0x00300000 0x20000>; ++ ranges = <0 0x00300000 0x20000>; ++ #address-cells = <1>; ++ #size-cells = <1>; + }; + }; + }; +diff --git a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-cpuimx25.dtsi b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-cpuimx25.dtsi +index 0703f62d10d1cb..93a6e4e680b451 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-cpuimx25.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-cpuimx25.dtsi +@@ -27,7 +27,7 @@ &i2c1 { + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + +- pcf8563@51 { ++ rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; +diff --git a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts +index fc8a502fc957f0..6cddb2cc36fe2a 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts +@@ -16,7 +16,7 @@ cmo_qvga: display { + bus-width = <18>; + display-timings { + native-mode = <&qvga_timings>; +- qvga_timings: 320x240 { ++ qvga_timings: timing0 { + clock-frequency = <6500000>; + hactive = <320>; + vactive = <240>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-svga.dts b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-svga.dts +index 80a7f96de4c6ac..64b2ffac463b2a 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-svga.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-svga.dts +@@ -16,7 +16,7 @@ dvi_svga: display { + bus-width = <18>; + display-timings { + native-mode = <&dvi_svga_timings>; +- dvi_svga_timings: 800x600 { ++ dvi_svga_timings: timing0 { + clock-frequency = <40000000>; + hactive = <800>; + vactive = <600>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dts b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dts +index 24027a1fb46d11..fb074bfdaa8dc2 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dts +@@ -16,7 +16,7 @@ dvi_vga: display { + bus-width = <18>; + display-timings { + native-mode = <&dvi_vga_timings>; +- dvi_vga_timings: 640x480 { ++ dvi_vga_timings: timing0 { + clock-frequency = <31250000>; + hactive = <640>; + vactive = <480>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx25-pdk.dts b/arch/arm/boot/dts/nxp/imx/imx25-pdk.dts +index 04f4b127a17257..e93bf3b7115fac 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx25-pdk.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx25-pdk.dts +@@ -68,7 +68,7 @@ wvga: display { + bus-width = <18>; + display-timings { + native-mode = <&wvga_timings>; +- wvga_timings: 640x480 { ++ wvga_timings: timing0 { + hactive = <640>; + vactive = <480>; + hback-porch = <45>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx25.dtsi b/arch/arm/boot/dts/nxp/imx/imx25.dtsi +index 5f90d72b840b0e..5ac4549286bd7f 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx25.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx25.dtsi +@@ -543,7 +543,7 @@ pwm1: pwm@53fe0000 { + }; + + iim: efuse@53ff0000 { +- compatible = "fsl,imx25-iim", "fsl,imx27-iim"; ++ compatible = "fsl,imx25-iim"; + reg = <0x53ff0000 0x4000>; + interrupts = <19>; + clocks = <&clks 99>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx27-apf27dev.dts b/arch/arm/boot/dts/nxp/imx/imx27-apf27dev.dts +index a21f1f7c24b88d..849306cb4532db 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx27-apf27dev.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx27-apf27dev.dts +@@ -16,7 +16,7 @@ display: display { + fsl,pcr = <0xfae80083>; /* non-standard but required */ + display-timings { + native-mode = <&timing0>; +- timing0: 800x480 { ++ timing0: timing0 { + clock-frequency = <33000033>; + hactive = <800>; + vactive = <480>; +@@ -47,7 +47,7 @@ leds { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_leds>; + +- user { ++ led-user { + label = "Heartbeat"; + gpios = <&gpio6 14 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; +diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi +index 74110bbcd9d4f2..c7e92358487826 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi +@@ -33,7 +33,7 @@ &i2c1 { + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + +- pcf8563@51 { ++ rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; +@@ -90,7 +90,7 @@ &usbotg { + &weim { + status = "okay"; + +- nor: nor@0,0 { ++ nor: flash@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; +diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts +index 145e459625b32d..d78793601306cf 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts +@@ -16,7 +16,7 @@ display0: CMO-QVGA { + + display-timings { + native-mode = <&timing0>; +- timing0: 320x240 { ++ timing0: timing0 { + clock-frequency = <6500000>; + hactive = <320>; + vactive = <240>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycard-s-rdk.dts b/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycard-s-rdk.dts +index 25442eba21c1e0..27c93b9fe0499f 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycard-s-rdk.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycard-s-rdk.dts +@@ -19,7 +19,7 @@ display: display { + fsl,pcr = <0xf0c88080>; /* non-standard but required */ + display-timings { + native-mode = <&timing0>; +- timing0: 640x480 { ++ timing0: timing0 { + hactive = <640>; + vactive = <480>; + hback-porch = <112>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-rdk.dts b/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-rdk.dts +index 7f0cd4d3ec2de4..67b235044b708c 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-rdk.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-rdk.dts +@@ -19,7 +19,7 @@ display0: LQ035Q7 { + + display-timings { + native-mode = <&timing0>; +- timing0: 240x320 { ++ timing0: timing0 { + clock-frequency = <5500000>; + hactive = <240>; + vactive = <320>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-som.dtsi b/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-som.dtsi +index 7191e10712b956..efce284b57969b 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-som.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-som.dtsi +@@ -314,7 +314,7 @@ &usbotg { + &weim { + status = "okay"; + +- nor: nor@0,0 { ++ nor: flash@0,0 { + compatible = "cfi-flash"; + reg = <0 0x00000000 0x02000000>; + bank-width = <2>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx27.dtsi b/arch/arm/boot/dts/nxp/imx/imx27.dtsi +index faba12ee7465eb..cac4b3d68986a0 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx27.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx27.dtsi +@@ -588,6 +588,9 @@ weim: weim@d8002000 { + iram: sram@ffff4c00 { + compatible = "mmio-sram"; + reg = <0xffff4c00 0xb400>; ++ ranges = <0 0xffff4c00 0xb400>; ++ #address-cells = <1>; ++ #size-cells = <1>; + }; + }; + }; +diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-yapp4-common.dtsi b/arch/arm/boot/dts/nxp/imx/imx6dl-yapp4-common.dtsi +index 3be38a3c4bb11c..c32ea040fecdda 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6dl-yapp4-common.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6dl-yapp4-common.dtsi +@@ -117,17 +117,9 @@ mdio { + #address-cells = <1>; + #size-cells = <0>; + +- phy_port2: phy@1 { +- reg = <1>; +- }; +- +- phy_port3: phy@2 { +- reg = <2>; +- }; +- + switch@10 { + compatible = "qca,qca8334"; +- reg = <10>; ++ reg = <0x10>; + reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>; + + switch_ports: ports { +@@ -149,15 +141,30 @@ fixed-link { + eth2: port@2 { + reg = <2>; + label = "eth2"; ++ phy-mode = "internal"; + phy-handle = <&phy_port2>; + }; + + eth1: port@3 { + reg = <3>; + label = "eth1"; ++ phy-mode = "internal"; + phy-handle = <&phy_port3>; + }; + }; ++ ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ phy_port2: ethernet-phy@1 { ++ reg = <1>; ++ }; ++ ++ phy_port3: ethernet-phy@2 { ++ reg = <2>; ++ }; ++ }; + }; + }; + }; +diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-yapp43-common.dtsi b/arch/arm/boot/dts/nxp/imx/imx6dl-yapp43-common.dtsi +index 52a0f6ee426f97..bcf4d9c870ec97 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6dl-yapp43-common.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6dl-yapp43-common.dtsi +@@ -274,24 +274,24 @@ leds: led-controller@30 { + + led@0 { + chan-name = "R"; +- led-cur = /bits/ 8 <0x20>; +- max-cur = /bits/ 8 <0x60>; ++ led-cur = /bits/ 8 <0x6e>; ++ max-cur = /bits/ 8 <0xc8>; + reg = <0>; + color = ; + }; + + led@1 { + chan-name = "G"; +- led-cur = /bits/ 8 <0x20>; +- max-cur = /bits/ 8 <0x60>; ++ led-cur = /bits/ 8 <0xbe>; ++ max-cur = /bits/ 8 <0xc8>; + reg = <1>; + color = ; + }; + + led@2 { + chan-name = "B"; +- led-cur = /bits/ 8 <0x20>; +- max-cur = /bits/ 8 <0x60>; ++ led-cur = /bits/ 8 <0xbe>; ++ max-cur = /bits/ 8 <0xc8>; + reg = <2>; + color = ; + }; +diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-apalis-ixora-v1.2.dts b/arch/arm/boot/dts/nxp/imx/imx6q-apalis-ixora-v1.2.dts +index 717decda0cebd5..3ac7a45016205a 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6q-apalis-ixora-v1.2.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx6q-apalis-ixora-v1.2.dts +@@ -76,6 +76,7 @@ reg_can1_supply: regulator-can1-supply { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enable_can1_power>; + regulator-name = "can1_supply"; ++ startup-delay-us = <1000>; + }; + + reg_can2_supply: regulator-can2-supply { +@@ -85,6 +86,7 @@ reg_can2_supply: regulator-can2-supply { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enable_can2_power>; + regulator-name = "can2_supply"; ++ startup-delay-us = <1000>; + }; + }; + +diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-b850v3.dts b/arch/arm/boot/dts/nxp/imx/imx6q-b850v3.dts +index db8c332df6a1d5..cad112e054758f 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6q-b850v3.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx6q-b850v3.dts +@@ -227,7 +227,6 @@ bridge@1,0 { + + #address-cells = <3>; + #size-cells = <2>; +- #interrupt-cells = <1>; + + bridge@2,1 { + compatible = "pci10b5,8605"; +@@ -235,7 +234,6 @@ bridge@2,1 { + + #address-cells = <3>; + #size-cells = <2>; +- #interrupt-cells = <1>; + + /* Intel Corporation I210 Gigabit Network Connection */ + ethernet@3,0 { +@@ -250,7 +248,6 @@ bridge@2,2 { + + #address-cells = <3>; + #size-cells = <2>; +- #interrupt-cells = <1>; + + /* Intel Corporation I210 Gigabit Network Connection */ + switch_nic: ethernet@4,0 { +diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-bx50v3.dtsi b/arch/arm/boot/dts/nxp/imx/imx6q-bx50v3.dtsi +index 99f4f6ac71d4a1..c1ae7c47b44227 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6q-bx50v3.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6q-bx50v3.dtsi +@@ -245,6 +245,7 @@ pca9539: pca9539@74 { + reg = <0x74>; + gpio-controller; + #gpio-cells = <2>; ++ #interrupt-cells = <2>; + interrupt-controller; + interrupt-parent = <&gpio2>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; +@@ -390,7 +391,6 @@ pci_root: root@0,0 { + + #address-cells = <3>; + #size-cells = <2>; +- #interrupt-cells = <1>; + }; + }; + +diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi +index 4d6a0c3e8455f9..ff062f4fd726eb 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6q-kontron-samx6i.dtsi +@@ -5,31 +5,8 @@ + + #include "imx6q.dtsi" + #include "imx6qdl-kontron-samx6i.dtsi" +-#include + + / { + model = "Kontron SMARC sAMX6i Quad/Dual"; + compatible = "kontron,imx6q-samx6i", "fsl,imx6q"; + }; +- +-/* Quad/Dual SoMs have 3 chip-select signals */ +-&ecspi4 { +- cs-gpios = <&gpio3 24 GPIO_ACTIVE_LOW>, +- <&gpio3 29 GPIO_ACTIVE_LOW>, +- <&gpio3 25 GPIO_ACTIVE_LOW>; +-}; +- +-&pinctrl_ecspi4 { +- fsl,pins = < +- MX6QDL_PAD_EIM_D21__ECSPI4_SCLK 0x100b1 +- MX6QDL_PAD_EIM_D28__ECSPI4_MOSI 0x100b1 +- MX6QDL_PAD_EIM_D22__ECSPI4_MISO 0x100b1 +- +- /* SPI4_IMX_CS2# - connected to internal flash */ +- MX6QDL_PAD_EIM_D24__GPIO3_IO24 0x1b0b0 +- /* SPI4_IMX_CS0# - connected to SMARC SPI0_CS0# */ +- MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1b0b0 +- /* SPI4_CS3# - connected to SMARC SPI0_CS1# */ +- MX6QDL_PAD_EIM_D25__GPIO3_IO25 0x1b0b0 +- >; +-}; +diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-skov-reve-mi1010ait-1cp1.dts b/arch/arm/boot/dts/nxp/imx/imx6q-skov-reve-mi1010ait-1cp1.dts +index a3f247c722b438..0342a79ccd5db2 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6q-skov-reve-mi1010ait-1cp1.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx6q-skov-reve-mi1010ait-1cp1.dts +@@ -37,9 +37,9 @@ panel_in: endpoint { + + &clks { + assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>, +- <&clks IMX6QDL_CLK_LDB_DI1_SEL>; ++ <&clks IMX6QDL_CLK_LDB_DI1_SEL>, <&clks IMX6QDL_CLK_ENET_REF_SEL>; + assigned-clock-parents = <&clks IMX6QDL_CLK_PLL5_VIDEO_DIV>, +- <&clks IMX6QDL_CLK_PLL5_VIDEO_DIV>; ++ <&clks IMX6QDL_CLK_PLL5_VIDEO_DIV>, <&clk50m_phy>; + }; + + &hdmi { +diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi +index 4cc965277c5219..dcb4f6a32f8092 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi +@@ -619,7 +619,6 @@ stmpe811@41 { + blocks = <0x5>; + id = <0>; + interrupts = <10 IRQ_TYPE_LEVEL_LOW>; +- interrupt-controller; + interrupt-parent = <&gpio4>; + irq-trigger = <0x1>; + pinctrl-names = "default"; +diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi +index 11d9c7a2dacb14..6cc4d6fd5f28be 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi +@@ -543,7 +543,6 @@ stmpe811@41 { + blocks = <0x5>; + interrupts = <20 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&gpio6>; +- interrupt-controller; + id = <0>; + irq-trigger = <0x1>; + pinctrl-names = "default"; +diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon.dtsi +index a63e73adc1fc53..42b2ba23aefc9e 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon.dtsi +@@ -225,7 +225,6 @@ da9063: pmic@58 { + pinctrl-0 = <&pinctrl_pmic>; + interrupt-parent = <&gpio2>; + interrupts = <8 IRQ_TYPE_LEVEL_LOW>; +- interrupt-controller; + + onkey { + compatible = "dlg,da9063-onkey"; +diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-kontron-samx6i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-kontron-samx6i.dtsi +index 85aeebc9485dd3..668d33d1ff0c1c 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6qdl-kontron-samx6i.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-kontron-samx6i.dtsi +@@ -244,7 +244,8 @@ &ecspi4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi4>; + cs-gpios = <&gpio3 24 GPIO_ACTIVE_LOW>, +- <&gpio3 29 GPIO_ACTIVE_LOW>; ++ <&gpio3 29 GPIO_ACTIVE_LOW>, ++ <&gpio3 25 GPIO_ACTIVE_LOW>; + status = "okay"; + + /* default boot source: workaround #1 for errata ERR006282 */ +@@ -259,7 +260,7 @@ smarc_flash: flash@0 { + &fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; +- phy-mode = "rgmii"; ++ phy-connection-type = "rgmii-id"; + phy-handle = <ðphy>; + + mdio { +@@ -269,7 +270,7 @@ mdio { + ethphy: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; +- reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>; ++ reset-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>; + reset-assert-us = <1000>; + }; + }; +@@ -464,6 +465,8 @@ MX6QDL_PAD_EIM_D22__ECSPI4_MISO 0x100b1 + MX6QDL_PAD_EIM_D24__GPIO3_IO24 0x1b0b0 + /* SPI_IMX_CS0# - connected to SMARC SPI0_CS0# */ + MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1b0b0 ++ /* SPI4_CS3# - connected to SMARC SPI0_CS1# */ ++ MX6QDL_PAD_EIM_D25__GPIO3_IO25 0x1b0b0 + >; + }; + +@@ -516,7 +519,7 @@ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 +- MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b0b0 /* RST_GBE0_PHY# */ ++ MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 /* RST_GBE0_PHY# */ + >; + }; + +@@ -729,7 +732,7 @@ &pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pcie>; + wake-up-gpio = <&gpio6 18 GPIO_ACTIVE_HIGH>; +- reset-gpio = <&gpio3 13 GPIO_ACTIVE_HIGH>; ++ reset-gpio = <&gpio3 13 GPIO_ACTIVE_LOW>; + }; + + /* LCD_BKLT_PWM */ +@@ -817,5 +820,6 @@ &wdog1 { + /* CPLD is feeded by watchdog (hardwired) */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog1>; ++ fsl,ext-reset-output; + status = "okay"; + }; +diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-pfla02.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-pfla02.dtsi +index 113974520d544b..c0c47adc5866e3 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-pfla02.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-pfla02.dtsi +@@ -124,6 +124,7 @@ pmic@58 { + reg = <0x58>; + interrupt-parent = <&gpio2>; + interrupts = <9 IRQ_TYPE_LEVEL_LOW>; /* active-low GPIO2_9 */ ++ #interrupt-cells = <2>; + interrupt-controller; + + regulators { +diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-phycore-som.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-phycore-som.dtsi +index 86b4269e0e0117..85e278eb201610 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-phycore-som.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-phycore-som.dtsi +@@ -100,6 +100,7 @@ pmic: pmic@58 { + interrupt-parent = <&gpio1>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; ++ #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + +diff --git a/arch/arm/boot/dts/nxp/imx/imx6ul-geam.dts b/arch/arm/boot/dts/nxp/imx/imx6ul-geam.dts +index 875ae699c5cb80..ce9f4c22672939 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6ul-geam.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx6ul-geam.dts +@@ -366,7 +366,7 @@ MX6UL_PAD_ENET1_RX_ER__PWM8_OUT 0x110b0 + }; + + pinctrl_tsc: tscgrp { +- fsl,pin = < ++ fsl,pins = < + MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0 + MX6UL_PAD_GPIO1_IO02__GPIO1_IO02 0xb0 + MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0xb0 +diff --git a/arch/arm/boot/dts/nxp/imx/imx6ul-pico.dtsi b/arch/arm/boot/dts/nxp/imx/imx6ul-pico.dtsi +index 4ffe99ed55ca2c..07dcecbe485dca 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6ul-pico.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6ul-pico.dtsi +@@ -121,6 +121,8 @@ ethphy1: ethernet-phy@1 { + max-speed = <100>; + interrupt-parent = <&gpio5>; + interrupts = <6 IRQ_TYPE_LEVEL_LOW>; ++ clocks = <&clks IMX6UL_CLK_ENET_REF>; ++ clock-names = "rmii-ref"; + }; + }; + }; +diff --git a/arch/arm/boot/dts/nxp/imx/imx6ull-phytec-tauri.dtsi b/arch/arm/boot/dts/nxp/imx/imx6ull-phytec-tauri.dtsi +index ea627638e40cf6..7dd1fe5a2fb768 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6ull-phytec-tauri.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6ull-phytec-tauri.dtsi +@@ -121,7 +121,7 @@ &ecspi1 { + tpm_tis: tpm@1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tpm>; +- compatible = "tcg,tpm_tis-spi"; ++ compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + reg = <1>; + spi-max-frequency = <20000000>; + interrupt-parent = <&gpio5>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx6ull-tarragon-common.dtsi b/arch/arm/boot/dts/nxp/imx/imx6ull-tarragon-common.dtsi +index 3fdece5bd31f9d..5248a058230c86 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6ull-tarragon-common.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6ull-tarragon-common.dtsi +@@ -805,6 +805,7 @@ &usbotg1 { + &pinctrl_usb_pwr>; + dr_mode = "host"; + power-active-high; ++ over-current-active-low; + disable-over-current; + status = "okay"; + }; +diff --git a/arch/arm/boot/dts/nxp/imx/imx7d-flex-concentrator.dts b/arch/arm/boot/dts/nxp/imx/imx7d-flex-concentrator.dts +index 3a723843d5626f..9984b343cdf0ca 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx7d-flex-concentrator.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx7d-flex-concentrator.dts +@@ -130,7 +130,7 @@ &ecspi4 { + * TCG specification - Section 6.4.1 Clocking: + * TPM shall support a SPI clock frequency range of 10-24 MHz. + */ +- st33htph: tpm-tis@0 { ++ st33htph: tpm@0 { + compatible = "st,st33htpm-spi", "tcg,tpm_tis-spi"; + reg = <0>; + spi-max-frequency = <24000000>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx7d-pico-dwarf.dts b/arch/arm/boot/dts/nxp/imx/imx7d-pico-dwarf.dts +index 12361fcbe24aff..1b965652291bfa 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx7d-pico-dwarf.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx7d-pico-dwarf.dts +@@ -63,6 +63,7 @@ pca9554: io-expander@25 { + gpio-controller; + #gpio-cells = <2>; + #interrupt-cells = <2>; ++ interrupt-controller; + reg = <0x25>; + }; + +diff --git a/arch/arm/boot/dts/nxp/imx/imx7d-zii-rmu2.dts b/arch/arm/boot/dts/nxp/imx/imx7d-zii-rmu2.dts +index 521493342fe972..8f5566027c25a2 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx7d-zii-rmu2.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx7d-zii-rmu2.dts +@@ -350,7 +350,7 @@ MX7D_PAD_SD3_RESET_B__SD3_RESET_B 0x59 + + &iomuxc_lpsr { + pinctrl_enet1_phy_interrupt: enet1phyinterruptgrp { +- fsl,phy = < ++ fsl,pins = < + MX7D_PAD_LPSR_GPIO1_IO02__GPIO1_IO2 0x08 + >; + }; +diff --git a/arch/arm/boot/dts/nxp/imx/imx7d.dtsi b/arch/arm/boot/dts/nxp/imx/imx7d.dtsi +index 4b94b8afb55d91..0484e349e064e4 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx7d.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx7d.dtsi +@@ -217,9 +217,6 @@ fec2: ethernet@30bf0000 { + }; + + &ca_funnel_in_ports { +- #address-cells = <1>; +- #size-cells = <0>; +- + port@1 { + reg = <1>; + ca_funnel_in_port1: endpoint { +diff --git a/arch/arm/boot/dts/nxp/imx/imx7s-warp.dts b/arch/arm/boot/dts/nxp/imx/imx7s-warp.dts +index ba7231b364bb8c..7bab113ca6da79 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx7s-warp.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx7s-warp.dts +@@ -210,6 +210,7 @@ ov2680_to_mipi: endpoint { + remote-endpoint = <&mipi_from_sensor>; + clock-lanes = <0>; + data-lanes = <1>; ++ link-frequencies = /bits/ 64 <330000000>; + }; + }; + }; +diff --git a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi +index e152d08f27d49e..39e9f1411ebb80 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi +@@ -190,7 +190,11 @@ funnel@30041000 { + clock-names = "apb_pclk"; + + ca_funnel_in_ports: in-ports { +- port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; + ca_funnel_in_port0: endpoint { + remote-endpoint = <&etm0_out_port>; + }; +@@ -454,7 +458,7 @@ iomuxc_lpsr: pinctrl@302c0000 { + }; + + gpt1: timer@302d0000 { +- compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt"; ++ compatible = "fsl,imx7d-gpt", "fsl,imx6dl-gpt"; + reg = <0x302d0000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_GPT1_ROOT_CLK>, +@@ -463,7 +467,7 @@ gpt1: timer@302d0000 { + }; + + gpt2: timer@302e0000 { +- compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt"; ++ compatible = "fsl,imx7d-gpt", "fsl,imx6dl-gpt"; + reg = <0x302e0000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_GPT2_ROOT_CLK>, +@@ -473,7 +477,7 @@ gpt2: timer@302e0000 { + }; + + gpt3: timer@302f0000 { +- compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt"; ++ compatible = "fsl,imx7d-gpt", "fsl,imx6dl-gpt"; + reg = <0x302f0000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_GPT3_ROOT_CLK>, +@@ -483,7 +487,7 @@ gpt3: timer@302f0000 { + }; + + gpt4: timer@30300000 { +- compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt"; ++ compatible = "fsl,imx7d-gpt", "fsl,imx6dl-gpt"; + reg = <0x30300000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_GPT4_ROOT_CLK>, +@@ -814,7 +818,7 @@ csi_from_csi_mux: endpoint { + }; + + lcdif: lcdif@30730000 { +- compatible = "fsl,imx7d-lcdif", "fsl,imx28-lcdif"; ++ compatible = "fsl,imx7d-lcdif", "fsl,imx6sx-lcdif"; + reg = <0x30730000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_LCDIF_PIXEL_ROOT_CLK>, +@@ -1278,7 +1282,7 @@ dma_apbh: dma-controller@33000000 { + gpmi: nand-controller@33002000 { + compatible = "fsl,imx7d-gpmi-nand"; + #address-cells = <1>; +- #size-cells = <1>; ++ #size-cells = <0>; + reg = <0x33002000 0x2000>, <0x33004000 0x4000>; + reg-names = "gpmi-nand", "bch"; + interrupts = ; +diff --git a/arch/arm/boot/dts/nxp/mxs/imx23-sansa.dts b/arch/arm/boot/dts/nxp/mxs/imx23-sansa.dts +index 46057d9bf555b6..c2efcc20ae8026 100644 +--- a/arch/arm/boot/dts/nxp/mxs/imx23-sansa.dts ++++ b/arch/arm/boot/dts/nxp/mxs/imx23-sansa.dts +@@ -175,10 +175,8 @@ i2c-0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "i2c-gpio"; +- gpios = < +- &gpio1 24 0 /* SDA */ +- &gpio1 22 0 /* SCL */ +- >; ++ sda-gpios = <&gpio1 24 0>; ++ scl-gpios = <&gpio1 22 0>; + i2c-gpio,delay-us = <2>; /* ~100 kHz */ + }; + +@@ -186,10 +184,8 @@ i2c-1 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "i2c-gpio"; +- gpios = < +- &gpio0 31 0 /* SDA */ +- &gpio0 30 0 /* SCL */ +- >; ++ sda-gpios = <&gpio0 31 0>; ++ scl-gpios = <&gpio0 30 0>; + i2c-gpio,delay-us = <2>; /* ~100 kHz */ + + touch: touch@20 { +diff --git a/arch/arm/boot/dts/nxp/mxs/imx23.dtsi b/arch/arm/boot/dts/nxp/mxs/imx23.dtsi +index 5eca942a52fd44..14c07b585f8220 100644 +--- a/arch/arm/boot/dts/nxp/mxs/imx23.dtsi ++++ b/arch/arm/boot/dts/nxp/mxs/imx23.dtsi +@@ -412,7 +412,7 @@ emi@80020000 { + status = "disabled"; + }; + +- dma_apbx: dma-apbx@80024000 { ++ dma_apbx: dma-controller@80024000 { + compatible = "fsl,imx23-dma-apbx"; + reg = <0x80024000 0x2000>; + interrupts = <7>, <5>, <9>, <26>, +diff --git a/arch/arm/boot/dts/nxp/mxs/imx28-xea.dts b/arch/arm/boot/dts/nxp/mxs/imx28-xea.dts +index a400c108f66a2d..6c5e6856648af9 100644 +--- a/arch/arm/boot/dts/nxp/mxs/imx28-xea.dts ++++ b/arch/arm/boot/dts/nxp/mxs/imx28-xea.dts +@@ -8,6 +8,7 @@ + #include "imx28-lwe.dtsi" + + / { ++ model = "Liebherr XEA board"; + compatible = "lwn,imx28-xea", "fsl,imx28"; + }; + +diff --git a/arch/arm/boot/dts/nxp/mxs/imx28.dtsi b/arch/arm/boot/dts/nxp/mxs/imx28.dtsi +index 763adeb995ee76..9b73130887ea14 100644 +--- a/arch/arm/boot/dts/nxp/mxs/imx28.dtsi ++++ b/arch/arm/boot/dts/nxp/mxs/imx28.dtsi +@@ -990,7 +990,7 @@ etm: etm@80022000 { + status = "disabled"; + }; + +- dma_apbx: dma-apbx@80024000 { ++ dma_apbx: dma-controller@80024000 { + compatible = "fsl,imx28-dma-apbx"; + reg = <0x80024000 0x2000>; + interrupts = <78>, <79>, <66>, <0>, +diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-dev-rev-b.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-dev-rev-b.dts +index 16b4e06c4efad3..a248b8a4534210 100644 +--- a/arch/arm/boot/dts/nxp/vf/vf610-zii-dev-rev-b.dts ++++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-dev-rev-b.dts +@@ -338,6 +338,7 @@ gpio6: io-expander@22 { + reg = <0x22>; + gpio-controller; + #gpio-cells = <2>; ++ #interrupt-cells = <2>; + interrupt-controller; + interrupt-parent = <&gpio3>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; +diff --git a/arch/arm/boot/dts/qcom/pm8226.dtsi b/arch/arm/boot/dts/qcom/pm8226.dtsi +new file mode 100644 +index 00000000000000..2413778f371507 +--- /dev/null ++++ b/arch/arm/boot/dts/qcom/pm8226.dtsi +@@ -0,0 +1,180 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++#include ++#include ++#include ++#include ++ ++/ { ++ thermal-zones { ++ pm8226-thermal { ++ polling-delay-passive = <100>; ++ polling-delay = <0>; ++ thermal-sensors = <&pm8226_temp>; ++ ++ trips { ++ trip0 { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ ++ trip1 { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ ++ crit { ++ temperature = <145000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&spmi_bus { ++ pm8226_0: pm8226@0 { ++ compatible = "qcom,pm8226", "qcom,spmi-pmic"; ++ reg = <0x0 SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pon@800 { ++ compatible = "qcom,pm8916-pon"; ++ reg = <0x800>; ++ ++ pwrkey { ++ compatible = "qcom,pm8941-pwrkey"; ++ interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; ++ debounce = <15625>; ++ bias-pull-up; ++ linux,code = ; ++ }; ++ ++ pm8226_resin: resin { ++ compatible = "qcom,pm8941-resin"; ++ interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>; ++ debounce = <15625>; ++ bias-pull-up; ++ status = "disabled"; ++ }; ++ }; ++ ++ smbb: charger@1000 { ++ compatible = "qcom,pm8226-charger"; ++ reg = <0x1000>; ++ interrupts = <0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>, ++ <0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>, ++ <0x0 0x10 4 IRQ_TYPE_EDGE_BOTH>, ++ <0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>, ++ <0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>, ++ <0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>, ++ <0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>, ++ <0x0 0x14 1 IRQ_TYPE_EDGE_BOTH>; ++ interrupt-names = "chg-done", ++ "chg-fast", ++ "chg-trkl", ++ "bat-temp-ok", ++ "bat-present", ++ "chg-gone", ++ "usb-valid", ++ "dc-valid"; ++ ++ chg_otg: otg-vbus { }; ++ }; ++ ++ pm8226_temp: temp-alarm@2400 { ++ compatible = "qcom,spmi-temp-alarm"; ++ reg = <0x2400>; ++ interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>; ++ io-channels = <&pm8226_vadc VADC_DIE_TEMP>; ++ io-channel-names = "thermal"; ++ #thermal-sensor-cells = <0>; ++ }; ++ ++ pm8226_vadc: adc@3100 { ++ compatible = "qcom,spmi-vadc"; ++ reg = <0x3100>; ++ interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #io-channel-cells = <1>; ++ ++ channel@7 { ++ reg = ; ++ qcom,pre-scaling = <1 3>; ++ label = "vph_pwr"; ++ }; ++ channel@8 { ++ reg = ; ++ label = "die_temp"; ++ }; ++ channel@9 { ++ reg = ; ++ label = "ref_625mv"; ++ }; ++ channel@a { ++ reg = ; ++ label = "ref_1250mv"; ++ }; ++ channel@e { ++ reg = ; ++ }; ++ channel@f { ++ reg = ; ++ }; ++ }; ++ ++ pm8226_iadc: adc@3600 { ++ compatible = "qcom,pm8226-iadc", "qcom,spmi-iadc"; ++ reg = <0x3600>; ++ interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>; ++ }; ++ ++ rtc@6000 { ++ compatible = "qcom,pm8941-rtc"; ++ reg = <0x6000>, <0x6100>; ++ reg-names = "rtc", "alarm"; ++ interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; ++ }; ++ ++ pm8226_mpps: mpps@a000 { ++ compatible = "qcom,pm8226-mpp", "qcom,spmi-mpp"; ++ reg = <0xa000>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pm8226_mpps 0 0 8>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ pm8226_gpios: gpio@c000 { ++ compatible = "qcom,pm8226-gpio", "qcom,spmi-gpio"; ++ reg = <0xc000>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pm8226_gpios 0 0 8>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ }; ++ ++ pm8226_1: pm8226@1 { ++ compatible = "qcom,pm8226", "qcom,spmi-pmic"; ++ reg = <0x1 SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pm8226_spmi_regulators: regulators { ++ compatible = "qcom,pm8226-regulators"; ++ }; ++ ++ pm8226_vib: vibrator@c000 { ++ compatible = "qcom,pm8916-vib"; ++ reg = <0xc000>; ++ status = "disabled"; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/qcom/pm8841.dtsi b/arch/arm/boot/dts/qcom/pm8841.dtsi +new file mode 100644 +index 00000000000000..3bf2ce5c86a641 +--- /dev/null ++++ b/arch/arm/boot/dts/qcom/pm8841.dtsi +@@ -0,0 +1,68 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include ++#include ++ ++ ++/ { ++ thermal-zones { ++ pm8841-thermal { ++ polling-delay-passive = <100>; ++ polling-delay = <0>; ++ thermal-sensors = <&pm8841_temp>; ++ ++ trips { ++ trip0 { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ ++ trip1 { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ ++ crit { ++ temperature = <140000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&spmi_bus { ++ ++ pm8841_0: pm8841@4 { ++ compatible = "qcom,pm8841", "qcom,spmi-pmic"; ++ reg = <0x4 SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pm8841_mpps: mpps@a000 { ++ compatible = "qcom,pm8841-mpp", "qcom,spmi-mpp"; ++ reg = <0xa000>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pm8841_mpps 0 0 4>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ pm8841_temp: temp-alarm@2400 { ++ compatible = "qcom,spmi-temp-alarm"; ++ reg = <0x2400>; ++ interrupts = <4 0x24 0 IRQ_TYPE_EDGE_RISING>; ++ #thermal-sensor-cells = <0>; ++ }; ++ }; ++ ++ pm8841_1: pm8841@5 { ++ compatible = "qcom,pm8841", "qcom,spmi-pmic"; ++ reg = <0x5 SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++}; +diff --git a/arch/arm/boot/dts/qcom/pm8941.dtsi b/arch/arm/boot/dts/qcom/pm8941.dtsi +new file mode 100644 +index 00000000000000..ed0ba591c75581 +--- /dev/null ++++ b/arch/arm/boot/dts/qcom/pm8941.dtsi +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include ++#include ++#include ++ ++ ++/ { ++ thermal-zones { ++ pm8941-thermal { ++ polling-delay-passive = <100>; ++ polling-delay = <0>; ++ thermal-sensors = <&pm8941_temp>; ++ ++ trips { ++ trip0 { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ ++ trip1 { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ ++ crit { ++ temperature = <145000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&spmi_bus { ++ ++ pm8941_0: pm8941@0 { ++ compatible = "qcom,pm8941", "qcom,spmi-pmic"; ++ reg = <0x0 SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ rtc@6000 { ++ compatible = "qcom,pm8941-rtc"; ++ reg = <0x6000>, ++ <0x6100>; ++ reg-names = "rtc", "alarm"; ++ interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; ++ }; ++ ++ pon@800 { ++ compatible = "qcom,pm8941-pon"; ++ reg = <0x800>; ++ ++ pwrkey { ++ compatible = "qcom,pm8941-pwrkey"; ++ interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; ++ debounce = <15625>; ++ bias-pull-up; ++ }; ++ ++ pm8941_resin: resin { ++ compatible = "qcom,pm8941-resin"; ++ interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>; ++ debounce = <15625>; ++ bias-pull-up; ++ status = "disabled"; ++ }; ++ }; ++ ++ usb_id: usb-detect@900 { ++ compatible = "qcom,pm8941-misc"; ++ reg = <0x900>; ++ interrupts = <0x0 0x9 0 IRQ_TYPE_EDGE_BOTH>; ++ interrupt-names = "usb_id"; ++ }; ++ ++ smbb: charger@1000 { ++ compatible = "qcom,pm8941-charger"; ++ reg = <0x1000>; ++ interrupts = <0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>, ++ <0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>, ++ <0x0 0x10 4 IRQ_TYPE_EDGE_BOTH>, ++ <0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>, ++ <0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>, ++ <0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>, ++ <0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>, ++ <0x0 0x14 1 IRQ_TYPE_EDGE_BOTH>; ++ interrupt-names = "chg-done", ++ "chg-fast", ++ "chg-trkl", ++ "bat-temp-ok", ++ "bat-present", ++ "chg-gone", ++ "usb-valid", ++ "dc-valid"; ++ ++ usb-otg-in-supply = <&pm8941_5vs1>; ++ ++ chg_otg: otg-vbus { }; ++ }; ++ ++ pm8941_gpios: gpio@c000 { ++ compatible = "qcom,pm8941-gpio", "qcom,spmi-gpio"; ++ reg = <0xc000>; ++ gpio-controller; ++ gpio-ranges = <&pm8941_gpios 0 0 36>; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ ++ boost_bypass_n_pin: boost-bypass-state { ++ pins = "gpio21"; ++ function = "normal"; ++ }; ++ }; ++ ++ pm8941_mpps: mpps@a000 { ++ compatible = "qcom,pm8941-mpp", "qcom,spmi-mpp"; ++ reg = <0xa000>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pm8941_mpps 0 0 8>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ pm8941_temp: temp-alarm@2400 { ++ compatible = "qcom,spmi-temp-alarm"; ++ reg = <0x2400>; ++ interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>; ++ io-channels = <&pm8941_vadc VADC_DIE_TEMP>; ++ io-channel-names = "thermal"; ++ #thermal-sensor-cells = <0>; ++ }; ++ ++ pm8941_vadc: adc@3100 { ++ compatible = "qcom,spmi-vadc"; ++ reg = <0x3100>; ++ interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #io-channel-cells = <1>; ++ ++ ++ channel@6 { ++ reg = ; ++ }; ++ ++ channel@8 { ++ reg = ; ++ }; ++ ++ channel@9 { ++ reg = ; ++ }; ++ ++ channel@a { ++ reg = ; ++ }; ++ ++ channel@e { ++ reg = ; ++ }; ++ ++ channel@f { ++ reg = ; ++ }; ++ ++ channel@30 { ++ reg = ; ++ }; ++ }; ++ ++ pm8941_iadc: adc@3600 { ++ compatible = "qcom,pm8941-iadc", "qcom,spmi-iadc"; ++ reg = <0x3600>; ++ interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>; ++ qcom,external-resistor-micro-ohms = <10000>; ++ }; ++ ++ pm8941_coincell: charger@2800 { ++ compatible = "qcom,pm8941-coincell"; ++ reg = <0x2800>; ++ status = "disabled"; ++ }; ++ }; ++ ++ pm8941_1: pm8941@1 { ++ compatible = "qcom,pm8941", "qcom,spmi-pmic"; ++ reg = <0x1 SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pm8941_lpg: pwm { ++ compatible = "qcom,pm8941-lpg"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #pwm-cells = <2>; ++ ++ status = "disabled"; ++ }; ++ ++ pm8941_vib: vibrator@c000 { ++ compatible = "qcom,pm8916-vib"; ++ reg = <0xc000>; ++ status = "disabled"; ++ }; ++ ++ pm8941_wled: wled@d800 { ++ compatible = "qcom,pm8941-wled"; ++ reg = <0xd800>; ++ label = "backlight"; ++ ++ status = "disabled"; ++ }; ++ ++ regulators { ++ compatible = "qcom,pm8941-regulators"; ++ interrupts = <0x1 0x83 0x2 0>, <0x1 0x84 0x2 0>; ++ interrupt-names = "ocp-5vs1", "ocp-5vs2"; ++ vin_5vs-supply = <&pm8941_5v>; ++ ++ pm8941_5v: s4 { ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-enable-ramp-delay = <500>; ++ }; ++ ++ pm8941_5vs1: 5vs1 { ++ regulator-enable-ramp-delay = <1000>; ++ regulator-pull-down; ++ regulator-over-current-protection; ++ qcom,ocp-max-retries = <10>; ++ qcom,ocp-retry-delay = <30>; ++ qcom,vs-soft-start-strength = <0>; ++ regulator-initial-mode = <1>; ++ }; ++ ++ pm8941_5vs2: 5vs2 { ++ regulator-enable-ramp-delay = <1000>; ++ regulator-pull-down; ++ regulator-over-current-protection; ++ qcom,ocp-max-retries = <10>; ++ qcom,ocp-retry-delay = <30>; ++ qcom,vs-soft-start-strength = <0>; ++ regulator-initial-mode = <1>; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/qcom/pma8084.dtsi b/arch/arm/boot/dts/qcom/pma8084.dtsi +new file mode 100644 +index 00000000000000..2985f4805b93ee +--- /dev/null ++++ b/arch/arm/boot/dts/qcom/pma8084.dtsi +@@ -0,0 +1,99 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include ++#include ++#include ++ ++&spmi_bus { ++ ++ pma8084_0: pma8084@0 { ++ compatible = "qcom,pma8084", "qcom,spmi-pmic"; ++ reg = <0x0 SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ rtc@6000 { ++ compatible = "qcom,pm8941-rtc"; ++ reg = <0x6000>, ++ <0x6100>; ++ reg-names = "rtc", "alarm"; ++ interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; ++ }; ++ ++ pwrkey@800 { ++ compatible = "qcom,pm8941-pwrkey"; ++ reg = <0x800>; ++ interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; ++ debounce = <15625>; ++ bias-pull-up; ++ }; ++ ++ pma8084_gpios: gpio@c000 { ++ compatible = "qcom,pma8084-gpio", "qcom,spmi-gpio"; ++ reg = <0xc000>; ++ gpio-controller; ++ gpio-ranges = <&pma8084_gpios 0 0 22>; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ pma8084_mpps: mpps@a000 { ++ compatible = "qcom,pma8084-mpp", "qcom,spmi-mpp"; ++ reg = <0xa000>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pma8084_mpps 0 0 8>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ pma8084_temp: temp-alarm@2400 { ++ compatible = "qcom,spmi-temp-alarm"; ++ reg = <0x2400>; ++ interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>; ++ #thermal-sensor-cells = <0>; ++ io-channels = <&pma8084_vadc VADC_DIE_TEMP>; ++ io-channel-names = "thermal"; ++ }; ++ ++ pma8084_vadc: adc@3100 { ++ compatible = "qcom,spmi-vadc"; ++ reg = <0x3100>; ++ interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #io-channel-cells = <1>; ++ ++ channel@8 { ++ reg = ; ++ }; ++ ++ channel@9 { ++ reg = ; ++ }; ++ ++ channel@a { ++ reg = ; ++ }; ++ ++ channel@c { ++ reg = ; ++ }; ++ ++ channel@e { ++ reg = ; ++ }; ++ ++ channel@f { ++ reg = ; ++ }; ++ }; ++ }; ++ ++ pma8084_1: pma8084@1 { ++ compatible = "qcom,pma8084", "qcom,spmi-pmic"; ++ reg = <0x1 SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++}; +diff --git a/arch/arm/boot/dts/qcom/pmx55.dtsi b/arch/arm/boot/dts/qcom/pmx55.dtsi +new file mode 100644 +index 00000000000000..da0851173c6997 +--- /dev/null ++++ b/arch/arm/boot/dts/qcom/pmx55.dtsi +@@ -0,0 +1,85 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++ ++/* ++ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2020, Linaro Limited ++ */ ++ ++#include ++#include ++#include ++ ++&spmi_bus { ++ pmic@8 { ++ compatible = "qcom,pmx55", "qcom,spmi-pmic"; ++ reg = <0x8 SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pon@800 { ++ compatible = "qcom,pm8916-pon"; ++ reg = <0x0800>; ++ ++ status = "disabled"; ++ }; ++ ++ pmx55_temp: temp-alarm@2400 { ++ compatible = "qcom,spmi-temp-alarm"; ++ reg = <0x2400>; ++ interrupts = <0x8 0x24 0x0 IRQ_TYPE_EDGE_BOTH>; ++ io-channels = <&pmx55_adc ADC5_DIE_TEMP>; ++ io-channel-names = "thermal"; ++ #thermal-sensor-cells = <0>; ++ }; ++ ++ pmx55_adc: adc@3100 { ++ compatible = "qcom,spmi-adc5"; ++ reg = <0x3100>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #io-channel-cells = <1>; ++ interrupts = <0x8 0x31 0x0 IRQ_TYPE_EDGE_RISING>; ++ ++ channel@0 { ++ reg = ; ++ qcom,pre-scaling = <1 1>; ++ label = "ref_gnd"; ++ }; ++ ++ channel@1 { ++ reg = ; ++ qcom,pre-scaling = <1 1>; ++ label = "vref_1p25"; ++ }; ++ ++ channel@6 { ++ reg = ; ++ qcom,pre-scaling = <1 1>; ++ label = "die_temp"; ++ }; ++ ++ channel@9 { ++ reg = ; ++ qcom,pre-scaling = <1 1>; ++ label = "chg_temp"; ++ }; ++ }; ++ ++ pmx55_gpios: gpio@c000 { ++ compatible = "qcom,pmx55-gpio", "qcom,spmi-gpio"; ++ reg = <0xc000>; ++ gpio-controller; ++ gpio-ranges = <&pmx55_gpios 0 0 11>; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ }; ++ ++ pmic@9 { ++ compatible = "qcom,pmx55", "qcom,spmi-pmic"; ++ reg = <0x9 SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++}; +diff --git a/arch/arm/boot/dts/qcom/pmx65.dtsi b/arch/arm/boot/dts/qcom/pmx65.dtsi +new file mode 100644 +index 00000000000000..1c7fdf59c1f56a +--- /dev/null ++++ b/arch/arm/boot/dts/qcom/pmx65.dtsi +@@ -0,0 +1,33 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. ++ */ ++ ++#include ++#include ++ ++&spmi_bus { ++ pmic@1 { ++ compatible = "qcom,pmx65", "qcom,spmi-pmic"; ++ reg = <1 SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pmx65_temp: temp-alarm@a00 { ++ compatible = "qcom,spmi-temp-alarm"; ++ reg = <0xa00>; ++ interrupts = <0x1 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; ++ #thermal-sensor-cells = <0>; ++ }; ++ ++ pmx65_gpios: gpio@8800 { ++ compatible = "qcom,pmx65-gpio", "qcom,spmi-gpio"; ++ reg = <0x8800>; ++ gpio-controller; ++ gpio-ranges = <&pmx65_gpios 0 0 16>; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts b/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts +index aa0e0e8d2a973e..a39f5a161b03bb 100644 +--- a/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts ++++ b/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts +@@ -6,7 +6,7 @@ + /dts-v1/; + + #include "qcom-msm8226.dtsi" +-#include "qcom-pm8226.dtsi" ++#include "pm8226.dtsi" + + /delete-node/ &adsp_region; + +diff --git a/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts b/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts +index de19640efe5538..59b218042d32dd 100644 +--- a/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts ++++ b/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts +@@ -6,7 +6,7 @@ + /dts-v1/; + + #include "qcom-msm8226.dtsi" +-#include "qcom-pm8226.dtsi" ++#include "pm8226.dtsi" + #include + + /delete-node/ &adsp_region; +diff --git a/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts b/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts +index b887e5361ec3a2..feb78afef3a6e0 100644 +--- a/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts ++++ b/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts +@@ -6,7 +6,7 @@ + /dts-v1/; + + #include "qcom-msm8226.dtsi" +-#include "qcom-pm8226.dtsi" ++#include "pm8226.dtsi" + + /delete-node/ &adsp_region; + +diff --git a/arch/arm/boot/dts/qcom/qcom-apq8026-samsung-matisse-wifi.dts b/arch/arm/boot/dts/qcom/qcom-apq8026-samsung-matisse-wifi.dts +index 884d99297d4cf1..cffc069712b2f1 100644 +--- a/arch/arm/boot/dts/qcom/qcom-apq8026-samsung-matisse-wifi.dts ++++ b/arch/arm/boot/dts/qcom/qcom-apq8026-samsung-matisse-wifi.dts +@@ -7,7 +7,7 @@ + + #include + #include "qcom-msm8226.dtsi" +-#include "qcom-pm8226.dtsi" ++#include "pm8226.dtsi" + + /delete-node/ &adsp_region; + /delete-node/ &smem_region; +@@ -45,11 +45,11 @@ gpio-hall-sensor { + + event-hall-sensor { + label = "Hall Effect Sensor"; +- gpios = <&tlmm 110 GPIO_ACTIVE_HIGH>; +- interrupts = <&tlmm 110 IRQ_TYPE_EDGE_FALLING>; ++ gpios = <&tlmm 110 GPIO_ACTIVE_LOW>; + linux,input-type = ; + linux,code = ; + debounce-interval = <15>; ++ linux,can-disable; + wakeup-source; + }; + }; +diff --git a/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts b/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts +index db4c791b2e2fb2..48fd1a1feea342 100644 +--- a/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts ++++ b/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts +@@ -72,7 +72,7 @@ cm3605 { + /* Trig on both edges - getting close or far away */ + interrupts-extended = <&pm8058_gpio 34 IRQ_TYPE_EDGE_BOTH>; + /* MPP05 analog input to the XOADC */ +- io-channels = <&xoadc 0x00 0x05>; ++ io-channels = <&pm8058_xoadc 0x00 0x05>; + io-channel-names = "aout"; + pinctrl-names = "default"; + pinctrl-0 = <&dragon_cm3605_gpios>, <&dragon_cm3605_mpps>; +@@ -945,7 +945,7 @@ irq-pins { + }; + }; + +-&xoadc { ++&pm8058_xoadc { + /* Reference voltage 2.2 V */ + xoadc-ref-supply = <&pm8058_l18>; + +diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi +index 516f0d2495e2d0..950adb63af7016 100644 +--- a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi ++++ b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi +@@ -738,7 +738,7 @@ pwrkey@1c { + + xoadc: xoadc@197 { + compatible = "qcom,pm8921-adc"; +- reg = <197>; ++ reg = <0x197>; + interrupts-extended = <&pmicintc 78 IRQ_TYPE_EDGE_RISING>; + #address-cells = <2>; + #size-cells = <0>; +diff --git a/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts b/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts +index 6d1b2439ae3ace..950fa652f9856a 100644 +--- a/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts ++++ b/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts +@@ -4,8 +4,8 @@ + #include + #include + #include "qcom-msm8974.dtsi" +-#include "qcom-pm8841.dtsi" +-#include "qcom-pm8941.dtsi" ++#include "pm8841.dtsi" ++#include "pm8941.dtsi" + + /delete-node/ &mpss_region; + +diff --git a/arch/arm/boot/dts/qcom/qcom-apq8084-ifc6540.dts b/arch/arm/boot/dts/qcom/qcom-apq8084-ifc6540.dts +index 116e59a3b76d01..1df24c922be9f3 100644 +--- a/arch/arm/boot/dts/qcom/qcom-apq8084-ifc6540.dts ++++ b/arch/arm/boot/dts/qcom/qcom-apq8084-ifc6540.dts +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + #include "qcom-apq8084.dtsi" +-#include "qcom-pma8084.dtsi" ++#include "pma8084.dtsi" + + / { + model = "Qualcomm APQ8084/IFC6540"; +diff --git a/arch/arm/boot/dts/qcom/qcom-apq8084-mtp.dts b/arch/arm/boot/dts/qcom/qcom-apq8084-mtp.dts +index c6b6680248a69e..d4e6aee034afd1 100644 +--- a/arch/arm/boot/dts/qcom/qcom-apq8084-mtp.dts ++++ b/arch/arm/boot/dts/qcom/qcom-apq8084-mtp.dts +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + #include "qcom-apq8084.dtsi" +-#include "qcom-pma8084.dtsi" ++#include "pma8084.dtsi" + + / { + model = "Qualcomm APQ 8084-MTP"; +diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi +index 92c8003dac252d..dac3aa793f7115 100644 +--- a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi ++++ b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi +@@ -76,7 +76,7 @@ reset-out-pins { + }; + }; + +-&pmicgpio { ++&pm8018_gpio { + usb_vbus_5v_pins: usb-vbus-5v-state { + pins = "gpio4"; + function = "normal"; +diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi +index fc4f52f9e9f7dc..c0a60bae703b11 100644 +--- a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi ++++ b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi +@@ -47,14 +47,12 @@ cxo_board: cxo_board { + }; + }; + +- regulators { +- vsdcc_fixed: vsdcc-regulator { +- compatible = "regulator-fixed"; +- regulator-name = "SDCC Power"; +- regulator-min-microvolt = <2700000>; +- regulator-max-microvolt = <2700000>; +- regulator-always-on; +- }; ++ vsdcc_fixed: vsdcc-regulator { ++ compatible = "regulator-fixed"; ++ regulator-name = "SDCC Power"; ++ regulator-min-microvolt = <2700000>; ++ regulator-max-microvolt = <2700000>; ++ regulator-always-on; + }; + + soc: soc { +@@ -263,7 +261,7 @@ qcom,ssbi@500000 { + reg = <0x500000 0x1000>; + qcom,controller-type = "pmic-arbiter"; + +- pmicintc: pmic { ++ pm8018: pmic { + compatible = "qcom,pm8018", "qcom,pm8921"; + interrupts = ; + #interrupt-cells = <2>; +@@ -274,38 +272,38 @@ pmicintc: pmic { + pwrkey@1c { + compatible = "qcom,pm8018-pwrkey", "qcom,pm8921-pwrkey"; + reg = <0x1c>; +- interrupt-parent = <&pmicintc>; ++ interrupt-parent = <&pm8018>; + interrupts = <50 IRQ_TYPE_EDGE_RISING>, + <51 IRQ_TYPE_EDGE_RISING>; + debounce = <15625>; + pull-up; + }; + +- pmicmpp: mpps@50 { ++ pm8018_mpps: mpps@50 { + compatible = "qcom,pm8018-mpp", "qcom,ssbi-mpp"; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x50>; + gpio-controller; + #gpio-cells = <2>; +- gpio-ranges = <&pmicmpp 0 0 6>; ++ gpio-ranges = <&pm8018_mpps 0 0 6>; + }; + + rtc@11d { + compatible = "qcom,pm8018-rtc", "qcom,pm8921-rtc"; +- interrupt-parent = <&pmicintc>; ++ interrupt-parent = <&pm8018>; + interrupts = <39 IRQ_TYPE_EDGE_RISING>; + reg = <0x11d>; + allow-set-time; + }; + +- pmicgpio: gpio@150 { ++ pm8018_gpio: gpio@150 { + compatible = "qcom,pm8018-gpio", "qcom,ssbi-gpio"; + reg = <0x150>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; +- gpio-ranges = <&pmicgpio 0 0 6>; ++ gpio-ranges = <&pm8018_gpio 0 0 6>; + #gpio-cells = <2>; + }; + }; +diff --git a/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi +index 44f3f0127fd709..78738371f634cf 100644 +--- a/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi ++++ b/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi +@@ -404,8 +404,8 @@ mmcc: clock-controller@fd8c0000 { + <&gcc GPLL0_VOTE>, + <&gcc GPLL1_VOTE>, + <&rpmcc RPM_SMD_GFX3D_CLK_SRC>, +- <0>, +- <0>; ++ <&mdss_dsi0_phy 1>, ++ <&mdss_dsi0_phy 0>; + clock-names = "xo", + "mmss_gpll0_vote", + "gpll0_vote", +diff --git a/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi +index 78023ed2fdf71f..9217ced108c42f 100644 +--- a/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi ++++ b/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi +@@ -80,13 +80,13 @@ sleep-clk { + */ + iio-hwmon { + compatible = "iio-hwmon"; +- io-channels = <&xoadc 0x00 0x01>, /* Battery */ +- <&xoadc 0x00 0x02>, /* DC in (charger) */ +- <&xoadc 0x00 0x04>, /* VPH the main system voltage */ +- <&xoadc 0x00 0x0b>, /* Die temperature */ +- <&xoadc 0x00 0x0c>, /* Reference voltage 1.25V */ +- <&xoadc 0x00 0x0d>, /* Reference voltage 0.625V */ +- <&xoadc 0x00 0x0e>; /* Reference voltage 0.325V */ ++ io-channels = <&pm8058_xoadc 0x00 0x01>, /* Battery */ ++ <&pm8058_xoadc 0x00 0x02>, /* DC in (charger) */ ++ <&pm8058_xoadc 0x00 0x04>, /* VPH the main system voltage */ ++ <&pm8058_xoadc 0x00 0x0b>, /* Die temperature */ ++ <&pm8058_xoadc 0x00 0x0c>, /* Reference voltage 1.25V */ ++ <&pm8058_xoadc 0x00 0x0d>, /* Reference voltage 0.625V */ ++ <&pm8058_xoadc 0x00 0x0e>; /* Reference voltage 0.325V */ + }; + + soc: soc { +@@ -390,7 +390,7 @@ pm8058_keypad: keypad@148 { + row-hold = <91500>; + }; + +- xoadc: xoadc@197 { ++ pm8058_xoadc: xoadc@197 { + compatible = "qcom,pm8058-adc"; + reg = <0x197>; + interrupts-extended = <&pm8058 76 IRQ_TYPE_EDGE_RISING>; +diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts b/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts +index 60bdfddeae69eb..da99f770d4f57b 100644 +--- a/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts ++++ b/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + #include "qcom-msm8974.dtsi" +-#include "qcom-pm8841.dtsi" +-#include "qcom-pm8941.dtsi" ++#include "pm8841.dtsi" ++#include "pm8941.dtsi" + #include + #include + #include +diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi +index 68a2f9094e536f..23ae474698aa7b 100644 +--- a/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi ++++ b/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + #include "qcom-msm8974.dtsi" +-#include "qcom-pm8841.dtsi" +-#include "qcom-pm8941.dtsi" ++#include "pm8841.dtsi" ++#include "pm8941.dtsi" + #include + #include + #include +diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi +index 706fef53767e10..4a8eb8b423290f 100644 +--- a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi ++++ b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi +@@ -1194,7 +1194,7 @@ restart@fc4ab000 { + + qfprom: qfprom@fc4bc000 { + compatible = "qcom,msm8974-qfprom", "qcom,qfprom"; +- reg = <0xfc4bc000 0x1000>; ++ reg = <0xfc4bc000 0x2100>; + #address-cells = <1>; + #size-cells = <1>; + +diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts +index 42d253b75dad02..6c4153689b39e5 100644 +--- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts ++++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + #include "qcom-msm8974pro.dtsi" +-#include "qcom-pm8841.dtsi" +-#include "qcom-pm8941.dtsi" ++#include "pm8841.dtsi" ++#include "pm8941.dtsi" + #include + #include + #include +diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts +index 8230d0e1d95d1d..c0ca264d8140db 100644 +--- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts ++++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + #include "qcom-msm8974pro.dtsi" +-#include "qcom-pm8841.dtsi" +-#include "qcom-pm8941.dtsi" ++#include "pm8841.dtsi" ++#include "pm8941.dtsi" + #include + #include + +diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts +index 3e2c86591ee2f7..325feb89b343ab 100644 +--- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts ++++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + #include "qcom-msm8974pro.dtsi" +-#include "qcom-pma8084.dtsi" ++#include "pma8084.dtsi" + #include + #include + #include +diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts +index 11468d1409f722..0798cce3dbea01 100644 +--- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts ++++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + #include "qcom-msm8974pro.dtsi" +-#include "qcom-pm8841.dtsi" +-#include "qcom-pm8941.dtsi" ++#include "pm8841.dtsi" ++#include "pm8941.dtsi" + #include + #include + #include +diff --git a/arch/arm/boot/dts/qcom/qcom-pm8226.dtsi b/arch/arm/boot/dts/qcom/qcom-pm8226.dtsi +deleted file mode 100644 +index 2413778f371507..00000000000000 +--- a/arch/arm/boot/dts/qcom/qcom-pm8226.dtsi ++++ /dev/null +@@ -1,180 +0,0 @@ +-// SPDX-License-Identifier: BSD-3-Clause +-#include +-#include +-#include +-#include +- +-/ { +- thermal-zones { +- pm8226-thermal { +- polling-delay-passive = <100>; +- polling-delay = <0>; +- thermal-sensors = <&pm8226_temp>; +- +- trips { +- trip0 { +- temperature = <105000>; +- hysteresis = <2000>; +- type = "passive"; +- }; +- +- trip1 { +- temperature = <125000>; +- hysteresis = <2000>; +- type = "hot"; +- }; +- +- crit { +- temperature = <145000>; +- hysteresis = <2000>; +- type = "critical"; +- }; +- }; +- }; +- }; +-}; +- +-&spmi_bus { +- pm8226_0: pm8226@0 { +- compatible = "qcom,pm8226", "qcom,spmi-pmic"; +- reg = <0x0 SPMI_USID>; +- #address-cells = <1>; +- #size-cells = <0>; +- +- pon@800 { +- compatible = "qcom,pm8916-pon"; +- reg = <0x800>; +- +- pwrkey { +- compatible = "qcom,pm8941-pwrkey"; +- interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; +- debounce = <15625>; +- bias-pull-up; +- linux,code = ; +- }; +- +- pm8226_resin: resin { +- compatible = "qcom,pm8941-resin"; +- interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>; +- debounce = <15625>; +- bias-pull-up; +- status = "disabled"; +- }; +- }; +- +- smbb: charger@1000 { +- compatible = "qcom,pm8226-charger"; +- reg = <0x1000>; +- interrupts = <0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>, +- <0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>, +- <0x0 0x10 4 IRQ_TYPE_EDGE_BOTH>, +- <0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>, +- <0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>, +- <0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>, +- <0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>, +- <0x0 0x14 1 IRQ_TYPE_EDGE_BOTH>; +- interrupt-names = "chg-done", +- "chg-fast", +- "chg-trkl", +- "bat-temp-ok", +- "bat-present", +- "chg-gone", +- "usb-valid", +- "dc-valid"; +- +- chg_otg: otg-vbus { }; +- }; +- +- pm8226_temp: temp-alarm@2400 { +- compatible = "qcom,spmi-temp-alarm"; +- reg = <0x2400>; +- interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>; +- io-channels = <&pm8226_vadc VADC_DIE_TEMP>; +- io-channel-names = "thermal"; +- #thermal-sensor-cells = <0>; +- }; +- +- pm8226_vadc: adc@3100 { +- compatible = "qcom,spmi-vadc"; +- reg = <0x3100>; +- interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; +- #address-cells = <1>; +- #size-cells = <0>; +- #io-channel-cells = <1>; +- +- channel@7 { +- reg = ; +- qcom,pre-scaling = <1 3>; +- label = "vph_pwr"; +- }; +- channel@8 { +- reg = ; +- label = "die_temp"; +- }; +- channel@9 { +- reg = ; +- label = "ref_625mv"; +- }; +- channel@a { +- reg = ; +- label = "ref_1250mv"; +- }; +- channel@e { +- reg = ; +- }; +- channel@f { +- reg = ; +- }; +- }; +- +- pm8226_iadc: adc@3600 { +- compatible = "qcom,pm8226-iadc", "qcom,spmi-iadc"; +- reg = <0x3600>; +- interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>; +- }; +- +- rtc@6000 { +- compatible = "qcom,pm8941-rtc"; +- reg = <0x6000>, <0x6100>; +- reg-names = "rtc", "alarm"; +- interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; +- }; +- +- pm8226_mpps: mpps@a000 { +- compatible = "qcom,pm8226-mpp", "qcom,spmi-mpp"; +- reg = <0xa000>; +- gpio-controller; +- #gpio-cells = <2>; +- gpio-ranges = <&pm8226_mpps 0 0 8>; +- interrupt-controller; +- #interrupt-cells = <2>; +- }; +- +- pm8226_gpios: gpio@c000 { +- compatible = "qcom,pm8226-gpio", "qcom,spmi-gpio"; +- reg = <0xc000>; +- gpio-controller; +- #gpio-cells = <2>; +- gpio-ranges = <&pm8226_gpios 0 0 8>; +- interrupt-controller; +- #interrupt-cells = <2>; +- }; +- }; +- +- pm8226_1: pm8226@1 { +- compatible = "qcom,pm8226", "qcom,spmi-pmic"; +- reg = <0x1 SPMI_USID>; +- #address-cells = <1>; +- #size-cells = <0>; +- +- pm8226_spmi_regulators: regulators { +- compatible = "qcom,pm8226-regulators"; +- }; +- +- pm8226_vib: vibrator@c000 { +- compatible = "qcom,pm8916-vib"; +- reg = <0xc000>; +- status = "disabled"; +- }; +- }; +-}; +diff --git a/arch/arm/boot/dts/qcom/qcom-pm8841.dtsi b/arch/arm/boot/dts/qcom/qcom-pm8841.dtsi +deleted file mode 100644 +index 3bf2ce5c86a641..00000000000000 +--- a/arch/arm/boot/dts/qcom/qcom-pm8841.dtsi ++++ /dev/null +@@ -1,68 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-#include +-#include +- +- +-/ { +- thermal-zones { +- pm8841-thermal { +- polling-delay-passive = <100>; +- polling-delay = <0>; +- thermal-sensors = <&pm8841_temp>; +- +- trips { +- trip0 { +- temperature = <105000>; +- hysteresis = <2000>; +- type = "passive"; +- }; +- +- trip1 { +- temperature = <125000>; +- hysteresis = <2000>; +- type = "hot"; +- }; +- +- crit { +- temperature = <140000>; +- hysteresis = <2000>; +- type = "critical"; +- }; +- }; +- }; +- }; +-}; +- +-&spmi_bus { +- +- pm8841_0: pm8841@4 { +- compatible = "qcom,pm8841", "qcom,spmi-pmic"; +- reg = <0x4 SPMI_USID>; +- #address-cells = <1>; +- #size-cells = <0>; +- +- pm8841_mpps: mpps@a000 { +- compatible = "qcom,pm8841-mpp", "qcom,spmi-mpp"; +- reg = <0xa000>; +- gpio-controller; +- #gpio-cells = <2>; +- gpio-ranges = <&pm8841_mpps 0 0 4>; +- interrupt-controller; +- #interrupt-cells = <2>; +- }; +- +- pm8841_temp: temp-alarm@2400 { +- compatible = "qcom,spmi-temp-alarm"; +- reg = <0x2400>; +- interrupts = <4 0x24 0 IRQ_TYPE_EDGE_RISING>; +- #thermal-sensor-cells = <0>; +- }; +- }; +- +- pm8841_1: pm8841@5 { +- compatible = "qcom,pm8841", "qcom,spmi-pmic"; +- reg = <0x5 SPMI_USID>; +- #address-cells = <1>; +- #size-cells = <0>; +- }; +-}; +diff --git a/arch/arm/boot/dts/qcom/qcom-pm8941.dtsi b/arch/arm/boot/dts/qcom/qcom-pm8941.dtsi +deleted file mode 100644 +index ed0ba591c75581..00000000000000 +--- a/arch/arm/boot/dts/qcom/qcom-pm8941.dtsi ++++ /dev/null +@@ -1,254 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-#include +-#include +-#include +- +- +-/ { +- thermal-zones { +- pm8941-thermal { +- polling-delay-passive = <100>; +- polling-delay = <0>; +- thermal-sensors = <&pm8941_temp>; +- +- trips { +- trip0 { +- temperature = <105000>; +- hysteresis = <2000>; +- type = "passive"; +- }; +- +- trip1 { +- temperature = <125000>; +- hysteresis = <2000>; +- type = "hot"; +- }; +- +- crit { +- temperature = <145000>; +- hysteresis = <2000>; +- type = "critical"; +- }; +- }; +- }; +- }; +-}; +- +-&spmi_bus { +- +- pm8941_0: pm8941@0 { +- compatible = "qcom,pm8941", "qcom,spmi-pmic"; +- reg = <0x0 SPMI_USID>; +- #address-cells = <1>; +- #size-cells = <0>; +- +- rtc@6000 { +- compatible = "qcom,pm8941-rtc"; +- reg = <0x6000>, +- <0x6100>; +- reg-names = "rtc", "alarm"; +- interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; +- }; +- +- pon@800 { +- compatible = "qcom,pm8941-pon"; +- reg = <0x800>; +- +- pwrkey { +- compatible = "qcom,pm8941-pwrkey"; +- interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; +- debounce = <15625>; +- bias-pull-up; +- }; +- +- pm8941_resin: resin { +- compatible = "qcom,pm8941-resin"; +- interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>; +- debounce = <15625>; +- bias-pull-up; +- status = "disabled"; +- }; +- }; +- +- usb_id: usb-detect@900 { +- compatible = "qcom,pm8941-misc"; +- reg = <0x900>; +- interrupts = <0x0 0x9 0 IRQ_TYPE_EDGE_BOTH>; +- interrupt-names = "usb_id"; +- }; +- +- smbb: charger@1000 { +- compatible = "qcom,pm8941-charger"; +- reg = <0x1000>; +- interrupts = <0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>, +- <0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>, +- <0x0 0x10 4 IRQ_TYPE_EDGE_BOTH>, +- <0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>, +- <0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>, +- <0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>, +- <0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>, +- <0x0 0x14 1 IRQ_TYPE_EDGE_BOTH>; +- interrupt-names = "chg-done", +- "chg-fast", +- "chg-trkl", +- "bat-temp-ok", +- "bat-present", +- "chg-gone", +- "usb-valid", +- "dc-valid"; +- +- usb-otg-in-supply = <&pm8941_5vs1>; +- +- chg_otg: otg-vbus { }; +- }; +- +- pm8941_gpios: gpio@c000 { +- compatible = "qcom,pm8941-gpio", "qcom,spmi-gpio"; +- reg = <0xc000>; +- gpio-controller; +- gpio-ranges = <&pm8941_gpios 0 0 36>; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- +- boost_bypass_n_pin: boost-bypass-state { +- pins = "gpio21"; +- function = "normal"; +- }; +- }; +- +- pm8941_mpps: mpps@a000 { +- compatible = "qcom,pm8941-mpp", "qcom,spmi-mpp"; +- reg = <0xa000>; +- gpio-controller; +- #gpio-cells = <2>; +- gpio-ranges = <&pm8941_mpps 0 0 8>; +- interrupt-controller; +- #interrupt-cells = <2>; +- }; +- +- pm8941_temp: temp-alarm@2400 { +- compatible = "qcom,spmi-temp-alarm"; +- reg = <0x2400>; +- interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>; +- io-channels = <&pm8941_vadc VADC_DIE_TEMP>; +- io-channel-names = "thermal"; +- #thermal-sensor-cells = <0>; +- }; +- +- pm8941_vadc: adc@3100 { +- compatible = "qcom,spmi-vadc"; +- reg = <0x3100>; +- interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; +- #address-cells = <1>; +- #size-cells = <0>; +- #io-channel-cells = <1>; +- +- +- channel@6 { +- reg = ; +- }; +- +- channel@8 { +- reg = ; +- }; +- +- channel@9 { +- reg = ; +- }; +- +- channel@a { +- reg = ; +- }; +- +- channel@e { +- reg = ; +- }; +- +- channel@f { +- reg = ; +- }; +- +- channel@30 { +- reg = ; +- }; +- }; +- +- pm8941_iadc: adc@3600 { +- compatible = "qcom,pm8941-iadc", "qcom,spmi-iadc"; +- reg = <0x3600>; +- interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>; +- qcom,external-resistor-micro-ohms = <10000>; +- }; +- +- pm8941_coincell: charger@2800 { +- compatible = "qcom,pm8941-coincell"; +- reg = <0x2800>; +- status = "disabled"; +- }; +- }; +- +- pm8941_1: pm8941@1 { +- compatible = "qcom,pm8941", "qcom,spmi-pmic"; +- reg = <0x1 SPMI_USID>; +- #address-cells = <1>; +- #size-cells = <0>; +- +- pm8941_lpg: pwm { +- compatible = "qcom,pm8941-lpg"; +- +- #address-cells = <1>; +- #size-cells = <0>; +- #pwm-cells = <2>; +- +- status = "disabled"; +- }; +- +- pm8941_vib: vibrator@c000 { +- compatible = "qcom,pm8916-vib"; +- reg = <0xc000>; +- status = "disabled"; +- }; +- +- pm8941_wled: wled@d800 { +- compatible = "qcom,pm8941-wled"; +- reg = <0xd800>; +- label = "backlight"; +- +- status = "disabled"; +- }; +- +- regulators { +- compatible = "qcom,pm8941-regulators"; +- interrupts = <0x1 0x83 0x2 0>, <0x1 0x84 0x2 0>; +- interrupt-names = "ocp-5vs1", "ocp-5vs2"; +- vin_5vs-supply = <&pm8941_5v>; +- +- pm8941_5v: s4 { +- regulator-min-microvolt = <5000000>; +- regulator-max-microvolt = <5000000>; +- regulator-enable-ramp-delay = <500>; +- }; +- +- pm8941_5vs1: 5vs1 { +- regulator-enable-ramp-delay = <1000>; +- regulator-pull-down; +- regulator-over-current-protection; +- qcom,ocp-max-retries = <10>; +- qcom,ocp-retry-delay = <30>; +- qcom,vs-soft-start-strength = <0>; +- regulator-initial-mode = <1>; +- }; +- +- pm8941_5vs2: 5vs2 { +- regulator-enable-ramp-delay = <1000>; +- regulator-pull-down; +- regulator-over-current-protection; +- qcom,ocp-max-retries = <10>; +- qcom,ocp-retry-delay = <30>; +- qcom,vs-soft-start-strength = <0>; +- regulator-initial-mode = <1>; +- }; +- }; +- }; +-}; +diff --git a/arch/arm/boot/dts/qcom/qcom-pma8084.dtsi b/arch/arm/boot/dts/qcom/qcom-pma8084.dtsi +deleted file mode 100644 +index 2985f4805b93ee..00000000000000 +--- a/arch/arm/boot/dts/qcom/qcom-pma8084.dtsi ++++ /dev/null +@@ -1,99 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-#include +-#include +-#include +- +-&spmi_bus { +- +- pma8084_0: pma8084@0 { +- compatible = "qcom,pma8084", "qcom,spmi-pmic"; +- reg = <0x0 SPMI_USID>; +- #address-cells = <1>; +- #size-cells = <0>; +- +- rtc@6000 { +- compatible = "qcom,pm8941-rtc"; +- reg = <0x6000>, +- <0x6100>; +- reg-names = "rtc", "alarm"; +- interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; +- }; +- +- pwrkey@800 { +- compatible = "qcom,pm8941-pwrkey"; +- reg = <0x800>; +- interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; +- debounce = <15625>; +- bias-pull-up; +- }; +- +- pma8084_gpios: gpio@c000 { +- compatible = "qcom,pma8084-gpio", "qcom,spmi-gpio"; +- reg = <0xc000>; +- gpio-controller; +- gpio-ranges = <&pma8084_gpios 0 0 22>; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- }; +- +- pma8084_mpps: mpps@a000 { +- compatible = "qcom,pma8084-mpp", "qcom,spmi-mpp"; +- reg = <0xa000>; +- gpio-controller; +- #gpio-cells = <2>; +- gpio-ranges = <&pma8084_mpps 0 0 8>; +- interrupt-controller; +- #interrupt-cells = <2>; +- }; +- +- pma8084_temp: temp-alarm@2400 { +- compatible = "qcom,spmi-temp-alarm"; +- reg = <0x2400>; +- interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>; +- #thermal-sensor-cells = <0>; +- io-channels = <&pma8084_vadc VADC_DIE_TEMP>; +- io-channel-names = "thermal"; +- }; +- +- pma8084_vadc: adc@3100 { +- compatible = "qcom,spmi-vadc"; +- reg = <0x3100>; +- interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; +- #address-cells = <1>; +- #size-cells = <0>; +- #io-channel-cells = <1>; +- +- channel@8 { +- reg = ; +- }; +- +- channel@9 { +- reg = ; +- }; +- +- channel@a { +- reg = ; +- }; +- +- channel@c { +- reg = ; +- }; +- +- channel@e { +- reg = ; +- }; +- +- channel@f { +- reg = ; +- }; +- }; +- }; +- +- pma8084_1: pma8084@1 { +- compatible = "qcom,pma8084", "qcom,spmi-pmic"; +- reg = <0x1 SPMI_USID>; +- #address-cells = <1>; +- #size-cells = <0>; +- }; +-}; +diff --git a/arch/arm/boot/dts/qcom/qcom-pmx55.dtsi b/arch/arm/boot/dts/qcom/qcom-pmx55.dtsi +deleted file mode 100644 +index da0851173c6997..00000000000000 +--- a/arch/arm/boot/dts/qcom/qcom-pmx55.dtsi ++++ /dev/null +@@ -1,85 +0,0 @@ +-// SPDX-License-Identifier: BSD-3-Clause +- +-/* +- * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. +- * Copyright (c) 2020, Linaro Limited +- */ +- +-#include +-#include +-#include +- +-&spmi_bus { +- pmic@8 { +- compatible = "qcom,pmx55", "qcom,spmi-pmic"; +- reg = <0x8 SPMI_USID>; +- #address-cells = <1>; +- #size-cells = <0>; +- +- pon@800 { +- compatible = "qcom,pm8916-pon"; +- reg = <0x0800>; +- +- status = "disabled"; +- }; +- +- pmx55_temp: temp-alarm@2400 { +- compatible = "qcom,spmi-temp-alarm"; +- reg = <0x2400>; +- interrupts = <0x8 0x24 0x0 IRQ_TYPE_EDGE_BOTH>; +- io-channels = <&pmx55_adc ADC5_DIE_TEMP>; +- io-channel-names = "thermal"; +- #thermal-sensor-cells = <0>; +- }; +- +- pmx55_adc: adc@3100 { +- compatible = "qcom,spmi-adc5"; +- reg = <0x3100>; +- #address-cells = <1>; +- #size-cells = <0>; +- #io-channel-cells = <1>; +- interrupts = <0x8 0x31 0x0 IRQ_TYPE_EDGE_RISING>; +- +- channel@0 { +- reg = ; +- qcom,pre-scaling = <1 1>; +- label = "ref_gnd"; +- }; +- +- channel@1 { +- reg = ; +- qcom,pre-scaling = <1 1>; +- label = "vref_1p25"; +- }; +- +- channel@6 { +- reg = ; +- qcom,pre-scaling = <1 1>; +- label = "die_temp"; +- }; +- +- channel@9 { +- reg = ; +- qcom,pre-scaling = <1 1>; +- label = "chg_temp"; +- }; +- }; +- +- pmx55_gpios: gpio@c000 { +- compatible = "qcom,pmx55-gpio", "qcom,spmi-gpio"; +- reg = <0xc000>; +- gpio-controller; +- gpio-ranges = <&pmx55_gpios 0 0 11>; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- }; +- }; +- +- pmic@9 { +- compatible = "qcom,pmx55", "qcom,spmi-pmic"; +- reg = <0x9 SPMI_USID>; +- #address-cells = <1>; +- #size-cells = <0>; +- }; +-}; +diff --git a/arch/arm/boot/dts/qcom/qcom-pmx65.dtsi b/arch/arm/boot/dts/qcom/qcom-pmx65.dtsi +deleted file mode 100644 +index 1c7fdf59c1f56a..00000000000000 +--- a/arch/arm/boot/dts/qcom/qcom-pmx65.dtsi ++++ /dev/null +@@ -1,33 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0-only +-/* +- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. +- */ +- +-#include +-#include +- +-&spmi_bus { +- pmic@1 { +- compatible = "qcom,pmx65", "qcom,spmi-pmic"; +- reg = <1 SPMI_USID>; +- #address-cells = <1>; +- #size-cells = <0>; +- +- pmx65_temp: temp-alarm@a00 { +- compatible = "qcom,spmi-temp-alarm"; +- reg = <0xa00>; +- interrupts = <0x1 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; +- #thermal-sensor-cells = <0>; +- }; +- +- pmx65_gpios: gpio@8800 { +- compatible = "qcom,pmx65-gpio", "qcom,spmi-gpio"; +- reg = <0x8800>; +- gpio-controller; +- gpio-ranges = <&pmx65_gpios 0 0 16>; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- }; +- }; +-}; +diff --git a/arch/arm/boot/dts/qcom/qcom-sdx55-mtp.dts b/arch/arm/boot/dts/qcom/qcom-sdx55-mtp.dts +index 7e97ad5803d87b..2470693619090b 100644 +--- a/arch/arm/boot/dts/qcom/qcom-sdx55-mtp.dts ++++ b/arch/arm/boot/dts/qcom/qcom-sdx55-mtp.dts +@@ -9,7 +9,7 @@ + #include "qcom-sdx55.dtsi" + #include + #include +-#include "qcom-pmx55.dtsi" ++#include "pmx55.dtsi" + + / { + model = "Qualcomm Technologies, Inc. SDX55 MTP"; +diff --git a/arch/arm/boot/dts/qcom/qcom-sdx55-t55.dts b/arch/arm/boot/dts/qcom/qcom-sdx55-t55.dts +index 51058b06527979..082f7ed1a01fb8 100644 +--- a/arch/arm/boot/dts/qcom/qcom-sdx55-t55.dts ++++ b/arch/arm/boot/dts/qcom/qcom-sdx55-t55.dts +@@ -8,7 +8,7 @@ + #include + #include + #include "qcom-sdx55.dtsi" +-#include "qcom-pmx55.dtsi" ++#include "pmx55.dtsi" + + / { + model = "Thundercomm T55 Development Kit"; +diff --git a/arch/arm/boot/dts/qcom/qcom-sdx55-telit-fn980-tlb.dts b/arch/arm/boot/dts/qcom/qcom-sdx55-telit-fn980-tlb.dts +index 8fadc6e70692a5..e336a15b45c4c6 100644 +--- a/arch/arm/boot/dts/qcom/qcom-sdx55-telit-fn980-tlb.dts ++++ b/arch/arm/boot/dts/qcom/qcom-sdx55-telit-fn980-tlb.dts +@@ -8,7 +8,7 @@ + #include + #include + #include "qcom-sdx55.dtsi" +-#include "qcom-pmx55.dtsi" ++#include "pmx55.dtsi" + + / { + model = "Telit FN980 TLB"; +diff --git a/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi b/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi +index 55ce87b7525394..f9ad5abfbd28bf 100644 +--- a/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi ++++ b/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi +@@ -345,10 +345,10 @@ pcie_rc: pcie@1c00000 { + "msi8"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; +- interrupt-map = <0 0 0 1 &intc 0 0 0 141 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ +- <0 0 0 2 &intc 0 0 0 142 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ +- <0 0 0 3 &intc 0 0 0 143 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ +- <0 0 0 4 &intc 0 0 0 144 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ ++ interrupt-map = <0 0 0 1 &intc 0 141 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ ++ <0 0 0 2 &intc 0 142 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ ++ <0 0 0 3 &intc 0 143 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ ++ <0 0 0 4 &intc 0 144 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ + + clocks = <&gcc GCC_PCIE_PIPE_CLK>, + <&gcc GCC_PCIE_AUX_CLK>, +@@ -592,10 +592,10 @@ usb: usb@a6f8800 { + <&gcc GCC_USB30_MASTER_CLK>; + assigned-clock-rates = <19200000>, <200000000>; + +- interrupts = , +- , +- , +- ; ++ interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc 51 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc 11 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc 10 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hs_phy_irq", "ss_phy_irq", + "dm_hs_phy_irq", "dp_hs_phy_irq"; + +@@ -619,7 +619,7 @@ pdc: interrupt-controller@b210000 { + compatible = "qcom,sdx55-pdc", "qcom,pdc"; + reg = <0x0b210000 0x30000>; + qcom,pdc-ranges = <0 179 52>; +- #interrupt-cells = <3>; ++ #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupt-controller; + }; +diff --git a/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts b/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts +index fcf1c51c5e7a7a..b87c5434cc29e4 100644 +--- a/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts ++++ b/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts +@@ -8,7 +8,7 @@ + #include + #include + #include +-#include "qcom-pmx65.dtsi" ++#include "pmx65.dtsi" + + / { + model = "Qualcomm Technologies, Inc. SDX65 MTP"; +diff --git a/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi b/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi +index 1a3583029a649e..271899c861c01c 100644 +--- a/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi ++++ b/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi +@@ -338,7 +338,7 @@ pcie_ep: pcie-ep@1c00000 { + power-domains = <&gcc PCIE_GDSC>; + + phys = <&pcie_phy>; +- phy-names = "pcie-phy"; ++ phy-names = "pciephy"; + + max-link-speed = <3>; + num-lanes = <2>; +@@ -530,7 +530,7 @@ restart@c264000 { + reg = <0x0c264000 0x1000>; + }; + +- spmi_bus: qcom,spmi@c440000 { ++ spmi_bus: spmi@c440000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0xc440000 0xd00>, + <0xc600000 0x2000000>, +diff --git a/arch/arm/boot/dts/renesas/r8a73a4-ape6evm.dts b/arch/arm/boot/dts/renesas/r8a73a4-ape6evm.dts +index e81a7213d30477..4282bafbb50431 100644 +--- a/arch/arm/boot/dts/renesas/r8a73a4-ape6evm.dts ++++ b/arch/arm/boot/dts/renesas/r8a73a4-ape6evm.dts +@@ -209,6 +209,18 @@ &cmt1 { + status = "okay"; + }; + ++&extal1_clk { ++ clock-frequency = <26000000>; ++}; ++ ++&extal2_clk { ++ clock-frequency = <48000000>; ++}; ++ ++&extalr_clk { ++ clock-frequency = <32768>; ++}; ++ + &pfc { + scifa0_pins: scifa0 { + groups = "scifa0_data"; +diff --git a/arch/arm/boot/dts/renesas/r8a73a4.dtsi b/arch/arm/boot/dts/renesas/r8a73a4.dtsi +index c39066967053f0..d1f4cbd099efb4 100644 +--- a/arch/arm/boot/dts/renesas/r8a73a4.dtsi ++++ b/arch/arm/boot/dts/renesas/r8a73a4.dtsi +@@ -450,17 +450,20 @@ clocks { + extalr_clk: extalr { + compatible = "fixed-clock"; + #clock-cells = <0>; +- clock-frequency = <32768>; ++ /* This value must be overridden by the board. */ ++ clock-frequency = <0>; + }; + extal1_clk: extal1 { + compatible = "fixed-clock"; + #clock-cells = <0>; +- clock-frequency = <25000000>; ++ /* This value must be overridden by the board. */ ++ clock-frequency = <0>; + }; + extal2_clk: extal2 { + compatible = "fixed-clock"; + #clock-cells = <0>; +- clock-frequency = <48000000>; ++ /* This value must be overridden by the board. */ ++ clock-frequency = <0>; + }; + fsiack_clk: fsiack { + compatible = "fixed-clock"; +diff --git a/arch/arm/boot/dts/renesas/r8a7790-lager.dts b/arch/arm/boot/dts/renesas/r8a7790-lager.dts +index 5ad5349a50dc9b..ab7e9fa90b9fe2 100644 +--- a/arch/arm/boot/dts/renesas/r8a7790-lager.dts ++++ b/arch/arm/boot/dts/renesas/r8a7790-lager.dts +@@ -437,6 +437,7 @@ pmic@58 { + interrupt-parent = <&irqc0>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; ++ #interrupt-cells = <2>; + + rtc { + compatible = "dlg,da9063-rtc"; +diff --git a/arch/arm/boot/dts/renesas/r8a7790-stout.dts b/arch/arm/boot/dts/renesas/r8a7790-stout.dts +index fe14727eefe1ec..25956661a87541 100644 +--- a/arch/arm/boot/dts/renesas/r8a7790-stout.dts ++++ b/arch/arm/boot/dts/renesas/r8a7790-stout.dts +@@ -332,6 +332,7 @@ pmic@58 { + interrupt-parent = <&irqc0>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; ++ #interrupt-cells = <2>; + + onkey { + compatible = "dlg,da9063-onkey"; +diff --git a/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts b/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts +index 26a40782cc899b..4a76be68887b43 100644 +--- a/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts ++++ b/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts +@@ -800,6 +800,7 @@ pmic@58 { + interrupt-parent = <&irqc0>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; ++ #interrupt-cells = <2>; + + rtc { + compatible = "dlg,da9063-rtc"; +diff --git a/arch/arm/boot/dts/renesas/r8a7791-porter.dts b/arch/arm/boot/dts/renesas/r8a7791-porter.dts +index ec0a20d5130d6f..fcc9a2313e1dfd 100644 +--- a/arch/arm/boot/dts/renesas/r8a7791-porter.dts ++++ b/arch/arm/boot/dts/renesas/r8a7791-porter.dts +@@ -389,6 +389,7 @@ pmic@5a { + interrupt-parent = <&irqc0>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; ++ #interrupt-cells = <2>; + + watchdog { + compatible = "dlg,da9063-watchdog"; +diff --git a/arch/arm/boot/dts/renesas/r8a7792-blanche.dts b/arch/arm/boot/dts/renesas/r8a7792-blanche.dts +index c66de9dd12dfca..20963c9bbf0ada 100644 +--- a/arch/arm/boot/dts/renesas/r8a7792-blanche.dts ++++ b/arch/arm/boot/dts/renesas/r8a7792-blanche.dts +@@ -239,7 +239,7 @@ du1_pins: du1 { + }; + + keyboard_pins: keyboard { +- pins = "GP_3_10", "GP_3_11", "GP_3_12", "GP_3_15", "GP_11_02"; ++ pins = "GP_3_10", "GP_3_11", "GP_3_12", "GP_3_15", "GP_11_2"; + bias-pull-up; + }; + +@@ -330,6 +330,7 @@ pmic@58 { + interrupt-parent = <&irqc>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; ++ #interrupt-cells = <2>; + + rtc { + compatible = "dlg,da9063-rtc"; +diff --git a/arch/arm/boot/dts/renesas/r8a7793-gose.dts b/arch/arm/boot/dts/renesas/r8a7793-gose.dts +index 79b537b2464266..9358fc7d0e9f6f 100644 +--- a/arch/arm/boot/dts/renesas/r8a7793-gose.dts ++++ b/arch/arm/boot/dts/renesas/r8a7793-gose.dts +@@ -735,6 +735,7 @@ pmic@58 { + interrupt-parent = <&irqc0>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; ++ #interrupt-cells = <2>; + + rtc { + compatible = "dlg,da9063-rtc"; +diff --git a/arch/arm/boot/dts/renesas/r8a7794-alt.dts b/arch/arm/boot/dts/renesas/r8a7794-alt.dts +index 4d93319674c6ef..3a9db455ddec94 100644 +--- a/arch/arm/boot/dts/renesas/r8a7794-alt.dts ++++ b/arch/arm/boot/dts/renesas/r8a7794-alt.dts +@@ -458,6 +458,7 @@ pmic@58 { + interrupt-parent = <&gpio3>; + interrupts = <31 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; ++ #interrupt-cells = <2>; + + rtc { + compatible = "dlg,da9063-rtc"; +diff --git a/arch/arm/boot/dts/renesas/r8a7794-silk.dts b/arch/arm/boot/dts/renesas/r8a7794-silk.dts +index b7af1befa126ba..b825f2e25dd060 100644 +--- a/arch/arm/boot/dts/renesas/r8a7794-silk.dts ++++ b/arch/arm/boot/dts/renesas/r8a7794-silk.dts +@@ -424,6 +424,7 @@ pmic@58 { + interrupt-parent = <&gpio3>; + interrupts = <31 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; ++ #interrupt-cells = <2>; + + onkey { + compatible = "dlg,da9063-onkey"; +diff --git a/arch/arm/boot/dts/rockchip/rk3036.dtsi b/arch/arm/boot/dts/rockchip/rk3036.dtsi +index 78686fc72ce69a..c420c7c642cb0b 100644 +--- a/arch/arm/boot/dts/rockchip/rk3036.dtsi ++++ b/arch/arm/boot/dts/rockchip/rk3036.dtsi +@@ -402,12 +402,20 @@ hdmi: hdmi@20034000 { + pinctrl-0 = <&hdmi_ctl>; + status = "disabled"; + +- hdmi_in: port { ++ ports { + #address-cells = <1>; + #size-cells = <0>; +- hdmi_in_vop: endpoint@0 { ++ ++ hdmi_in: port@0 { + reg = <0>; +- remote-endpoint = <&vop_out_hdmi>; ++ ++ hdmi_in_vop: endpoint { ++ remote-endpoint = <&vop_out_hdmi>; ++ }; ++ }; ++ ++ hdmi_out: port@1 { ++ reg = <1>; + }; + }; + }; +diff --git a/arch/arm/boot/dts/rockchip/rk3066a.dtsi b/arch/arm/boot/dts/rockchip/rk3066a.dtsi +index de9915d946f74f..b98d5e357baf35 100644 +--- a/arch/arm/boot/dts/rockchip/rk3066a.dtsi ++++ b/arch/arm/boot/dts/rockchip/rk3066a.dtsi +@@ -123,6 +123,7 @@ hdmi: hdmi@10116000 { + pinctrl-0 = <&hdmii2c_xfer>, <&hdmi_hpd>; + power-domains = <&power RK3066_PD_VIO>; + rockchip,grf = <&grf>; ++ #sound-dai-cells = <0>; + status = "disabled"; + + ports { +diff --git a/arch/arm/boot/dts/rockchip/rk3128.dtsi b/arch/arm/boot/dts/rockchip/rk3128.dtsi +index 88a4b0d6d928d4..80d81af5fe0efe 100644 +--- a/arch/arm/boot/dts/rockchip/rk3128.dtsi ++++ b/arch/arm/boot/dts/rockchip/rk3128.dtsi +@@ -795,7 +795,7 @@ sdmmc_wp: sdmmc-wp { + }; + + sdmmc_pwren: sdmmc-pwren { +- rockchip,pins = <1 RK_PB6 1 &pcfg_pull_default>; ++ rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_default>; + }; + + sdmmc_bus4: sdmmc-bus4 { +diff --git a/arch/arm/boot/dts/rockchip/rk322x.dtsi b/arch/arm/boot/dts/rockchip/rk322x.dtsi +index ffc16d6b97e1bd..03d9baddcbabaa 100644 +--- a/arch/arm/boot/dts/rockchip/rk322x.dtsi ++++ b/arch/arm/boot/dts/rockchip/rk322x.dtsi +@@ -732,14 +732,20 @@ hdmi: hdmi@200a0000 { + status = "disabled"; + + ports { +- hdmi_in: port { +- #address-cells = <1>; +- #size-cells = <0>; +- hdmi_in_vop: endpoint@0 { +- reg = <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ hdmi_in: port@0 { ++ reg = <0>; ++ ++ hdmi_in_vop: endpoint { + remote-endpoint = <&vop_out_hdmi>; + }; + }; ++ ++ hdmi_out: port@1 { ++ reg = <1>; ++ }; + }; + }; + +diff --git a/arch/arm/boot/dts/rockchip/rk3288.dtsi b/arch/arm/boot/dts/rockchip/rk3288.dtsi +index cb9cdaddffd429..8593a835993767 100644 +--- a/arch/arm/boot/dts/rockchip/rk3288.dtsi ++++ b/arch/arm/boot/dts/rockchip/rk3288.dtsi +@@ -1231,27 +1231,37 @@ hdmi: hdmi@ff980000 { + compatible = "rockchip,rk3288-dw-hdmi"; + reg = <0x0 0xff980000 0x0 0x20000>; + reg-io-width = <4>; +- #sound-dai-cells = <0>; +- rockchip,grf = <&grf>; + interrupts = ; + clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>, <&cru SCLK_HDMI_CEC>; + clock-names = "iahb", "isfr", "cec"; + power-domains = <&power RK3288_PD_VIO>; ++ rockchip,grf = <&grf>; ++ #sound-dai-cells = <0>; + status = "disabled"; + + ports { +- hdmi_in: port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ hdmi_in: port@0 { ++ reg = <0>; + #address-cells = <1>; + #size-cells = <0>; ++ + hdmi_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_hdmi>; + }; ++ + hdmi_in_vopl: endpoint@1 { + reg = <1>; + remote-endpoint = <&vopl_out_hdmi>; + }; + }; ++ ++ hdmi_out: port@1 { ++ reg = <1>; ++ }; + }; + }; + +diff --git a/arch/arm/boot/dts/rockchip/rv1108.dtsi b/arch/arm/boot/dts/rockchip/rv1108.dtsi +index abf3006f0a8424..f3291f3bbc6fd2 100644 +--- a/arch/arm/boot/dts/rockchip/rv1108.dtsi ++++ b/arch/arm/boot/dts/rockchip/rv1108.dtsi +@@ -196,7 +196,6 @@ spi: spi@10270000 { + pwm4: pwm@10280000 { + compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm"; + reg = <0x10280000 0x10>; +- interrupts = ; + clocks = <&cru SCLK_PWM>, <&cru PCLK_PWM>; + clock-names = "pwm", "pclk"; + pinctrl-names = "default"; +@@ -208,7 +207,6 @@ pwm4: pwm@10280000 { + pwm5: pwm@10280010 { + compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm"; + reg = <0x10280010 0x10>; +- interrupts = ; + clocks = <&cru SCLK_PWM>, <&cru PCLK_PWM>; + clock-names = "pwm", "pclk"; + pinctrl-names = "default"; +@@ -220,7 +218,6 @@ pwm5: pwm@10280010 { + pwm6: pwm@10280020 { + compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm"; + reg = <0x10280020 0x10>; +- interrupts = ; + clocks = <&cru SCLK_PWM>, <&cru PCLK_PWM>; + clock-names = "pwm", "pclk"; + pinctrl-names = "default"; +@@ -232,7 +229,6 @@ pwm6: pwm@10280020 { + pwm7: pwm@10280030 { + compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm"; + reg = <0x10280030 0x10>; +- interrupts = ; + clocks = <&cru SCLK_PWM>, <&cru PCLK_PWM>; + clock-names = "pwm", "pclk"; + pinctrl-names = "default"; +@@ -386,7 +382,6 @@ i2c0: i2c@20000000 { + pwm0: pwm@20040000 { + compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm"; + reg = <0x20040000 0x10>; +- interrupts = ; + clocks = <&cru SCLK_PWM0_PMU>, <&cru PCLK_PWM0_PMU>; + clock-names = "pwm", "pclk"; + pinctrl-names = "default"; +@@ -398,7 +393,6 @@ pwm0: pwm@20040000 { + pwm1: pwm@20040010 { + compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm"; + reg = <0x20040010 0x10>; +- interrupts = ; + clocks = <&cru SCLK_PWM0_PMU>, <&cru PCLK_PWM0_PMU>; + clock-names = "pwm", "pclk"; + pinctrl-names = "default"; +@@ -410,7 +404,6 @@ pwm1: pwm@20040010 { + pwm2: pwm@20040020 { + compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm"; + reg = <0x20040020 0x10>; +- interrupts = ; + clocks = <&cru SCLK_PWM0_PMU>, <&cru PCLK_PWM0_PMU>; + clock-names = "pwm", "pclk"; + pinctrl-names = "default"; +@@ -422,7 +415,6 @@ pwm2: pwm@20040020 { + pwm3: pwm@20040030 { + compatible = "rockchip,rv1108-pwm", "rockchip,rk3288-pwm"; + reg = <0x20040030 0x10>; +- interrupts = ; + clocks = <&cru SCLK_PWM0_PMU>, <&cru PCLK_PWM0_PMU>; + clock-names = "pwm", "pclk"; + pinctrl-names = "default"; +diff --git a/arch/arm/boot/dts/samsung/exynos4.dtsi b/arch/arm/boot/dts/samsung/exynos4.dtsi +index f775b9377a38b5..7f981b5c0d64b5 100644 +--- a/arch/arm/boot/dts/samsung/exynos4.dtsi ++++ b/arch/arm/boot/dts/samsung/exynos4.dtsi +@@ -203,16 +203,16 @@ dsi_0: dsi@11c80000 { + + camera: camera@11800000 { + compatible = "samsung,fimc"; ++ ranges = <0x0 0x11800000 0xa0000>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <1>; + #clock-cells = <1>; + clock-output-names = "cam_a_clkout", "cam_b_clkout"; +- ranges; + +- fimc_0: fimc@11800000 { ++ fimc_0: fimc@0 { + compatible = "samsung,exynos4210-fimc"; +- reg = <0x11800000 0x1000>; ++ reg = <0x0 0x1000>; + interrupts = ; + clocks = <&clock CLK_FIMC0>, + <&clock CLK_SCLK_FIMC0>; +@@ -223,9 +223,9 @@ fimc_0: fimc@11800000 { + status = "disabled"; + }; + +- fimc_1: fimc@11810000 { ++ fimc_1: fimc@10000 { + compatible = "samsung,exynos4210-fimc"; +- reg = <0x11810000 0x1000>; ++ reg = <0x00010000 0x1000>; + interrupts = ; + clocks = <&clock CLK_FIMC1>, + <&clock CLK_SCLK_FIMC1>; +@@ -236,9 +236,9 @@ fimc_1: fimc@11810000 { + status = "disabled"; + }; + +- fimc_2: fimc@11820000 { ++ fimc_2: fimc@20000 { + compatible = "samsung,exynos4210-fimc"; +- reg = <0x11820000 0x1000>; ++ reg = <0x00020000 0x1000>; + interrupts = ; + clocks = <&clock CLK_FIMC2>, + <&clock CLK_SCLK_FIMC2>; +@@ -249,9 +249,9 @@ fimc_2: fimc@11820000 { + status = "disabled"; + }; + +- fimc_3: fimc@11830000 { ++ fimc_3: fimc@30000 { + compatible = "samsung,exynos4210-fimc"; +- reg = <0x11830000 0x1000>; ++ reg = <0x00030000 0x1000>; + interrupts = ; + clocks = <&clock CLK_FIMC3>, + <&clock CLK_SCLK_FIMC3>; +@@ -262,9 +262,9 @@ fimc_3: fimc@11830000 { + status = "disabled"; + }; + +- csis_0: csis@11880000 { ++ csis_0: csis@80000 { + compatible = "samsung,exynos4210-csis"; +- reg = <0x11880000 0x4000>; ++ reg = <0x00080000 0x4000>; + interrupts = ; + clocks = <&clock CLK_CSIS0>, + <&clock CLK_SCLK_CSIS0>; +@@ -278,9 +278,9 @@ csis_0: csis@11880000 { + #size-cells = <0>; + }; + +- csis_1: csis@11890000 { ++ csis_1: csis@90000 { + compatible = "samsung,exynos4210-csis"; +- reg = <0x11890000 0x4000>; ++ reg = <0x00090000 0x4000>; + interrupts = ; + clocks = <&clock CLK_CSIS1>, + <&clock CLK_SCLK_CSIS1>; +diff --git a/arch/arm/boot/dts/samsung/exynos4210-i9100.dts b/arch/arm/boot/dts/samsung/exynos4210-i9100.dts +index a9ec1f6c1dea15..a076a1dfe41f8f 100644 +--- a/arch/arm/boot/dts/samsung/exynos4210-i9100.dts ++++ b/arch/arm/boot/dts/samsung/exynos4210-i9100.dts +@@ -527,6 +527,14 @@ vtcam_reg: LDO12 { + regulator-name = "VT_CAM_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; ++ ++ /* ++ * Force-enable this regulator; otherwise the ++ * kernel hangs very early in the boot process ++ * for about 12 seconds, without apparent ++ * reason. ++ */ ++ regulator-always-on; + }; + + vcclcd_reg: LDO13 { +diff --git a/arch/arm/boot/dts/samsung/exynos4210-smdkv310.dts b/arch/arm/boot/dts/samsung/exynos4210-smdkv310.dts +index b566f878ed84f9..18f4f494093ba8 100644 +--- a/arch/arm/boot/dts/samsung/exynos4210-smdkv310.dts ++++ b/arch/arm/boot/dts/samsung/exynos4210-smdkv310.dts +@@ -88,7 +88,7 @@ eeprom@52 { + &keypad { + samsung,keypad-num-rows = <2>; + samsung,keypad-num-columns = <8>; +- linux,keypad-no-autorepeat; ++ linux,input-no-autorepeat; + wakeup-source; + pinctrl-names = "default"; + pinctrl-0 = <&keypad_rows &keypad_cols>; +diff --git a/arch/arm/boot/dts/samsung/exynos4212-tab3.dtsi b/arch/arm/boot/dts/samsung/exynos4212-tab3.dtsi +index ce81e42bf5eb3d..39469b708f910b 100644 +--- a/arch/arm/boot/dts/samsung/exynos4212-tab3.dtsi ++++ b/arch/arm/boot/dts/samsung/exynos4212-tab3.dtsi +@@ -435,6 +435,7 @@ &exynos_usbphy { + }; + + &fimd { ++ samsung,invert-vclk; + status = "okay"; + }; + +diff --git a/arch/arm/boot/dts/samsung/exynos4412-origen.dts b/arch/arm/boot/dts/samsung/exynos4412-origen.dts +index 23b151645d6686..10ab7bc90f502f 100644 +--- a/arch/arm/boot/dts/samsung/exynos4412-origen.dts ++++ b/arch/arm/boot/dts/samsung/exynos4412-origen.dts +@@ -453,7 +453,7 @@ buck9_reg: BUCK9 { + &keypad { + samsung,keypad-num-rows = <3>; + samsung,keypad-num-columns = <2>; +- linux,keypad-no-autorepeat; ++ linux,input-no-autorepeat; + wakeup-source; + pinctrl-0 = <&keypad_rows &keypad_cols>; + pinctrl-names = "default"; +diff --git a/arch/arm/boot/dts/samsung/exynos4412-smdk4412.dts b/arch/arm/boot/dts/samsung/exynos4412-smdk4412.dts +index 715dfcba141743..e16df9e75fcb0d 100644 +--- a/arch/arm/boot/dts/samsung/exynos4412-smdk4412.dts ++++ b/arch/arm/boot/dts/samsung/exynos4412-smdk4412.dts +@@ -69,7 +69,7 @@ cooling_map1: map1 { + &keypad { + samsung,keypad-num-rows = <3>; + samsung,keypad-num-columns = <8>; +- linux,keypad-no-autorepeat; ++ linux,input-no-autorepeat; + wakeup-source; + pinctrl-0 = <&keypad_rows &keypad_cols>; + pinctrl-names = "default"; +diff --git a/arch/arm/boot/dts/samsung/exynos4x12.dtsi b/arch/arm/boot/dts/samsung/exynos4x12.dtsi +index 84c1db221c984b..83d9d0a0a61754 100644 +--- a/arch/arm/boot/dts/samsung/exynos4x12.dtsi ++++ b/arch/arm/boot/dts/samsung/exynos4x12.dtsi +@@ -451,14 +451,15 @@ &combiner { + }; + + &camera { ++ ranges = <0x0 0x11800000 0xba1000>; + clocks = <&clock CLK_SCLK_CAM0>, <&clock CLK_SCLK_CAM1>, + <&clock CLK_PIXELASYNCM0>, <&clock CLK_PIXELASYNCM1>; + clock-names = "sclk_cam0", "sclk_cam1", "pxl_async0", "pxl_async1"; + + /* fimc_[0-3] are configured outside, under phandles */ +- fimc_lite_0: fimc-lite@12390000 { ++ fimc_lite_0: fimc-lite@b90000 { + compatible = "samsung,exynos4212-fimc-lite"; +- reg = <0x12390000 0x1000>; ++ reg = <0x00b90000 0x1000>; + interrupts = ; + power-domains = <&pd_isp>; + clocks = <&isp_clock CLK_ISP_FIMC_LITE0>; +@@ -467,9 +468,9 @@ fimc_lite_0: fimc-lite@12390000 { + status = "disabled"; + }; + +- fimc_lite_1: fimc-lite@123a0000 { ++ fimc_lite_1: fimc-lite@ba0000 { + compatible = "samsung,exynos4212-fimc-lite"; +- reg = <0x123a0000 0x1000>; ++ reg = <0x00ba0000 0x1000>; + interrupts = ; + power-domains = <&pd_isp>; + clocks = <&isp_clock CLK_ISP_FIMC_LITE1>; +@@ -478,9 +479,9 @@ fimc_lite_1: fimc-lite@123a0000 { + status = "disabled"; + }; + +- fimc_is: fimc-is@12000000 { ++ fimc_is: fimc-is@800000 { + compatible = "samsung,exynos4212-fimc-is"; +- reg = <0x12000000 0x260000>; ++ reg = <0x00800000 0x260000>; + interrupts = , + ; + power-domains = <&pd_isp>; +@@ -525,9 +526,9 @@ pmu@10020000 { + reg = <0x10020000 0x3000>; + }; + +- i2c1_isp: i2c-isp@12140000 { ++ i2c1_isp: i2c-isp@940000 { + compatible = "samsung,exynos4212-i2c-isp"; +- reg = <0x12140000 0x100>; ++ reg = <0x00940000 0x100>; + clocks = <&isp_clock CLK_ISP_I2C1_ISP>; + clock-names = "i2c_isp"; + #address-cells = <1>; +diff --git a/arch/arm/boot/dts/samsung/s5pv210.dtsi b/arch/arm/boot/dts/samsung/s5pv210.dtsi +index f7de5b5f2f3837..ed560c9a3aa1ef 100644 +--- a/arch/arm/boot/dts/samsung/s5pv210.dtsi ++++ b/arch/arm/boot/dts/samsung/s5pv210.dtsi +@@ -549,17 +549,17 @@ i2c1: i2c@fab00000 { + + camera: camera@fa600000 { + compatible = "samsung,fimc"; ++ ranges = <0x0 0xfa600000 0xe01000>; + clocks = <&clocks SCLK_CAM0>, <&clocks SCLK_CAM1>; + clock-names = "sclk_cam0", "sclk_cam1"; + #address-cells = <1>; + #size-cells = <1>; + #clock-cells = <1>; + clock-output-names = "cam_a_clkout", "cam_b_clkout"; +- ranges; + +- csis0: csis@fa600000 { ++ csis0: csis@0 { + compatible = "samsung,s5pv210-csis"; +- reg = <0xfa600000 0x4000>; ++ reg = <0x00000000 0x4000>; + interrupt-parent = <&vic2>; + interrupts = <29>; + clocks = <&clocks CLK_CSIS>, +@@ -572,9 +572,9 @@ csis0: csis@fa600000 { + #size-cells = <0>; + }; + +- fimc0: fimc@fb200000 { ++ fimc0: fimc@c00000 { + compatible = "samsung,s5pv210-fimc"; +- reg = <0xfb200000 0x1000>; ++ reg = <0x00c00000 0x1000>; + interrupts = <5>; + interrupt-parent = <&vic2>; + clocks = <&clocks CLK_FIMC0>, +@@ -586,9 +586,9 @@ fimc0: fimc@fb200000 { + samsung,cam-if; + }; + +- fimc1: fimc@fb300000 { ++ fimc1: fimc@d00000 { + compatible = "samsung,s5pv210-fimc"; +- reg = <0xfb300000 0x1000>; ++ reg = <0x00d00000 0x1000>; + interrupt-parent = <&vic2>; + interrupts = <6>; + clocks = <&clocks CLK_FIMC1>, +@@ -602,9 +602,9 @@ fimc1: fimc@fb300000 { + samsung,lcd-wb; + }; + +- fimc2: fimc@fb400000 { ++ fimc2: fimc@e00000 { + compatible = "samsung,s5pv210-fimc"; +- reg = <0xfb400000 0x1000>; ++ reg = <0x00e00000 0x1000>; + interrupt-parent = <&vic2>; + interrupts = <7>; + clocks = <&clocks CLK_FIMC2>, +diff --git a/arch/arm/boot/dts/st/stm32429i-eval.dts b/arch/arm/boot/dts/st/stm32429i-eval.dts +index 576235ec3c516e..afa417b34b25ff 100644 +--- a/arch/arm/boot/dts/st/stm32429i-eval.dts ++++ b/arch/arm/boot/dts/st/stm32429i-eval.dts +@@ -222,7 +222,6 @@ stmpe1600: stmpe1600@42 { + reg = <0x42>; + interrupts = <8 3>; + interrupt-parent = <&gpioi>; +- interrupt-controller; + wakeup-source; + + stmpegpio: stmpe_gpio { +diff --git a/arch/arm/boot/dts/st/stm32f7-pinctrl.dtsi b/arch/arm/boot/dts/st/stm32f7-pinctrl.dtsi +index 65480a9f5cc4e1..842f2b17c4a81c 100644 +--- a/arch/arm/boot/dts/st/stm32f7-pinctrl.dtsi ++++ b/arch/arm/boot/dts/st/stm32f7-pinctrl.dtsi +@@ -376,7 +376,6 @@ pins2 { + }; + }; + +- + ltdc_pins_a: ltdc-0 { + pins { + pinmux = , /* LCD_B0 */ +diff --git a/arch/arm/boot/dts/st/stm32mp151.dtsi b/arch/arm/boot/dts/st/stm32mp151.dtsi +index 61508917521c36..aec7fa5ab5d8c6 100644 +--- a/arch/arm/boot/dts/st/stm32mp151.dtsi ++++ b/arch/arm/boot/dts/st/stm32mp151.dtsi +@@ -50,6 +50,7 @@ timer { + , + ; + interrupt-parent = <&intc>; ++ arm,no-tick-in-suspend; + }; + + clocks { +diff --git a/arch/arm/boot/dts/st/stm32mp157a-dk1-scmi.dts b/arch/arm/boot/dts/st/stm32mp157a-dk1-scmi.dts +index afcd6285890cc0..c27963898b5e6c 100644 +--- a/arch/arm/boot/dts/st/stm32mp157a-dk1-scmi.dts ++++ b/arch/arm/boot/dts/st/stm32mp157a-dk1-scmi.dts +@@ -11,7 +11,7 @@ + + / { + model = "STMicroelectronics STM32MP157A-DK1 SCMI Discovery Board"; +- compatible = "st,stm32mp157a-dk1-scmi", "st,stm32mp157a-dk1", "st,stm32mp157"; ++ compatible = "st,stm32mp157a-dk1-scmi", "st,stm32mp157"; + + reserved-memory { + optee@de000000 { +diff --git a/arch/arm/boot/dts/st/stm32mp157c-dk2-scmi.dts b/arch/arm/boot/dts/st/stm32mp157c-dk2-scmi.dts +index 39358d90200031..62261894313407 100644 +--- a/arch/arm/boot/dts/st/stm32mp157c-dk2-scmi.dts ++++ b/arch/arm/boot/dts/st/stm32mp157c-dk2-scmi.dts +@@ -11,7 +11,7 @@ + + / { + model = "STMicroelectronics STM32MP157C-DK2 SCMI Discovery Board"; +- compatible = "st,stm32mp157c-dk2-scmi", "st,stm32mp157c-dk2", "st,stm32mp157"; ++ compatible = "st,stm32mp157c-dk2-scmi", "st,stm32mp157"; + + reserved-memory { + optee@de000000 { +diff --git a/arch/arm/boot/dts/st/stm32mp157c-dk2.dts b/arch/arm/boot/dts/st/stm32mp157c-dk2.dts +index 510cca5acb79ca..7a701f7ef0c704 100644 +--- a/arch/arm/boot/dts/st/stm32mp157c-dk2.dts ++++ b/arch/arm/boot/dts/st/stm32mp157c-dk2.dts +@@ -64,7 +64,6 @@ touchscreen@38 { + reg = <0x38>; + interrupts = <2 2>; + interrupt-parent = <&gpiof>; +- interrupt-controller; + touchscreen-size-x = <480>; + touchscreen-size-y = <800>; + status = "okay"; +diff --git a/arch/arm/boot/dts/st/stm32mp157c-ed1-scmi.dts b/arch/arm/boot/dts/st/stm32mp157c-ed1-scmi.dts +index 07ea765a4553a5..c7c4d7e89d6123 100644 +--- a/arch/arm/boot/dts/st/stm32mp157c-ed1-scmi.dts ++++ b/arch/arm/boot/dts/st/stm32mp157c-ed1-scmi.dts +@@ -11,7 +11,7 @@ + + / { + model = "STMicroelectronics STM32MP157C-ED1 SCMI eval daughter"; +- compatible = "st,stm32mp157c-ed1-scmi", "st,stm32mp157c-ed1", "st,stm32mp157"; ++ compatible = "st,stm32mp157c-ed1-scmi", "st,stm32mp157"; + + reserved-memory { + optee@fe000000 { +diff --git a/arch/arm/boot/dts/st/stm32mp157c-ev1-scmi.dts b/arch/arm/boot/dts/st/stm32mp157c-ev1-scmi.dts +index 813086ec248959..2ab77e64f1bbb9 100644 +--- a/arch/arm/boot/dts/st/stm32mp157c-ev1-scmi.dts ++++ b/arch/arm/boot/dts/st/stm32mp157c-ev1-scmi.dts +@@ -11,8 +11,7 @@ + + / { + model = "STMicroelectronics STM32MP157C-EV1 SCMI eval daughter on eval mother"; +- compatible = "st,stm32mp157c-ev1-scmi", "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", +- "st,stm32mp157"; ++ compatible = "st,stm32mp157c-ev1-scmi", "st,stm32mp157c-ed1", "st,stm32mp157"; + + reserved-memory { + optee@fe000000 { +diff --git a/arch/arm/boot/dts/ti/omap/am335x-moxa-uc-2100-common.dtsi b/arch/arm/boot/dts/ti/omap/am335x-moxa-uc-2100-common.dtsi +index b8730aa52ce6fe..a59331aa58e55e 100644 +--- a/arch/arm/boot/dts/ti/omap/am335x-moxa-uc-2100-common.dtsi ++++ b/arch/arm/boot/dts/ti/omap/am335x-moxa-uc-2100-common.dtsi +@@ -217,7 +217,7 @@ &spi1 { + pinctrl-names = "default"; + pinctrl-0 = <&spi1_pins>; + +- tpm_spi_tis@0 { ++ tpm@0 { + compatible = "tcg,tpm_tis-spi"; + reg = <0>; + spi-max-frequency = <500000>; +diff --git a/arch/arm/boot/dts/ti/omap/am33xx.dtsi b/arch/arm/boot/dts/ti/omap/am33xx.dtsi +index 1a2cd5baf40210..5b9e01a8aa5d5a 100644 +--- a/arch/arm/boot/dts/ti/omap/am33xx.dtsi ++++ b/arch/arm/boot/dts/ti/omap/am33xx.dtsi +@@ -359,6 +359,7 @@ usb: target-module@47400000 { + , + , + ; ++ ti,sysc-delay-us = <2>; + clocks = <&l3s_clkctrl AM3_L3S_USB_OTG_HS_CLKCTRL 0>; + clock-names = "fck"; + #address-cells = <1>; +diff --git a/arch/arm/boot/dts/ti/omap/am3517-evm.dts b/arch/arm/boot/dts/ti/omap/am3517-evm.dts +index af9df15274bed1..866f68c5b504dc 100644 +--- a/arch/arm/boot/dts/ti/omap/am3517-evm.dts ++++ b/arch/arm/boot/dts/ti/omap/am3517-evm.dts +@@ -271,13 +271,6 @@ OMAP3_CORE1_IOPAD(0x21c4, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c3_sda */ + >; + }; + +- leds_pins: leds-pins { +- pinctrl-single,pins = < +- OMAP3_WKUP_IOPAD(0x2a24, PIN_OUTPUT_PULLUP | MUX_MODE4) /* jtag_emu0.gpio_11 */ +- OMAP3_WKUP_IOPAD(0x2a26, PIN_OUTPUT_PULLUP | MUX_MODE4) /* jtag_emu1.gpio_31 */ +- >; +- }; +- + mmc1_pins: mmc1-pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x2144, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */ +@@ -355,3 +348,12 @@ OMAP3430_CORE2_IOPAD(0x25e2, PIN_INPUT | MUX_MODE3) /* etk_d3.hsusb1_data7 */ + >; + }; + }; ++ ++&omap3_pmx_wkup { ++ leds_pins: leds-pins { ++ pinctrl-single,pins = < ++ OMAP3_WKUP_IOPAD(0x2a24, PIN_OUTPUT_PULLUP | MUX_MODE4) /* jtag_emu0.gpio_11 */ ++ OMAP3_WKUP_IOPAD(0x2a26, PIN_OUTPUT_PULLUP | MUX_MODE4) /* jtag_emu1.gpio_31 */ ++ >; ++ }; ++}; +diff --git a/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts b/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts +index 9a234dc1431d12..5b240769d300e5 100644 +--- a/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts ++++ b/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts +@@ -415,7 +415,6 @@ stmpe811@41 { + reg = <0x41>; + interrupts = <30 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&gpio2>; +- interrupt-controller; + id = <0>; + blocks = <0x5>; + irq-trigger = <0x1>; +diff --git a/arch/arm/boot/dts/ti/omap/dra7.dtsi b/arch/arm/boot/dts/ti/omap/dra7.dtsi +index 3f3e52e3b37526..6509c742fb58c9 100644 +--- a/arch/arm/boot/dts/ti/omap/dra7.dtsi ++++ b/arch/arm/boot/dts/ti/omap/dra7.dtsi +@@ -147,7 +147,7 @@ ocp: ocp { + + l3-noc@44000000 { + compatible = "ti,dra7-l3-noc"; +- reg = <0x44000000 0x1000>, ++ reg = <0x44000000 0x1000000>, + <0x45000000 0x1000>; + interrupts-extended = <&crossbar_mpu GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, + <&wakeupgen GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>; +diff --git a/arch/arm/boot/dts/ti/omap/omap3-n900.dts b/arch/arm/boot/dts/ti/omap/omap3-n900.dts +index d3348534125173..036e472b77bebb 100644 +--- a/arch/arm/boot/dts/ti/omap/omap3-n900.dts ++++ b/arch/arm/boot/dts/ti/omap/omap3-n900.dts +@@ -781,7 +781,7 @@ accelerometer@1d { + + mount-matrix = "-1", "0", "0", + "0", "1", "0", +- "0", "0", "1"; ++ "0", "0", "-1"; + }; + + cam1: camera@3e { +diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig +index 0a90583f9f017e..8f9dbe8d90291e 100644 +--- a/arch/arm/configs/imx_v6_v7_defconfig ++++ b/arch/arm/configs/imx_v6_v7_defconfig +@@ -297,6 +297,7 @@ CONFIG_FB_MODE_HELPERS=y + CONFIG_LCD_CLASS_DEVICE=y + CONFIG_LCD_L4F00242T03=y + CONFIG_LCD_PLATFORM=y ++CONFIG_BACKLIGHT_CLASS_DEVICE=y + CONFIG_BACKLIGHT_PWM=y + CONFIG_BACKLIGHT_GPIO=y + CONFIG_FRAMEBUFFER_CONSOLE=y +diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig +index bddc82f7894211..a83d29fed17563 100644 +--- a/arch/arm/configs/sunxi_defconfig ++++ b/arch/arm/configs/sunxi_defconfig +@@ -110,6 +110,7 @@ CONFIG_DRM_PANEL_LVDS=y + CONFIG_DRM_PANEL_SIMPLE=y + CONFIG_DRM_PANEL_EDP=y + CONFIG_DRM_SIMPLE_BRIDGE=y ++CONFIG_DRM_DW_HDMI=y + CONFIG_DRM_LIMA=y + CONFIG_FB_SIMPLE=y + CONFIG_BACKLIGHT_CLASS_DEVICE=y +diff --git a/arch/arm/crypto/aes-ce-glue.c b/arch/arm/crypto/aes-ce-glue.c +index b668c97663ec0c..f5b66f4cf45d96 100644 +--- a/arch/arm/crypto/aes-ce-glue.c ++++ b/arch/arm/crypto/aes-ce-glue.c +@@ -711,7 +711,7 @@ static int __init aes_init(void) + algname = aes_algs[i].base.cra_name + 2; + drvname = aes_algs[i].base.cra_driver_name + 2; + basename = aes_algs[i].base.cra_driver_name; +- simd = simd_skcipher_create_compat(algname, drvname, basename); ++ simd = simd_skcipher_create_compat(aes_algs + i, algname, drvname, basename); + err = PTR_ERR(simd); + if (IS_ERR(simd)) + goto unregister_simds; +diff --git a/arch/arm/crypto/aes-neonbs-glue.c b/arch/arm/crypto/aes-neonbs-glue.c +index f00f042ef3570e..0ca94b90bc4ec5 100644 +--- a/arch/arm/crypto/aes-neonbs-glue.c ++++ b/arch/arm/crypto/aes-neonbs-glue.c +@@ -539,7 +539,7 @@ static int __init aes_init(void) + algname = aes_algs[i].base.cra_name + 2; + drvname = aes_algs[i].base.cra_driver_name + 2; + basename = aes_algs[i].base.cra_driver_name; +- simd = simd_skcipher_create_compat(algname, drvname, basename); ++ simd = simd_skcipher_create_compat(aes_algs + i, algname, drvname, basename); + err = PTR_ERR(simd); + if (IS_ERR(simd)) + goto unregister_simds; +diff --git a/arch/arm/crypto/sha256_glue.c b/arch/arm/crypto/sha256_glue.c +index 433ee4ddce6c81..f85933fdec75fd 100644 +--- a/arch/arm/crypto/sha256_glue.c ++++ b/arch/arm/crypto/sha256_glue.c +@@ -24,8 +24,8 @@ + + #include "sha256_glue.h" + +-asmlinkage void sha256_block_data_order(u32 *digest, const void *data, +- unsigned int num_blks); ++asmlinkage void sha256_block_data_order(struct sha256_state *state, ++ const u8 *data, int num_blks); + + int crypto_sha256_arm_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +@@ -33,23 +33,20 @@ int crypto_sha256_arm_update(struct shash_desc *desc, const u8 *data, + /* make sure casting to sha256_block_fn() is safe */ + BUILD_BUG_ON(offsetof(struct sha256_state, state) != 0); + +- return sha256_base_do_update(desc, data, len, +- (sha256_block_fn *)sha256_block_data_order); ++ return sha256_base_do_update(desc, data, len, sha256_block_data_order); + } + EXPORT_SYMBOL(crypto_sha256_arm_update); + + static int crypto_sha256_arm_final(struct shash_desc *desc, u8 *out) + { +- sha256_base_do_finalize(desc, +- (sha256_block_fn *)sha256_block_data_order); ++ sha256_base_do_finalize(desc, sha256_block_data_order); + return sha256_base_finish(desc, out); + } + + int crypto_sha256_arm_finup(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) + { +- sha256_base_do_update(desc, data, len, +- (sha256_block_fn *)sha256_block_data_order); ++ sha256_base_do_update(desc, data, len, sha256_block_data_order); + return crypto_sha256_arm_final(desc, out); + } + EXPORT_SYMBOL(crypto_sha256_arm_finup); +diff --git a/arch/arm/crypto/sha512-glue.c b/arch/arm/crypto/sha512-glue.c +index 0635a65aa488ba..1be5bd498af36f 100644 +--- a/arch/arm/crypto/sha512-glue.c ++++ b/arch/arm/crypto/sha512-glue.c +@@ -25,27 +25,25 @@ MODULE_ALIAS_CRYPTO("sha512"); + MODULE_ALIAS_CRYPTO("sha384-arm"); + MODULE_ALIAS_CRYPTO("sha512-arm"); + +-asmlinkage void sha512_block_data_order(u64 *state, u8 const *src, int blocks); ++asmlinkage void sha512_block_data_order(struct sha512_state *state, ++ u8 const *src, int blocks); + + int sha512_arm_update(struct shash_desc *desc, const u8 *data, + unsigned int len) + { +- return sha512_base_do_update(desc, data, len, +- (sha512_block_fn *)sha512_block_data_order); ++ return sha512_base_do_update(desc, data, len, sha512_block_data_order); + } + + static int sha512_arm_final(struct shash_desc *desc, u8 *out) + { +- sha512_base_do_finalize(desc, +- (sha512_block_fn *)sha512_block_data_order); ++ sha512_base_do_finalize(desc, sha512_block_data_order); + return sha512_base_finish(desc, out); + } + + int sha512_arm_finup(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) + { +- sha512_base_do_update(desc, data, len, +- (sha512_block_fn *)sha512_block_data_order); ++ sha512_base_do_update(desc, data, len, sha512_block_data_order); + return sha512_arm_final(desc, out); + } + +diff --git a/arch/arm/include/asm/arm_pmuv3.h b/arch/arm/include/asm/arm_pmuv3.h +index 72529f5e2bed95..a41b503b7dcde0 100644 +--- a/arch/arm/include/asm/arm_pmuv3.h ++++ b/arch/arm/include/asm/arm_pmuv3.h +@@ -23,6 +23,8 @@ + #define PMUSERENR __ACCESS_CP15(c9, 0, c14, 0) + #define PMINTENSET __ACCESS_CP15(c9, 0, c14, 1) + #define PMINTENCLR __ACCESS_CP15(c9, 0, c14, 2) ++#define PMCEID2 __ACCESS_CP15(c9, 0, c14, 4) ++#define PMCEID3 __ACCESS_CP15(c9, 0, c14, 5) + #define PMMIR __ACCESS_CP15(c9, 0, c14, 6) + #define PMCCFILTR __ACCESS_CP15(c14, 0, c15, 7) + +@@ -150,21 +152,6 @@ static inline u64 read_pmccntr(void) + return read_sysreg(PMCCNTR); + } + +-static inline void write_pmxevcntr(u32 val) +-{ +- write_sysreg(val, PMXEVCNTR); +-} +- +-static inline u32 read_pmxevcntr(void) +-{ +- return read_sysreg(PMXEVCNTR); +-} +- +-static inline void write_pmxevtyper(u32 val) +-{ +- write_sysreg(val, PMXEVTYPER); +-} +- + static inline void write_pmcntenset(u32 val) + { + write_sysreg(val, PMCNTENSET); +@@ -205,16 +192,6 @@ static inline void write_pmuserenr(u32 val) + write_sysreg(val, PMUSERENR); + } + +-static inline u32 read_pmceid0(void) +-{ +- return read_sysreg(PMCEID0); +-} +- +-static inline u32 read_pmceid1(void) +-{ +- return read_sysreg(PMCEID1); +-} +- + static inline void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr) {} + static inline void kvm_clr_pmu_events(u32 clr) {} + static inline bool kvm_pmu_counter_deferred(struct perf_event_attr *attr) +@@ -231,6 +208,7 @@ static inline void kvm_vcpu_pmu_resync_el0(void) {} + + /* PMU Version in DFR Register */ + #define ARMV8_PMU_DFR_VER_NI 0 ++#define ARMV8_PMU_DFR_VER_V3P1 0x4 + #define ARMV8_PMU_DFR_VER_V3P4 0x5 + #define ARMV8_PMU_DFR_VER_V3P5 0x6 + #define ARMV8_PMU_DFR_VER_IMP_DEF 0xF +@@ -251,4 +229,24 @@ static inline bool is_pmuv3p5(int pmuver) + return pmuver >= ARMV8_PMU_DFR_VER_V3P5; + } + ++static inline u64 read_pmceid0(void) ++{ ++ u64 val = read_sysreg(PMCEID0); ++ ++ if (read_pmuver() >= ARMV8_PMU_DFR_VER_V3P1) ++ val |= (u64)read_sysreg(PMCEID2) << 32; ++ ++ return val; ++} ++ ++static inline u64 read_pmceid1(void) ++{ ++ u64 val = read_sysreg(PMCEID1); ++ ++ if (read_pmuver() >= ARMV8_PMU_DFR_VER_V3P1) ++ val |= (u64)read_sysreg(PMCEID3) << 32; ++ ++ return val; ++} ++ + #endif +diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h +index f6181f69577fe5..1075534b0a2eeb 100644 +--- a/arch/arm/include/asm/cacheflush.h ++++ b/arch/arm/include/asm/cacheflush.h +@@ -340,6 +340,8 @@ static inline void flush_cache_vmap(unsigned long start, unsigned long end) + dsb(ishst); + } + ++#define flush_cache_vmap_early(start, end) do { } while (0) ++ + static inline void flush_cache_vunmap(unsigned long start, unsigned long end) + { + if (!cache_is_vipt_nonaliasing()) +diff --git a/arch/arm/include/asm/dma.h b/arch/arm/include/asm/dma.h +index c6aded1b069cf0..e2a1916013e75e 100644 +--- a/arch/arm/include/asm/dma.h ++++ b/arch/arm/include/asm/dma.h +@@ -12,6 +12,9 @@ + extern phys_addr_t arm_dma_zone_size; \ + arm_dma_zone_size && arm_dma_zone_size < (0x100000000ULL - PAGE_OFFSET) ? \ + (PAGE_OFFSET + arm_dma_zone_size) : 0xffffffffUL; }) ++ ++extern phys_addr_t arm_dma_limit; ++#define ARCH_LOW_ADDRESS_LIMIT arm_dma_limit + #endif + + #ifdef CONFIG_ISA_DMA_API +diff --git a/arch/arm/include/asm/exception.h b/arch/arm/include/asm/exception.h +index 58e039a851af03..3c82975d46db35 100644 +--- a/arch/arm/include/asm/exception.h ++++ b/arch/arm/include/asm/exception.h +@@ -10,10 +10,6 @@ + + #include + +-#ifdef CONFIG_FUNCTION_GRAPH_TRACER + #define __exception_irq_entry __irq_entry +-#else +-#define __exception_irq_entry +-#endif + + #endif /* __ASM_ARM_EXCEPTION_H */ +diff --git a/arch/arm/include/asm/irq_work.h b/arch/arm/include/asm/irq_work.h +index 3149e4dc1b5405..8895999834cc0b 100644 +--- a/arch/arm/include/asm/irq_work.h ++++ b/arch/arm/include/asm/irq_work.h +@@ -9,6 +9,4 @@ static inline bool arch_irq_work_has_interrupt(void) + return is_smp(); + } + +-extern void arch_irq_work_raise(void); +- + #endif /* _ASM_ARM_IRQ_WORK_H */ +diff --git a/arch/arm/include/asm/jump_label.h b/arch/arm/include/asm/jump_label.h +index e12d7d096fc034..e4eb54f6cd9fef 100644 +--- a/arch/arm/include/asm/jump_label.h ++++ b/arch/arm/include/asm/jump_label.h +@@ -11,7 +11,7 @@ + + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + WASM(nop) "\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".word 1b, %l[l_yes], %c0\n\t" +@@ -25,7 +25,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran + + static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + WASM(b) " %l[l_yes]\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".word 1b, %l[l_yes], %c0\n\t" +diff --git a/arch/arm/include/asm/kexec.h b/arch/arm/include/asm/kexec.h +index e62832dcba7600..a8287e7ab9d41a 100644 +--- a/arch/arm/include/asm/kexec.h ++++ b/arch/arm/include/asm/kexec.h +@@ -2,8 +2,6 @@ + #ifndef _ARM_KEXEC_H + #define _ARM_KEXEC_H + +-#ifdef CONFIG_KEXEC +- + /* Maximum physical address we can use pages from */ + #define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) + /* Maximum address we can reach in physical address mode */ +@@ -82,6 +80,4 @@ static inline struct page *boot_pfn_to_page(unsigned long boot_pfn) + + #endif /* __ASSEMBLY__ */ + +-#endif /* CONFIG_KEXEC */ +- + #endif /* _ARM_KEXEC_H */ +diff --git a/arch/arm/include/asm/mman.h b/arch/arm/include/asm/mman.h +new file mode 100644 +index 00000000000000..2189e507c8e08b +--- /dev/null ++++ b/arch/arm/include/asm/mman.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __ASM_MMAN_H__ ++#define __ASM_MMAN_H__ ++ ++#include ++#include ++ ++static inline bool arch_memory_deny_write_exec_supported(void) ++{ ++ return cpu_architecture() >= CPU_ARCH_ARMv6; ++} ++#define arch_memory_deny_write_exec_supported arch_memory_deny_write_exec_supported ++ ++#endif /* __ASM_MMAN_H__ */ +diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h +index 16b02f44c7d312..d657b84b6bf706 100644 +--- a/arch/arm/include/asm/pgtable.h ++++ b/arch/arm/include/asm/pgtable.h +@@ -151,6 +151,8 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, + + extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; + ++#define pgdp_get(pgpd) READ_ONCE(*pgdp) ++ + #define pud_page(pud) pmd_page(__pmd(pud_val(pud))) + #define pud_write(pud) pmd_write(__pmd(pud_val(pud))) + +diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h +index bb5c8182311774..c28f5ec21e417b 100644 +--- a/arch/arm/include/asm/uaccess.h ++++ b/arch/arm/include/asm/uaccess.h +@@ -109,16 +109,6 @@ extern int __get_user_64t_1(void *); + extern int __get_user_64t_2(void *); + extern int __get_user_64t_4(void *); + +-#define __GUP_CLOBBER_1 "lr", "cc" +-#ifdef CONFIG_CPU_USE_DOMAINS +-#define __GUP_CLOBBER_2 "ip", "lr", "cc" +-#else +-#define __GUP_CLOBBER_2 "lr", "cc" +-#endif +-#define __GUP_CLOBBER_4 "lr", "cc" +-#define __GUP_CLOBBER_32t_8 "lr", "cc" +-#define __GUP_CLOBBER_8 "lr", "cc" +- + #define __get_user_x(__r2, __p, __e, __l, __s) \ + __asm__ __volatile__ ( \ + __asmeq("%0", "r0") __asmeq("%1", "r2") \ +@@ -126,7 +116,7 @@ extern int __get_user_64t_4(void *); + "bl __get_user_" #__s \ + : "=&r" (__e), "=r" (__r2) \ + : "0" (__p), "r" (__l) \ +- : __GUP_CLOBBER_##__s) ++ : "ip", "lr", "cc") + + /* narrowing a double-word get into a single 32bit word register: */ + #ifdef __ARMEB__ +@@ -148,7 +138,7 @@ extern int __get_user_64t_4(void *); + "bl __get_user_64t_" #__s \ + : "=&r" (__e), "=r" (__r2) \ + : "0" (__p), "r" (__l) \ +- : __GUP_CLOBBER_##__s) ++ : "ip", "lr", "cc") + #else + #define __get_user_x_64t __get_user_x + #endif +diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile +index d53f56d6f84085..ae2f2b2b4e5abc 100644 +--- a/arch/arm/kernel/Makefile ++++ b/arch/arm/kernel/Makefile +@@ -59,7 +59,7 @@ obj-$(CONFIG_FUNCTION_TRACER) += entry-ftrace.o + obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o patch.o + obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o patch.o + obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o +-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o ++obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o relocate_kernel.o + # Main staffs in KPROBES are in arch/arm/probes/ . + obj-$(CONFIG_KPROBES) += patch.o insn.o + obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o +@@ -75,8 +75,6 @@ obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o + obj-$(CONFIG_CPU_XSCALE) += xscale-cp0.o + obj-$(CONFIG_CPU_XSC3) += xscale-cp0.o + obj-$(CONFIG_CPU_MOHAWK) += xscale-cp0.o +-obj-$(CONFIG_CPU_PJ4) += pj4-cp0.o +-obj-$(CONFIG_CPU_PJ4B) += pj4-cp0.o + obj-$(CONFIG_IWMMXT) += iwmmxt.o + obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o + obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_xscale.o perf_event_v6.o \ +diff --git a/arch/arm/kernel/iwmmxt.S b/arch/arm/kernel/iwmmxt.S +index a0218c4867b9b6..4a335d3c59690b 100644 +--- a/arch/arm/kernel/iwmmxt.S ++++ b/arch/arm/kernel/iwmmxt.S +@@ -18,18 +18,6 @@ + #include + #include "iwmmxt.h" + +-#if defined(CONFIG_CPU_PJ4) || defined(CONFIG_CPU_PJ4B) +-#define PJ4(code...) code +-#define XSC(code...) +-#elif defined(CONFIG_CPU_MOHAWK) || \ +- defined(CONFIG_CPU_XSC3) || \ +- defined(CONFIG_CPU_XSCALE) +-#define PJ4(code...) +-#define XSC(code...) code +-#else +-#error "Unsupported iWMMXt architecture" +-#endif +- + #define MMX_WR0 (0x00) + #define MMX_WR1 (0x08) + #define MMX_WR2 (0x10) +@@ -81,17 +69,13 @@ ENDPROC(iwmmxt_undef_handler) + ENTRY(iwmmxt_task_enable) + inc_preempt_count r10, r3 + +- XSC(mrc p15, 0, r2, c15, c1, 0) +- PJ4(mrc p15, 0, r2, c1, c0, 2) ++ mrc p15, 0, r2, c15, c1, 0 + @ CP0 and CP1 accessible? +- XSC(tst r2, #0x3) +- PJ4(tst r2, #0xf) ++ tst r2, #0x3 + bne 4f @ if so no business here + @ enable access to CP0 and CP1 +- XSC(orr r2, r2, #0x3) +- XSC(mcr p15, 0, r2, c15, c1, 0) +- PJ4(orr r2, r2, #0xf) +- PJ4(mcr p15, 0, r2, c1, c0, 2) ++ orr r2, r2, #0x3 ++ mcr p15, 0, r2, c15, c1, 0 + + ldr r3, =concan_owner + ldr r2, [r0, #S_PC] @ current task pc value +@@ -218,12 +202,9 @@ ENTRY(iwmmxt_task_disable) + bne 1f @ no: quit + + @ enable access to CP0 and CP1 +- XSC(mrc p15, 0, r4, c15, c1, 0) +- XSC(orr r4, r4, #0x3) +- XSC(mcr p15, 0, r4, c15, c1, 0) +- PJ4(mrc p15, 0, r4, c1, c0, 2) +- PJ4(orr r4, r4, #0xf) +- PJ4(mcr p15, 0, r4, c1, c0, 2) ++ mrc p15, 0, r4, c15, c1, 0 ++ orr r4, r4, #0x3 ++ mcr p15, 0, r4, c15, c1, 0 + + mov r0, #0 @ nothing to load + str r0, [r3] @ no more current owner +@@ -232,10 +213,8 @@ ENTRY(iwmmxt_task_disable) + bl concan_save + + @ disable access to CP0 and CP1 +- XSC(bic r4, r4, #0x3) +- XSC(mcr p15, 0, r4, c15, c1, 0) +- PJ4(bic r4, r4, #0xf) +- PJ4(mcr p15, 0, r4, c1, c0, 2) ++ bic r4, r4, #0x3 ++ mcr p15, 0, r4, c15, c1, 0 + + mrc p15, 0, r2, c2, c0, 0 + mov r2, r2 @ cpwait +@@ -330,11 +309,9 @@ ENDPROC(iwmmxt_task_restore) + */ + ENTRY(iwmmxt_task_switch) + +- XSC(mrc p15, 0, r1, c15, c1, 0) +- PJ4(mrc p15, 0, r1, c1, c0, 2) ++ mrc p15, 0, r1, c15, c1, 0 + @ CP0 and CP1 accessible? +- XSC(tst r1, #0x3) +- PJ4(tst r1, #0xf) ++ tst r1, #0x3 + bne 1f @ yes: block them for next task + + ldr r2, =concan_owner +@@ -344,10 +321,8 @@ ENTRY(iwmmxt_task_switch) + retne lr @ no: leave Concan disabled + + 1: @ flip Concan access +- XSC(eor r1, r1, #0x3) +- XSC(mcr p15, 0, r1, c15, c1, 0) +- PJ4(eor r1, r1, #0xf) +- PJ4(mcr p15, 0, r1, c1, c0, 2) ++ eor r1, r1, #0x3 ++ mcr p15, 0, r1, c15, c1, 0 + + mrc p15, 0, r1, c2, c0, 0 + sub pc, lr, r1, lsr #32 @ cpwait and return +diff --git a/arch/arm/kernel/perf_callchain.c b/arch/arm/kernel/perf_callchain.c +index 7147edbe56c67c..1d230ac9d0eb5c 100644 +--- a/arch/arm/kernel/perf_callchain.c ++++ b/arch/arm/kernel/perf_callchain.c +@@ -85,8 +85,7 @@ static bool + callchain_trace(void *data, unsigned long pc) + { + struct perf_callchain_entry_ctx *entry = data; +- perf_callchain_store(entry, pc); +- return true; ++ return perf_callchain_store(entry, pc) == 0; + } + + void +diff --git a/arch/arm/kernel/pj4-cp0.c b/arch/arm/kernel/pj4-cp0.c +deleted file mode 100644 +index 4bca8098c4ff55..00000000000000 +--- a/arch/arm/kernel/pj4-cp0.c ++++ /dev/null +@@ -1,135 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0-only +-/* +- * linux/arch/arm/kernel/pj4-cp0.c +- * +- * PJ4 iWMMXt coprocessor context switching and handling +- * +- * Copyright (c) 2010 Marvell International Inc. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t) +-{ +- struct thread_info *thread = t; +- +- switch (cmd) { +- case THREAD_NOTIFY_FLUSH: +- /* +- * flush_thread() zeroes thread->fpstate, so no need +- * to do anything here. +- * +- * FALLTHROUGH: Ensure we don't try to overwrite our newly +- * initialised state information on the first fault. +- */ +- +- case THREAD_NOTIFY_EXIT: +- iwmmxt_task_release(thread); +- break; +- +- case THREAD_NOTIFY_SWITCH: +- iwmmxt_task_switch(thread); +- break; +- } +- +- return NOTIFY_DONE; +-} +- +-static struct notifier_block __maybe_unused iwmmxt_notifier_block = { +- .notifier_call = iwmmxt_do, +-}; +- +- +-static u32 __init pj4_cp_access_read(void) +-{ +- u32 value; +- +- __asm__ __volatile__ ( +- "mrc p15, 0, %0, c1, c0, 2\n\t" +- : "=r" (value)); +- return value; +-} +- +-static void __init pj4_cp_access_write(u32 value) +-{ +- u32 temp; +- +- __asm__ __volatile__ ( +- "mcr p15, 0, %1, c1, c0, 2\n\t" +-#ifdef CONFIG_THUMB2_KERNEL +- "isb\n\t" +-#else +- "mrc p15, 0, %0, c1, c0, 2\n\t" +- "mov %0, %0\n\t" +- "sub pc, pc, #4\n\t" +-#endif +- : "=r" (temp) : "r" (value)); +-} +- +-static int __init pj4_get_iwmmxt_version(void) +-{ +- u32 cp_access, wcid; +- +- cp_access = pj4_cp_access_read(); +- pj4_cp_access_write(cp_access | 0xf); +- +- /* check if coprocessor 0 and 1 are available */ +- if ((pj4_cp_access_read() & 0xf) != 0xf) { +- pj4_cp_access_write(cp_access); +- return -ENODEV; +- } +- +- /* read iWMMXt coprocessor id register p1, c0 */ +- __asm__ __volatile__ ("mrc p1, 0, %0, c0, c0, 0\n" : "=r" (wcid)); +- +- pj4_cp_access_write(cp_access); +- +- /* iWMMXt v1 */ +- if ((wcid & 0xffffff00) == 0x56051000) +- return 1; +- /* iWMMXt v2 */ +- if ((wcid & 0xffffff00) == 0x56052000) +- return 2; +- +- return -EINVAL; +-} +- +-/* +- * Disable CP0/CP1 on boot, and let call_fpe() and the iWMMXt lazy +- * switch code handle iWMMXt context switching. +- */ +-static int __init pj4_cp0_init(void) +-{ +- u32 __maybe_unused cp_access; +- int vers; +- +- if (!cpu_is_pj4()) +- return 0; +- +- vers = pj4_get_iwmmxt_version(); +- if (vers < 0) +- return 0; +- +-#ifndef CONFIG_IWMMXT +- pr_info("PJ4 iWMMXt coprocessor detected, but kernel support is missing.\n"); +-#else +- cp_access = pj4_cp_access_read() & ~0xf; +- pj4_cp_access_write(cp_access); +- +- pr_info("PJ4 iWMMXt v%d coprocessor enabled.\n", vers); +- elf_hwcap |= HWCAP_IWMMXT; +- thread_register_notifier(&iwmmxt_notifier_block); +- register_iwmmxt_undef_handler(); +-#endif +- +- return 0; +-} +- +-late_initcall(pj4_cp0_init); +diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S +index a86a1d4f34618c..93afd1005b43c9 100644 +--- a/arch/arm/kernel/sleep.S ++++ b/arch/arm/kernel/sleep.S +@@ -127,6 +127,10 @@ cpu_resume_after_mmu: + instr_sync + #endif + bl cpu_init @ restore the und/abt/irq banked regs ++#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK) ++ mov r0, sp ++ bl kasan_unpoison_task_stack_below ++#endif + mov r0, #0 @ return zero on success + ldmfd sp!, {r4 - r11, pc} + ENDPROC(cpu_resume_after_mmu) +diff --git a/arch/arm/lib/memset.S b/arch/arm/lib/memset.S +index d71ab61430b261..de75ae4d5ab41c 100644 +--- a/arch/arm/lib/memset.S ++++ b/arch/arm/lib/memset.S +@@ -17,6 +17,7 @@ ENTRY(__memset) + ENTRY(mmioset) + WEAK(memset) + UNWIND( .fnstart ) ++ and r1, r1, #255 @ cast to unsigned char + ands r3, r0, #3 @ 1 unaligned? + mov ip, r0 @ preserve r0 as return value + bne 6f @ 1 +diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig +index 4316e1370627cf..2a8a9fe46586d2 100644 +--- a/arch/arm/mach-davinci/Kconfig ++++ b/arch/arm/mach-davinci/Kconfig +@@ -4,12 +4,14 @@ menuconfig ARCH_DAVINCI + bool "TI DaVinci" + depends on ARCH_MULTI_V5 + depends on CPU_LITTLE_ENDIAN ++ select CPU_ARM926T + select DAVINCI_TIMER + select ZONE_DMA + select PM_GENERIC_DOMAINS if PM + select PM_GENERIC_DOMAINS_OF if PM && OF + select REGMAP_MMIO + select RESET_CONTROLLER ++ select PINCTRL + select PINCTRL_SINGLE + + if ARCH_DAVINCI +diff --git a/arch/arm/mach-davinci/pm.c b/arch/arm/mach-davinci/pm.c +index 8aa39db095d761..2c5155bd376ba8 100644 +--- a/arch/arm/mach-davinci/pm.c ++++ b/arch/arm/mach-davinci/pm.c +@@ -61,7 +61,7 @@ static void davinci_pm_suspend(void) + + /* Configure sleep count in deep sleep register */ + val = __raw_readl(pm_config.deepsleep_reg); +- val &= ~DEEPSLEEP_SLEEPCOUNT_MASK, ++ val &= ~DEEPSLEEP_SLEEPCOUNT_MASK; + val |= pm_config.sleepcount; + __raw_writel(val, pm_config.deepsleep_reg); + +diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c +index 85a496ddc6197e..e9f72a529b5089 100644 +--- a/arch/arm/mach-ep93xx/clock.c ++++ b/arch/arm/mach-ep93xx/clock.c +@@ -359,7 +359,7 @@ static unsigned long ep93xx_div_recalc_rate(struct clk_hw *hw, + u32 val = __raw_readl(psc->reg); + u8 index = (val & psc->mask) >> psc->shift; + +- if (index > psc->num_div) ++ if (index >= psc->num_div) + return 0; + + return DIV_ROUND_UP_ULL(parent_rate, psc->div[index]); +diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c +index 71b1139764204c..8b1ec60a9a467a 100644 +--- a/arch/arm/mach-ep93xx/core.c ++++ b/arch/arm/mach-ep93xx/core.c +@@ -339,6 +339,7 @@ static struct gpiod_lookup_table ep93xx_i2c_gpiod_table = { + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("G", 0, NULL, 1, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), ++ { } + }, + }; + +diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c +index 2157493b78a9bd..df69af9323754f 100644 +--- a/arch/arm/mach-imx/mmdc.c ++++ b/arch/arm/mach-imx/mmdc.c +@@ -501,6 +501,10 @@ static int imx_mmdc_perf_init(struct platform_device *pdev, void __iomem *mmdc_b + + name = devm_kasprintf(&pdev->dev, + GFP_KERNEL, "mmdc%d", ret); ++ if (!name) { ++ ret = -ENOMEM; ++ goto pmu_release_id; ++ } + + pmu_mmdc->mmdc_ipg_clk = mmdc_ipg_clk; + pmu_mmdc->devtype_data = (struct fsl_mmdc_devtype_data *)of_id->data; +@@ -523,9 +527,10 @@ static int imx_mmdc_perf_init(struct platform_device *pdev, void __iomem *mmdc_b + + pmu_register_err: + pr_warn("MMDC Perf PMU failed (%d), disabled\n", ret); +- ida_simple_remove(&mmdc_ida, pmu_mmdc->id); + cpuhp_state_remove_instance_nocalls(cpuhp_mmdc_state, &pmu_mmdc->node); + hrtimer_cancel(&pmu_mmdc->hrtimer); ++pmu_release_id: ++ ida_simple_remove(&mmdc_ida, pmu_mmdc->id); + pmu_free: + kfree(pmu_mmdc); + return ret; +diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c +index 8e3b5068d4ab07..b45a3879eb344c 100644 +--- a/arch/arm/mach-omap2/board-n8x0.c ++++ b/arch/arm/mach-omap2/board-n8x0.c +@@ -79,10 +79,8 @@ static struct musb_hdrc_platform_data tusb_data = { + static struct gpiod_lookup_table tusb_gpio_table = { + .dev_id = "musb-tusb", + .table = { +- GPIO_LOOKUP("gpio-0-15", 0, "enable", +- GPIO_ACTIVE_HIGH), +- GPIO_LOOKUP("gpio-48-63", 10, "int", +- GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("gpio-0-31", 0, "enable", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("gpio-32-63", 26, "int", GPIO_ACTIVE_HIGH), + { } + }, + }; +@@ -140,12 +138,11 @@ static int slot1_cover_open; + static int slot2_cover_open; + static struct device *mmc_device; + +-static struct gpiod_lookup_table nokia8xx_mmc_gpio_table = { ++static struct gpiod_lookup_table nokia800_mmc_gpio_table = { + .dev_id = "mmci-omap.0", + .table = { + /* Slot switch, GPIO 96 */ +- GPIO_LOOKUP("gpio-80-111", 16, +- "switch", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("gpio-96-127", 0, "switch", GPIO_ACTIVE_HIGH), + { } + }, + }; +@@ -153,12 +150,12 @@ static struct gpiod_lookup_table nokia8xx_mmc_gpio_table = { + static struct gpiod_lookup_table nokia810_mmc_gpio_table = { + .dev_id = "mmci-omap.0", + .table = { ++ /* Slot switch, GPIO 96 */ ++ GPIO_LOOKUP("gpio-96-127", 0, "switch", GPIO_ACTIVE_HIGH), + /* Slot index 1, VSD power, GPIO 23 */ +- GPIO_LOOKUP_IDX("gpio-16-31", 7, +- "vsd", 1, GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP_IDX("gpio-0-31", 23, "vsd", 1, GPIO_ACTIVE_HIGH), + /* Slot index 1, VIO power, GPIO 9 */ +- GPIO_LOOKUP_IDX("gpio-0-15", 9, +- "vio", 1, GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP_IDX("gpio-0-31", 9, "vio", 1, GPIO_ACTIVE_HIGH), + { } + }, + }; +@@ -415,8 +412,6 @@ static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC]; + + static void __init n8x0_mmc_init(void) + { +- gpiod_add_lookup_table(&nokia8xx_mmc_gpio_table); +- + if (board_is_n810()) { + mmc1_data.slots[0].name = "external"; + +@@ -429,6 +424,8 @@ static void __init n8x0_mmc_init(void) + mmc1_data.slots[1].name = "internal"; + mmc1_data.slots[1].ban_openended = 1; + gpiod_add_lookup_table(&nokia810_mmc_gpio_table); ++ } else { ++ gpiod_add_lookup_table(&nokia800_mmc_gpio_table); + } + + mmc1_data.nr_slots = 2; +diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c +index 98999aa8cc0c09..7f387706368a68 100644 +--- a/arch/arm/mach-omap2/id.c ++++ b/arch/arm/mach-omap2/id.c +@@ -793,11 +793,16 @@ void __init omap_soc_device_init(void) + + soc_dev_attr->machine = soc_name; + soc_dev_attr->family = omap_get_family(); ++ if (!soc_dev_attr->family) { ++ kfree(soc_dev_attr); ++ return; ++ } + soc_dev_attr->revision = soc_rev; + soc_dev_attr->custom_attr_group = omap_soc_groups[0]; + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { ++ kfree(soc_dev_attr->family); + kfree(soc_dev_attr); + return; + } +diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c +index c1c0121f478d66..b947bacf23a376 100644 +--- a/arch/arm/mach-omap2/pdata-quirks.c ++++ b/arch/arm/mach-omap2/pdata-quirks.c +@@ -275,9 +275,19 @@ static struct platform_device pandora_backlight = { + .id = -1, + }; + ++static struct gpiod_lookup_table pandora_soc_audio_gpios = { ++ .dev_id = "soc-audio", ++ .table = { ++ GPIO_LOOKUP("gpio-112-127", 6, "dac", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("gpio-0-15", 14, "amp", GPIO_ACTIVE_HIGH), ++ { } ++ }, ++}; ++ + static void __init omap3_pandora_legacy_init(void) + { + platform_device_register(&pandora_backlight); ++ gpiod_add_lookup_table(&pandora_soc_audio_gpios); + } + #endif /* CONFIG_ARCH_OMAP3 */ + +diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c +index cc691b199429ca..a42417de53f74d 100644 +--- a/arch/arm/mach-pxa/spitz.c ++++ b/arch/arm/mach-pxa/spitz.c +@@ -520,10 +520,8 @@ static struct gpiod_lookup_table spitz_ads7846_gpio_table = { + static struct gpiod_lookup_table spitz_lcdcon_gpio_table = { + .dev_id = "spi2.1", + .table = { +- GPIO_LOOKUP("gpio-pxa", SPITZ_GPIO_BACKLIGHT_CONT, +- "BL_CONT", GPIO_ACTIVE_LOW), +- GPIO_LOOKUP("gpio-pxa", SPITZ_GPIO_BACKLIGHT_ON, +- "BL_ON", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("sharp-scoop.1", 6, "BL_CONT", GPIO_ACTIVE_LOW), ++ GPIO_LOOKUP("sharp-scoop.1", 7, "BL_ON", GPIO_ACTIVE_HIGH), + { }, + }, + }; +@@ -531,10 +529,8 @@ static struct gpiod_lookup_table spitz_lcdcon_gpio_table = { + static struct gpiod_lookup_table akita_lcdcon_gpio_table = { + .dev_id = "spi2.1", + .table = { +- GPIO_LOOKUP("gpio-pxa", AKITA_GPIO_BACKLIGHT_CONT, +- "BL_CONT", GPIO_ACTIVE_LOW), +- GPIO_LOOKUP("gpio-pxa", AKITA_GPIO_BACKLIGHT_ON, +- "BL_ON", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("i2c-max7310", 3, "BL_ON", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("i2c-max7310", 4, "BL_CONT", GPIO_ACTIVE_LOW), + { }, + }, + }; +@@ -941,12 +937,9 @@ static inline void spitz_i2c_init(void) {} + static struct gpiod_lookup_table spitz_audio_gpio_table = { + .dev_id = "spitz-audio", + .table = { +- GPIO_LOOKUP("sharp-scoop.0", SPITZ_GPIO_MUTE_L - SPITZ_SCP_GPIO_BASE, +- "mute-l", GPIO_ACTIVE_HIGH), +- GPIO_LOOKUP("sharp-scoop.0", SPITZ_GPIO_MUTE_R - SPITZ_SCP_GPIO_BASE, +- "mute-r", GPIO_ACTIVE_HIGH), +- GPIO_LOOKUP("sharp-scoop.1", SPITZ_GPIO_MIC_BIAS - SPITZ_SCP2_GPIO_BASE, +- "mic", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("sharp-scoop.0", 3, "mute-l", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("sharp-scoop.0", 4, "mute-r", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("sharp-scoop.1", 8, "mic", GPIO_ACTIVE_HIGH), + { }, + }, + }; +@@ -954,12 +947,9 @@ static struct gpiod_lookup_table spitz_audio_gpio_table = { + static struct gpiod_lookup_table akita_audio_gpio_table = { + .dev_id = "spitz-audio", + .table = { +- GPIO_LOOKUP("sharp-scoop.0", SPITZ_GPIO_MUTE_L - SPITZ_SCP_GPIO_BASE, +- "mute-l", GPIO_ACTIVE_HIGH), +- GPIO_LOOKUP("sharp-scoop.0", SPITZ_GPIO_MUTE_R - SPITZ_SCP_GPIO_BASE, +- "mute-r", GPIO_ACTIVE_HIGH), +- GPIO_LOOKUP("i2c-max7310", AKITA_GPIO_MIC_BIAS - AKITA_IOEXP_GPIO_BASE, +- "mic", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("sharp-scoop.0", 3, "mute-l", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("sharp-scoop.0", 4, "mute-r", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("i2c-max7310", 2, "mic", GPIO_ACTIVE_HIGH), + { }, + }, + }; +diff --git a/arch/arm/mach-sunxi/mc_smp.c b/arch/arm/mach-sunxi/mc_smp.c +index cb63921232a6f8..277f6aa8e6c25f 100644 +--- a/arch/arm/mach-sunxi/mc_smp.c ++++ b/arch/arm/mach-sunxi/mc_smp.c +@@ -803,16 +803,16 @@ static int __init sunxi_mc_smp_init(void) + for (i = 0; i < ARRAY_SIZE(sunxi_mc_smp_data); i++) { + ret = of_property_match_string(node, "enable-method", + sunxi_mc_smp_data[i].enable_method); +- if (!ret) ++ if (ret >= 0) + break; + } + +- is_a83t = sunxi_mc_smp_data[i].is_a83t; +- + of_node_put(node); +- if (ret) ++ if (ret < 0) + return -ENODEV; + ++ is_a83t = sunxi_mc_smp_data[i].is_a83t; ++ + if (!sunxi_mc_smp_cpu_table_init()) + return -EINVAL; + +diff --git a/arch/arm/mach-versatile/platsmp-realview.c b/arch/arm/mach-versatile/platsmp-realview.c +index 5d363385c80192..059d796b26bc8e 100644 +--- a/arch/arm/mach-versatile/platsmp-realview.c ++++ b/arch/arm/mach-versatile/platsmp-realview.c +@@ -66,6 +66,7 @@ static void __init realview_smp_prepare_cpus(unsigned int max_cpus) + return; + } + map = syscon_node_to_regmap(np); ++ of_node_put(np); + if (IS_ERR(map)) { + pr_err("PLATSMP: No syscon regmap\n"); + return; +diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c +index d19d140a10c7d5..0749cf8a66371b 100644 +--- a/arch/arm/mm/flush.c ++++ b/arch/arm/mm/flush.c +@@ -296,6 +296,9 @@ void __sync_icache_dcache(pte_t pteval) + return; + + folio = page_folio(pfn_to_page(pfn)); ++ if (folio_test_reserved(folio)) ++ return; ++ + if (cache_is_vipt_aliasing()) + mapping = folio_flush_mapping(folio); + else +diff --git a/arch/arm/vdso/Makefile b/arch/arm/vdso/Makefile +index 515ca33b854c1a..d761bd2e2f4072 100644 +--- a/arch/arm/vdso/Makefile ++++ b/arch/arm/vdso/Makefile +@@ -63,28 +63,3 @@ quiet_cmd_vdsold_and_vdso_check = LD $@ + + quiet_cmd_vdsomunge = MUNGE $@ + cmd_vdsomunge = $(objtree)/$(obj)/vdsomunge $< $@ +- +-# +-# Install the unstripped copy of vdso.so.dbg. If our toolchain +-# supports build-id, install .build-id links as well. +-# +-# Cribbed from arch/x86/vdso/Makefile. +-# +-quiet_cmd_vdso_install = INSTALL $< +-define cmd_vdso_install +- cp $< "$(MODLIB)/vdso/vdso.so"; \ +- if readelf -n $< | grep -q 'Build ID'; then \ +- buildid=`readelf -n $< |grep 'Build ID' |sed -e 's/^.*Build ID: \(.*\)$$/\1/'`; \ +- first=`echo $$buildid | cut -b-2`; \ +- last=`echo $$buildid | cut -b3-`; \ +- mkdir -p "$(MODLIB)/vdso/.build-id/$$first"; \ +- ln -sf "../../vdso.so" "$(MODLIB)/vdso/.build-id/$$first/$$last.debug"; \ +- fi +-endef +- +-$(MODLIB)/vdso: FORCE +- @mkdir -p $(MODLIB)/vdso +- +-PHONY += vdso_install +-vdso_install: $(obj)/vdso.so.dbg $(MODLIB)/vdso +- $(call cmd,vdso_install) +diff --git a/arch/arm/vfp/vfpinstr.h b/arch/arm/vfp/vfpinstr.h +index 3c7938fd40aad6..32090b0fb250b8 100644 +--- a/arch/arm/vfp/vfpinstr.h ++++ b/arch/arm/vfp/vfpinstr.h +@@ -64,33 +64,37 @@ + + #ifdef CONFIG_AS_VFP_VMRS_FPINST + +-#define fmrx(_vfp_) ({ \ +- u32 __v; \ +- asm(".fpu vfpv2\n" \ +- "vmrs %0, " #_vfp_ \ +- : "=r" (__v) : : "cc"); \ +- __v; \ +- }) +- +-#define fmxr(_vfp_,_var_) \ +- asm(".fpu vfpv2\n" \ +- "vmsr " #_vfp_ ", %0" \ +- : : "r" (_var_) : "cc") ++#define fmrx(_vfp_) ({ \ ++ u32 __v; \ ++ asm volatile (".fpu vfpv2\n" \ ++ "vmrs %0, " #_vfp_ \ ++ : "=r" (__v) : : "cc"); \ ++ __v; \ ++}) ++ ++#define fmxr(_vfp_, _var_) ({ \ ++ asm volatile (".fpu vfpv2\n" \ ++ "vmsr " #_vfp_ ", %0" \ ++ : : "r" (_var_) : "cc"); \ ++}) + + #else + + #define vfpreg(_vfp_) #_vfp_ + +-#define fmrx(_vfp_) ({ \ +- u32 __v; \ +- asm("mrc p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmrx %0, " #_vfp_ \ +- : "=r" (__v) : : "cc"); \ +- __v; \ +- }) +- +-#define fmxr(_vfp_,_var_) \ +- asm("mcr p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmxr " #_vfp_ ", %0" \ +- : : "r" (_var_) : "cc") ++#define fmrx(_vfp_) ({ \ ++ u32 __v; \ ++ asm volatile ("mrc p10, 7, %0, " vfpreg(_vfp_) "," \ ++ "cr0, 0 @ fmrx %0, " #_vfp_ \ ++ : "=r" (__v) : : "cc"); \ ++ __v; \ ++}) ++ ++#define fmxr(_vfp_, _var_) ({ \ ++ asm volatile ("mcr p10, 7, %0, " vfpreg(_vfp_) "," \ ++ "cr0, 0 @ fmxr " #_vfp_ ", %0" \ ++ : : "r" (_var_) : "cc"); \ ++}) + + #endif + +diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c +index c392e18f1e4317..a395b6c0aae2a9 100644 +--- a/arch/arm/xen/enlighten.c ++++ b/arch/arm/xen/enlighten.c +@@ -164,9 +164,6 @@ static int xen_starting_cpu(unsigned int cpu) + BUG_ON(err); + per_cpu(xen_vcpu, cpu) = vcpup; + +- if (!xen_kernel_unmapped_at_usr()) +- xen_setup_runstate_info(cpu); +- + after_register_vcpu_info: + enable_percpu_irq(xen_events_irq, 0); + return 0; +@@ -487,7 +484,8 @@ static int __init xen_guest_init(void) + * for secondary CPUs as they are brought up. + * For uniformity we use VCPUOP_register_vcpu_info even on cpu0. + */ +- xen_vcpu_info = alloc_percpu(struct vcpu_info); ++ xen_vcpu_info = __alloc_percpu(sizeof(struct vcpu_info), ++ 1 << fls(sizeof(struct vcpu_info) - 1)); + if (xen_vcpu_info == NULL) + return -ENOMEM; + +@@ -523,9 +521,6 @@ static int __init xen_guest_init(void) + return -EINVAL; + } + +- if (!xen_kernel_unmapped_at_usr()) +- xen_time_setup_guest(); +- + if (xen_initial_domain()) + pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier); + +@@ -535,7 +530,13 @@ static int __init xen_guest_init(void) + } + early_initcall(xen_guest_init); + +-static int __init xen_pm_init(void) ++static int xen_starting_runstate_cpu(unsigned int cpu) ++{ ++ xen_setup_runstate_info(cpu); ++ return 0; ++} ++ ++static int __init xen_late_init(void) + { + if (!xen_domain()) + return -ENODEV; +@@ -548,9 +549,16 @@ static int __init xen_pm_init(void) + do_settimeofday64(&ts); + } + +- return 0; ++ if (xen_kernel_unmapped_at_usr()) ++ return 0; ++ ++ xen_time_setup_guest(); ++ ++ return cpuhp_setup_state(CPUHP_AP_ARM_XEN_RUNSTATE_STARTING, ++ "arm/xen_runstate:starting", ++ xen_starting_runstate_cpu, NULL); + } +-late_initcall(xen_pm_init); ++late_initcall(xen_late_init); + + + /* empty stubs */ +diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig +index 78f20e6327120e..eab866d6903347 100644 +--- a/arch/arm64/Kconfig ++++ b/arch/arm64/Kconfig +@@ -191,12 +191,13 @@ config ARM64 + select HAVE_DMA_CONTIGUOUS + select HAVE_DYNAMIC_FTRACE + select HAVE_DYNAMIC_FTRACE_WITH_ARGS \ +- if $(cc-option,-fpatchable-function-entry=2) ++ if (GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS || \ ++ CLANG_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS) + select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS \ + if DYNAMIC_FTRACE_WITH_ARGS && DYNAMIC_FTRACE_WITH_CALL_OPS + select HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS \ + if (DYNAMIC_FTRACE_WITH_ARGS && !CFI_CLANG && \ +- !CC_OPTIMIZE_FOR_SIZE) ++ (CC_IS_CLANG || !CC_OPTIMIZE_FOR_SIZE)) + select FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY \ + if DYNAMIC_FTRACE_WITH_ARGS + select HAVE_SAMPLE_FTRACE_DIRECT +@@ -262,12 +263,10 @@ config CLANG_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS + def_bool CC_IS_CLANG + # https://github.com/ClangBuiltLinux/linux/issues/1507 + depends on AS_IS_GNU || (AS_IS_LLVM && (LD_IS_LLD || LD_VERSION >= 23600)) +- select HAVE_DYNAMIC_FTRACE_WITH_ARGS + + config GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS + def_bool CC_IS_GCC + depends on $(cc-option,-fpatchable-function-entry=2) +- select HAVE_DYNAMIC_FTRACE_WITH_ARGS + + config 64BIT + def_bool y +@@ -420,7 +419,7 @@ config AMPERE_ERRATUM_AC03_CPU_38 + default y + help + This option adds an alternative code sequence to work around Ampere +- erratum AC03_CPU_38 on AmpereOne. ++ errata AC03_CPU_38 and AC04_CPU_10 on AmpereOne. + + The affected design reports FEAT_HAFDBS as not implemented in + ID_AA64MMFR1_EL1.HAFDBS, but (V)TCR_ELx.{HA,HD} are not RES0 +@@ -1037,8 +1036,12 @@ config ARM64_ERRATUM_2645198 + + If unsure, say Y. + ++config ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD ++ bool ++ + config ARM64_ERRATUM_2966298 + bool "Cortex-A520: 2966298: workaround for speculatively executed unprivileged load" ++ select ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD + default y + help + This option adds the workaround for ARM Cortex-A520 erratum 2966298. +@@ -1050,6 +1053,60 @@ config ARM64_ERRATUM_2966298 + + If unsure, say Y. + ++config ARM64_ERRATUM_3117295 ++ bool "Cortex-A510: 3117295: workaround for speculatively executed unprivileged load" ++ select ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD ++ default y ++ help ++ This option adds the workaround for ARM Cortex-A510 erratum 3117295. ++ ++ On an affected Cortex-A510 core, a speculatively executed unprivileged ++ load might leak data from a privileged level via a cache side channel. ++ ++ Work around this problem by executing a TLBI before returning to EL0. ++ ++ If unsure, say Y. ++ ++config ARM64_ERRATUM_3194386 ++ bool "Cortex-*/Neoverse-*: workaround for MSR SSBS not self-synchronizing" ++ default y ++ help ++ This option adds the workaround for the following errata: ++ ++ * ARM Cortex-A76 erratum 3324349 ++ * ARM Cortex-A77 erratum 3324348 ++ * ARM Cortex-A78 erratum 3324344 ++ * ARM Cortex-A78C erratum 3324346 ++ * ARM Cortex-A78C erratum 3324347 ++ * ARM Cortex-A710 erratam 3324338 ++ * ARM Cortex-A715 errartum 3456084 ++ * ARM Cortex-A720 erratum 3456091 ++ * ARM Cortex-A725 erratum 3456106 ++ * ARM Cortex-X1 erratum 3324344 ++ * ARM Cortex-X1C erratum 3324346 ++ * ARM Cortex-X2 erratum 3324338 ++ * ARM Cortex-X3 erratum 3324335 ++ * ARM Cortex-X4 erratum 3194386 ++ * ARM Cortex-X925 erratum 3324334 ++ * ARM Neoverse-N1 erratum 3324349 ++ * ARM Neoverse N2 erratum 3324339 ++ * ARM Neoverse-N3 erratum 3456111 ++ * ARM Neoverse-V1 erratum 3324341 ++ * ARM Neoverse V2 erratum 3324336 ++ * ARM Neoverse-V3 erratum 3312417 ++ ++ On affected cores "MSR SSBS, #0" instructions may not affect ++ subsequent speculative instructions, which may permit unexepected ++ speculative store bypassing. ++ ++ Work around this problem by placing a Speculation Barrier (SB) or ++ Instruction Synchronization Barrier (ISB) after kernel changes to ++ SSBS. The presence of the SSBS special-purpose register is hidden ++ from hwcaps and EL0 reads of ID_AA64PFR1_EL1, such that userspace ++ will use the PR_SPEC_STORE_BYPASS prctl to change SSBS. ++ ++ If unsure, say Y. ++ + config CAVIUM_ERRATUM_22375 + bool "Cavium erratum 22375, 24313" + default y +@@ -1368,6 +1425,8 @@ choice + config CPU_BIG_ENDIAN + bool "Build big-endian kernel" + depends on !LD_IS_LLD || LLD_VERSION >= 130000 ++ # https://github.com/llvm/llvm-project/commit/1379b150991f70a5782e9a143c2ba5308da1161c ++ depends on AS_IS_GNU || AS_VERSION >= 150000 + help + Say Y if you plan on running a kernel with a big-endian userspace. + +diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile +index 2d49aea0ff67a8..9a2d3723cd0fa9 100644 +--- a/arch/arm64/Makefile ++++ b/arch/arm64/Makefile +@@ -158,7 +158,7 @@ endif + + all: $(notdir $(KBUILD_IMAGE)) + +- ++vmlinuz.efi: Image + Image vmlinuz.efi: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + +@@ -169,12 +169,6 @@ install: KBUILD_IMAGE := $(boot)/Image + install zinstall: + $(call cmd,install) + +-PHONY += vdso_install +-vdso_install: +- $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@ +- $(if $(CONFIG_COMPAT_VDSO), \ +- $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 $@) +- + archprepare: + $(Q)$(MAKE) $(build)=arch/arm64/tools kapi + ifeq ($(CONFIG_ARM64_ERRATUM_843419),y) +@@ -205,6 +199,9 @@ ifdef CONFIG_COMPAT_VDSO + endif + endif + ++vdso-install-y += arch/arm64/kernel/vdso/vdso.so.dbg ++vdso-install-$(CONFIG_COMPAT_VDSO) += arch/arm64/kernel/vdso32/vdso.so.dbg:vdso32.so ++ + include $(srctree)/scripts/Makefile.defconf + + PHONY += virtconfig +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +index 9ec49ac2f6fd5d..381d58cea092d9 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +@@ -291,6 +291,8 @@ sw { + }; + + &spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spdif_tx_pin>; + status = "okay"; + }; + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi +index 4903d6358112de..855b7d43bc503a 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi +@@ -166,6 +166,8 @@ &r_ir { + }; + + &spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spdif_tx_pin>; + status = "okay"; + }; + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +index ca1d287a0a01d9..d11e5041bae9a4 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +@@ -406,6 +406,7 @@ spi1_cs_pin: spi1-cs-pin { + function = "spi1"; + }; + ++ /omit-if-no-ref/ + spdif_tx_pin: spdif-tx-pin { + pins = "PH7"; + function = "spdif"; +@@ -655,10 +656,8 @@ spdif: spdif@5093000 { + clocks = <&ccu CLK_BUS_SPDIF>, <&ccu CLK_SPDIF>; + clock-names = "apb", "spdif"; + resets = <&ccu RST_BUS_SPDIF>; +- dmas = <&dma 2>; +- dma-names = "tx"; +- pinctrl-names = "default"; +- pinctrl-0 = <&spdif_tx_pin>; ++ dmas = <&dma 2>, <&dma 2>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero.dtsi +index 15290e6892fca4..fc7315b9440659 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero.dtsi +@@ -68,10 +68,7 @@ &ehci1 { + &emac0 { + pinctrl-names = "default"; + pinctrl-0 = <&ext_rgmii_pins>; +- phy-mode = "rgmii"; + phy-handle = <&ext_rgmii_phy>; +- allwinner,rx-delay-ps = <3100>; +- allwinner,tx-delay-ps = <700>; + status = "okay"; + }; + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero2.dts +index d83852e72f0634..b5d713926a341a 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero2.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero2.dts +@@ -13,6 +13,9 @@ / { + }; + + &emac0 { ++ allwinner,rx-delay-ps = <3100>; ++ allwinner,tx-delay-ps = <700>; ++ phy-mode = "rgmii"; + phy-supply = <®_dcdce>; + }; + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero3.dts b/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero3.dts +index 00fe28caac939a..b3b1b8692125f9 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero3.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero3.dts +@@ -13,6 +13,8 @@ / { + }; + + &emac0 { ++ allwinner,tx-delay-ps = <700>; ++ phy-mode = "rgmii-rxid"; + phy-supply = <®_dldo1>; + }; + +diff --git a/arch/arm64/boot/dts/amazon/alpine-v2.dtsi b/arch/arm64/boot/dts/amazon/alpine-v2.dtsi +index dccbba6e7f98e4..dbf2dce8d1d68a 100644 +--- a/arch/arm64/boot/dts/amazon/alpine-v2.dtsi ++++ b/arch/arm64/boot/dts/amazon/alpine-v2.dtsi +@@ -145,7 +145,6 @@ pci@fbc00000 { + msix: msix@fbe00000 { + compatible = "al,alpine-msix"; + reg = <0x0 0xfbe00000 0x0 0x100000>; +- interrupt-controller; + msi-controller; + al,msi-base-spi = <160>; + al,msi-num-spis = <160>; +diff --git a/arch/arm64/boot/dts/amazon/alpine-v3.dtsi b/arch/arm64/boot/dts/amazon/alpine-v3.dtsi +index 39481d7fd7d4da..3ea178acdddfe2 100644 +--- a/arch/arm64/boot/dts/amazon/alpine-v3.dtsi ++++ b/arch/arm64/boot/dts/amazon/alpine-v3.dtsi +@@ -355,7 +355,6 @@ pcie@fbd00000 { + msix: msix@fbe00000 { + compatible = "al,alpine-msix"; + reg = <0x0 0xfbe00000 0x0 0x100000>; +- interrupt-controller; + msi-controller; + al,msi-base-spi = <336>; + al,msi-num-spis = <959>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index ff68b911b72971..0ff0d090548d0e 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -215,6 +215,11 @@ hdmi_tx: hdmi-tx@0 { + #sound-dai-cells = <0>; + status = "disabled"; + ++ assigned-clocks = <&clkc CLKID_HDMI_SEL>, ++ <&clkc CLKID_HDMI>; ++ assigned-clock-parents = <&xtal>, <0>; ++ assigned-clock-rates = <0>, <24000000>; ++ + /* VPU VENC Input */ + hdmi_tx_venc_port: port@0 { + reg = <0>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12.dtsi +index 6a1f4dcf64885f..7b655e07e80cf6 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12.dtsi +@@ -367,6 +367,10 @@ ðmac { + power-domains = <&pwrc PWRC_G12A_ETH_ID>; + }; + ++&hdmi_tx { ++ power-domains = <&pwrc PWRC_G12A_VPU_ID>; ++}; ++ + &vpu { + power-domains = <&pwrc PWRC_G12A_VPU_ID>; + }; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +index 12ef6e81c8bd63..ed00e67e6923a0 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +@@ -311,10 +311,16 @@ &hdmi_tx { + <&reset RESET_HDMI_SYSTEM_RESET>, + <&reset RESET_HDMI_TX>; + reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy"; +- clocks = <&clkc CLKID_HDMI_PCLK>, +- <&clkc CLKID_CLK81>, ++ clocks = <&clkc CLKID_HDMI>, ++ <&clkc CLKID_HDMI_PCLK>, + <&clkc CLKID_GCLK_VENCI_INT0>; + clock-names = "isfr", "iahb", "venci"; ++ power-domains = <&pwrc PWRC_GXBB_VPU_ID>; ++ ++ assigned-clocks = <&clkc CLKID_HDMI_SEL>, ++ <&clkc CLKID_HDMI>; ++ assigned-clock-parents = <&xtal>, <0>; ++ assigned-clock-rates = <0>, <24000000>; + }; + + &sysctrl { +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +index 17bcfa4702e170..f58d1790de1cb4 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +@@ -323,10 +323,16 @@ &hdmi_tx { + <&reset RESET_HDMI_SYSTEM_RESET>, + <&reset RESET_HDMI_TX>; + reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy"; +- clocks = <&clkc CLKID_HDMI_PCLK>, +- <&clkc CLKID_CLK81>, ++ clocks = <&clkc CLKID_HDMI>, ++ <&clkc CLKID_HDMI_PCLK>, + <&clkc CLKID_GCLK_VENCI_INT0>; + clock-names = "isfr", "iahb", "venci"; ++ power-domains = <&pwrc PWRC_GXBB_VPU_ID>; ++ ++ assigned-clocks = <&clkc CLKID_HDMI_SEL>, ++ <&clkc CLKID_HDMI>; ++ assigned-clock-parents = <&xtal>, <0>; ++ assigned-clock-rates = <0>, <24000000>; + }; + + &sysctrl { +diff --git a/arch/arm64/boot/dts/amlogic/meson-s4-s805x2-aq222.dts b/arch/arm64/boot/dts/amlogic/meson-s4-s805x2-aq222.dts +index 8ffbcb2b1ac594..bbd3c05cbd9089 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-s4-s805x2-aq222.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-s4-s805x2-aq222.dts +@@ -15,7 +15,7 @@ / { + #size-cells = <2>; + + aliases { +- serial0 = &uart_B; ++ serial0 = &uart_b; + }; + + memory@0 { +@@ -25,6 +25,6 @@ memory@0 { + + }; + +-&uart_B { ++&uart_b { + status = "okay"; + }; +diff --git a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +index f24460186d3d82..a781eabe21f04a 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +@@ -61,10 +61,15 @@ xtal: xtal-clk { + #clock-cells = <0>; + }; + +- pwrc: power-controller { +- compatible = "amlogic,meson-s4-pwrc"; +- #power-domain-cells = <1>; +- status = "okay"; ++ firmware { ++ sm: secure-monitor { ++ compatible = "amlogic,meson-gxbb-sm"; ++ ++ pwrc: power-controller { ++ compatible = "amlogic,meson-s4-pwrc"; ++ #power-domain-cells = <1>; ++ }; ++ }; + }; + + soc { +@@ -118,14 +123,14 @@ gpio_intc: interrupt-controller@4080 { + <10 11 12 13 14 15 16 17 18 19 20 21>; + }; + +- uart_B: serial@7a000 { ++ uart_b: serial@7a000 { + compatible = "amlogic,meson-s4-uart", + "amlogic,meson-ao-uart"; + reg = <0x0 0x7a000 0x0 0x18>; + interrupts = ; +- status = "disabled"; + clocks = <&xtal>, <&xtal>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; ++ status = "disabled"; + }; + + reset: reset-controller@2000 { +diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi b/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi +index 643f94d9d08e10..13e742ba00bea0 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi +@@ -339,7 +339,7 @@ tdmin_lb: audio-controller@3c0 { + }; + + spdifin: audio-controller@400 { +- compatible = "amlogic,g12a-spdifin", ++ compatible = "amlogic,sm1-spdifin", + "amlogic,axg-spdifin"; + reg = <0x0 0x400 0x0 0x30>; + #sound-dai-cells = <0>; +@@ -353,7 +353,7 @@ spdifin: audio-controller@400 { + }; + + spdifout_a: audio-controller@480 { +- compatible = "amlogic,g12a-spdifout", ++ compatible = "amlogic,sm1-spdifout", + "amlogic,axg-spdifout"; + reg = <0x0 0x480 0x0 0x50>; + #sound-dai-cells = <0>; +@@ -518,6 +518,10 @@ &gpio_intc { + "amlogic,meson-gpio-intc"; + }; + ++&hdmi_tx { ++ power-domains = <&pwrc PWRC_SM1_VPU_ID>; ++}; ++ + &pcie { + power-domains = <&pwrc PWRC_SM1_PCIE_ID>; + }; +diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm4908.dtsi b/arch/arm64/boot/dts/broadcom/bcmbca/bcm4908.dtsi +index 2f124b027bbf0a..aadfa0ae052526 100644 +--- a/arch/arm64/boot/dts/broadcom/bcmbca/bcm4908.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcmbca/bcm4908.dtsi +@@ -227,9 +227,6 @@ ethernet-switch@0 { + brcm,num-gphy = <5>; + brcm,num-rgmii-ports = <2>; + +- #address-cells = <1>; +- #size-cells = <0>; +- + ports: ports { + #address-cells = <1>; + #size-cells = <0>; +diff --git a/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi b/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi +index 9dcd25ec2c0418..896d1f33b5b617 100644 +--- a/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi ++++ b/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi +@@ -586,6 +586,7 @@ gpio_g: gpio@660a0000 { + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; ++ #interrupt-cells = <2>; + interrupts = ; + }; + +diff --git a/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi b/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi +index f049687d6b96d2..d8516ec0dae745 100644 +--- a/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi ++++ b/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi +@@ -450,6 +450,7 @@ gpio_hsls: gpio@d0000 { + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; ++ #interrupt-cells = <2>; + interrupts = ; + gpio-ranges = <&pinmux 0 0 16>, + <&pinmux 16 71 2>, +diff --git a/arch/arm64/boot/dts/exynos/exynos7885-jackpotlte.dts b/arch/arm64/boot/dts/exynos/exynos7885-jackpotlte.dts +index 47a389d9ff7d71..9d74fa6bfed9fb 100644 +--- a/arch/arm64/boot/dts/exynos/exynos7885-jackpotlte.dts ++++ b/arch/arm64/boot/dts/exynos/exynos7885-jackpotlte.dts +@@ -32,7 +32,7 @@ memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x3da00000>, + <0x0 0xc0000000 0x40000000>, +- <0x8 0x80000000 0x40000000>; ++ <0x8 0x80000000 0x80000000>; + }; + + gpio-keys { +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi +index d2f5345d056007..717288bbdb8b63 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi +@@ -1186,26 +1186,34 @@ sata1: sata@3210000 { + dma-coherent; + }; + +- usb0: usb@3100000 { +- status = "disabled"; +- compatible = "snps,dwc3"; +- reg = <0x0 0x3100000 0x0 0x10000>; +- interrupts = <0 80 0x4>; /* Level high type */ +- dr_mode = "host"; +- snps,quirk-frame-length-adjustment = <0x20>; +- snps,dis_rxdet_inp3_quirk; +- snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>; +- }; ++ bus: bus { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ compatible = "simple-bus"; ++ ranges; ++ dma-ranges = <0x0 0x0 0x0 0x0 0x100 0x00000000>; ++ ++ usb0: usb@3100000 { ++ compatible = "snps,dwc3"; ++ reg = <0x0 0x3100000 0x0 0x10000>; ++ interrupts = <0 80 0x4>; /* Level high type */ ++ dr_mode = "host"; ++ snps,quirk-frame-length-adjustment = <0x20>; ++ snps,dis_rxdet_inp3_quirk; ++ snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>; ++ status = "disabled"; ++ }; + +- usb1: usb@3110000 { +- status = "disabled"; +- compatible = "snps,dwc3"; +- reg = <0x0 0x3110000 0x0 0x10000>; +- interrupts = <0 81 0x4>; /* Level high type */ +- dr_mode = "host"; +- snps,quirk-frame-length-adjustment = <0x20>; +- snps,dis_rxdet_inp3_quirk; +- snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>; ++ usb1: usb@3110000 { ++ compatible = "snps,dwc3"; ++ reg = <0x0 0x3110000 0x0 0x10000>; ++ interrupts = <0 81 0x4>; /* Level high type */ ++ dr_mode = "host"; ++ snps,quirk-frame-length-adjustment = <0x20>; ++ snps,dis_rxdet_inp3_quirk; ++ snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>; ++ status = "disabled"; ++ }; + }; + + ccn@4000000 { +diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-v1.1.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-v1.1.dtsi +index 9b1b522517f8ef..0878a15acc1ba5 100644 +--- a/arch/arm64/boot/dts/freescale/imx8-apalis-v1.1.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8-apalis-v1.1.dtsi +@@ -82,12 +82,9 @@ reg_module_wifi: regulator-module-wifi { + pinctrl-0 = <&pinctrl_wifi_pdn>; + gpio = <&lsio_gpio1 28 GPIO_ACTIVE_HIGH>; + enable-active-high; ++ regulator-always-on; + regulator-name = "wifi_pwrdn_fake_regulator"; + regulator-settling-time-us = <100>; +- +- regulator-state-mem { +- regulator-off-in-suspend; +- }; + }; + + reg_pcie_switch: regulator-pcie-switch { +diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi +index fc1a5d34382b7e..49298cd9eb0da0 100644 +--- a/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi +@@ -41,7 +41,7 @@ usbotg1: usb@5b0d0000 { + interrupts = ; + fsl,usbphy = <&usbphy1>; + fsl,usbmisc = <&usbmisc1 0>; +- clocks = <&usb2_lpcg 0>; ++ clocks = <&usb2_lpcg IMX_LPCG_CLK_6>; + ahb-burst-config = <0x0>; + tx-burst-size-dword = <0x10>; + rx-burst-size-dword = <0x10>; +@@ -58,7 +58,7 @@ usbmisc1: usbmisc@5b0d0200 { + usbphy1: usbphy@5b100000 { + compatible = "fsl,imx7ulp-usbphy"; + reg = <0x5b100000 0x1000>; +- clocks = <&usb2_lpcg 1>; ++ clocks = <&usb2_lpcg IMX_LPCG_CLK_7>; + power-domains = <&pd IMX_SC_R_USB_0_PHY>; + status = "disabled"; + }; +@@ -67,8 +67,8 @@ usdhc1: mmc@5b010000 { + interrupts = ; + reg = <0x5b010000 0x10000>; + clocks = <&sdhc0_lpcg IMX_LPCG_CLK_4>, +- <&sdhc0_lpcg IMX_LPCG_CLK_0>, +- <&sdhc0_lpcg IMX_LPCG_CLK_5>; ++ <&sdhc0_lpcg IMX_LPCG_CLK_5>, ++ <&sdhc0_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "ahb", "per"; + power-domains = <&pd IMX_SC_R_SDHC_0>; + status = "disabled"; +@@ -78,8 +78,8 @@ usdhc2: mmc@5b020000 { + interrupts = ; + reg = <0x5b020000 0x10000>; + clocks = <&sdhc1_lpcg IMX_LPCG_CLK_4>, +- <&sdhc1_lpcg IMX_LPCG_CLK_0>, +- <&sdhc1_lpcg IMX_LPCG_CLK_5>; ++ <&sdhc1_lpcg IMX_LPCG_CLK_5>, ++ <&sdhc1_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "ahb", "per"; + power-domains = <&pd IMX_SC_R_SDHC_1>; + fsl,tuning-start-tap = <20>; +@@ -91,8 +91,8 @@ usdhc3: mmc@5b030000 { + interrupts = ; + reg = <0x5b030000 0x10000>; + clocks = <&sdhc2_lpcg IMX_LPCG_CLK_4>, +- <&sdhc2_lpcg IMX_LPCG_CLK_0>, +- <&sdhc2_lpcg IMX_LPCG_CLK_5>; ++ <&sdhc2_lpcg IMX_LPCG_CLK_5>, ++ <&sdhc2_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "ahb", "per"; + power-domains = <&pd IMX_SC_R_SDHC_2>; + status = "disabled"; +diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi +index adb98a72bdfd91..89857e14c46140 100644 +--- a/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi +@@ -27,8 +27,8 @@ lpspi0: spi@5a000000 { + #size-cells = <0>; + interrupts = ; + interrupt-parent = <&gic>; +- clocks = <&spi0_lpcg 0>, +- <&spi0_lpcg 1>; ++ clocks = <&spi0_lpcg IMX_LPCG_CLK_0>, ++ <&spi0_lpcg IMX_LPCG_CLK_4>; + clock-names = "per", "ipg"; + assigned-clocks = <&clk IMX_SC_R_SPI_0 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <60000000>; +@@ -43,8 +43,8 @@ lpspi1: spi@5a010000 { + #size-cells = <0>; + interrupts = ; + interrupt-parent = <&gic>; +- clocks = <&spi1_lpcg 0>, +- <&spi1_lpcg 1>; ++ clocks = <&spi1_lpcg IMX_LPCG_CLK_0>, ++ <&spi1_lpcg IMX_LPCG_CLK_4>; + clock-names = "per", "ipg"; + assigned-clocks = <&clk IMX_SC_R_SPI_1 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <60000000>; +@@ -59,8 +59,8 @@ lpspi2: spi@5a020000 { + #size-cells = <0>; + interrupts = ; + interrupt-parent = <&gic>; +- clocks = <&spi2_lpcg 0>, +- <&spi2_lpcg 1>; ++ clocks = <&spi2_lpcg IMX_LPCG_CLK_0>, ++ <&spi2_lpcg IMX_LPCG_CLK_4>; + clock-names = "per", "ipg"; + assigned-clocks = <&clk IMX_SC_R_SPI_2 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <60000000>; +@@ -75,8 +75,8 @@ lpspi3: spi@5a030000 { + #size-cells = <0>; + interrupts = ; + interrupt-parent = <&gic>; +- clocks = <&spi3_lpcg 0>, +- <&spi3_lpcg 1>; ++ clocks = <&spi3_lpcg IMX_LPCG_CLK_0>, ++ <&spi3_lpcg IMX_LPCG_CLK_4>; + clock-names = "per", "ipg"; + assigned-clocks = <&clk IMX_SC_R_SPI_3 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <60000000>; +@@ -282,8 +282,8 @@ adc0: adc@5a880000 { + reg = <0x5a880000 0x10000>; + interrupts = ; + interrupt-parent = <&gic>; +- clocks = <&adc0_lpcg 0>, +- <&adc0_lpcg 1>; ++ clocks = <&adc0_lpcg IMX_LPCG_CLK_0>, ++ <&adc0_lpcg IMX_LPCG_CLK_4>; + clock-names = "per", "ipg"; + assigned-clocks = <&clk IMX_SC_R_ADC_0 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <24000000>; +@@ -297,8 +297,8 @@ adc1: adc@5a890000 { + reg = <0x5a890000 0x10000>; + interrupts = ; + interrupt-parent = <&gic>; +- clocks = <&adc1_lpcg 0>, +- <&adc1_lpcg 1>; ++ clocks = <&adc1_lpcg IMX_LPCG_CLK_0>, ++ <&adc1_lpcg IMX_LPCG_CLK_4>; + clock-names = "per", "ipg"; + assigned-clocks = <&clk IMX_SC_R_ADC_1 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <24000000>; +@@ -311,8 +311,8 @@ flexcan1: can@5a8d0000 { + reg = <0x5a8d0000 0x10000>; + interrupts = ; + interrupt-parent = <&gic>; +- clocks = <&can0_lpcg 1>, +- <&can0_lpcg 0>; ++ clocks = <&can0_lpcg IMX_LPCG_CLK_4>, ++ <&can0_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "per"; + assigned-clocks = <&clk IMX_SC_R_CAN_0 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <40000000>; +@@ -332,8 +332,8 @@ flexcan2: can@5a8e0000 { + * CAN1 shares CAN0's clock and to enable CAN0's clock it + * has to be powered on. + */ +- clocks = <&can0_lpcg 1>, +- <&can0_lpcg 0>; ++ clocks = <&can0_lpcg IMX_LPCG_CLK_4>, ++ <&can0_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "per"; + assigned-clocks = <&clk IMX_SC_R_CAN_0 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <40000000>; +@@ -353,8 +353,8 @@ flexcan3: can@5a8f0000 { + * CAN2 shares CAN0's clock and to enable CAN0's clock it + * has to be powered on. + */ +- clocks = <&can0_lpcg 1>, +- <&can0_lpcg 0>; ++ clocks = <&can0_lpcg IMX_LPCG_CLK_4>, ++ <&can0_lpcg IMX_LPCG_CLK_0>; + clock-names = "ipg", "per"; + assigned-clocks = <&clk IMX_SC_R_CAN_0 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <40000000>; +diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-lsio.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-lsio.dtsi +index ea8c93757521b3..c66449798efce1 100644 +--- a/arch/arm64/boot/dts/freescale/imx8-ss-lsio.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8-ss-lsio.dtsi +@@ -32,11 +32,12 @@ lsio_pwm0: pwm@5d000000 { + compatible = "fsl,imx27-pwm"; + reg = <0x5d000000 0x10000>; + clock-names = "ipg", "per"; +- clocks = <&pwm0_lpcg 4>, +- <&pwm0_lpcg 1>; ++ clocks = <&pwm0_lpcg IMX_LPCG_CLK_6>, ++ <&pwm0_lpcg IMX_LPCG_CLK_1>; + assigned-clocks = <&clk IMX_SC_R_PWM_0 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <24000000>; +- #pwm-cells = <2>; ++ #pwm-cells = <3>; ++ interrupts = ; + status = "disabled"; + }; + +@@ -44,11 +45,12 @@ lsio_pwm1: pwm@5d010000 { + compatible = "fsl,imx27-pwm"; + reg = <0x5d010000 0x10000>; + clock-names = "ipg", "per"; +- clocks = <&pwm1_lpcg 4>, +- <&pwm1_lpcg 1>; ++ clocks = <&pwm1_lpcg IMX_LPCG_CLK_6>, ++ <&pwm1_lpcg IMX_LPCG_CLK_1>; + assigned-clocks = <&clk IMX_SC_R_PWM_1 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <24000000>; +- #pwm-cells = <2>; ++ #pwm-cells = <3>; ++ interrupts = ; + status = "disabled"; + }; + +@@ -56,11 +58,12 @@ lsio_pwm2: pwm@5d020000 { + compatible = "fsl,imx27-pwm"; + reg = <0x5d020000 0x10000>; + clock-names = "ipg", "per"; +- clocks = <&pwm2_lpcg 4>, +- <&pwm2_lpcg 1>; ++ clocks = <&pwm2_lpcg IMX_LPCG_CLK_6>, ++ <&pwm2_lpcg IMX_LPCG_CLK_1>; + assigned-clocks = <&clk IMX_SC_R_PWM_2 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <24000000>; +- #pwm-cells = <2>; ++ #pwm-cells = <3>; ++ interrupts = ; + status = "disabled"; + }; + +@@ -68,11 +71,12 @@ lsio_pwm3: pwm@5d030000 { + compatible = "fsl,imx27-pwm"; + reg = <0x5d030000 0x10000>; + clock-names = "ipg", "per"; +- clocks = <&pwm3_lpcg 4>, +- <&pwm3_lpcg 1>; ++ clocks = <&pwm3_lpcg IMX_LPCG_CLK_6>, ++ <&pwm3_lpcg IMX_LPCG_CLK_1>; + assigned-clocks = <&clk IMX_SC_R_PWM_3 IMX_SC_PM_CLK_PER>; + assigned-clock-rates = <24000000>; +- #pwm-cells = <2>; ++ #pwm-cells = <3>; ++ interrupts = ; + status = "disabled"; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl-osm-s.dts b/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl-osm-s.dts +index 8b16bd68576c0b..d9fa0deea7002e 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl-osm-s.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl-osm-s.dts +@@ -294,8 +294,8 @@ MX8MM_IOMUXC_SAI3_MCLK_GPIO5_IO2 0x19 + + pinctrl_i2c4: i2c4grp { + fsl,pins = < +- MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x400001c3 +- MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA 0x400001c3 ++ MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x40000083 ++ MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA 0x40000083 + >; + }; + +@@ -313,19 +313,19 @@ MX8MM_IOMUXC_SAI5_MCLK_GPIO3_IO25 0x19 + + pinctrl_uart1: uart1grp { + fsl,pins = < +- MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX 0x140 +- MX8MM_IOMUXC_SAI2_RXFS_UART1_DCE_TX 0x140 +- MX8MM_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B 0x140 +- MX8MM_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B 0x140 ++ MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX 0x0 ++ MX8MM_IOMUXC_SAI2_RXFS_UART1_DCE_TX 0x0 ++ MX8MM_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B 0x0 ++ MX8MM_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B 0x0 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < +- MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX 0x140 +- MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX 0x140 +- MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B 0x140 +- MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B 0x140 ++ MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX 0x0 ++ MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX 0x0 ++ MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B 0x0 ++ MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B 0x0 + >; + }; + +@@ -337,40 +337,40 @@ MX8MM_IOMUXC_NAND_CE1_B_GPIO3_IO2 0x19 + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < +- MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x190 ++ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x90 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d0 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d0 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d0 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d0 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d0 +- MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x019 +- MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 ++ MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x19 ++ MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xd0 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + fsl,pins = < +- MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x194 ++ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x94 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d4 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d4 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d4 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d4 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d4 +- MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x019 +- MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 ++ MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x19 ++ MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xd0 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + fsl,pins = < +- MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x196 ++ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x96 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d6 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d6 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d6 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d6 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d6 +- MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x019 +- MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 ++ MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x19 ++ MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xd0 + >; + }; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl.dts b/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl.dts +index dcec57c20399ed..aab8e24216501e 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl.dts +@@ -279,8 +279,8 @@ MX8MM_IOMUXC_SAI3_MCLK_GPIO5_IO2 0x19 + + pinctrl_i2c4: i2c4grp { + fsl,pins = < +- MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x400001c3 +- MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA 0x400001c3 ++ MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x40000083 ++ MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA 0x40000083 + >; + }; + +@@ -292,19 +292,19 @@ MX8MM_IOMUXC_SPDIF_RX_PWM2_OUT 0x19 + + pinctrl_uart1: uart1grp { + fsl,pins = < +- MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX 0x140 +- MX8MM_IOMUXC_SAI2_RXFS_UART1_DCE_TX 0x140 +- MX8MM_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B 0x140 +- MX8MM_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B 0x140 ++ MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX 0x0 ++ MX8MM_IOMUXC_SAI2_RXFS_UART1_DCE_TX 0x0 ++ MX8MM_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B 0x0 ++ MX8MM_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B 0x0 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < +- MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX 0x140 +- MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX 0x140 +- MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B 0x140 +- MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B 0x140 ++ MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX 0x0 ++ MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX 0x0 ++ MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B 0x0 ++ MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B 0x0 + >; + }; + +@@ -316,40 +316,40 @@ MX8MM_IOMUXC_NAND_CE1_B_GPIO3_IO2 0x19 + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < +- MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x190 ++ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x90 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d0 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d0 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d0 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d0 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d0 +- MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x019 +- MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 ++ MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x19 ++ MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xd0 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + fsl,pins = < +- MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x194 ++ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x94 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d4 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d4 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d4 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d4 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d4 +- MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x019 +- MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 ++ MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x19 ++ MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xd0 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + fsl,pins = < +- MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x196 ++ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x96 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d6 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d6 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d6 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d6 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d6 +- MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x019 +- MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 ++ MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x19 ++ MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xd0 + >; + }; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-kontron-osm-s.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-kontron-osm-s.dtsi +index 6e75ab879bf59c..60abcb636cedf3 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-kontron-osm-s.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-kontron-osm-s.dtsi +@@ -210,7 +210,7 @@ rv3028: rtc@52 { + reg = <0x52>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rtc>; +- interrupts-extended = <&gpio4 1 IRQ_TYPE_LEVEL_HIGH>; ++ interrupts-extended = <&gpio4 1 IRQ_TYPE_LEVEL_LOW>; + trickle-diode-disable; + }; + }; +@@ -252,8 +252,8 @@ MX8MM_IOMUXC_ECSPI1_SS0_GPIO5_IO9 0x19 + + pinctrl_i2c1: i2c1grp { + fsl,pins = < +- MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL 0x400001c3 +- MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x400001c3 ++ MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL 0x40000083 ++ MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x40000083 + >; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-kontron-sl.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-kontron-sl.dtsi +index 1f8326613ee9e3..2076148e08627a 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-kontron-sl.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-kontron-sl.dtsi +@@ -237,8 +237,8 @@ MX8MM_IOMUXC_ECSPI1_SS0_GPIO5_IO9 0x19 + + pinctrl_i2c1: i2c1grp { + fsl,pins = < +- MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL 0x400001c3 +- MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x400001c3 ++ MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL 0x40000083 ++ MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x40000083 + >; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi +index 0ce60ad9c7d50f..26d4afdbca6f40 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi +@@ -47,17 +47,6 @@ pps { + gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; +- +- reg_usb_otg1_vbus: regulator-usb-otg1 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_reg_usb1_en>; +- compatible = "regulator-fixed"; +- regulator-name = "usb_otg1_vbus"; +- gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>; +- enable-active-high; +- regulator-min-microvolt = <5000000>; +- regulator-max-microvolt = <5000000>; +- }; + }; + + /* off-board header */ +@@ -145,9 +134,10 @@ &uart3 { + }; + + &usbotg1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg1>; + dr_mode = "otg"; + over-current-active-low; +- vbus-supply = <®_usb_otg1_vbus>; + status = "okay"; + }; + +@@ -205,14 +195,6 @@ MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15 0x41 + >; + }; + +- pinctrl_reg_usb1_en: regusb1grp { +- fsl,pins = < +- MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x41 +- MX8MM_IOMUXC_GPIO1_IO12_GPIO1_IO12 0x141 +- MX8MM_IOMUXC_GPIO1_IO13_USB1_OTG_OC 0x41 +- >; +- }; +- + pinctrl_spi2: spi2grp { + fsl,pins = < + MX8MM_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK 0xd6 +@@ -235,4 +217,11 @@ MX8MM_IOMUXC_UART3_RXD_UART3_DCE_RX 0x140 + MX8MM_IOMUXC_UART3_TXD_UART3_DCE_TX 0x140 + >; + }; ++ ++ pinctrl_usbotg1: usbotg1grp { ++ fsl,pins = < ++ MX8MM_IOMUXC_GPIO1_IO12_GPIO1_IO12 0x141 ++ MX8MM_IOMUXC_GPIO1_IO13_USB1_OTG_OC 0x41 ++ >; ++ }; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi +index 6f0811587142d2..14d20a33af8e15 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi +@@ -929,7 +929,7 @@ pinctrl_gpio8: gpio8grp { + /* Verdin GPIO_9_DSI (pulled-up as active-low) */ + pinctrl_gpio_9_dsi: gpio9dsigrp { + fsl,pins = +- ; /* SODIMM 17 */ ++ ; /* SODIMM 17 */ + }; + + /* Verdin GPIO_10_DSI (pulled-up as active-low) */ +diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi +index 236fe44f779df3..54faf83cb436e5 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi +@@ -399,6 +399,7 @@ micfil: audio-controller@30080000 { + "pll8k", "pll11k", "clkext3"; + dmas = <&sdma2 24 25 0x80000000>; + dma-names = "rx"; ++ #sound-dai-cells = <0>; + status = "disabled"; + }; + +@@ -1407,7 +1408,7 @@ gpu_3d: gpu@38000000 { + assigned-clocks = <&clk IMX8MM_CLK_GPU3D_CORE>, + <&clk IMX8MM_GPU_PLL_OUT>; + assigned-clock-parents = <&clk IMX8MM_GPU_PLL_OUT>; +- assigned-clock-rates = <0>, <1000000000>; ++ assigned-clock-rates = <0>, <800000000>; + power-domains = <&pgc_gpu>; + }; + +@@ -1422,7 +1423,7 @@ gpu_2d: gpu@38008000 { + assigned-clocks = <&clk IMX8MM_CLK_GPU2D_CORE>, + <&clk IMX8MM_GPU_PLL_OUT>; + assigned-clock-parents = <&clk IMX8MM_GPU_PLL_OUT>; +- assigned-clock-rates = <0>, <1000000000>; ++ assigned-clock-rates = <0>, <800000000>; + power-domains = <&pgc_gpu>; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8mn.dtsi b/arch/arm64/boot/dts/freescale/imx8mn.dtsi +index aa38dd6dc9ba54..1bb1d0c1bae4de 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mn.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi +@@ -371,6 +371,7 @@ micfil: audio-controller@30080000 { + "pll8k", "pll11k", "clkext3"; + dmas = <&sdma2 24 25 0x80000000>; + dma-names = "rx"; ++ #sound-dai-cells = <0>; + status = "disabled"; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts b/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts +index acd265d8b58ed9..e094f409028ddb 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts +@@ -163,13 +163,12 @@ sound-wm8962 { + + simple-audio-card,cpu { + sound-dai = <&sai3>; ++ frame-master; ++ bitclock-master; + }; + + simple-audio-card,codec { + sound-dai = <&wm8962>; +- clocks = <&clk IMX8MP_CLK_IPP_DO_CLKO1>; +- frame-master; +- bitclock-master; + }; + }; + }; +@@ -381,10 +380,9 @@ &pcie_phy { + &sai3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai3>; +- assigned-clocks = <&clk IMX8MP_CLK_SAI3>, +- <&clk IMX8MP_AUDIO_PLL2> ; +- assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL2_OUT>; +- assigned-clock-rates = <12288000>, <361267200>; ++ assigned-clocks = <&clk IMX8MP_CLK_SAI3>; ++ assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>; ++ assigned-clock-rates = <12288000>; + fsl,sai-mclk-direction-output; + status = "okay"; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts +index 13674dc64be9d3..cd44bf83745cae 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts +@@ -121,7 +121,7 @@ &ecspi1 { + flash@0 { /* W25Q128JVEI */ + compatible = "jedec,spi-nor"; + reg = <0>; +- spi-max-frequency = <100000000>; /* Up to 133 MHz */ ++ spi-max-frequency = <40000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + }; +@@ -484,7 +484,7 @@ &uart3 { /* A53 Debug */ + &uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; +- status = "okay"; ++ status = "disabled"; + }; + + &usb3_phy0 { +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 28db9349ed62c4..267ceffc02d840 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts +@@ -284,7 +284,6 @@ &usb_dwc3_1 { + usb_hub_2_x: hub@1 { + compatible = "usbbda,5411"; + reg = <1>; +- reset-gpios = <&gpio4 25 GPIO_ACTIVE_LOW>; + vdd-supply = <®_usb_hub>; + peer-hub = <&usb_hub_3_x>; + }; +@@ -293,7 +292,6 @@ usb_hub_2_x: hub@1 { + usb_hub_3_x: hub@2 { + compatible = "usbbda,411"; + reg = <2>; +- reset-gpios = <&gpio4 25 GPIO_ACTIVE_LOW>; + vdd-supply = <®_usb_hub>; + peer-hub = <&usb_hub_2_x>; + }; +@@ -443,7 +441,6 @@ MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX 0x49 + pinctrl_usb1: usb1grp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR 0x10 +- MX8MP_IOMUXC_SAI2_TXC__GPIO4_IO25 0x19 + >; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +index cb1953d14aa907..eae39c1cb98568 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +@@ -251,8 +251,8 @@ tc_bridge: bridge@f { + <&clk IMX8MP_CLK_CLKOUT2>, + <&clk IMX8MP_AUDIO_PLL2_OUT>; + assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL2_OUT>; +- assigned-clock-rates = <13000000>, <13000000>, <156000000>; +- reset-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; ++ assigned-clock-rates = <13000000>, <13000000>, <208000000>; ++ reset-gpios = <&gpio4 1 GPIO_ACTIVE_HIGH>; + status = "disabled"; + + ports { +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +index cc9d468b43ab8d..92f8cc05fe9da1 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +@@ -23,7 +23,7 @@ hdmi-connector { + + port { + hdmi_connector_in: endpoint { +- remote-endpoint = <&adv7533_out>; ++ remote-endpoint = <&adv7535_out>; + }; + }; + }; +@@ -107,6 +107,13 @@ reg_usdhc2_vmmc: regulator-usdhc2 { + enable-active-high; + }; + ++ reg_vext_3v3: regulator-vext-3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VEXT_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "wm8960-audio"; +@@ -342,7 +349,7 @@ BUCK4 { + regulator-always-on; + }; + +- BUCK5 { ++ reg_buck5: BUCK5 { + regulator-name = "BUCK5"; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <1950000>; +@@ -393,14 +400,16 @@ &i2c2 { + + hdmi@3d { + compatible = "adi,adv7535"; +- reg = <0x3d>, <0x3c>, <0x3e>, <0x3f>; +- reg-names = "main", "cec", "edid", "packet"; ++ reg = <0x3d>; ++ interrupt-parent = <&gpio1>; ++ interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + adi,dsi-lanes = <4>; +- adi,input-depth = <8>; +- adi,input-colorspace = "rgb"; +- adi,input-clock = "1x"; +- adi,input-style = <1>; +- adi,input-justification = "evenly"; ++ avdd-supply = <®_buck5>; ++ dvdd-supply = <®_buck5>; ++ pvdd-supply = <®_buck5>; ++ a2vdd-supply = <®_buck5>; ++ v3p3-supply = <®_vext_3v3>; ++ v1p2-supply = <®_buck5>; + + ports { + #address-cells = <1>; +@@ -409,7 +418,7 @@ ports { + port@0 { + reg = <0>; + +- adv7533_in: endpoint { ++ adv7535_in: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; +@@ -417,7 +426,7 @@ adv7533_in: endpoint { + port@1 { + reg = <1>; + +- adv7533_out: endpoint { ++ adv7535_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; +@@ -502,7 +511,7 @@ port@1 { + reg = <1>; + + dsi_out: endpoint { +- remote-endpoint = <&adv7533_in>; ++ remote-endpoint = <&adv7535_in>; + data-lanes = <1 2 3 4>; + }; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +index 4240e20d38ac32..258e90cc16ff3a 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +@@ -168,6 +168,13 @@ reg_vcc_12v0: regulator-12v0 { + enable-active-high; + }; + ++ reg_vcc_1v8: regulator-1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ + reg_vcc_3v3: regulator-3v3 { + compatible = "regulator-fixed"; + regulator-name = "VCC_3V3"; +@@ -464,7 +471,7 @@ tlv320aic3x04: audio-codec@18 { + clock-names = "mclk"; + clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1>; + reset-gpios = <&gpio4 29 GPIO_ACTIVE_LOW>; +- iov-supply = <®_vcc_3v3>; ++ iov-supply = <®_vcc_1v8>; + ldoin-supply = <®_vcc_3v3>; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw73xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw73xx.dtsi +index 68c62def4c06e1..d27bfba1b4b8c4 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw73xx.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw73xx.dtsi +@@ -161,7 +161,7 @@ &uart3 { + + bluetooth { + compatible = "brcm,bcm4330-bt"; +- shutdown-gpios = <&gpio4 16 GPIO_ACTIVE_HIGH>; ++ shutdown-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; + }; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi +index 83d907294fbc73..d1488ebfef3f02 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi +@@ -785,6 +785,23 @@ pgc_usb2_phy: power-domain@3 { + reg = ; + }; + ++ pgc_mlmix: power-domain@4 { ++ #power-domain-cells = <0>; ++ reg = ; ++ clocks = <&clk IMX8MP_CLK_ML_AXI>, ++ <&clk IMX8MP_CLK_ML_AHB>, ++ <&clk IMX8MP_CLK_NPU_ROOT>; ++ assigned-clocks = <&clk IMX8MP_CLK_ML_CORE>, ++ <&clk IMX8MP_CLK_ML_AXI>, ++ <&clk IMX8MP_CLK_ML_AHB>; ++ assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>, ++ <&clk IMX8MP_SYS_PLL1_800M>, ++ <&clk IMX8MP_SYS_PLL1_800M>; ++ assigned-clock-rates = <800000000>, ++ <800000000>, ++ <300000000>; ++ }; ++ + pgc_audio: power-domain@5 { + #power-domain-cells = <0>; + reg = ; +@@ -817,6 +834,12 @@ pgc_gpumix: power-domain@7 { + assigned-clock-rates = <800000000>, <400000000>; + }; + ++ pgc_vpumix: power-domain@8 { ++ #power-domain-cells = <0>; ++ reg = ; ++ clocks = <&clk IMX8MP_CLK_VPU_ROOT>; ++ }; ++ + pgc_gpu3d: power-domain@9 { + #power-domain-cells = <0>; + reg = ; +@@ -832,60 +855,64 @@ pgc_mediamix: power-domain@10 { + <&clk IMX8MP_CLK_MEDIA_APB_ROOT>; + }; + +- pgc_mipi_phy2: power-domain@16 { ++ pgc_vpu_g1: power-domain@11 { + #power-domain-cells = <0>; +- reg = ; ++ power-domains = <&pgc_vpumix>; ++ reg = ; ++ clocks = <&clk IMX8MP_CLK_VPU_G1_ROOT>; + }; + +- pgc_hsiomix: power-domain@17 { ++ pgc_vpu_g2: power-domain@12 { + #power-domain-cells = <0>; +- reg = ; +- clocks = <&clk IMX8MP_CLK_HSIO_AXI>, +- <&clk IMX8MP_CLK_HSIO_ROOT>; +- assigned-clocks = <&clk IMX8MP_CLK_HSIO_AXI>; +- assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_500M>; +- assigned-clock-rates = <500000000>; ++ power-domains = <&pgc_vpumix>; ++ reg = ; ++ clocks = <&clk IMX8MP_CLK_VPU_G2_ROOT>; ++ + }; + +- pgc_ispdwp: power-domain@18 { ++ pgc_vpu_vc8000e: power-domain@13 { + #power-domain-cells = <0>; +- reg = ; +- clocks = <&clk IMX8MP_CLK_MEDIA_ISP_ROOT>; ++ power-domains = <&pgc_vpumix>; ++ reg = ; ++ clocks = <&clk IMX8MP_CLK_VPU_VC8KE_ROOT>; + }; + +- pgc_vpumix: power-domain@19 { ++ pgc_hdmimix: power-domain@14 { + #power-domain-cells = <0>; +- reg = ; +- clocks = <&clk IMX8MP_CLK_VPU_ROOT>; ++ reg = ; ++ clocks = <&clk IMX8MP_CLK_HDMI_ROOT>, ++ <&clk IMX8MP_CLK_HDMI_APB>; ++ assigned-clocks = <&clk IMX8MP_CLK_HDMI_AXI>, ++ <&clk IMX8MP_CLK_HDMI_APB>; ++ assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_500M>, ++ <&clk IMX8MP_SYS_PLL1_133M>; ++ assigned-clock-rates = <500000000>, <133000000>; + }; + +- pgc_vpu_g1: power-domain@20 { ++ pgc_hdmi_phy: power-domain@15 { + #power-domain-cells = <0>; +- power-domains = <&pgc_vpumix>; +- reg = ; +- clocks = <&clk IMX8MP_CLK_VPU_G1_ROOT>; ++ reg = ; + }; + +- pgc_vpu_g2: power-domain@21 { ++ pgc_mipi_phy2: power-domain@16 { + #power-domain-cells = <0>; +- power-domains = <&pgc_vpumix>; +- reg = ; +- clocks = <&clk IMX8MP_CLK_VPU_G2_ROOT>; ++ reg = ; + }; + +- pgc_vpu_vc8000e: power-domain@22 { ++ pgc_hsiomix: power-domain@17 { + #power-domain-cells = <0>; +- power-domains = <&pgc_vpumix>; +- reg = ; +- clocks = <&clk IMX8MP_CLK_VPU_VC8KE_ROOT>; ++ reg = ; ++ clocks = <&clk IMX8MP_CLK_HSIO_AXI>, ++ <&clk IMX8MP_CLK_HSIO_ROOT>; ++ assigned-clocks = <&clk IMX8MP_CLK_HSIO_AXI>; ++ assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_500M>; ++ assigned-clock-rates = <500000000>; + }; + +- pgc_mlmix: power-domain@24 { ++ pgc_ispdwp: power-domain@18 { + #power-domain-cells = <0>; +- reg = ; +- clocks = <&clk IMX8MP_CLK_ML_AXI>, +- <&clk IMX8MP_CLK_ML_AHB>, +- <&clk IMX8MP_CLK_NPU_ROOT>; ++ reg = ; ++ clocks = <&clk IMX8MP_CLK_MEDIA_ISP_ROOT>; + }; + }; + }; +@@ -1831,6 +1858,27 @@ hsio_blk_ctrl: blk-ctrl@32f10000 { + #power-domain-cells = <1>; + #clock-cells = <0>; + }; ++ ++ hdmi_blk_ctrl: blk-ctrl@32fc0000 { ++ compatible = "fsl,imx8mp-hdmi-blk-ctrl", "syscon"; ++ reg = <0x32fc0000 0x1000>; ++ clocks = <&clk IMX8MP_CLK_HDMI_APB>, ++ <&clk IMX8MP_CLK_HDMI_ROOT>, ++ <&clk IMX8MP_CLK_HDMI_REF_266M>, ++ <&clk IMX8MP_CLK_HDMI_24M>, ++ <&clk IMX8MP_CLK_HDMI_FDCC_TST>; ++ clock-names = "apb", "axi", "ref_266m", "ref_24m", "fdcc"; ++ power-domains = <&pgc_hdmimix>, <&pgc_hdmimix>, ++ <&pgc_hdmimix>, <&pgc_hdmimix>, ++ <&pgc_hdmimix>, <&pgc_hdmimix>, ++ <&pgc_hdmimix>, <&pgc_hdmi_phy>, ++ <&pgc_hdmimix>, <&pgc_hdmimix>; ++ power-domain-names = "bus", "irqsteer", "lcdif", ++ "pai", "pvi", "trng", ++ "hdmi-tx", "hdmi-tx-phy", ++ "hdcp", "hrv"; ++ #power-domain-cells = <1>; ++ }; + }; + + pcie: pcie@33800000 { +@@ -1970,6 +2018,18 @@ vpumix_blk_ctrl: blk-ctrl@38330000 { + interconnect-names = "g1", "g2", "vc8000e"; + }; + ++ npu: npu@38500000 { ++ compatible = "vivante,gc"; ++ reg = <0x38500000 0x200000>; ++ interrupts = ; ++ clocks = <&clk IMX8MP_CLK_NPU_ROOT>, ++ <&clk IMX8MP_CLK_NPU_ROOT>, ++ <&clk IMX8MP_CLK_ML_AXI>, ++ <&clk IMX8MP_CLK_ML_AHB>; ++ clock-names = "core", "shader", "bus", "reg"; ++ power-domains = <&pgc_mlmix>; ++ }; ++ + gic: interrupt-controller@38800000 { + compatible = "arm,gic-v3"; + reg = <0x38800000 0x10000>, +@@ -2030,6 +2090,7 @@ usb_dwc3_0: usb@38100000 { + phys = <&usb3_phy0>, <&usb3_phy0>; + phy-names = "usb2-phy", "usb3-phy"; + snps,gfladj-refclk-lpm-sel-quirk; ++ snps,parkmode-disable-ss-quirk; + }; + + }; +@@ -2072,6 +2133,7 @@ usb_dwc3_1: usb@38200000 { + phys = <&usb3_phy1>, <&usb3_phy1>; + phy-names = "usb2-phy", "usb3-phy"; + snps,gfladj-refclk-lpm-sel-quirk; ++ snps,parkmode-disable-ss-quirk; + }; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi +index 35f07dfb4ca8df..052ba9baa400f8 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi +@@ -1649,6 +1649,7 @@ usb_dwc3_0: usb@38100000 { + phys = <&usb3_phy0>, <&usb3_phy0>; + phy-names = "usb2-phy", "usb3-phy"; + power-domains = <&pgc_otg1>; ++ snps,parkmode-disable-ss-quirk; + status = "disabled"; + }; + +@@ -1680,6 +1681,7 @@ usb_dwc3_1: usb@38200000 { + phys = <&usb3_phy1>, <&usb3_phy1>; + phy-names = "usb2-phy", "usb3-phy"; + power-domains = <&pgc_otg2>; ++ snps,parkmode-disable-ss-quirk; + status = "disabled"; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts +index 0b34cc2250e14c..a9ab87699f3d56 100644 +--- a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts ++++ b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts +@@ -36,7 +36,7 @@ reg_usdhc2_vmmc: usdhc2-vmmc { + regulator-name = "SD1_SPWR"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; +- gpio = <&lsio_gpio4 19 GPIO_ACTIVE_HIGH>; ++ gpio = <&lsio_gpio4 7 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi +index e9b198c13b2fd8..d896135f31fcd8 100644 +--- a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi +@@ -49,15 +49,15 @@ &flexcan1 { + }; + + &flexcan2 { +- clocks = <&can1_lpcg 1>, +- <&can1_lpcg 0>; ++ clocks = <&can1_lpcg IMX_LPCG_CLK_4>, ++ <&can1_lpcg IMX_LPCG_CLK_0>; + assigned-clocks = <&clk IMX_SC_R_CAN_1 IMX_SC_PM_CLK_PER>; + fsl,clk-source = /bits/ 8 <1>; + }; + + &flexcan3 { +- clocks = <&can2_lpcg 1>, +- <&can2_lpcg 0>; ++ clocks = <&can2_lpcg IMX_LPCG_CLK_4>, ++ <&can2_lpcg IMX_LPCG_CLK_0>; + assigned-clocks = <&clk IMX_SC_R_CAN_2 IMX_SC_PM_CLK_PER>; + fsl,clk-source = /bits/ 8 <1>; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-img.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-img.dtsi +index 7764b4146e0ab4..2bbdacb1313f9d 100644 +--- a/arch/arm64/boot/dts/freescale/imx8qm-ss-img.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-img.dtsi +@@ -8,5 +8,5 @@ &jpegdec { + }; + + &jpegenc { +- compatible = "nxp,imx8qm-jpgdec", "nxp,imx8qxp-jpgenc"; ++ compatible = "nxp,imx8qm-jpgenc", "nxp,imx8qxp-jpgenc"; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts +index cafd39130eb887..a06ca740f540c7 100644 +--- a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts +@@ -168,7 +168,6 @@ &usdhc2 { + vmmc-supply = <®_usdhc2_vmmc>; + bus-width = <4>; + status = "okay"; +- no-sdio; + no-mmc; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dts b/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dts +index f06139bdff97e3..aaf9685ef0fbbb 100644 +--- a/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dts ++++ b/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dts +@@ -437,7 +437,7 @@ &usdhc2 { + pinctrl-0 = <&pinctrl_usdhc2_hs>, <&pinctrl_usdhc2_gpio>; + pinctrl-1 = <&pinctrl_usdhc2_uhs>, <&pinctrl_usdhc2_gpio>; + pinctrl-2 = <&pinctrl_usdhc2_uhs>, <&pinctrl_usdhc2_gpio>; +- cd-gpios = <&gpio3 00 GPIO_ACTIVE_LOW>; ++ cd-gpios = <&gpio3 0 GPIO_ACTIVE_LOW>; + vmmc-supply = <®_usdhc2_vmmc>; + bus-width = <4>; + no-sdio; +@@ -577,7 +577,7 @@ pinctrl_uart2: uart2grp { + fsl,pins = < + MX93_PAD_UART2_TXD__LPUART2_TX 0x31e + MX93_PAD_UART2_RXD__LPUART2_RX 0x31e +- MX93_PAD_SAI1_TXD0__LPUART2_RTS_B 0x31e ++ MX93_PAD_SAI1_TXD0__LPUART2_RTS_B 0x51e + >; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx93-tqma9352.dtsi b/arch/arm64/boot/dts/freescale/imx93-tqma9352.dtsi +index f6e422dc2663e9..b6f3c076fe54a1 100644 +--- a/arch/arm64/boot/dts/freescale/imx93-tqma9352.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx93-tqma9352.dtsi +@@ -19,7 +19,7 @@ reserved-memory { + linux,cma { + compatible = "shared-dma-pool"; + reusable; +- alloc-ranges = <0 0x60000000 0 0x40000000>; ++ alloc-ranges = <0 0x80000000 0 0x40000000>; + size = <0 0x10000000>; + linux,cma-default; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi +index dcf6e4846ac9de..35155b009dd249 100644 +--- a/arch/arm64/boot/dts/freescale/imx93.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx93.dtsi +@@ -373,7 +373,7 @@ mediamix: power-domain@44462400 { + compatible = "fsl,imx93-src-slice"; + reg = <0x44462400 0x400>, <0x44465800 0x400>; + #power-domain-cells = <0>; +- clocks = <&clk IMX93_CLK_MEDIA_AXI>, ++ clocks = <&clk IMX93_CLK_NIC_MEDIA_GATE>, + <&clk IMX93_CLK_MEDIA_APB>; + }; + }; +@@ -786,6 +786,8 @@ fec: ethernet@42890000 { + fsl,num-tx-queues = <3>; + fsl,num-rx-queues = <3>; + fsl,stop-mode = <&wakeupmix_gpr 0x0c 1>; ++ nvmem-cells = <ð_mac1>; ++ nvmem-cell-names = "mac-address"; + status = "disabled"; + }; + +@@ -807,7 +809,9 @@ eqos: ethernet@428a0000 { + <&clk IMX93_CLK_SYS_PLL_PFD0_DIV2>; + assigned-clock-rates = <100000000>, <250000000>; + intf_mode = <&wakeupmix_gpr 0x28>; +- snps,clk-csr = <0>; ++ snps,clk-csr = <6>; ++ nvmem-cells = <ð_mac2>; ++ nvmem-cell-names = "mac-address"; + status = "disabled"; + }; + +@@ -888,6 +892,15 @@ ocotp: efuse@47510000 { + reg = <0x47510000 0x10000>; + #address-cells = <1>; + #size-cells = <1>; ++ ++ eth_mac1: mac-address@4ec { ++ reg = <0x4ec 0x6>; ++ }; ++ ++ eth_mac2: mac-address@4f2 { ++ reg = <0x4f2 0x6>; ++ }; ++ + }; + + s4muap: mailbox@47520000 { +diff --git a/arch/arm64/boot/dts/hisilicon/hi3798cv200.dtsi b/arch/arm64/boot/dts/hisilicon/hi3798cv200.dtsi +index ed1b5a7a606786..d01023401d7e3f 100644 +--- a/arch/arm64/boot/dts/hisilicon/hi3798cv200.dtsi ++++ b/arch/arm64/boot/dts/hisilicon/hi3798cv200.dtsi +@@ -58,7 +58,7 @@ cpu@3 { + gic: interrupt-controller@f1001000 { + compatible = "arm,gic-400"; + reg = <0x0 0xf1001000 0x0 0x1000>, /* GICD */ +- <0x0 0xf1002000 0x0 0x100>; /* GICC */ ++ <0x0 0xf1002000 0x0 0x2000>; /* GICC */ + #address-cells = <0>; + #interrupt-cells = <3>; + interrupt-controller; +diff --git a/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi b/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi +index 970047f2dabd51..c06e011a6c3ffc 100644 +--- a/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi ++++ b/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi +@@ -25,9 +25,6 @@ pmic: pmic@0 { + gpios = <&gpio28 0 0>; + + regulators { +- #address-cells = <1>; +- #size-cells = <0>; +- + ldo3: ldo3 { /* HDMI */ + regulator-name = "ldo3"; + regulator-min-microvolt = <1500000>; +diff --git a/arch/arm64/boot/dts/lg/lg1312.dtsi b/arch/arm64/boot/dts/lg/lg1312.dtsi +index 48ec4ebec0a83e..b864ffa74ea8b6 100644 +--- a/arch/arm64/boot/dts/lg/lg1312.dtsi ++++ b/arch/arm64/boot/dts/lg/lg1312.dtsi +@@ -126,7 +126,6 @@ eth0: ethernet@c1b00000 { + amba { + #address-cells = <2>; + #size-cells = <1>; +- #interrupt-cells = <3>; + + compatible = "simple-bus"; + interrupt-parent = <&gic>; +diff --git a/arch/arm64/boot/dts/lg/lg1313.dtsi b/arch/arm64/boot/dts/lg/lg1313.dtsi +index 3869460aa5dcb5..996fb39bb50c1f 100644 +--- a/arch/arm64/boot/dts/lg/lg1313.dtsi ++++ b/arch/arm64/boot/dts/lg/lg1313.dtsi +@@ -126,7 +126,6 @@ eth0: ethernet@c3700000 { + amba { + #address-cells = <2>; + #size-cells = <1>; +- #interrupt-cells = <3>; + + compatible = "simple-bus"; + interrupt-parent = <&gic>; +diff --git a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts +index 9eab2bb221348a..805ef2d79b4012 100644 +--- a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts ++++ b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts +@@ -130,7 +130,7 @@ rtc@6f { + compatible = "microchip,mcp7940x"; + reg = <0x6f>; + interrupt-parent = <&gpiosb>; +- interrupts = <5 0>; /* GPIO2_5 */ ++ interrupts = <5 IRQ_TYPE_EDGE_FALLING>; /* GPIO2_5 */ + }; + }; + +diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +index e300145ad1a6f5..1cc3fa1c354de8 100644 +--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +@@ -431,14 +431,14 @@ xor11 { + crypto: crypto@90000 { + compatible = "inside-secure,safexcel-eip97ies"; + reg = <0x90000 0x20000>; +- interrupts = , +- , ++ interrupts = , + , + , + , +- ; +- interrupt-names = "mem", "ring0", "ring1", +- "ring2", "ring3", "eip"; ++ , ++ ; ++ interrupt-names = "ring0", "ring1", "ring2", ++ "ring3", "eip", "mem"; + clocks = <&nb_periph_clk 15>; + }; + +diff --git a/arch/arm64/boot/dts/marvell/armada-ap80x.dtsi b/arch/arm64/boot/dts/marvell/armada-ap80x.dtsi +index 2c920e22cec2b5..7ec7c789d87eff 100644 +--- a/arch/arm64/boot/dts/marvell/armada-ap80x.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-ap80x.dtsi +@@ -138,7 +138,6 @@ pmu { + + odmi: odmi@300000 { + compatible = "marvell,odmi-controller"; +- interrupt-controller; + msi-controller; + marvell,odmi-frames = <4>; + reg = <0x300000 0x4000>, +diff --git a/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi b/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi +index 4ec1aae0a3a9c3..7e595ac80043aa 100644 +--- a/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi +@@ -511,14 +511,14 @@ CP11X_LABEL(sdhci0): mmc@780000 { + CP11X_LABEL(crypto): crypto@800000 { + compatible = "inside-secure,safexcel-eip197b"; + reg = <0x800000 0x200000>; +- interrupts = <87 IRQ_TYPE_LEVEL_HIGH>, +- <88 IRQ_TYPE_LEVEL_HIGH>, ++ interrupts = <88 IRQ_TYPE_LEVEL_HIGH>, + <89 IRQ_TYPE_LEVEL_HIGH>, + <90 IRQ_TYPE_LEVEL_HIGH>, + <91 IRQ_TYPE_LEVEL_HIGH>, +- <92 IRQ_TYPE_LEVEL_HIGH>; +- interrupt-names = "mem", "ring0", "ring1", +- "ring2", "ring3", "eip"; ++ <92 IRQ_TYPE_LEVEL_HIGH>, ++ <87 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "ring0", "ring1", "ring2", "ring3", ++ "eip", "mem"; + clock-names = "core", "reg"; + clocks = <&CP11X_LABEL(clk) 1 26>, + <&CP11X_LABEL(clk) 1 17>; +diff --git a/arch/arm64/boot/dts/marvell/cn9130-crb.dtsi b/arch/arm64/boot/dts/marvell/cn9130-crb.dtsi +index 32cfb3e2efc3a4..47d45ff3d6f578 100644 +--- a/arch/arm64/boot/dts/marvell/cn9130-crb.dtsi ++++ b/arch/arm64/boot/dts/marvell/cn9130-crb.dtsi +@@ -120,7 +120,7 @@ cp0_sdhci_pins: cp0-sdhi-pins-0 { + "mpp59", "mpp60", "mpp61"; + marvell,function = "sdio"; + }; +- cp0_spi0_pins: cp0-spi-pins-0 { ++ cp0_spi1_pins: cp0-spi-pins-1 { + marvell,pins = "mpp13", "mpp14", "mpp15", "mpp16"; + marvell,function = "spi1"; + }; +@@ -170,7 +170,7 @@ &cp0_sdhci0 { + + &cp0_spi1 { + pinctrl-names = "default"; +- pinctrl-0 = <&cp0_spi0_pins>; ++ pinctrl-0 = <&cp0_spi1_pins>; + reg = <0x700680 0x50>, /* control */ + <0x2000000 0x1000000>; /* CS0 */ + status = "okay"; +diff --git a/arch/arm64/boot/dts/marvell/cn9130-db.dtsi b/arch/arm64/boot/dts/marvell/cn9130-db.dtsi +index c7de1ea0d470a9..6eb6a175de38d5 100644 +--- a/arch/arm64/boot/dts/marvell/cn9130-db.dtsi ++++ b/arch/arm64/boot/dts/marvell/cn9130-db.dtsi +@@ -307,7 +307,7 @@ &cp0_sdhci0 { + &cp0_spi1 { + status = "disabled"; + pinctrl-names = "default"; +- pinctrl-0 = <&cp0_spi0_pins>; ++ pinctrl-0 = <&cp0_spi1_pins>; + reg = <0x700680 0x50>; + + flash@0 { +@@ -371,7 +371,7 @@ cp0_sdhci_pins: cp0-sdhi-pins-0 { + "mpp59", "mpp60", "mpp61"; + marvell,function = "sdio"; + }; +- cp0_spi0_pins: cp0-spi-pins-0 { ++ cp0_spi1_pins: cp0-spi-pins-1 { + marvell,pins = "mpp13", "mpp14", "mpp15", "mpp16"; + marvell,function = "spi1"; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt2712-evb.dts b/arch/arm64/boot/dts/mediatek/mt2712-evb.dts +index fffdb7bbf889e4..2d0ef6f23b3a93 100644 +--- a/arch/arm64/boot/dts/mediatek/mt2712-evb.dts ++++ b/arch/arm64/boot/dts/mediatek/mt2712-evb.dts +@@ -129,7 +129,7 @@ ethernet_phy0: ethernet-phy@5 { + }; + + &pio { +- eth_default: eth_default { ++ eth_default: eth-default-pins { + tx_pins { + pinmux = , + , +@@ -156,7 +156,7 @@ mdio_pins { + }; + }; + +- eth_sleep: eth_sleep { ++ eth_sleep: eth-sleep-pins { + tx_pins { + pinmux = , + , +@@ -182,14 +182,14 @@ mdio_pins { + }; + }; + +- usb0_id_pins_float: usb0_iddig { ++ usb0_id_pins_float: usb0-iddig-pins { + pins_iddig { + pinmux = ; + bias-pull-up; + }; + }; + +- usb1_id_pins_float: usb1_iddig { ++ usb1_id_pins_float: usb1-iddig-pins { + pins_iddig { + pinmux = ; + bias-pull-up; +diff --git a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi +index ed1a9d31941530..f767f921bdee16 100644 +--- a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi +@@ -249,10 +249,11 @@ topckgen: syscon@10000000 { + #clock-cells = <1>; + }; + +- infracfg: syscon@10001000 { ++ infracfg: clock-controller@10001000 { + compatible = "mediatek,mt2712-infracfg", "syscon"; + reg = <0 0x10001000 0 0x1000>; + #clock-cells = <1>; ++ #reset-cells = <1>; + }; + + pericfg: syscon@10003000 { +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +index 86cedb0bf1a900..15838c1ee8cc33 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +@@ -73,8 +73,9 @@ led-1 { + }; + }; + +- memory { ++ memory@40000000 { + reg = <0 0x40000000 0 0x40000000>; ++ device_type = "memory"; + }; + + reg_1p8v: regulator-1p8v { +@@ -317,8 +318,8 @@ asm_sel { + /* eMMC is shared pin with parallel NAND */ + emmc_pins_default: emmc-pins-default { + mux { +- function = "emmc", "emmc_rst"; +- groups = "emmc"; ++ function = "emmc"; ++ groups = "emmc", "emmc_rst"; + }; + + /* "NDL0","NDL1","NDL2","NDL3","NDL4","NDL5","NDL6","NDL7", +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +index dad8e683aac5bc..0a14ef1da60de8 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +@@ -55,8 +55,9 @@ key-wps { + }; + }; + +- memory { ++ memory@40000000 { + reg = <0 0x40000000 0 0x20000000>; ++ device_type = "memory"; + }; + + reg_1p8v: regulator-1p8v { +@@ -243,8 +244,8 @@ &pio { + /* eMMC is shared pin with parallel NAND */ + emmc_pins_default: emmc-pins-default { + mux { +- function = "emmc", "emmc_rst"; +- groups = "emmc"; ++ function = "emmc"; ++ groups = "emmc", "emmc_rst"; + }; + + /* "NDL0","NDL1","NDL2","NDL3","NDL4","NDL5","NDL6","NDL7", +diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +index 3ee9266fa8e985..917fa39a74f8d7 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -252,7 +252,7 @@ scpsys: power-controller@10006000 { + clock-names = "hif_sel"; + }; + +- cir: cir@10009000 { ++ cir: ir-receiver@10009000 { + compatible = "mediatek,mt7622-cir"; + reg = <0 0x10009000 0 0x1000>; + interrupts = ; +@@ -283,16 +283,14 @@ thermal_calibration: calib@198 { + }; + }; + +- apmixedsys: apmixedsys@10209000 { +- compatible = "mediatek,mt7622-apmixedsys", +- "syscon"; ++ apmixedsys: clock-controller@10209000 { ++ compatible = "mediatek,mt7622-apmixedsys"; + reg = <0 0x10209000 0 0x1000>; + #clock-cells = <1>; + }; + +- topckgen: topckgen@10210000 { +- compatible = "mediatek,mt7622-topckgen", +- "syscon"; ++ topckgen: clock-controller@10210000 { ++ compatible = "mediatek,mt7622-topckgen"; + reg = <0 0x10210000 0 0x1000>; + #clock-cells = <1>; + }; +@@ -515,7 +513,6 @@ thermal: thermal@1100b000 { + <&pericfg CLK_PERI_AUXADC_PD>; + clock-names = "therm", "auxadc"; + resets = <&pericfg MT7622_PERI_THERM_SW_RST>; +- reset-names = "therm"; + mediatek,auxadc = <&auxadc>; + mediatek,apmixedsys = <&apmixedsys>; + nvmem-cells = <&thermal_calibration>; +@@ -734,9 +731,8 @@ wmac: wmac@18000000 { + power-domains = <&scpsys MT7622_POWER_DOMAIN_WB>; + }; + +- ssusbsys: ssusbsys@1a000000 { +- compatible = "mediatek,mt7622-ssusbsys", +- "syscon"; ++ ssusbsys: clock-controller@1a000000 { ++ compatible = "mediatek,mt7622-ssusbsys"; + reg = <0 0x1a000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; +@@ -793,9 +789,8 @@ u2port1: usb-phy@1a0c5000 { + }; + }; + +- pciesys: pciesys@1a100800 { +- compatible = "mediatek,mt7622-pciesys", +- "syscon"; ++ pciesys: clock-controller@1a100800 { ++ compatible = "mediatek,mt7622-pciesys"; + reg = <0 0x1a100800 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; +@@ -921,12 +916,13 @@ sata_port: sata-phy@1a243000 { + }; + }; + +- hifsys: syscon@1af00000 { +- compatible = "mediatek,mt7622-hifsys", "syscon"; ++ hifsys: clock-controller@1af00000 { ++ compatible = "mediatek,mt7622-hifsys"; + reg = <0 0x1af00000 0 0x70>; ++ #clock-cells = <1>; + }; + +- ethsys: syscon@1b000000 { ++ ethsys: clock-controller@1b000000 { + compatible = "mediatek,mt7622-ethsys", + "syscon"; + reg = <0 0x1b000000 0 0x1000>; +@@ -966,9 +962,7 @@ wed1: wed@1020b000 { + }; + + eth: ethernet@1b100000 { +- compatible = "mediatek,mt7622-eth", +- "mediatek,mt2701-eth", +- "syscon"; ++ compatible = "mediatek,mt7622-eth"; + reg = <0 0x1b100000 0 0x20000>; + interrupts = , + , +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts +index af4a4309bda4b9..aba6686eb34a3a 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts +@@ -43,7 +43,7 @@ fan: pwm-fan { + #cooling-cells = <2>; + /* cooling level (0, 1, 2) - pwm inverted */ + cooling-levels = <255 96 0>; +- pwms = <&pwm 0 10000 0>; ++ pwms = <&pwm 0 10000>; + status = "okay"; + }; + +@@ -126,6 +126,7 @@ sfp1: sfp-1 { + compatible = "sff,sfp"; + i2c-bus = <&i2c_sfp1>; + los-gpios = <&pio 46 GPIO_ACTIVE_HIGH>; ++ maximum-power-milliwatt = <3000>; + mod-def0-gpios = <&pio 49 GPIO_ACTIVE_LOW>; + tx-disable-gpios = <&pio 20 GPIO_ACTIVE_HIGH>; + tx-fault-gpios = <&pio 7 GPIO_ACTIVE_HIGH>; +@@ -137,6 +138,7 @@ sfp2: sfp-2 { + i2c-bus = <&i2c_sfp2>; + los-gpios = <&pio 31 GPIO_ACTIVE_HIGH>; + mod-def0-gpios = <&pio 47 GPIO_ACTIVE_LOW>; ++ maximum-power-milliwatt = <3000>; + tx-disable-gpios = <&pio 15 GPIO_ACTIVE_HIGH>; + tx-fault-gpios = <&pio 48 GPIO_ACTIVE_HIGH>; + }; +@@ -144,22 +146,22 @@ sfp2: sfp-2 { + + &cpu_thermal { + cooling-maps { +- cpu-active-high { ++ map-cpu-active-high { + /* active: set fan to cooling level 2 */ + cooling-device = <&fan 2 2>; + trip = <&cpu_trip_active_high>; + }; + +- cpu-active-low { ++ map-cpu-active-med { + /* active: set fan to cooling level 1 */ + cooling-device = <&fan 1 1>; +- trip = <&cpu_trip_active_low>; ++ trip = <&cpu_trip_active_med>; + }; + +- cpu-passive { +- /* passive: set fan to cooling level 0 */ ++ map-cpu-active-low { ++ /* active: set fan to cooling level 0 */ + cooling-device = <&fan 0 0>; +- trip = <&cpu_trip_passive>; ++ trip = <&cpu_trip_active_low>; + }; + }; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts +index 3ef371ca254e81..2f884c24f1eb46 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts +@@ -237,12 +237,13 @@ &spi0 { + pinctrl-0 = <&spi_flash_pins>; + cs-gpios = <0>, <0>; + status = "okay"; +- spi_nand: spi_nand@0 { ++ ++ spi_nand: flash@0 { + compatible = "spi-nand"; + reg = <0>; + spi-max-frequency = <10000000>; +- spi-tx-buswidth = <4>; +- spi-rx-buswidth = <4>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; + }; + }; + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +index 24eda00e320d3a..559990dcd1d179 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +@@ -16,49 +16,49 @@ / { + #address-cells = <2>; + #size-cells = <2>; + +- clk40m: oscillator-40m { +- compatible = "fixed-clock"; +- clock-frequency = <40000000>; +- #clock-cells = <0>; +- clock-output-names = "clkxtal"; +- }; +- + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu0: cpu@0 { +- device_type = "cpu"; + compatible = "arm,cortex-a53"; +- enable-method = "psci"; + reg = <0x0>; ++ device_type = "cpu"; ++ enable-method = "psci"; + #cooling-cells = <2>; + }; + + cpu1: cpu@1 { +- device_type = "cpu"; + compatible = "arm,cortex-a53"; +- enable-method = "psci"; + reg = <0x1>; ++ device_type = "cpu"; ++ enable-method = "psci"; + #cooling-cells = <2>; + }; + + cpu2: cpu@2 { +- device_type = "cpu"; + compatible = "arm,cortex-a53"; +- enable-method = "psci"; + reg = <0x2>; ++ device_type = "cpu"; ++ enable-method = "psci"; + #cooling-cells = <2>; + }; + + cpu3: cpu@3 { +- device_type = "cpu"; +- enable-method = "psci"; + compatible = "arm,cortex-a53"; + reg = <0x3>; ++ device_type = "cpu"; ++ enable-method = "psci"; + #cooling-cells = <2>; + }; + }; + ++ clk40m: oscillator-40m { ++ compatible = "fixed-clock"; ++ clock-frequency = <40000000>; ++ #clock-cells = <0>; ++ clock-output-names = "clkxtal"; ++ }; ++ + psci { + compatible = "arm,psci-0.2"; + method = "smc"; +@@ -121,38 +121,30 @@ wo_boot: wo-boot@15194000 { + + }; + +- timer { +- compatible = "arm,armv8-timer"; +- interrupt-parent = <&gic>; +- interrupts = , +- , +- , +- ; +- }; +- + soc { +- #address-cells = <2>; +- #size-cells = <2>; + compatible = "simple-bus"; + ranges; ++ #address-cells = <2>; ++ #size-cells = <2>; + + gic: interrupt-controller@c000000 { + compatible = "arm,gic-v3"; +- #interrupt-cells = <3>; +- interrupt-parent = <&gic>; +- interrupt-controller; + reg = <0 0x0c000000 0 0x10000>, /* GICD */ + <0 0x0c080000 0 0x80000>, /* GICR */ + <0 0x0c400000 0 0x2000>, /* GICC */ + <0 0x0c410000 0 0x1000>, /* GICH */ + <0 0x0c420000 0 0x2000>; /* GICV */ ++ interrupt-parent = <&gic>; + interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <3>; + }; + + infracfg: infracfg@10001000 { + compatible = "mediatek,mt7986-infracfg", "syscon"; + reg = <0 0x10001000 0 0x1000>; + #clock-cells = <1>; ++ #reset-cells = <1>; + }; + + wed_pcie: wed-pcie@10003000 { +@@ -202,6 +194,19 @@ pio: pinctrl@1001f000 { + #interrupt-cells = <2>; + }; + ++ pwm: pwm@10048000 { ++ compatible = "mediatek,mt7986-pwm"; ++ reg = <0 0x10048000 0 0x1000>; ++ #pwm-cells = <2>; ++ interrupts = ; ++ clocks = <&topckgen CLK_TOP_PWM_SEL>, ++ <&infracfg CLK_INFRA_PWM_STA>, ++ <&infracfg CLK_INFRA_PWM1_CK>, ++ <&infracfg CLK_INFRA_PWM2_CK>; ++ clock-names = "top", "main", "pwm1", "pwm2"; ++ status = "disabled"; ++ }; ++ + sgmiisys0: syscon@10060000 { + compatible = "mediatek,mt7986-sgmiisys_0", + "syscon"; +@@ -234,26 +239,11 @@ crypto: crypto@10320000 { + ; + interrupt-names = "ring0", "ring1", "ring2", "ring3"; + clocks = <&infracfg CLK_INFRA_EIP97_CK>; +- clock-names = "infra_eip97_ck"; + assigned-clocks = <&topckgen CLK_TOP_EIP_B_SEL>; + assigned-clock-parents = <&apmixedsys CLK_APMIXED_NET2PLL>; + status = "disabled"; + }; + +- pwm: pwm@10048000 { +- compatible = "mediatek,mt7986-pwm"; +- reg = <0 0x10048000 0 0x1000>; +- #clock-cells = <1>; +- #pwm-cells = <2>; +- interrupts = ; +- clocks = <&topckgen CLK_TOP_PWM_SEL>, +- <&infracfg CLK_INFRA_PWM_STA>, +- <&infracfg CLK_INFRA_PWM1_CK>, +- <&infracfg CLK_INFRA_PWM2_CK>; +- clock-names = "top", "main", "pwm1", "pwm2"; +- status = "disabled"; +- }; +- + uart0: serial@11002000 { + compatible = "mediatek,mt7986-uart", + "mediatek,mt6577-uart"; +@@ -311,9 +301,9 @@ i2c0: i2c@11008000 { + + spi0: spi@1100a000 { + compatible = "mediatek,mt7986-spi-ipm", "mediatek,spi-ipm"; ++ reg = <0 0x1100a000 0 0x100>; + #address-cells = <1>; + #size-cells = <0>; +- reg = <0 0x1100a000 0 0x100>; + interrupts = ; + clocks = <&topckgen CLK_TOP_MPLL_D2>, + <&topckgen CLK_TOP_SPI_SEL>, +@@ -325,9 +315,9 @@ spi0: spi@1100a000 { + + spi1: spi@1100b000 { + compatible = "mediatek,mt7986-spi-ipm", "mediatek,spi-ipm"; ++ reg = <0 0x1100b000 0 0x100>; + #address-cells = <1>; + #size-cells = <0>; +- reg = <0 0x1100b000 0 0x100>; + interrupts = ; + clocks = <&topckgen CLK_TOP_MPLL_D2>, + <&topckgen CLK_TOP_SPIM_MST_SEL>, +@@ -337,6 +327,20 @@ spi1: spi@1100b000 { + status = "disabled"; + }; + ++ thermal: thermal@1100c800 { ++ compatible = "mediatek,mt7986-thermal"; ++ reg = <0 0x1100c800 0 0x800>; ++ interrupts = ; ++ clocks = <&infracfg CLK_INFRA_THERM_CK>, ++ <&infracfg CLK_INFRA_ADC_26M_CK>; ++ clock-names = "therm", "auxadc"; ++ nvmem-cells = <&thermal_calibration>; ++ nvmem-cell-names = "calibration-data"; ++ #thermal-sensor-cells = <1>; ++ mediatek,auxadc = <&auxadc>; ++ mediatek,apmixedsys = <&apmixedsys>; ++ }; ++ + auxadc: adc@1100d000 { + compatible = "mediatek,mt7986-auxadc"; + reg = <0 0x1100d000 0 0x1000>; +@@ -374,6 +378,10 @@ mmc0: mmc@11230000 { + reg = <0 0x11230000 0 0x1000>, + <0 0x11c20000 0 0x1000>; + interrupts = ; ++ assigned-clocks = <&topckgen CLK_TOP_EMMC_416M_SEL>, ++ <&topckgen CLK_TOP_EMMC_250M_SEL>; ++ assigned-clock-parents = <&apmixedsys CLK_APMIXED_MPLL>, ++ <&topckgen CLK_TOP_NET1PLL_D5_D2>; + clocks = <&topckgen CLK_TOP_EMMC_416M_SEL>, + <&infracfg CLK_INFRA_MSDC_HCK_CK>, + <&infracfg CLK_INFRA_MSDC_CK>, +@@ -384,39 +392,23 @@ mmc0: mmc@11230000 { + status = "disabled"; + }; + +- thermal: thermal@1100c800 { +- #thermal-sensor-cells = <1>; +- compatible = "mediatek,mt7986-thermal"; +- reg = <0 0x1100c800 0 0x800>; +- interrupts = ; +- clocks = <&infracfg CLK_INFRA_THERM_CK>, +- <&infracfg CLK_INFRA_ADC_26M_CK>, +- <&infracfg CLK_INFRA_ADC_FRC_CK>; +- clock-names = "therm", "auxadc", "adc_32k"; +- mediatek,auxadc = <&auxadc>; +- mediatek,apmixedsys = <&apmixedsys>; +- nvmem-cells = <&thermal_calibration>; +- nvmem-cell-names = "calibration-data"; +- }; +- + pcie: pcie@11280000 { + compatible = "mediatek,mt7986-pcie", + "mediatek,mt8192-pcie"; ++ reg = <0x00 0x11280000 0x00 0x4000>; ++ reg-names = "pcie-mac"; ++ ranges = <0x82000000 0x00 0x20000000 0x00 ++ 0x20000000 0x00 0x10000000>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; +- reg = <0x00 0x11280000 0x00 0x4000>; +- reg-names = "pcie-mac"; + interrupts = ; + bus-range = <0x00 0xff>; +- ranges = <0x82000000 0x00 0x20000000 0x00 +- 0x20000000 0x00 0x10000000>; + clocks = <&infracfg CLK_INFRA_IPCIE_PIPE_CK>, + <&infracfg CLK_INFRA_IPCIE_CK>, + <&infracfg CLK_INFRA_IPCIER_CK>, + <&infracfg CLK_INFRA_IPCIEB_CK>; + clock-names = "pl_250m", "tl_26m", "peri_26m", "top_133m"; +- status = "disabled"; + + phys = <&pcie_port PHY_TYPE_PCIE>; + phy-names = "pcie-phy"; +@@ -427,6 +419,8 @@ pcie: pcie@11280000 { + <0 0 0 2 &pcie_intc 1>, + <0 0 0 3 &pcie_intc 2>, + <0 0 0 4 &pcie_intc 3>; ++ status = "disabled"; ++ + pcie_intc: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; +@@ -437,9 +431,9 @@ pcie_intc: interrupt-controller { + pcie_phy: t-phy { + compatible = "mediatek,mt7986-tphy", + "mediatek,generic-tphy-v2"; ++ ranges; + #address-cells = <2>; + #size-cells = <2>; +- ranges; + status = "disabled"; + + pcie_port: pcie-phy@11c00000 { +@@ -464,9 +458,9 @@ thermal_calibration: calib@274 { + usb_phy: t-phy@11e10000 { + compatible = "mediatek,mt7986-tphy", + "mediatek,generic-tphy-v2"; ++ ranges = <0 0 0x11e10000 0x1700>; + #address-cells = <1>; + #size-cells = <1>; +- ranges = <0 0 0x11e10000 0x1700>; + status = "disabled"; + + u2port0: usb-phy@0 { +@@ -494,8 +488,6 @@ u2port1: usb-phy@1000 { + }; + + ethsys: syscon@15000000 { +- #address-cells = <1>; +- #size-cells = <1>; + compatible = "mediatek,mt7986-ethsys", + "syscon"; + reg = <0 0x15000000 0 0x1000>; +@@ -529,20 +521,6 @@ wed1: wed@15011000 { + mediatek,wo-ccif = <&wo_ccif1>; + }; + +- wo_ccif0: syscon@151a5000 { +- compatible = "mediatek,mt7986-wo-ccif", "syscon"; +- reg = <0 0x151a5000 0 0x1000>; +- interrupt-parent = <&gic>; +- interrupts = ; +- }; +- +- wo_ccif1: syscon@151ad000 { +- compatible = "mediatek,mt7986-wo-ccif", "syscon"; +- reg = <0 0x151ad000 0 0x1000>; +- interrupt-parent = <&gic>; +- interrupts = ; +- }; +- + eth: ethernet@15100000 { + compatible = "mediatek,mt7986-eth"; + reg = <0 0x15100000 0 0x80000>; +@@ -575,26 +553,39 @@ eth: ethernet@15100000 { + <&topckgen CLK_TOP_SGM_325M_SEL>; + assigned-clock-parents = <&apmixedsys CLK_APMIXED_NET2PLL>, + <&apmixedsys CLK_APMIXED_SGMPLL>; ++ #address-cells = <1>; ++ #size-cells = <0>; + mediatek,ethsys = <ðsys>; + mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>; + mediatek,wed-pcie = <&wed_pcie>; + mediatek,wed = <&wed0>, <&wed1>; +- #reset-cells = <1>; +- #address-cells = <1>; +- #size-cells = <0>; + status = "disabled"; + }; + ++ wo_ccif0: syscon@151a5000 { ++ compatible = "mediatek,mt7986-wo-ccif", "syscon"; ++ reg = <0 0x151a5000 0 0x1000>; ++ interrupt-parent = <&gic>; ++ interrupts = ; ++ }; ++ ++ wo_ccif1: syscon@151ad000 { ++ compatible = "mediatek,mt7986-wo-ccif", "syscon"; ++ reg = <0 0x151ad000 0 0x1000>; ++ interrupt-parent = <&gic>; ++ interrupts = ; ++ }; ++ + wifi: wifi@18000000 { + compatible = "mediatek,mt7986-wmac"; ++ reg = <0 0x18000000 0 0x1000000>, ++ <0 0x10003000 0 0x1000>, ++ <0 0x11d10000 0 0x1000>; + resets = <&watchdog MT7986_TOPRGU_CONSYS_SW_RST>; + reset-names = "consys"; + clocks = <&topckgen CLK_TOP_CONN_MCUSYS_SEL>, + <&topckgen CLK_TOP_AP2CNN_HOST_SEL>; + clock-names = "mcu", "ap2conn"; +- reg = <0 0x18000000 0 0x1000000>, +- <0 0x10003000 0 0x1000>, +- <0 0x11d10000 0 0x1000>; + interrupts = , + , + , +@@ -610,24 +601,45 @@ cpu_thermal: cpu-thermal { + thermal-sensors = <&thermal 0>; + + trips { ++ cpu_trip_crit: crit { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ ++ cpu_trip_hot: hot { ++ temperature = <120000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ + cpu_trip_active_high: active-high { + temperature = <115000>; + hysteresis = <2000>; + type = "active"; + }; + +- cpu_trip_active_low: active-low { ++ cpu_trip_active_med: active-med { + temperature = <85000>; + hysteresis = <2000>; + type = "active"; + }; + +- cpu_trip_passive: passive { +- temperature = <40000>; ++ cpu_trip_active_low: active-low { ++ temperature = <60000>; + hysteresis = <2000>; +- type = "passive"; ++ type = "active"; + }; + }; + }; + }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupt-parent = <&gic>; ++ interrupts = , ++ , ++ , ++ ; ++ }; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts b/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts +index dde190442e3866..57dcaeef31d7fc 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts +@@ -152,12 +152,13 @@ &spi0 { + pinctrl-0 = <&spi_flash_pins>; + cs-gpios = <0>, <0>; + status = "okay"; +- spi_nand: spi_nand@0 { ++ ++ spi_nand: flash@0 { + compatible = "spi-nand"; + reg = <0>; + spi-max-frequency = <10000000>; +- spi-tx-buswidth = <4>; +- spi-rx-buswidth = <4>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; + }; + }; + +diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts +index 5122963d8743ab..d258c80213b264 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts +@@ -44,7 +44,7 @@ extcon_usb: extcon_iddig { + id-gpio = <&pio 16 GPIO_ACTIVE_HIGH>; + }; + +- usb_p1_vbus: regulator@0 { ++ usb_p1_vbus: regulator-usb-p1 { + compatible = "regulator-fixed"; + regulator-name = "usb_vbus"; + regulator-min-microvolt = <5000000>; +@@ -53,7 +53,7 @@ usb_p1_vbus: regulator@0 { + enable-active-high; + }; + +- usb_p0_vbus: regulator@1 { ++ usb_p0_vbus: regulator-usb-p0 { + compatible = "regulator-fixed"; + regulator-name = "vbus"; + regulator-min-microvolt = <5000000>; +diff --git a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts +index d8bd5180768327..77f9ab94c00bd9 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts +@@ -31,14 +31,14 @@ reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; +- scp_mem_reserved: scp_mem_region { ++ scp_mem_reserved: memory@50000000 { + compatible = "shared-dma-pool"; + reg = <0 0x50000000 0 0x2900000>; + no-map; + }; + }; + +- ntc@0 { ++ thermal-sensor { + compatible = "murata,ncp03wf104"; + pullup-uv = <1800000>; + pullup-ohm = <390000>; +@@ -155,8 +155,8 @@ &mt6358_vsram_gpu_reg { + }; + + &pio { +- i2c_pins_0: i2c0{ +- pins_i2c{ ++ i2c_pins_0: i2c0 { ++ pins_i2c { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +@@ -164,8 +164,8 @@ pins_i2c{ + }; + }; + +- i2c_pins_1: i2c1{ +- pins_i2c{ ++ i2c_pins_1: i2c1 { ++ pins_i2c { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +@@ -173,8 +173,8 @@ pins_i2c{ + }; + }; + +- i2c_pins_2: i2c2{ +- pins_i2c{ ++ i2c_pins_2: i2c2 { ++ pins_i2c { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +@@ -182,8 +182,8 @@ pins_i2c{ + }; + }; + +- i2c_pins_3: i2c3{ +- pins_i2c{ ++ i2c_pins_3: i2c3 { ++ pins_i2c { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +@@ -191,8 +191,8 @@ pins_i2c{ + }; + }; + +- i2c_pins_4: i2c4{ +- pins_i2c{ ++ i2c_pins_4: i2c4 { ++ pins_i2c { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +@@ -200,8 +200,8 @@ pins_i2c{ + }; + }; + +- i2c_pins_5: i2c5{ +- pins_i2c{ ++ i2c_pins_5: i2c5 { ++ pins_i2c { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +@@ -209,8 +209,8 @@ pins_i2c{ + }; + }; + +- spi_pins_0: spi0{ +- pins_spi{ ++ spi_pins_0: spi0 { ++ pins_spi { + pinmux = , + , + , +@@ -324,8 +324,8 @@ pins_clk { + }; + }; + +- spi_pins_1: spi1{ +- pins_spi{ ++ spi_pins_1: spi1 { ++ pins_spi { + pinmux = , + , + , +@@ -334,8 +334,8 @@ pins_spi{ + }; + }; + +- spi_pins_2: spi2{ +- pins_spi{ ++ spi_pins_2: spi2 { ++ pins_spi { + pinmux = , + , + , +@@ -344,8 +344,8 @@ pins_spi{ + }; + }; + +- spi_pins_3: spi3{ +- pins_spi{ ++ spi_pins_3: spi3 { ++ pins_spi { + pinmux = , + , + , +@@ -354,8 +354,8 @@ pins_spi{ + }; + }; + +- spi_pins_4: spi4{ +- pins_spi{ ++ spi_pins_4: spi4 { ++ pins_spi { + pinmux = , + , + , +@@ -364,8 +364,8 @@ pins_spi{ + }; + }; + +- spi_pins_5: spi5{ +- pins_spi{ ++ spi_pins_5: spi5 { ++ pins_spi { + pinmux = , + , + , +diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-audio-da7219.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-audio-da7219.dtsi +index 2c69e7658dba6d..b9a6fd4f86d4a0 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-audio-da7219.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-audio-da7219.dtsi +@@ -28,7 +28,7 @@ da7219_aad { + dlg,btn-cfg = <50>; + dlg,mic-det-thr = <500>; + dlg,jack-ins-deb = <20>; +- dlg,jack-det-rate = "32ms_64ms"; ++ dlg,jack-det-rate = "32_64"; + dlg,jack-rem-deb = <1>; + + dlg,a-d-btn-thr = <0xa>; +diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi +index bf97b60ae4d17e..32f6899f885ef7 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi +@@ -91,6 +91,8 @@ cros_ec_pwm: pwm { + + &dsi0 { + status = "okay"; ++ /delete-property/#size-cells; ++ /delete-property/#address-cells; + /delete-node/panel@0; + ports { + port { +@@ -154,21 +156,24 @@ anx_bridge: anx7625@58 { + vdd18-supply = <&pp1800_mipibrdg>; + vdd33-supply = <&vddio_mipibrdg>; + +- #address-cells = <1>; +- #size-cells = <0>; +- port@0 { +- reg = <0>; ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; + +- anx7625_in: endpoint { +- remote-endpoint = <&dsi_out>; ++ port@0 { ++ reg = <0>; ++ ++ anx7625_in: endpoint { ++ remote-endpoint = <&dsi_out>; ++ }; + }; +- }; + +- port@1 { +- reg = <1>; ++ port@1 { ++ reg = <1>; + +- anx7625_out: endpoint { +- remote-endpoint = <&panel_in>; ++ anx7625_out: endpoint { ++ remote-endpoint = <&panel_in>; ++ }; + }; + }; + +@@ -441,20 +446,20 @@ pins2 { + }; + + touchscreen_pins: touchscreen-pins { +- touch_int_odl { ++ touch-int-odl { + pinmux = ; + input-enable; + bias-pull-up; + }; + +- touch_rst_l { ++ touch-rst-l { + pinmux = ; + output-high; + }; + }; + + trackpad_pins: trackpad-pins { +- trackpad_int { ++ trackpad-int { + pinmux = ; + input-enable; + bias-disable; /* pulled externally */ +diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi +index a11adeb29b1f2e..0d3c7b8162ff0b 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi +@@ -373,6 +373,10 @@ pen_eject { + }; + + &cros_ec { ++ cbas { ++ compatible = "google,cros-cbas"; ++ }; ++ + keyboard-controller { + compatible = "google,cros-ec-keyb-switches"; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi +index 4864c39e53a4fd..e73113cb51f538 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi +@@ -340,6 +340,10 @@ touch_pin_reset: pin_reset { + }; + + &cros_ec { ++ cbas { ++ compatible = "google,cros-cbas"; ++ }; ++ + keyboard-controller { + compatible = "google,cros-ec-keyb-switches"; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi +index d5f41c6c98814a..181da69d18f46a 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi +@@ -344,6 +344,10 @@ rst_pin { + }; + + &cros_ec { ++ cbas { ++ compatible = "google,cros-cbas"; ++ }; ++ + keyboard-controller { + compatible = "google,cros-ec-keyb-switches"; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi +index 6ce16a265e0530..2c6587f260f82b 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi +@@ -108,7 +108,7 @@ reserved_memory: reserved-memory { + #size-cells = <2>; + ranges; + +- scp_mem_reserved: scp_mem_region { ++ scp_mem_reserved: memory@50000000 { + compatible = "shared-dma-pool"; + reg = <0 0x50000000 0 0x2900000>; + no-map; +@@ -405,7 +405,6 @@ &mt6358codec { + }; + + &mt6358_vgpu_reg { +- regulator-min-microvolt = <625000>; + regulator-max-microvolt = <900000>; + + regulator-coupled-with = <&mt6358_vsram_gpu_reg>; +@@ -432,7 +431,7 @@ &mt6358_vsram_gpu_reg { + + &pio { + aud_pins_default: audiopins { +- pins_bus { ++ pins-bus { + pinmux = , + , + , +@@ -454,7 +453,7 @@ pins_bus { + }; + + aud_pins_tdm_out_on: audiotdmouton { +- pins_bus { ++ pins-bus { + pinmux = , + , + , +@@ -466,7 +465,7 @@ pins_bus { + }; + + aud_pins_tdm_out_off: audiotdmoutoff { +- pins_bus { ++ pins-bus { + pinmux = , + , + , +@@ -480,13 +479,13 @@ pins_bus { + }; + + bt_pins: bt-pins { +- pins_bt_en { ++ pins-bt-en { + pinmux = ; + output-low; + }; + }; + +- ec_ap_int_odl: ec_ap_int_odl { ++ ec_ap_int_odl: ec-ap-int-odl { + pins1 { + pinmux = ; + input-enable; +@@ -494,7 +493,7 @@ pins1 { + }; + }; + +- h1_int_od_l: h1_int_od_l { ++ h1_int_od_l: h1-int-od-l { + pins1 { + pinmux = ; + input-enable; +@@ -502,7 +501,7 @@ pins1 { + }; + + i2c0_pins: i2c0 { +- pins_bus { ++ pins-bus { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +@@ -511,7 +510,7 @@ pins_bus { + }; + + i2c1_pins: i2c1 { +- pins_bus { ++ pins-bus { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +@@ -520,7 +519,7 @@ pins_bus { + }; + + i2c2_pins: i2c2 { +- pins_bus { ++ pins-bus { + pinmux = , + ; + bias-disable; +@@ -529,7 +528,7 @@ pins_bus { + }; + + i2c3_pins: i2c3 { +- pins_bus { ++ pins-bus { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +@@ -538,7 +537,7 @@ pins_bus { + }; + + i2c4_pins: i2c4 { +- pins_bus { ++ pins-bus { + pinmux = , + ; + bias-disable; +@@ -547,7 +546,7 @@ pins_bus { + }; + + i2c5_pins: i2c5 { +- pins_bus { ++ pins-bus { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +@@ -556,7 +555,7 @@ pins_bus { + }; + + i2c6_pins: i2c6 { +- pins_bus { ++ pins-bus { + pinmux = , + ; + bias-disable; +@@ -564,7 +563,7 @@ pins_bus { + }; + + mmc0_pins_default: mmc0-pins-default { +- pins_cmd_dat { ++ pins-cmd-dat { + pinmux = , + , + , +@@ -579,13 +578,13 @@ pins_cmd_dat { + mediatek,pull-up-adv = <01>; + }; + +- pins_clk { ++ pins-clk { + pinmux = ; + drive-strength = ; + mediatek,pull-down-adv = <10>; + }; + +- pins_rst { ++ pins-rst { + pinmux = ; + drive-strength = ; + mediatek,pull-down-adv = <01>; +@@ -593,7 +592,7 @@ pins_rst { + }; + + mmc0_pins_uhs: mmc0-pins-uhs { +- pins_cmd_dat { ++ pins-cmd-dat { + pinmux = , + , + , +@@ -608,19 +607,19 @@ pins_cmd_dat { + mediatek,pull-up-adv = <01>; + }; + +- pins_clk { ++ pins-clk { + pinmux = ; + drive-strength = ; + mediatek,pull-down-adv = <10>; + }; + +- pins_ds { ++ pins-ds { + pinmux = ; + drive-strength = ; + mediatek,pull-down-adv = <10>; + }; + +- pins_rst { ++ pins-rst { + pinmux = ; + drive-strength = ; + mediatek,pull-up-adv = <01>; +@@ -628,7 +627,7 @@ pins_rst { + }; + + mmc1_pins_default: mmc1-pins-default { +- pins_cmd_dat { ++ pins-cmd-dat { + pinmux = , + , + , +@@ -638,7 +637,7 @@ pins_cmd_dat { + mediatek,pull-up-adv = <10>; + }; + +- pins_clk { ++ pins-clk { + pinmux = ; + input-enable; + mediatek,pull-down-adv = <10>; +@@ -646,7 +645,7 @@ pins_clk { + }; + + mmc1_pins_uhs: mmc1-pins-uhs { +- pins_cmd_dat { ++ pins-cmd-dat { + pinmux = , + , + , +@@ -657,7 +656,7 @@ pins_cmd_dat { + mediatek,pull-up-adv = <10>; + }; + +- pins_clk { ++ pins-clk { + pinmux = ; + drive-strength = ; + mediatek,pull-down-adv = <10>; +@@ -665,15 +664,15 @@ pins_clk { + }; + }; + +- panel_pins_default: panel_pins_default { +- panel_reset { ++ panel_pins_default: panel-pins-default { ++ panel-reset { + pinmux = ; + output-low; + bias-pull-up; + }; + }; + +- pwm0_pin_default: pwm0_pin_default { ++ pwm0_pin_default: pwm0-pin-default { + pins1 { + pinmux = ; + output-high; +@@ -685,14 +684,14 @@ pins2 { + }; + + scp_pins: scp { +- pins_scp_uart { ++ pins-scp-uart { + pinmux = , + ; + }; + }; + + spi0_pins: spi0 { +- pins_spi{ ++ pins-spi { + pinmux = , + , + , +@@ -702,7 +701,7 @@ pins_spi{ + }; + + spi1_pins: spi1 { +- pins_spi{ ++ pins-spi { + pinmux = , + , + , +@@ -712,20 +711,20 @@ pins_spi{ + }; + + spi2_pins: spi2 { +- pins_spi{ ++ pins-spi { + pinmux = , + , + ; + bias-disable; + }; +- pins_spi_mi { ++ pins-spi-mi { + pinmux = ; + mediatek,pull-down-adv = <00>; + }; + }; + + spi3_pins: spi3 { +- pins_spi{ ++ pins-spi { + pinmux = , + , + , +@@ -735,7 +734,7 @@ pins_spi{ + }; + + spi4_pins: spi4 { +- pins_spi{ ++ pins-spi { + pinmux = , + , + , +@@ -745,7 +744,7 @@ pins_spi{ + }; + + spi5_pins: spi5 { +- pins_spi{ ++ pins-spi { + pinmux = , + , + , +@@ -755,63 +754,61 @@ pins_spi{ + }; + + uart0_pins_default: uart0-pins-default { +- pins_rx { ++ pins-rx { + pinmux = ; + input-enable; + bias-pull-up; + }; +- pins_tx { ++ pins-tx { + pinmux = ; + }; + }; + + uart1_pins_default: uart1-pins-default { +- pins_rx { ++ pins-rx { + pinmux = ; + input-enable; + bias-pull-up; + }; +- pins_tx { ++ pins-tx { + pinmux = ; + }; +- pins_rts { ++ pins-rts { + pinmux = ; +- output-enable; + }; +- pins_cts { ++ pins-cts { + pinmux = ; + input-enable; + }; + }; + + uart1_pins_sleep: uart1-pins-sleep { +- pins_rx { ++ pins-rx { + pinmux = ; + input-enable; + bias-pull-up; + }; +- pins_tx { ++ pins-tx { + pinmux = ; + }; +- pins_rts { ++ pins-rts { + pinmux = ; +- output-enable; + }; +- pins_cts { ++ pins-cts { + pinmux = ; + input-enable; + }; + }; + + wifi_pins_pwrseq: wifi-pins-pwrseq { +- pins_wifi_enable { ++ pins-wifi-enable { + pinmux = ; + output-low; + }; + }; + + wifi_pins_wakeup: wifi-pins-wakeup { +- pins_wifi_wakeup { ++ pins-wifi-wakeup { + pinmux = ; + input-enable; + }; +@@ -907,10 +904,6 @@ usbc_extcon: extcon0 { + google,usb-port-id = <0>; + }; + +- cbas { +- compatible = "google,cros-cbas"; +- }; +- + typec { + compatible = "google,cros-ec-typec"; + #address-cells = <1>; +diff --git a/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts b/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts +index 526bcae7a3f8ff..b5784a60c315d3 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts +@@ -193,7 +193,7 @@ &mt6358_vsram_gpu_reg { + + &pio { + i2c_pins_0: i2c0 { +- pins_i2c{ ++ pins_i2c { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +@@ -202,7 +202,7 @@ pins_i2c{ + }; + + i2c_pins_1: i2c1 { +- pins_i2c{ ++ pins_i2c { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +@@ -211,7 +211,7 @@ pins_i2c{ + }; + + i2c_pins_2: i2c2 { +- pins_i2c{ ++ pins_i2c { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +@@ -220,7 +220,7 @@ pins_i2c{ + }; + + i2c_pins_3: i2c3 { +- pins_i2c{ ++ pins_i2c { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +@@ -229,7 +229,7 @@ pins_i2c{ + }; + + i2c_pins_4: i2c4 { +- pins_i2c{ ++ pins_i2c { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +@@ -238,7 +238,7 @@ pins_i2c{ + }; + + i2c_pins_5: i2c5 { +- pins_i2c{ ++ pins_i2c { + pinmux = , + ; + mediatek,pull-up-adv = <3>; +diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi +index 5169779d01dfb4..8721a5ffca30a7 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi +@@ -1210,127 +1210,6 @@ thermal: thermal@1100b000 { + nvmem-cell-names = "calibration-data"; + }; + +- thermal_zones: thermal-zones { +- cpu_thermal: cpu-thermal { +- polling-delay-passive = <100>; +- polling-delay = <500>; +- thermal-sensors = <&thermal 0>; +- sustainable-power = <5000>; +- +- trips { +- threshold: trip-point0 { +- temperature = <68000>; +- hysteresis = <2000>; +- type = "passive"; +- }; +- +- target: trip-point1 { +- temperature = <80000>; +- hysteresis = <2000>; +- type = "passive"; +- }; +- +- cpu_crit: cpu-crit { +- temperature = <115000>; +- hysteresis = <2000>; +- type = "critical"; +- }; +- }; +- +- cooling-maps { +- map0 { +- trip = <&target>; +- cooling-device = <&cpu0 +- THERMAL_NO_LIMIT +- THERMAL_NO_LIMIT>, +- <&cpu1 +- THERMAL_NO_LIMIT +- THERMAL_NO_LIMIT>, +- <&cpu2 +- THERMAL_NO_LIMIT +- THERMAL_NO_LIMIT>, +- <&cpu3 +- THERMAL_NO_LIMIT +- THERMAL_NO_LIMIT>; +- contribution = <3072>; +- }; +- map1 { +- trip = <&target>; +- cooling-device = <&cpu4 +- THERMAL_NO_LIMIT +- THERMAL_NO_LIMIT>, +- <&cpu5 +- THERMAL_NO_LIMIT +- THERMAL_NO_LIMIT>, +- <&cpu6 +- THERMAL_NO_LIMIT +- THERMAL_NO_LIMIT>, +- <&cpu7 +- THERMAL_NO_LIMIT +- THERMAL_NO_LIMIT>; +- contribution = <1024>; +- }; +- }; +- }; +- +- /* The tzts1 ~ tzts6 don't need to polling */ +- /* The tzts1 ~ tzts6 don't need to thermal throttle */ +- +- tzts1: tzts1 { +- polling-delay-passive = <0>; +- polling-delay = <0>; +- thermal-sensors = <&thermal 1>; +- sustainable-power = <5000>; +- trips {}; +- cooling-maps {}; +- }; +- +- tzts2: tzts2 { +- polling-delay-passive = <0>; +- polling-delay = <0>; +- thermal-sensors = <&thermal 2>; +- sustainable-power = <5000>; +- trips {}; +- cooling-maps {}; +- }; +- +- tzts3: tzts3 { +- polling-delay-passive = <0>; +- polling-delay = <0>; +- thermal-sensors = <&thermal 3>; +- sustainable-power = <5000>; +- trips {}; +- cooling-maps {}; +- }; +- +- tzts4: tzts4 { +- polling-delay-passive = <0>; +- polling-delay = <0>; +- thermal-sensors = <&thermal 4>; +- sustainable-power = <5000>; +- trips {}; +- cooling-maps {}; +- }; +- +- tzts5: tzts5 { +- polling-delay-passive = <0>; +- polling-delay = <0>; +- thermal-sensors = <&thermal 5>; +- sustainable-power = <5000>; +- trips {}; +- cooling-maps {}; +- }; +- +- tztsABB: tztsABB { +- polling-delay-passive = <0>; +- polling-delay = <0>; +- thermal-sensors = <&thermal 6>; +- sustainable-power = <5000>; +- trips {}; +- cooling-maps {}; +- }; +- }; +- + pwm0: pwm@1100e000 { + compatible = "mediatek,mt8183-disp-pwm"; + reg = <0 0x1100e000 0 0x1000>; +@@ -1749,6 +1628,7 @@ mfgcfg: syscon@13000000 { + compatible = "mediatek,mt8183-mfgcfg", "syscon"; + reg = <0 0x13000000 0 0x1000>; + #clock-cells = <1>; ++ power-domains = <&spm MT8183_POWER_DOMAIN_MFG_ASYNC>; + }; + + gpu: gpu@13040000 { +@@ -1781,7 +1661,7 @@ mmsys: syscon@14000000 { + mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0 0x1000>; + }; + +- mdp3-rdma0@14001000 { ++ dma-controller0@14001000 { + compatible = "mediatek,mt8183-mdp3-rdma"; + reg = <0 0x14001000 0 0x1000>; + mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x1000 0x1000>; +@@ -1793,6 +1673,7 @@ mdp3-rdma0@14001000 { + iommus = <&iommu M4U_PORT_MDP_RDMA0>; + mboxes = <&gce 20 CMDQ_THR_PRIO_LOWEST 0>, + <&gce 21 CMDQ_THR_PRIO_LOWEST 0>; ++ #dma-cells = <1>; + }; + + mdp3-rsz0@14003000 { +@@ -1813,7 +1694,7 @@ mdp3-rsz1@14004000 { + clocks = <&mmsys CLK_MM_MDP_RSZ1>; + }; + +- mdp3-wrot0@14005000 { ++ dma-controller@14005000 { + compatible = "mediatek,mt8183-mdp3-wrot"; + reg = <0 0x14005000 0 0x1000>; + mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x5000 0x1000>; +@@ -1822,6 +1703,7 @@ mdp3-wrot0@14005000 { + power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; + clocks = <&mmsys CLK_MM_MDP_WROT0>; + iommus = <&iommu M4U_PORT_MDP_WROT0>; ++ #dma-cells = <1>; + }; + + mdp3-wdma@14006000 { +@@ -2105,4 +1987,125 @@ larb3: larb@1a002000 { + power-domains = <&spm MT8183_POWER_DOMAIN_CAM>; + }; + }; ++ ++ thermal_zones: thermal-zones { ++ cpu_thermal: cpu-thermal { ++ polling-delay-passive = <100>; ++ polling-delay = <500>; ++ thermal-sensors = <&thermal 0>; ++ sustainable-power = <5000>; ++ ++ trips { ++ threshold: trip-point0 { ++ temperature = <68000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ ++ target: trip-point1 { ++ temperature = <80000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ ++ cpu_crit: cpu-crit { ++ temperature = <115000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map0 { ++ trip = <&target>; ++ cooling-device = <&cpu0 ++ THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>, ++ <&cpu1 ++ THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>, ++ <&cpu2 ++ THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>, ++ <&cpu3 ++ THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>; ++ contribution = <3072>; ++ }; ++ map1 { ++ trip = <&target>; ++ cooling-device = <&cpu4 ++ THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>, ++ <&cpu5 ++ THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>, ++ <&cpu6 ++ THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>, ++ <&cpu7 ++ THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>; ++ contribution = <1024>; ++ }; ++ }; ++ }; ++ ++ /* The tzts1 ~ tzts6 don't need to polling */ ++ /* The tzts1 ~ tzts6 don't need to thermal throttle */ ++ ++ tzts1: tzts1 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&thermal 1>; ++ sustainable-power = <5000>; ++ trips {}; ++ cooling-maps {}; ++ }; ++ ++ tzts2: tzts2 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&thermal 2>; ++ sustainable-power = <5000>; ++ trips {}; ++ cooling-maps {}; ++ }; ++ ++ tzts3: tzts3 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&thermal 3>; ++ sustainable-power = <5000>; ++ trips {}; ++ cooling-maps {}; ++ }; ++ ++ tzts4: tzts4 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&thermal 4>; ++ sustainable-power = <5000>; ++ trips {}; ++ cooling-maps {}; ++ }; ++ ++ tzts5: tzts5 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&thermal 5>; ++ sustainable-power = <5000>; ++ trips {}; ++ cooling-maps {}; ++ }; ++ ++ tztsABB: tztsABB { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&thermal 6>; ++ sustainable-power = <5000>; ++ trips {}; ++ cooling-maps {}; ++ }; ++ }; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt8186.dtsi b/arch/arm64/boot/dts/mediatek/mt8186.dtsi +index f04ae70c470aa3..2c184f9e0fc390 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8186.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8186.dtsi +@@ -22,7 +22,7 @@ / { + + aliases { + ovl0 = &ovl0; +- ovl_2l0 = &ovl_2l0; ++ ovl-2l0 = &ovl_2l0; + rdma0 = &rdma0; + rdma1 = &rdma1; + }; +@@ -731,7 +731,7 @@ opp-850000000 { + opp-900000000-3 { + opp-hz = /bits/ 64 <900000000>; + opp-microvolt = <850000>; +- opp-supported-hw = <0x8>; ++ opp-supported-hw = <0xcf>; + }; + + opp-900000000-4 { +@@ -743,13 +743,13 @@ opp-900000000-4 { + opp-900000000-5 { + opp-hz = /bits/ 64 <900000000>; + opp-microvolt = <825000>; +- opp-supported-hw = <0x30>; ++ opp-supported-hw = <0x20>; + }; + + opp-950000000-3 { + opp-hz = /bits/ 64 <950000000>; + opp-microvolt = <900000>; +- opp-supported-hw = <0x8>; ++ opp-supported-hw = <0xcf>; + }; + + opp-950000000-4 { +@@ -761,13 +761,13 @@ opp-950000000-4 { + opp-950000000-5 { + opp-hz = /bits/ 64 <950000000>; + opp-microvolt = <850000>; +- opp-supported-hw = <0x30>; ++ opp-supported-hw = <0x20>; + }; + + opp-1000000000-3 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <950000>; +- opp-supported-hw = <0x8>; ++ opp-supported-hw = <0xcf>; + }; + + opp-1000000000-4 { +@@ -779,7 +779,7 @@ opp-1000000000-4 { + opp-1000000000-5 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <875000>; +- opp-supported-hw = <0x30>; ++ opp-supported-hw = <0x20>; + }; + }; + +@@ -924,17 +924,24 @@ power-domain@MT8186_POWER_DOMAIN_CSIRX_TOP { + reg = ; + clocks = <&topckgen CLK_TOP_SENINF>, + <&topckgen CLK_TOP_SENINF1>; +- clock-names = "csirx_top0", "csirx_top1"; ++ clock-names = "subsys-csirx-top0", ++ "subsys-csirx-top1"; + #power-domain-cells = <0>; + }; + + power-domain@MT8186_POWER_DOMAIN_SSUSB { + reg = ; ++ clocks = <&topckgen CLK_TOP_USB_TOP>, ++ <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_REF>; ++ clock-names = "sys_ck", "ref_ck"; + #power-domain-cells = <0>; + }; + + power-domain@MT8186_POWER_DOMAIN_SSUSB_P1 { + reg = ; ++ clocks = <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_SYS>, ++ <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_REF>; ++ clock-names = "sys_ck", "ref_ck"; + #power-domain-cells = <0>; + }; + +@@ -942,7 +949,8 @@ power-domain@MT8186_POWER_DOMAIN_ADSP_AO { + reg = ; + clocks = <&topckgen CLK_TOP_AUDIODSP>, + <&topckgen CLK_TOP_ADSP_BUS>; +- clock-names = "audioadsp", "adsp_bus"; ++ clock-names = "audioadsp", ++ "subsys-adsp-bus"; + #address-cells = <1>; + #size-cells = <0>; + #power-domain-cells = <1>; +@@ -975,8 +983,11 @@ power-domain@MT8186_POWER_DOMAIN_DIS { + <&mmsys CLK_MM_SMI_COMMON>, + <&mmsys CLK_MM_SMI_GALS>, + <&mmsys CLK_MM_SMI_IOMMU>; +- clock-names = "disp", "mdp", "smi_infra", "smi_common", +- "smi_gals", "smi_iommu"; ++ clock-names = "disp", "mdp", ++ "subsys-smi-infra", ++ "subsys-smi-common", ++ "subsys-smi-gals", ++ "subsys-smi-iommu"; + mediatek,infracfg = <&infracfg_ao>; + #address-cells = <1>; + #size-cells = <0>; +@@ -993,15 +1004,17 @@ power-domain@MT8186_POWER_DOMAIN_VDEC { + + power-domain@MT8186_POWER_DOMAIN_CAM { + reg = ; +- clocks = <&topckgen CLK_TOP_CAM>, +- <&topckgen CLK_TOP_SENINF>, ++ clocks = <&topckgen CLK_TOP_SENINF>, + <&topckgen CLK_TOP_SENINF1>, + <&topckgen CLK_TOP_SENINF2>, + <&topckgen CLK_TOP_SENINF3>, ++ <&camsys CLK_CAM2MM_GALS>, + <&topckgen CLK_TOP_CAMTM>, +- <&camsys CLK_CAM2MM_GALS>; +- clock-names = "cam-top", "cam0", "cam1", "cam2", +- "cam3", "cam-tm", "gals"; ++ <&topckgen CLK_TOP_CAM>; ++ clock-names = "cam0", "cam1", "cam2", ++ "cam3", "gals", ++ "subsys-cam-tm", ++ "subsys-cam-top"; + mediatek,infracfg = <&infracfg_ao>; + #address-cells = <1>; + #size-cells = <0>; +@@ -1020,9 +1033,9 @@ power-domain@MT8186_POWER_DOMAIN_CAM_RAWA { + + power-domain@MT8186_POWER_DOMAIN_IMG { + reg = ; +- clocks = <&topckgen CLK_TOP_IMG1>, +- <&imgsys1 CLK_IMG1_GALS_IMG1>; +- clock-names = "img-top", "gals"; ++ clocks = <&imgsys1 CLK_IMG1_GALS_IMG1>, ++ <&topckgen CLK_TOP_IMG1>; ++ clock-names = "gals", "subsys-img-top"; + mediatek,infracfg = <&infracfg_ao>; + #address-cells = <1>; + #size-cells = <0>; +@@ -1041,8 +1054,11 @@ power-domain@MT8186_POWER_DOMAIN_IPE { + <&ipesys CLK_IPE_LARB20>, + <&ipesys CLK_IPE_SMI_SUBCOM>, + <&ipesys CLK_IPE_GALS_IPE>; +- clock-names = "ipe-top", "ipe-larb0", "ipe-larb1", +- "ipe-smi", "ipe-gals"; ++ clock-names = "subsys-ipe-top", ++ "subsys-ipe-larb0", ++ "subsys-ipe-larb1", ++ "subsys-ipe-smi", ++ "subsys-ipe-gals"; + mediatek,infracfg = <&infracfg_ao>; + #power-domain-cells = <0>; + }; +@@ -1051,7 +1067,7 @@ power-domain@MT8186_POWER_DOMAIN_VENC { + reg = ; + clocks = <&topckgen CLK_TOP_VENC>, + <&vencsys CLK_VENC_CKE1_VENC>; +- clock-names = "venc0", "larb"; ++ clock-names = "venc0", "subsys-larb"; + mediatek,infracfg = <&infracfg_ao>; + #power-domain-cells = <0>; + }; +@@ -1061,7 +1077,9 @@ power-domain@MT8186_POWER_DOMAIN_WPE { + clocks = <&topckgen CLK_TOP_WPE>, + <&wpesys CLK_WPE_SMI_LARB8_CK_EN>, + <&wpesys CLK_WPE_SMI_LARB8_PCLK_EN>; +- clock-names = "wpe0", "larb-ck", "larb-pclk"; ++ clock-names = "wpe0", ++ "subsys-larb-ck", ++ "subsys-larb-pclk"; + mediatek,infracfg = <&infracfg_ao>; + #power-domain-cells = <0>; + }; +@@ -1148,14 +1166,14 @@ adsp: adsp@10680000 { + status = "disabled"; + }; + +- adsp_mailbox0: mailbox@10686000 { ++ adsp_mailbox0: mailbox@10686100 { + compatible = "mediatek,mt8186-adsp-mbox"; + #mbox-cells = <0>; + reg = <0 0x10686100 0 0x1000>; + interrupts = ; + }; + +- adsp_mailbox1: mailbox@10687000 { ++ adsp_mailbox1: mailbox@10687100 { + compatible = "mediatek,mt8186-adsp-mbox"; + #mbox-cells = <0>; + reg = <0 0x10687100 0 0x1000>; +@@ -1518,8 +1536,9 @@ ssusb0: usb@11201000 { + clocks = <&topckgen CLK_TOP_USB_TOP>, + <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_REF>, + <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_HCLK>, +- <&infracfg_ao CLK_INFRA_AO_ICUSB>; +- clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck"; ++ <&infracfg_ao CLK_INFRA_AO_ICUSB>, ++ <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_XHCI>; ++ clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck"; + interrupts = ; + phys = <&u2port0 PHY_TYPE_USB2>; + power-domains = <&spm MT8186_POWER_DOMAIN_SSUSB>; +@@ -1583,8 +1602,9 @@ ssusb1: usb@11281000 { + clocks = <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_SYS>, + <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_REF>, + <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_HCLK>, +- <&clk26m>; +- clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck"; ++ <&clk26m>, ++ <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_XHCI>; ++ clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck"; + interrupts = ; + phys = <&u2port1 PHY_TYPE_USB2>, <&u3port1 PHY_TYPE_USB3>; + power-domains = <&spm MT8186_POWER_DOMAIN_SSUSB_P1>; +@@ -1656,7 +1676,7 @@ efuse: efuse@11cb0000 { + #address-cells = <1>; + #size-cells = <1>; + +- gpu_speedbin: gpu-speed-bin@59c { ++ gpu_speedbin: gpu-speedbin@59c { + reg = <0x59c 0x4>; + bits = <0 3>; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi b/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi +index 0e8b341170907d..6b4b7a7cd35efb 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi +@@ -147,6 +147,7 @@ pp3300_mipibrdg: regulator-3v3-mipibrdg { + regulator-boot-on; + gpio = <&pio 127 GPIO_ACTIVE_HIGH>; + vin-supply = <&pp3300_g>; ++ off-on-delay-us = <500000>; + }; + + /* separately switched 3.3V power rail */ +@@ -1308,10 +1309,6 @@ cros_ec: ec@0 { + #address-cells = <1>; + #size-cells = <0>; + +- base_detection: cbas { +- compatible = "google,cros-cbas"; +- }; +- + cros_ec_pwm: pwm { + compatible = "google,cros-ec-pwm"; + #pwm-cells = <1>; +@@ -1396,7 +1393,7 @@ regulators { + mt6315_6_vbuck1: vbuck1 { + regulator-compatible = "vbuck1"; + regulator-name = "Vbcpu"; +- regulator-min-microvolt = <300000>; ++ regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1193750>; + regulator-enable-ramp-delay = <256>; + regulator-allowed-modes = <0 1 2>; +@@ -1406,7 +1403,7 @@ mt6315_6_vbuck1: vbuck1 { + mt6315_6_vbuck3: vbuck3 { + regulator-compatible = "vbuck3"; + regulator-name = "Vlcpu"; +- regulator-min-microvolt = <300000>; ++ regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1193750>; + regulator-enable-ramp-delay = <256>; + regulator-allowed-modes = <0 1 2>; +@@ -1423,7 +1420,7 @@ regulators { + mt6315_7_vbuck1: vbuck1 { + regulator-compatible = "vbuck1"; + regulator-name = "Vgpu"; +- regulator-min-microvolt = <606250>; ++ regulator-min-microvolt = <400000>; + regulator-max-microvolt = <800000>; + regulator-enable-ramp-delay = <256>; + regulator-allowed-modes = <0 1 2>; +diff --git a/arch/arm64/boot/dts/mediatek/mt8192.dtsi b/arch/arm64/boot/dts/mediatek/mt8192.dtsi +index 69f4cded5dbbf2..b1443adc55aab5 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8192.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8192.dtsi +@@ -1412,6 +1412,7 @@ mutex: mutex@14001000 { + reg = <0 0x14001000 0 0x1000>; + interrupts = ; + clocks = <&mmsys CLK_MM_DISP_MUTEX0>; ++ mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x1000 0x1000>; + mediatek,gce-events = , + ; + power-domains = <&spm MT8192_POWER_DOMAIN_DISP>; +@@ -1770,7 +1771,7 @@ vcodec_enc: vcodec@17020000 { + mediatek,scp = <&scp>; + power-domains = <&spm MT8192_POWER_DOMAIN_VENC>; + clocks = <&vencsys CLK_VENC_SET1_VENC>; +- clock-names = "venc-set1"; ++ clock-names = "venc_sel"; + assigned-clocks = <&topckgen CLK_TOP_VENC_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D4>; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r1.dts b/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r1.dts +index 2d5e8f371b6def..a82d716f10d449 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r1.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r1.dts +@@ -23,3 +23,7 @@ &sound { + &ts_10 { + status = "okay"; + }; ++ ++&watchdog { ++ /delete-property/ mediatek,disable-extrst; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r2.dts b/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r2.dts +index 2586c32ce6e6fe..2fe20e0dad836d 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r2.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r2.dts +@@ -43,3 +43,7 @@ &sound { + &ts_10 { + status = "okay"; + }; ++ ++&watchdog { ++ /delete-property/ mediatek,disable-extrst; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r3.dts b/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r3.dts +index f54f9477b99dad..dd294ca98194cc 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r3.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r3.dts +@@ -44,3 +44,7 @@ &sound { + &ts_10 { + status = "okay"; + }; ++ ++&watchdog { ++ /delete-property/ mediatek,disable-extrst; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi +index 37a3e9de90ff70..34e18eb5d7f450 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi +@@ -114,6 +114,77 @@ ppvar_sys: regulator-ppvar-sys { + regulator-boot-on; + }; + ++ /* Murata NCP03WF104F05RL */ ++ tboard_thermistor1: thermal-sensor-t1 { ++ compatible = "generic-adc-thermal"; ++ #thermal-sensor-cells = <0>; ++ io-channels = <&auxadc 0>; ++ io-channel-names = "sensor-channel"; ++ temperature-lookup-table = < (-10000) 1553 ++ (-5000) 1485 ++ 0 1406 ++ 5000 1317 ++ 10000 1219 ++ 15000 1115 ++ 20000 1007 ++ 25000 900 ++ 30000 796 ++ 35000 697 ++ 40000 605 ++ 45000 523 ++ 50000 449 ++ 55000 384 ++ 60000 327 ++ 65000 279 ++ 70000 237 ++ 75000 202 ++ 80000 172 ++ 85000 147 ++ 90000 125 ++ 95000 107 ++ 100000 92 ++ 105000 79 ++ 110000 68 ++ 115000 59 ++ 120000 51 ++ 125000 44>; ++ }; ++ ++ tboard_thermistor2: thermal-sensor-t2 { ++ compatible = "generic-adc-thermal"; ++ #thermal-sensor-cells = <0>; ++ io-channels = <&auxadc 1>; ++ io-channel-names = "sensor-channel"; ++ temperature-lookup-table = < (-10000) 1553 ++ (-5000) 1485 ++ 0 1406 ++ 5000 1317 ++ 10000 1219 ++ 15000 1115 ++ 20000 1007 ++ 25000 900 ++ 30000 796 ++ 35000 697 ++ 40000 605 ++ 45000 523 ++ 50000 449 ++ 55000 384 ++ 60000 327 ++ 65000 279 ++ 70000 237 ++ 75000 202 ++ 80000 172 ++ 85000 147 ++ 90000 125 ++ 95000 107 ++ 100000 92 ++ 105000 79 ++ 110000 68 ++ 115000 59 ++ 120000 51 ++ 125000 44>; ++ }; ++ + usb_vbus: regulator-5v0-usb-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb-vbus"; +@@ -176,6 +247,42 @@ &afe { + memory-region = <&afe_mem>; + }; + ++&auxadc { ++ status = "okay"; ++}; ++ ++&cpu0 { ++ cpu-supply = <&mt6359_vcore_buck_reg>; ++}; ++ ++&cpu1 { ++ cpu-supply = <&mt6359_vcore_buck_reg>; ++}; ++ ++&cpu2 { ++ cpu-supply = <&mt6359_vcore_buck_reg>; ++}; ++ ++&cpu3 { ++ cpu-supply = <&mt6359_vcore_buck_reg>; ++}; ++ ++&cpu4 { ++ cpu-supply = <&mt6315_6_vbuck1>; ++}; ++ ++&cpu5 { ++ cpu-supply = <&mt6315_6_vbuck1>; ++}; ++ ++&cpu6 { ++ cpu-supply = <&mt6315_6_vbuck1>; ++}; ++ ++&cpu7 { ++ cpu-supply = <&mt6315_6_vbuck1>; ++}; ++ + &dp_intf0 { + status = "okay"; + +@@ -362,7 +469,7 @@ &i2c7 { + pinctrl-0 = <&i2c7_pins>; + + pmic@34 { +- #interrupt-cells = <1>; ++ #interrupt-cells = <2>; + compatible = "mediatek,mt6360"; + reg = <0x34>; + interrupt-controller; +@@ -1098,7 +1205,7 @@ regulators { + mt6315_6_vbuck1: vbuck1 { + regulator-compatible = "vbuck1"; + regulator-name = "Vbcpu"; +- regulator-min-microvolt = <300000>; ++ regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1193750>; + regulator-enable-ramp-delay = <256>; + regulator-ramp-delay = <6250>; +@@ -1116,7 +1223,7 @@ regulators { + mt6315_7_vbuck1: vbuck1 { + regulator-compatible = "vbuck1"; + regulator-name = "Vgpu"; +- regulator-min-microvolt = <625000>; ++ regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1193750>; + regulator-enable-ramp-delay = <256>; + regulator-ramp-delay = <6250>; +@@ -1127,6 +1234,36 @@ mt6315_7_vbuck1: vbuck1 { + }; + }; + ++&thermal_zones { ++ soc-area-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <250>; ++ thermal-sensors = <&tboard_thermistor1>; ++ ++ trips { ++ trip-crit { ++ temperature = <84000>; ++ hysteresis = <1000>; ++ type = "critical"; ++ }; ++ }; ++ }; ++ ++ pmic-area-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <0>; ++ thermal-sensors = <&tboard_thermistor2>; ++ ++ trips { ++ trip-crit { ++ temperature = <84000>; ++ hysteresis = <1000>; ++ type = "critical"; ++ }; ++ }; ++ }; ++}; ++ + &u3phy0 { + status = "okay"; + }; +@@ -1175,6 +1312,7 @@ &xhci3 { + usb2-lpm-disable; + vusb33-supply = <&mt6359_vusb_ldo_reg>; + vbus-supply = <&usb_vbus>; ++ mediatek,u3p-dis-msk = <1>; + }; + + #include +diff --git a/arch/arm64/boot/dts/mediatek/mt8195-demo.dts b/arch/arm64/boot/dts/mediatek/mt8195-demo.dts +index 5d635085fe3fd0..9079e48aea23ea 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8195-demo.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8195-demo.dts +@@ -128,6 +128,7 @@ mt6360: pmic@34 { + compatible = "mediatek,mt6360"; + reg = <0x34>; + interrupt-controller; ++ #interrupt-cells = <1>; + interrupts-extended = <&pio 101 IRQ_TYPE_EDGE_FALLING>; + interrupt-names = "IRQB"; + +diff --git a/arch/arm64/boot/dts/mediatek/mt8195.dtsi b/arch/arm64/boot/dts/mediatek/mt8195.dtsi +index 54c674c45b49a2..d21ba00a5bd5df 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8195.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8195.dtsi +@@ -627,6 +627,8 @@ power-domain@MT8195_POWER_DOMAIN_VDEC1 { + + power-domain@MT8195_POWER_DOMAIN_VENC_CORE1 { + reg = ; ++ clocks = <&vencsys_core1 CLK_VENC_CORE1_LARB>; ++ clock-names = "venc1-larb"; + mediatek,infracfg = <&infracfg_ao>; + #power-domain-cells = <0>; + }; +@@ -689,6 +691,8 @@ power-domain@MT8195_POWER_DOMAIN_VDEC2 { + + power-domain@MT8195_POWER_DOMAIN_VENC { + reg = ; ++ clocks = <&vencsys CLK_VENC_LARB>; ++ clock-names = "venc0-larb"; + mediatek,infracfg = <&infracfg_ao>; + #power-domain-cells = <0>; + }; +@@ -1959,6 +1963,7 @@ vppsys0: syscon@14000000 { + compatible = "mediatek,mt8195-vppsys0", "syscon"; + reg = <0 0x14000000 0 0x1000>; + #clock-cells = <1>; ++ mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0 0x1000>; + }; + + mutex@1400f000 { +@@ -2073,6 +2078,7 @@ vppsys1: syscon@14f00000 { + compatible = "mediatek,mt8195-vppsys1", "syscon"; + reg = <0 0x14f00000 0 0x1000>; + #clock-cells = <1>; ++ mediatek,gce-client-reg = <&gce1 SUBSYS_14f0XXXX 0 0x1000>; + }; + + mutex@14f01000 { +@@ -2619,6 +2625,7 @@ vdosys0: syscon@1c01a000 { + reg = <0 0x1c01a000 0 0x1000>; + mboxes = <&gce0 0 CMDQ_THR_PRIO_4>; + #clock-cells = <1>; ++ mediatek,gce-client-reg = <&gce0 SUBSYS_1c01XXXX 0xa000 0x1000>; + }; + + +@@ -2665,7 +2672,7 @@ larb20: larb@1b010000 { + reg = <0 0x1b010000 0 0x1000>; + mediatek,larb-id = <20>; + mediatek,smi = <&smi_common_vpp>; +- clocks = <&vencsys_core1 CLK_VENC_CORE1_LARB>, ++ clocks = <&vencsys_core1 CLK_VENC_CORE1_VENC>, + <&vencsys_core1 CLK_VENC_CORE1_GALS>, + <&vppsys0 CLK_VPP0_GALS_VDO0_VDO1_VENCSYS_CORE1>; + clock-names = "apb", "smi", "gals"; +@@ -2759,10 +2766,10 @@ dp_intf0: dp-intf@1c015000 { + compatible = "mediatek,mt8195-dp-intf"; + reg = <0 0x1c015000 0 0x1000>; + interrupts = ; +- clocks = <&vdosys0 CLK_VDO0_DP_INTF0>, +- <&vdosys0 CLK_VDO0_DP_INTF0_DP_INTF>, ++ clocks = <&vdosys0 CLK_VDO0_DP_INTF0_DP_INTF>, ++ <&vdosys0 CLK_VDO0_DP_INTF0>, + <&apmixedsys CLK_APMIXED_TVDPLL1>; +- clock-names = "engine", "pixel", "pll"; ++ clock-names = "pixel", "engine", "pll"; + status = "disabled"; + }; + +@@ -2772,6 +2779,7 @@ mutex: mutex@1c016000 { + interrupts = ; + power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS0>; + clocks = <&vdosys0 CLK_VDO0_DISP_MUTEX0>; ++ mediatek,gce-client-reg = <&gce0 SUBSYS_1c01XXXX 0x6000 0x1000>; + mediatek,gce-events = ; + }; + +@@ -2842,6 +2850,7 @@ mutex1: mutex@1c101000 { + power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; + clocks = <&vdosys1 CLK_VDO1_DISP_MUTEX>; + clock-names = "vdo1_mutex"; ++ mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x1000 0x1000>; + mediatek,gce-events = ; + }; + +@@ -2869,7 +2878,7 @@ larb3: larb@1c103000 { + power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; + }; + +- vdo1_rdma0: rdma@1c104000 { ++ vdo1_rdma0: dma-controller@1c104000 { + compatible = "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c104000 0 0x1000>; + interrupts = ; +@@ -2877,9 +2886,10 @@ vdo1_rdma0: rdma@1c104000 { + power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; + iommus = <&iommu_vdo M4U_PORT_L2_MDP_RDMA0>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x4000 0x1000>; ++ #dma-cells = <1>; + }; + +- vdo1_rdma1: rdma@1c105000 { ++ vdo1_rdma1: dma-controller@1c105000 { + compatible = "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c105000 0 0x1000>; + interrupts = ; +@@ -2887,9 +2897,10 @@ vdo1_rdma1: rdma@1c105000 { + power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; + iommus = <&iommu_vpp M4U_PORT_L3_MDP_RDMA1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x5000 0x1000>; ++ #dma-cells = <1>; + }; + +- vdo1_rdma2: rdma@1c106000 { ++ vdo1_rdma2: dma-controller@1c106000 { + compatible = "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c106000 0 0x1000>; + interrupts = ; +@@ -2897,9 +2908,10 @@ vdo1_rdma2: rdma@1c106000 { + power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; + iommus = <&iommu_vdo M4U_PORT_L2_MDP_RDMA2>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x6000 0x1000>; ++ #dma-cells = <1>; + }; + +- vdo1_rdma3: rdma@1c107000 { ++ vdo1_rdma3: dma-controller@1c107000 { + compatible = "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c107000 0 0x1000>; + interrupts = ; +@@ -2907,9 +2919,10 @@ vdo1_rdma3: rdma@1c107000 { + power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; + iommus = <&iommu_vpp M4U_PORT_L3_MDP_RDMA3>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x7000 0x1000>; ++ #dma-cells = <1>; + }; + +- vdo1_rdma4: rdma@1c108000 { ++ vdo1_rdma4: dma-controller@1c108000 { + compatible = "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c108000 0 0x1000>; + interrupts = ; +@@ -2917,9 +2930,10 @@ vdo1_rdma4: rdma@1c108000 { + power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; + iommus = <&iommu_vdo M4U_PORT_L2_MDP_RDMA4>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x8000 0x1000>; ++ #dma-cells = <1>; + }; + +- vdo1_rdma5: rdma@1c109000 { ++ vdo1_rdma5: dma-controller@1c109000 { + compatible = "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c109000 0 0x1000>; + interrupts = ; +@@ -2927,9 +2941,10 @@ vdo1_rdma5: rdma@1c109000 { + power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; + iommus = <&iommu_vpp M4U_PORT_L3_MDP_RDMA5>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x9000 0x1000>; ++ #dma-cells = <1>; + }; + +- vdo1_rdma6: rdma@1c10a000 { ++ vdo1_rdma6: dma-controller@1c10a000 { + compatible = "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c10a000 0 0x1000>; + interrupts = ; +@@ -2937,9 +2952,10 @@ vdo1_rdma6: rdma@1c10a000 { + power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; + iommus = <&iommu_vdo M4U_PORT_L2_MDP_RDMA6>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0xa000 0x1000>; ++ #dma-cells = <1>; + }; + +- vdo1_rdma7: rdma@1c10b000 { ++ vdo1_rdma7: dma-controller@1c10b000 { + compatible = "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c10b000 0 0x1000>; + interrupts = ; +@@ -2947,6 +2963,7 @@ vdo1_rdma7: rdma@1c10b000 { + power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; + iommus = <&iommu_vpp M4U_PORT_L3_MDP_RDMA7>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0xb000 0x1000>; ++ #dma-cells = <1>; + }; + + merge1: vpp-merge@1c10c000 { +@@ -3019,10 +3036,10 @@ dp_intf1: dp-intf@1c113000 { + reg = <0 0x1c113000 0 0x1000>; + interrupts = ; + power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; +- clocks = <&vdosys1 CLK_VDO1_DP_INTF0_MM>, +- <&vdosys1 CLK_VDO1_DPINTF>, ++ clocks = <&vdosys1 CLK_VDO1_DPINTF>, ++ <&vdosys1 CLK_VDO1_DP_INTF0_MM>, + <&apmixedsys CLK_APMIXED_TVDPLL2>; +- clock-names = "engine", "pixel", "pll"; ++ clock-names = "pixel", "engine", "pll"; + status = "disabled"; + }; + +@@ -3378,7 +3395,7 @@ vpu1_crit: trip-crit { + }; + }; + +- gpu0-thermal { ++ gpu-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_ap MT8195_AP_GPU0>; +diff --git a/arch/arm64/boot/dts/nvidia/tegra132-norrin.dts b/arch/arm64/boot/dts/nvidia/tegra132-norrin.dts +index bbc2e9bef08da5..441216eda487f8 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra132-norrin.dts ++++ b/arch/arm64/boot/dts/nvidia/tegra132-norrin.dts +@@ -9,8 +9,8 @@ / { + compatible = "nvidia,norrin", "nvidia,tegra132", "nvidia,tegra124"; + + aliases { +- rtc0 = "/i2c@7000d000/as3722@40"; +- rtc1 = "/rtc@7000e000"; ++ rtc0 = &as3722; ++ rtc1 = &tegra_rtc; + serial0 = &uarta; + }; + +diff --git a/arch/arm64/boot/dts/nvidia/tegra132.dtsi b/arch/arm64/boot/dts/nvidia/tegra132.dtsi +index 8b78be8f4f9d0b..4b5435f5832344 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra132.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra132.dtsi +@@ -570,7 +570,7 @@ spi@7000de00 { + status = "disabled"; + }; + +- rtc@7000e000 { ++ tegra_rtc: rtc@7000e000 { + compatible = "nvidia,tegra124-rtc", "nvidia,tegra20-rtc"; + reg = <0x0 0x7000e000 0x0 0x100>; + interrupts = ; +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 4413a9b6da87a2..bf2ccc8ff93c4b 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 +@@ -174,7 +174,7 @@ ethernet@6800000 { + status = "okay"; + + phy-handle = <&mgbe0_phy>; +- phy-mode = "usxgmii"; ++ phy-mode = "10gbase-r"; + + mdio { + #address-cells = <1>; +diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi b/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi +index 5f592f1d81e2ee..fe08e131b7b9ef 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi +@@ -28,7 +28,7 @@ spi@3270000 { + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; +- spi-max-frequency = <136000000>; ++ spi-max-frequency = <102000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + }; +@@ -42,7 +42,7 @@ flash@0 { + mmc@3400000 { + status = "okay"; + bus-width = <4>; +- cd-gpios = <&gpio TEGRA234_MAIN_GPIO(G, 7) GPIO_ACTIVE_HIGH>; ++ cd-gpios = <&gpio TEGRA234_MAIN_GPIO(G, 7) GPIO_ACTIVE_LOW>; + disable-wp; + }; + +diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi +index 95524e5bce8262..ac69eacf8a6ba9 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi +@@ -43,12 +43,12 @@ timer@2080000 { + , + , + , +- , +- , +- , +- , +- , +- ; ++ , ++ , ++ , ++ , ++ , ++ ; + status = "okay"; + }; + +diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts +index 4f5541e9be0e98..dabe9f42a63ade 100644 +--- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts ++++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts +@@ -172,6 +172,9 @@ adv_bridge: bridge@39 { + pd-gpios = <&tlmm 32 GPIO_ACTIVE_HIGH>; + + avdd-supply = <&pm8916_l6>; ++ a2vdd-supply = <&pm8916_l6>; ++ dvdd-supply = <&pm8916_l6>; ++ pvdd-supply = <&pm8916_l6>; + v1p2-supply = <&pm8916_l6>; + v3p3-supply = <&pm8916_l17>; + +diff --git a/arch/arm64/boot/dts/qcom/ipq5332.dtsi b/arch/arm64/boot/dts/qcom/ipq5332.dtsi +index 8bfc2db44624af..e40c55adff23d1 100644 +--- a/arch/arm64/boot/dts/qcom/ipq5332.dtsi ++++ b/arch/arm64/boot/dts/qcom/ipq5332.dtsi +@@ -135,7 +135,7 @@ smem@4a800000 { + reg = <0x0 0x4a800000 0x0 0x100000>; + no-map; + +- hwlocks = <&tcsr_mutex 0>; ++ hwlocks = <&tcsr_mutex 3>; + }; + }; + +diff --git a/arch/arm64/boot/dts/qcom/ipq6018.dtsi b/arch/arm64/boot/dts/qcom/ipq6018.dtsi +index 47b8b1d6730ac6..fea16f3271c007 100644 +--- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi ++++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi +@@ -211,7 +211,7 @@ q6_region: memory@4ab00000 { + smem { + compatible = "qcom,smem"; + memory-region = <&smem_region>; +- hwlocks = <&tcsr_mutex 0>; ++ hwlocks = <&tcsr_mutex 3>; + }; + + soc: soc@0 { +@@ -393,7 +393,7 @@ gcc: gcc@1800000 { + + tcsr_mutex: hwlock@1905000 { + compatible = "qcom,ipq6018-tcsr-mutex", "qcom,tcsr-mutex"; +- reg = <0x0 0x01905000 0x0 0x1000>; ++ reg = <0x0 0x01905000 0x0 0x20000>; + #hwlock-cells = <1>; + }; + +@@ -565,7 +565,7 @@ usb3: usb@8af8800 { + <&gcc GCC_USB0_MOCK_UTMI_CLK>; + assigned-clock-rates = <133330000>, + <133330000>, +- <20000000>; ++ <24000000>; + + resets = <&gcc GCC_USB0_BCR>; + status = "disabled"; +@@ -579,6 +579,7 @@ dwc_0: usb@8a00000 { + clocks = <&xo>; + clock-names = "ref"; + tx-fifo-resize; ++ snps,parkmode-disable-ss-quirk; + snps,is-utmi-l1-suspend; + snps,hird-threshold = /bits/ 8 <0x0>; + snps,dis_u2_susphy_quirk; +@@ -767,10 +768,10 @@ pcie0: pci@20000000 { + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; +- interrupt-map = <0 0 0 1 &intc 0 75 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ +- <0 0 0 2 &intc 0 78 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ +- <0 0 0 3 &intc 0 79 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ +- <0 0 0 4 &intc 0 83 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ ++ interrupt-map = <0 0 0 1 &intc 0 0 0 75 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ ++ <0 0 0 2 &intc 0 0 0 78 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ ++ <0 0 0 3 &intc 0 0 0 79 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ ++ <0 0 0 4 &intc 0 0 0 83 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ + + clocks = <&gcc GCC_SYS_NOC_PCIE0_AXI_CLK>, + <&gcc GCC_PCIE0_AXI_M_CLK>, +diff --git a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi +index 00ed71936b4723..e5993a365870c1 100644 +--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi ++++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi +@@ -101,7 +101,7 @@ smem@4ab00000 { + reg = <0x0 0x4ab00000 0x0 0x100000>; + no-map; + +- hwlocks = <&tcsr_mutex 0>; ++ hwlocks = <&tcsr_mutex 3>; + }; + + memory@4ac00000 { +@@ -641,6 +641,7 @@ dwc_0: usb@8a00000 { + interrupts = ; + phys = <&qusb_phy_0>, <&usb0_ssphy>; + phy-names = "usb2-phy", "usb3-phy"; ++ snps,parkmode-disable-ss-quirk; + snps,is-utmi-l1-suspend; + snps,hird-threshold = /bits/ 8 <0x0>; + snps,dis_u2_susphy_quirk; +@@ -683,6 +684,7 @@ dwc_1: usb@8c00000 { + interrupts = ; + phys = <&qusb_phy_1>, <&usb1_ssphy>; + phy-names = "usb2-phy", "usb3-phy"; ++ snps,parkmode-disable-ss-quirk; + snps,is-utmi-l1-suspend; + snps,hird-threshold = /bits/ 8 <0x0>; + snps,dis_u2_susphy_quirk; +@@ -817,13 +819,13 @@ pcie1: pci@10000000 { + interrupt-names = "msi"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; +- interrupt-map = <0 0 0 1 &intc 0 142 ++ interrupt-map = <0 0 0 1 &intc 0 0 142 + IRQ_TYPE_LEVEL_HIGH>, /* int_a */ +- <0 0 0 2 &intc 0 143 ++ <0 0 0 2 &intc 0 0 143 + IRQ_TYPE_LEVEL_HIGH>, /* int_b */ +- <0 0 0 3 &intc 0 144 ++ <0 0 0 3 &intc 0 0 144 + IRQ_TYPE_LEVEL_HIGH>, /* int_c */ +- <0 0 0 4 &intc 0 145 ++ <0 0 0 4 &intc 0 0 145 + IRQ_TYPE_LEVEL_HIGH>; /* int_d */ + + clocks = <&gcc GCC_SYS_NOC_PCIE1_AXI_CLK>, +@@ -879,13 +881,13 @@ pcie0: pci@20000000 { + interrupt-names = "msi"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; +- interrupt-map = <0 0 0 1 &intc 0 75 ++ interrupt-map = <0 0 0 1 &intc 0 0 75 + IRQ_TYPE_LEVEL_HIGH>, /* int_a */ +- <0 0 0 2 &intc 0 78 ++ <0 0 0 2 &intc 0 0 78 + IRQ_TYPE_LEVEL_HIGH>, /* int_b */ +- <0 0 0 3 &intc 0 79 ++ <0 0 0 3 &intc 0 0 79 + IRQ_TYPE_LEVEL_HIGH>, /* int_c */ +- <0 0 0 4 &intc 0 83 ++ <0 0 0 4 &intc 0 0 83 + IRQ_TYPE_LEVEL_HIGH>; /* int_d */ + + clocks = <&gcc GCC_SYS_NOC_PCIE0_AXI_CLK>, +diff --git a/arch/arm64/boot/dts/qcom/ipq9574.dtsi b/arch/arm64/boot/dts/qcom/ipq9574.dtsi +index 51aba071c1eb30..8a72ad4afd0320 100644 +--- a/arch/arm64/boot/dts/qcom/ipq9574.dtsi ++++ b/arch/arm64/boot/dts/qcom/ipq9574.dtsi +@@ -195,7 +195,7 @@ tz_region: tz@4a600000 { + smem@4aa00000 { + compatible = "qcom,smem"; + reg = <0x0 0x4aa00000 0x0 0x100000>; +- hwlocks = <&tcsr_mutex 0>; ++ hwlocks = <&tcsr_mutex 3>; + no-map; + }; + }; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts +index 3892ad4f639a8f..4efc534b1d6e74 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts +@@ -88,6 +88,7 @@ led-controller@45 { + #size-cells = <0>; + + vcc-supply = <&pm8916_l17>; ++ vio-supply = <&pm8916_l6>; + + led@0 { + reg = <0>; +diff --git a/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts b/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts +index 8e238976ab1cef..43078b890d8605 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts ++++ b/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts +@@ -118,6 +118,7 @@ led-controller@45 { + #size-cells = <0>; + + vcc-supply = <&pm8916_l16>; ++ vio-supply = <&pm8916_l5>; + + led@0 { + reg = <0>; +diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi +index 33fb65d7310461..961ceb83a91fae 100644 +--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi +@@ -1813,7 +1813,7 @@ apps_iommu: iommu@1ef0000 { + #size-cells = <1>; + #iommu-cells = <1>; + compatible = "qcom,msm8916-iommu", "qcom,msm-iommu-v1"; +- ranges = <0 0x01e20000 0x40000>; ++ ranges = <0 0x01e20000 0x20000>; + reg = <0x01ef0000 0x3000>; + clocks = <&gcc GCC_SMMU_CFG_CLK>, + <&gcc GCC_APSS_TCU_CLK>; +@@ -2085,6 +2085,7 @@ blsp_dma: dma-controller@7884000 { + clock-names = "bam_clk"; + #dma-cells = <1>; + qcom,ee = <0>; ++ qcom,controlled-remotely; + }; + + blsp_uart1: serial@78af000 { +diff --git a/arch/arm64/boot/dts/qcom/msm8939.dtsi b/arch/arm64/boot/dts/qcom/msm8939.dtsi +index 6e24f0f2374fe5..3fd64cafe99c5f 100644 +--- a/arch/arm64/boot/dts/qcom/msm8939.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8939.dtsi +@@ -1447,7 +1447,7 @@ opp-19200000 { + apps_iommu: iommu@1ef0000 { + compatible = "qcom,msm8916-iommu", "qcom,msm-iommu-v1"; + reg = <0x01ef0000 0x3000>; +- ranges = <0 0x01e20000 0x40000>; ++ ranges = <0 0x01e20000 0x20000>; + clocks = <&gcc GCC_SMMU_CFG_CLK>, + <&gcc GCC_APSS_TCU_CLK>; + clock-names = "iface", "bus"; +@@ -1661,6 +1661,7 @@ blsp_dma: dma-controller@7884000 { + clock-names = "bam_clk"; + #dma-cells = <1>; + qcom,ee = <0>; ++ qcom,controlled-remotely; + }; + + blsp_uart1: serial@78af000 { +diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-mido.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-mido.dts +index ed95d09cedb1e3..6b9245cd8b0c3f 100644 +--- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-mido.dts ++++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-mido.dts +@@ -111,6 +111,7 @@ led-controller@45 { + reg = <0x45>; + + vcc-supply = <&pm8953_l10>; ++ vio-supply = <&pm8953_l5>; + + #address-cells = <1>; + #size-cells = <0>; +diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-tissot.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-tissot.dts +index 61ff629c9bf345..9ac4f507e321a6 100644 +--- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-tissot.dts ++++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-tissot.dts +@@ -104,6 +104,7 @@ led-controller@45 { + reg = <0x45>; + + vcc-supply = <&pm8953_l10>; ++ vio-supply = <&pm8953_l5>; + + #address-cells = <1>; + #size-cells = <0>; +diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts +index 1a1d3f92a51168..b0588f30f8f1a7 100644 +--- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts ++++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts +@@ -113,6 +113,7 @@ led-controller@45 { + reg = <0x45>; + + vcc-supply = <&pm8953_l10>; ++ vio-supply = <&pm8953_l5>; + + #address-cells = <1>; + #size-cells = <0>; +diff --git a/arch/arm64/boot/dts/qcom/msm8976.dtsi b/arch/arm64/boot/dts/qcom/msm8976.dtsi +index f9f5afbcc52bba..4c5be22b47feea 100644 +--- a/arch/arm64/boot/dts/qcom/msm8976.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8976.dtsi +@@ -379,7 +379,7 @@ adsp_smp2p_in: slave-kernel { + smp2p-modem { + compatible = "qcom,smp2p"; + interrupts = ; +- qcom,ipc = <&apcs 8 13>; ++ qcom,ipc = <&apcs 8 14>; + + qcom,local-pid = <0>; + qcom,remote-pid = <1>; +@@ -402,7 +402,7 @@ modem_smp2p_in: slave-kernel { + smp2p-wcnss { + compatible = "qcom,smp2p"; + interrupts = ; +- qcom,ipc = <&apcs 8 17>; ++ qcom,ipc = <&apcs 8 18>; + + qcom,local-pid = <0>; + qcom,remote-pid = <4>; +@@ -428,9 +428,9 @@ smsm { + #address-cells = <1>; + #size-cells = <0>; + +- qcom,ipc-1 = <&apcs 8 12>; ++ qcom,ipc-1 = <&apcs 8 13>; + qcom,ipc-2 = <&apcs 8 9>; +- qcom,ipc-3 = <&apcs 8 18>; ++ qcom,ipc-3 = <&apcs 8 19>; + + apps_smsm: apps@0 { + reg = <0>; +diff --git a/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts b/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts +index fcca1ba94da699..5fe5de9ceef99f 100644 +--- a/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts ++++ b/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts +@@ -109,11 +109,6 @@ rmtfs_mem: rmtfs@ca100000 { + qcom,client-id = <1>; + }; + +- audio_mem: audio@cb400000 { +- reg = <0 0xcb000000 0 0x400000>; +- no-mem; +- }; +- + qseecom_mem: qseecom@cb400000 { + reg = <0 0xcb400000 0 0x1c00000>; + no-mem; +diff --git a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-common.dtsi b/arch/arm64/boot/dts/qcom/msm8996-xiaomi-common.dtsi +index 06f8ff624181fc..d5b35ff0175cd4 100644 +--- a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8996-xiaomi-common.dtsi +@@ -405,7 +405,6 @@ &usb3_dwc3 { + + &hsusb_phy1 { + status = "okay"; +- extcon = <&typec>; + + vdda-pll-supply = <&vreg_l12a_1p8>; + vdda-phy-dpdm-supply = <&vreg_l24a_3p075>; +diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi +index c8e0986425ab4f..1f7cbb35886db5 100644 +--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi +@@ -443,6 +443,19 @@ memory@80000000 { + reg = <0x0 0x80000000 0x0 0x0>; + }; + ++ etm { ++ compatible = "qcom,coresight-remote-etm"; ++ ++ out-ports { ++ port { ++ modem_etm_out_funnel_in2: endpoint { ++ remote-endpoint = ++ <&funnel_in2_in_modem_etm>; ++ }; ++ }; ++ }; ++ }; ++ + psci { + compatible = "arm,psci-1.0"; + method = "smc"; +@@ -2077,7 +2090,7 @@ ufshc: ufshc@624000 { + <&gcc GCC_UFS_RX_SYMBOL_0_CLK>; + freq-table-hz = + <100000000 200000000>, +- <0 0>, ++ <100000000 200000000>, + <0 0>, + <0 0>, + <0 0>, +@@ -2643,6 +2656,14 @@ funnel@3023000 { + clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; + clock-names = "apb_pclk", "atclk"; + ++ in-ports { ++ port { ++ funnel_in2_in_modem_etm: endpoint { ++ remote-endpoint = ++ <&modem_etm_out_funnel_in2>; ++ }; ++ }; ++ }; + + out-ports { + port { +@@ -3061,6 +3082,7 @@ usb3_dwc3: usb@6a00000 { + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + snps,is-utmi-l1-suspend; ++ snps,parkmode-disable-ss-quirk; + tx-fifo-resize; + }; + }; +diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi +index f180047cacb057..7fcc15b6946ae8 100644 +--- a/arch/arm64/boot/dts/qcom/msm8998.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi +@@ -1588,7 +1588,6 @@ adreno_smmu: iommu@5040000 { + * SoC VDDMX RPM Power Domain in the Adreno driver. + */ + power-domains = <&gpucc GPU_GX_GDSC>; +- status = "disabled"; + }; + + gpucc: clock-controller@5065000 { +@@ -2034,9 +2033,11 @@ etm5: etm@7c40000 { + + cpu = <&CPU4>; + +- port { +- etm4_out: endpoint { +- remote-endpoint = <&apss_funnel_in4>; ++ out-ports { ++ port { ++ etm4_out: endpoint { ++ remote-endpoint = <&apss_funnel_in4>; ++ }; + }; + }; + }; +@@ -2051,9 +2052,11 @@ etm6: etm@7d40000 { + + cpu = <&CPU5>; + +- port { +- etm5_out: endpoint { +- remote-endpoint = <&apss_funnel_in5>; ++ out-ports { ++ port { ++ etm5_out: endpoint { ++ remote-endpoint = <&apss_funnel_in5>; ++ }; + }; + }; + }; +@@ -2068,9 +2071,11 @@ etm7: etm@7e40000 { + + cpu = <&CPU6>; + +- port { +- etm6_out: endpoint { +- remote-endpoint = <&apss_funnel_in6>; ++ out-ports { ++ port { ++ etm6_out: endpoint { ++ remote-endpoint = <&apss_funnel_in6>; ++ }; + }; + }; + }; +@@ -2085,9 +2090,11 @@ etm8: etm@7f40000 { + + cpu = <&CPU7>; + +- port { +- etm7_out: endpoint { +- remote-endpoint = <&apss_funnel_in7>; ++ out-ports { ++ port { ++ etm7_out: endpoint { ++ remote-endpoint = <&apss_funnel_in7>; ++ }; + }; + }; + }; +@@ -2152,7 +2159,8 @@ usb3_dwc3: usb@a800000 { + interrupts = ; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; +- phys = <&qusb2phy>, <&usb1_ssphy>; ++ snps,parkmode-disable-ss-quirk; ++ phys = <&qusb2phy>, <&usb3phy>; + phy-names = "usb2-phy", "usb3-phy"; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; +@@ -2161,33 +2169,26 @@ usb3_dwc3: usb@a800000 { + + usb3phy: phy@c010000 { + compatible = "qcom,msm8998-qmp-usb3-phy"; +- reg = <0x0c010000 0x18c>; +- status = "disabled"; +- #address-cells = <1>; +- #size-cells = <1>; +- ranges; ++ reg = <0x0c010000 0x1000>; + + clocks = <&gcc GCC_USB3_PHY_AUX_CLK>, ++ <&gcc GCC_USB3_CLKREF_CLK>, + <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, +- <&gcc GCC_USB3_CLKREF_CLK>; +- clock-names = "aux", "cfg_ahb", "ref"; ++ <&gcc GCC_USB3_PHY_PIPE_CLK>; ++ clock-names = "aux", ++ "ref", ++ "cfg_ahb", ++ "pipe"; ++ clock-output-names = "usb3_phy_pipe_clk_src"; ++ #clock-cells = <0>; ++ #phy-cells = <0>; + + resets = <&gcc GCC_USB3_PHY_BCR>, + <&gcc GCC_USB3PHY_PHY_BCR>; +- reset-names = "phy", "common"; ++ reset-names = "phy", ++ "phy_phy"; + +- usb1_ssphy: phy@c010200 { +- reg = <0xc010200 0x128>, +- <0xc010400 0x200>, +- <0xc010c00 0x20c>, +- <0xc010600 0x128>, +- <0xc010800 0x200>; +- #phy-cells = <0>; +- #clock-cells = <0>; +- clocks = <&gcc GCC_USB3_PHY_PIPE_CLK>; +- clock-names = "pipe0"; +- clock-output-names = "usb3_phy_pipe_clk_src"; +- }; ++ status = "disabled"; + }; + + qusb2phy: phy@c012000 { +diff --git a/arch/arm64/boot/dts/qcom/qcm2290.dtsi b/arch/arm64/boot/dts/qcom/qcm2290.dtsi +index d46e591e72b5c9..40a8506553ef5d 100644 +--- a/arch/arm64/boot/dts/qcom/qcm2290.dtsi ++++ b/arch/arm64/boot/dts/qcom/qcm2290.dtsi +@@ -418,6 +418,11 @@ tcsr_mutex: hwlock@340000 { + #hwlock-cells = <1>; + }; + ++ tcsr_regs: syscon@3c0000 { ++ compatible = "qcom,qcm2290-tcsr", "syscon"; ++ reg = <0x0 0x003c0000 0x0 0x40000>; ++ }; ++ + tlmm: pinctrl@500000 { + compatible = "qcom,qcm2290-tlmm"; + reg = <0x0 0x00500000 0x0 0x300000>; +@@ -665,6 +670,8 @@ usb_qmpphy: phy@1615000 { + + #phy-cells = <0>; + ++ qcom,tcsr-reg = <&tcsr_regs 0xb244>; ++ + status = "disabled"; + }; + +diff --git a/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi b/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi +index 10655401528e4e..a22b4501ce1ef5 100644 +--- a/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi ++++ b/arch/arm64/boot/dts/qcom/qcs404-evb.dtsi +@@ -62,7 +62,7 @@ bluetooth { + vddrf-supply = <&vreg_l1_1p3>; + vddch0-supply = <&vdd_ch0_3p3>; + +- local-bd-address = [ 02 00 00 00 5a ad ]; ++ local-bd-address = [ 00 00 00 00 00 00 ]; + + max-speed = <3200000>; + }; +diff --git a/arch/arm64/boot/dts/qcom/qdu1000.dtsi b/arch/arm64/boot/dts/qcom/qdu1000.dtsi +index 1c0e5d271e91bb..dbdc06be6260b7 100644 +--- a/arch/arm64/boot/dts/qcom/qdu1000.dtsi ++++ b/arch/arm64/boot/dts/qcom/qdu1000.dtsi +@@ -1452,7 +1452,21 @@ system-cache-controller@19200000 { + "llcc_broadcast_base", + "multi_channel_register"; + interrupts = ; +- multi-ch-bit-off = <24 2>; ++ ++ nvmem-cells = <&multi_chan_ddr>; ++ nvmem-cell-names = "multi-chan-ddr"; ++ }; ++ ++ sec_qfprom: efuse@221c8000 { ++ compatible = "qcom,qdu1000-sec-qfprom", "qcom,sec-qfprom"; ++ reg = <0 0x221c8000 0 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ multi_chan_ddr: multi-chan-ddr@12b { ++ reg = <0x12b 0x1>; ++ bits = <0 2>; ++ }; + }; + }; + +diff --git a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts +index eadba066972e87..37abb83ea46476 100644 +--- a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts ++++ b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts +@@ -13,7 +13,7 @@ / { + compatible = "qcom,qrb2210-rb1", "qcom,qrb2210", "qcom,qcm2290"; + + aliases { +- serial0 = &uart0; ++ serial0 = &uart4; + sdhc1 = &sdhc_1; + sdhc2 = &sdhc_2; + }; +@@ -150,15 +150,15 @@ regulators { + + pm2250_s3: s3 { + /* 0.4V-1.6625V -> 1.3V (Power tree requirements) */ +- regulator-min-microvolts = <1350000>; +- regulator-max-microvolts = <1350000>; ++ regulator-min-microvolt = <1352000>; ++ regulator-max-microvolt = <1352000>; + regulator-boot-on; + }; + + pm2250_s4: s4 { + /* 1.2V-2.35V -> 2.05V (Power tree requirements) */ +- regulator-min-microvolts = <2072000>; +- regulator-max-microvolts = <2072000>; ++ regulator-min-microvolt = <2072000>; ++ regulator-max-microvolt = <2072000>; + regulator-boot-on; + }; + +@@ -166,47 +166,47 @@ pm2250_s4: s4 { + + pm2250_l2: l2 { + /* LPDDR4X VDD2 */ +- regulator-min-microvolts = <1136000>; +- regulator-max-microvolts = <1136000>; ++ regulator-min-microvolt = <1136000>; ++ regulator-max-microvolt = <1136000>; + regulator-always-on; + regulator-boot-on; + }; + + pm2250_l3: l3 { + /* LPDDR4X VDDQ */ +- regulator-min-microvolts = <616000>; +- regulator-max-microvolts = <616000>; ++ regulator-min-microvolt = <616000>; ++ regulator-max-microvolt = <616000>; + regulator-always-on; + regulator-boot-on; + }; + + pm2250_l4: l4 { +- /* max = 3.05V -> max = just below 3V (SDHCI2) */ +- regulator-min-microvolts = <1648000>; +- regulator-max-microvolts = <2992000>; ++ /* max = 3.05V -> max = 2.7 to disable 3V signaling (SDHCI2) */ ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <2700000>; + regulator-allow-set-load; + }; + + pm2250_l5: l5 { + /* CSI/DSI */ +- regulator-min-microvolts = <1232000>; +- regulator-max-microvolts = <1232000>; ++ regulator-min-microvolt = <1232000>; ++ regulator-max-microvolt = <1232000>; + regulator-allow-set-load; + regulator-boot-on; + }; + + pm2250_l6: l6 { + /* DRAM PLL */ +- regulator-min-microvolts = <928000>; +- regulator-max-microvolts = <928000>; ++ regulator-min-microvolt = <928000>; ++ regulator-max-microvolt = <928000>; + regulator-always-on; + regulator-boot-on; + }; + + pm2250_l7: l7 { + /* Wi-Fi CX/MX */ +- regulator-min-microvolts = <664000>; +- regulator-max-microvolts = <664000>; ++ regulator-min-microvolt = <664000>; ++ regulator-max-microvolt = <664000>; + }; + + /* +@@ -216,37 +216,37 @@ pm2250_l7: l7 { + + pm2250_l10: l10 { + /* Wi-Fi RFA */ +- regulator-min-microvolts = <1300000>; +- regulator-max-microvolts = <1300000>; ++ regulator-min-microvolt = <1304000>; ++ regulator-max-microvolt = <1304000>; + }; + + pm2250_l11: l11 { + /* GPS RF1 */ +- regulator-min-microvolts = <1000000>; +- regulator-max-microvolts = <1000000>; ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <1000000>; + regulator-boot-on; + }; + + pm2250_l12: l12 { + /* USB PHYs */ +- regulator-min-microvolts = <928000>; +- regulator-max-microvolts = <928000>; ++ regulator-min-microvolt = <928000>; ++ regulator-max-microvolt = <928000>; + regulator-allow-set-load; + regulator-boot-on; + }; + + pm2250_l13: l13 { + /* USB/QFPROM/PLLs */ +- regulator-min-microvolts = <1800000>; +- regulator-max-microvolts = <1800000>; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; + regulator-allow-set-load; + regulator-boot-on; + }; + + pm2250_l14: l14 { + /* SDHCI1 VQMMC */ +- regulator-min-microvolts = <1800000>; +- regulator-max-microvolts = <1800000>; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; + regulator-allow-set-load; + /* Broken hardware, never turn it off! */ + regulator-always-on; +@@ -254,8 +254,8 @@ pm2250_l14: l14 { + + pm2250_l15: l15 { + /* WCD/DSI/BT VDDIO */ +- regulator-min-microvolts = <1800000>; +- regulator-max-microvolts = <1800000>; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; + regulator-allow-set-load; + regulator-always-on; + regulator-boot-on; +@@ -263,47 +263,47 @@ pm2250_l15: l15 { + + pm2250_l16: l16 { + /* GPS RF2 */ +- regulator-min-microvolts = <1800000>; +- regulator-max-microvolts = <1800000>; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + + pm2250_l17: l17 { +- regulator-min-microvolts = <3000000>; +- regulator-max-microvolts = <3000000>; ++ regulator-min-microvolt = <3000000>; ++ regulator-max-microvolt = <3000000>; + }; + + pm2250_l18: l18 { + /* VDD_PXn */ +- regulator-min-microvolts = <1800000>; +- regulator-max-microvolts = <1800000>; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; + }; + + pm2250_l19: l19 { + /* VDD_PXn */ +- regulator-min-microvolts = <1800000>; +- regulator-max-microvolts = <1800000>; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; + }; + + pm2250_l20: l20 { + /* SDHCI1 VMMC */ +- regulator-min-microvolts = <2856000>; +- regulator-max-microvolts = <2856000>; ++ regulator-min-microvolt = <2400000>; ++ regulator-max-microvolt = <3600000>; + regulator-allow-set-load; + }; + + pm2250_l21: l21 { + /* SDHCI2 VMMC */ +- regulator-min-microvolts = <2960000>; +- regulator-max-microvolts = <3300000>; ++ regulator-min-microvolt = <2960000>; ++ regulator-max-microvolt = <3300000>; + regulator-allow-set-load; + regulator-boot-on; + }; + + pm2250_l22: l22 { + /* Wi-Fi */ +- regulator-min-microvolts = <3312000>; +- regulator-max-microvolts = <3312000>; ++ regulator-min-microvolt = <3312000>; ++ regulator-max-microvolt = <3312000>; + }; + }; + }; +@@ -357,7 +357,7 @@ key_volp_n: key-volp-n-state { + }; + + /* UART connected to the Micro-USB port via a FTDI chip */ +-&uart0 { ++&uart4 { + compatible = "qcom,geni-debug-uart"; + status = "okay"; + }; +@@ -366,6 +366,16 @@ &usb { + status = "okay"; + }; + ++&usb_qmpphy { ++ vdda-phy-supply = <&pm2250_l12>; ++ vdda-pll-supply = <&pm2250_l13>; ++ status = "okay"; ++}; ++ ++&usb_dwc3 { ++ dr_mode = "host"; ++}; ++ + &usb_hsphy { + vdd-supply = <&pm2250_l12>; + vdda-pll-supply = <&pm2250_l13>; +diff --git a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +index a7278a9472ed9b..5def8c1154ceb3 100644 +--- a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts ++++ b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +@@ -57,6 +57,17 @@ hdmi_con: endpoint { + }; + }; + ++ i2c2_gpio: i2c { ++ compatible = "i2c-gpio"; ++ ++ sda-gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>; ++ scl-gpios = <&tlmm 7 GPIO_ACTIVE_HIGH>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "disabled"; ++ }; ++ + leds { + compatible = "gpio-leds"; + +@@ -187,7 +198,7 @@ zap-shader { + }; + }; + +-&i2c2 { ++&i2c2_gpio { + clock-frequency = <400000>; + status = "okay"; + +@@ -353,6 +364,8 @@ vreg_l8a_0p664: l8 { + vreg_l9a_1p8: l9 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; ++ regulator-always-on; ++ regulator-boot-on; + }; + + vreg_l10a_1p8: l10 { +@@ -518,7 +531,6 @@ &usb { + + &usb_dwc3 { + maximum-speed = "super-speed"; +- dr_mode = "peripheral"; + }; + + &usb_hsphy { +diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +index dfa8ee5c75af63..e95a004c33919a 100644 +--- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts ++++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +@@ -63,8 +63,8 @@ led-user4 { + function = LED_FUNCTION_INDICATOR; + color = ; + gpios = <&pm8150_gpios 10 GPIO_ACTIVE_HIGH>; +- linux,default-trigger = "panic-indicator"; + default-state = "off"; ++ panic-indicator; + }; + + led-wlan { +diff --git a/arch/arm64/boot/dts/qcom/sa8155p-adp.dts b/arch/arm64/boot/dts/qcom/sa8155p-adp.dts +index 5e4287f8c8cd19..b2cf2c988336c0 100644 +--- a/arch/arm64/boot/dts/qcom/sa8155p-adp.dts ++++ b/arch/arm64/boot/dts/qcom/sa8155p-adp.dts +@@ -367,6 +367,16 @@ queue0 { + }; + }; + ++&pmm8155au_1_gpios { ++ pmm8155au_1_sdc2_cd: sdc2-cd-default-state { ++ pins = "gpio4"; ++ function = "normal"; ++ input-enable; ++ bias-pull-up; ++ power-source = <0>; ++ }; ++}; ++ + &qupv3_id_1 { + status = "okay"; + }; +@@ -384,10 +394,10 @@ &remoteproc_cdsp { + &sdhc_2 { + status = "okay"; + +- cd-gpios = <&tlmm 4 GPIO_ACTIVE_LOW>; ++ cd-gpios = <&pmm8155au_1_gpios 4 GPIO_ACTIVE_LOW>; + pinctrl-names = "default", "sleep"; +- pinctrl-0 = <&sdc2_on>; +- pinctrl-1 = <&sdc2_off>; ++ pinctrl-0 = <&sdc2_on &pmm8155au_1_sdc2_cd>; ++ pinctrl-1 = <&sdc2_off &pmm8155au_1_sdc2_cd>; + vqmmc-supply = <&vreg_l13c_2p96>; /* IO line power */ + vmmc-supply = <&vreg_l17a_2p96>; /* Card power line */ + bus-width = <4>; +@@ -505,13 +515,6 @@ data-pins { + bias-pull-up; /* pull up */ + drive-strength = <16>; /* 16 MA */ + }; +- +- sd-cd-pins { +- pins = "gpio96"; +- function = "gpio"; +- bias-pull-up; /* pull up */ +- drive-strength = <2>; /* 2 MA */ +- }; + }; + + sdc2_off: sdc2-off-state { +@@ -532,13 +535,6 @@ data-pins { + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; +- +- sd-cd-pins { +- pins = "gpio96"; +- function = "gpio"; +- bias-pull-up; /* pull up */ +- drive-strength = <2>; /* 2 MA */ +- }; + }; + + usb2phy_ac_en1_default: usb2phy-ac-en1-default-state { +diff --git a/arch/arm64/boot/dts/qcom/sa8540p.dtsi b/arch/arm64/boot/dts/qcom/sa8540p.dtsi +index 96b2c59ad02b4d..23888029cc1179 100644 +--- a/arch/arm64/boot/dts/qcom/sa8540p.dtsi ++++ b/arch/arm64/boot/dts/qcom/sa8540p.dtsi +@@ -168,6 +168,9 @@ opp-2592000000 { + }; + + &gpucc { ++ /* SA8295P and SA8540P doesn't provide gfx.lvl */ ++ /delete-property/ power-domains; ++ + status = "disabled"; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sa8775p.dtsi b/arch/arm64/boot/dts/qcom/sa8775p.dtsi +index 9f4f58e831a4a6..f6766fa8df34d3 100644 +--- a/arch/arm64/boot/dts/qcom/sa8775p.dtsi ++++ b/arch/arm64/boot/dts/qcom/sa8775p.dtsi +@@ -1602,8 +1602,8 @@ usb_0: usb@a6f8800 { + assigned-clock-rates = <19200000>, <200000000>; + + interrupts-extended = <&intc GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>, +- <&pdc 14 IRQ_TYPE_EDGE_RISING>, +- <&pdc 15 IRQ_TYPE_EDGE_RISING>, ++ <&pdc 14 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc 15 IRQ_TYPE_EDGE_BOTH>, + <&pdc 12 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "pwr_event", + "dp_hs_phy_irq", +@@ -1689,8 +1689,8 @@ usb_1: usb@a8f8800 { + assigned-clock-rates = <19200000>, <200000000>; + + interrupts-extended = <&intc GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>, +- <&pdc 8 IRQ_TYPE_EDGE_RISING>, +- <&pdc 7 IRQ_TYPE_EDGE_RISING>, ++ <&pdc 8 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc 7 IRQ_TYPE_EDGE_BOTH>, + <&pdc 13 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "pwr_event", + "dp_hs_phy_irq", +@@ -1752,8 +1752,8 @@ usb_2: usb@a4f8800 { + assigned-clock-rates = <19200000>, <200000000>; + + interrupts-extended = <&intc GIC_SPI 444 IRQ_TYPE_LEVEL_HIGH>, +- <&pdc 10 IRQ_TYPE_EDGE_RISING>, +- <&pdc 9 IRQ_TYPE_EDGE_RISING>; ++ <&pdc 10 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc 9 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "pwr_event", + "dp_hs_phy_irq", + "dm_hs_phy_irq"; +@@ -1951,6 +1951,7 @@ apps_smmu: iommu@15000000 { + reg = <0x0 0x15000000 0x0 0x100000>; + #iommu-cells = <2>; + #global-interrupts = <2>; ++ dma-coherent; + + interrupts = , + , +@@ -2089,6 +2090,7 @@ pcie_smmu: iommu@15200000 { + reg = <0x0 0x15200000 0x0 0x80000>; + #iommu-cells = <2>; + #global-interrupts = <2>; ++ dma-coherent; + + interrupts = , + , +@@ -2173,7 +2175,7 @@ watchdog@17c10000 { + compatible = "qcom,apss-wdt-sa8775p", "qcom,kpss-wdt"; + reg = <0x0 0x17c10000 0x0 0x1000>; + clocks = <&sleep_clk>; +- interrupts = ; ++ interrupts = ; + }; + + memtimer: timer@17c20000 { +@@ -2350,6 +2352,7 @@ ethernet1: ethernet@23000000 { + phy-names = "serdes"; + + iommus = <&apps_smmu 0x140 0xf>; ++ dma-coherent; + + snps,tso; + snps,pbl = <32>; +@@ -2383,6 +2386,7 @@ ethernet0: ethernet@23040000 { + phy-names = "serdes"; + + iommus = <&apps_smmu 0x120 0xf>; ++ dma-coherent; + + snps,tso; + snps,pbl = <32>; +@@ -2398,7 +2402,7 @@ arch_timer: timer { + interrupts = , + , + , +- ; ++ ; + }; + + pcie0: pci@1c00000{ +diff --git a/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts b/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts +index dbb48934d49950..3342cb0480385f 100644 +--- a/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts ++++ b/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts +@@ -209,9 +209,22 @@ alc5682: codec@1a { + AVDD-supply = <&vreg_l15a_1p8>; + MICVDD-supply = <®_codec_3p3>; + VBAT-supply = <®_codec_3p3>; ++ DBVDD-supply = <&vreg_l15a_1p8>; ++ LDO1-IN-supply = <&vreg_l15a_1p8>; ++ ++ /* ++ * NOTE: The board has a path from this codec to the ++ * DMIC microphones in the lid, however some of the option ++ * resistors are absent and the microphones are connected ++ * to the SoC instead. ++ * ++ * If the resistors were to be changed by the user to ++ * connect the codec, the following could be used: ++ * ++ * realtek,dmic1-data-pin = <1>; ++ * realtek,dmic1-clk-pin = <1>; ++ */ + +- realtek,dmic1-data-pin = <1>; +- realtek,dmic1-clk-pin = <1>; + realtek,jd-src = <1>; + }; + }; +diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi +index 5a33e16a8b6776..c2f5e9f6679d69 100644 +--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi ++++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi +@@ -970,6 +970,8 @@ bluetooth: bluetooth { + vddrf-supply = <&pp1300_l2c>; + vddch0-supply = <&pp3300_l10c>; + max-speed = <3200000>; ++ ++ qcom,local-bd-address-broken; + }; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi +index a79c0f2e18799c..68b1c017a9fd5f 100644 +--- a/arch/arm64/boot/dts/qcom/sc7180.dtsi ++++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2795,49 +2796,28 @@ usb_1_hsphy: phy@88e3000 { + nvmem-cells = <&qusb2p_hstx_trim>; + }; + +- usb_1_qmpphy: phy-wrapper@88e9000 { ++ usb_1_qmpphy: phy@88e8000 { + compatible = "qcom,sc7180-qmp-usb3-dp-phy"; +- reg = <0 0x088e9000 0 0x18c>, +- <0 0x088e8000 0 0x3c>, +- <0 0x088ea000 0 0x18c>; ++ reg = <0 0x088e8000 0 0x3000>; + status = "disabled"; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; + + clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>, +- <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>, +- <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>; +- clock-names = "aux", "cfg_ahb", "ref", "com_aux"; ++ <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, ++ <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, ++ <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; ++ clock-names = "aux", ++ "ref", ++ "com_aux", ++ "usb3_pipe", ++ "cfg_ahb"; + + resets = <&gcc GCC_USB3_PHY_PRIM_BCR>, + <&gcc GCC_USB3_DP_PHY_PRIM_BCR>; + reset-names = "phy", "common"; + +- usb_1_ssphy: usb3-phy@88e9200 { +- reg = <0 0x088e9200 0 0x128>, +- <0 0x088e9400 0 0x200>, +- <0 0x088e9c00 0 0x218>, +- <0 0x088e9600 0 0x128>, +- <0 0x088e9800 0 0x200>, +- <0 0x088e9a00 0 0x18>; +- #clock-cells = <0>; +- #phy-cells = <0>; +- clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; +- clock-names = "pipe0"; +- clock-output-names = "usb3_phy_pipe_clk_src"; +- }; +- +- dp_phy: dp-phy@88ea200 { +- reg = <0 0x088ea200 0 0x200>, +- <0 0x088ea400 0 0x200>, +- <0 0x088eaa00 0 0x200>, +- <0 0x088ea600 0 0x200>, +- <0 0x088ea800 0 0x200>; +- #clock-cells = <1>; +- #phy-cells = <0>; +- }; ++ #clock-cells = <1>; ++ #phy-cells = <1>; + }; + + pmu@90b6300 { +@@ -2978,8 +2958,8 @@ usb_1: usb@a6f8800 { + + interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, +- <&pdc 8 IRQ_TYPE_LEVEL_HIGH>, +- <&pdc 9 IRQ_TYPE_LEVEL_HIGH>; ++ <&pdc 8 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc 9 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hs_phy_irq", "ss_phy_irq", + "dm_hs_phy_irq", "dp_hs_phy_irq"; + +@@ -3001,7 +2981,8 @@ usb_1_dwc3: usb@a600000 { + iommus = <&apps_smmu 0x540 0>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; +- phys = <&usb_1_hsphy>, <&usb_1_ssphy>; ++ snps,parkmode-disable-ss-quirk; ++ phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>; + phy-names = "usb2-phy", "usb3-phy"; + maximum-speed = "super-speed"; + }; +@@ -3307,8 +3288,9 @@ mdss_dp: displayport-controller@ae90000 { + "ctrl_link_iface", "stream_pixel"; + assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>; +- assigned-clock-parents = <&dp_phy 0>, <&dp_phy 1>; +- phys = <&dp_phy>; ++ assigned-clock-parents = <&usb_1_qmpphy QMP_USB43DP_DP_LINK_CLK>, ++ <&usb_1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; ++ phys = <&usb_1_qmpphy QMP_USB43DP_DP_PHY>; + phy-names = "dp"; + + operating-points-v2 = <&dp_opp_table>; +@@ -3365,8 +3347,8 @@ dispcc: clock-controller@af00000 { + <&gcc GCC_DISP_GPLL0_CLK_SRC>, + <&mdss_dsi0_phy 0>, + <&mdss_dsi0_phy 1>, +- <&dp_phy 0>, +- <&dp_phy 1>; ++ <&usb_1_qmpphy QMP_USB43DP_DP_LINK_CLK>, ++ <&usb_1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; + clock-names = "bi_tcxo", + "gcc_disp_gpll0_clk_src", + "dsi0_phy_pll_out_byteclk", +@@ -3587,7 +3569,7 @@ watchdog@17c10000 { + compatible = "qcom,apss-wdt-sc7180", "qcom,kpss-wdt"; + reg = <0 0x17c10000 0 0x1000>; + clocks = <&sleep_clk>; +- interrupts = ; ++ interrupts = ; + }; + + timer@17c20000 { +diff --git a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi +index 2e1cd219fc1822..5d462ae14ba122 100644 +--- a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi +@@ -46,6 +46,26 @@ wpss_mem: memory@9ae00000 { + }; + }; + ++&lpass_aon { ++ status = "okay"; ++}; ++ ++&lpass_core { ++ status = "okay"; ++}; ++ ++&lpass_hm { ++ status = "okay"; ++}; ++ ++&lpasscc { ++ status = "okay"; ++}; ++ ++&pdc_reset { ++ status = "okay"; ++}; ++ + /* The PMIC PON code isn't compatible w/ how Chrome EC/BIOS handle things. */ + &pmk8350_pon { + status = "disabled"; +@@ -84,6 +104,10 @@ &scm { + dma-coherent; + }; + ++&watchdog { ++ status = "okay"; ++}; ++ + &wifi { + status = "okay"; + +diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi +index 925428a5f6aea2..149c7962f2cbb7 100644 +--- a/arch/arm64/boot/dts/qcom/sc7280.dtsi ++++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -649,18 +650,6 @@ cpu7_opp_3014mhz: opp-3014400000 { + }; + }; + +- eud_typec: connector { +- compatible = "usb-c-connector"; +- +- ports { +- port@0 { +- con_eud: endpoint { +- remote-endpoint = <&eud_con>; +- }; +- }; +- }; +- }; +- + memory@80000000 { + device_type = "memory"; + /* We expect the bootloader to fill in the size */ +@@ -869,7 +858,8 @@ gcc: clock-controller@100000 { + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, <&sleep_clk>, + <0>, <&pcie1_lane>, +- <0>, <0>, <0>, <0>; ++ <0>, <0>, <0>, ++ <&usb_1_qmpphy QMP_USB43DP_USB3_PIPE_CLK>; + clock-names = "bi_tcxo", "bi_tcxo_ao", "sleep_clk", + "pcie_0_pipe_clk", "pcie_1_pipe_clk", + "ufs_phy_rx_symbol_0_clk", "ufs_phy_rx_symbol_1_clk", +@@ -936,6 +926,7 @@ sdhc_1: mmc@7c4000 { + + bus-width = <8>; + supports-cqe; ++ dma-coherent; + + qcom,dll-config = <0x0007642c>; + qcom,ddr-config = <0x80040868>; +@@ -2108,8 +2099,16 @@ pcie1: pci@1c08000 { + ranges = <0x01000000 0x0 0x00000000 0x0 0x40200000 0x0 0x100000>, + <0x02000000 0x0 0x40300000 0x0 0x40300000 0x0 0x1fd00000>; + +- interrupts = ; +- interrupt-names = "msi"; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ interrupt-names = "msi0", "msi1", "msi2", "msi3", ++ "msi4", "msi5", "msi6", "msi7"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &intc 0 0 0 434 IRQ_TYPE_LEVEL_HIGH>, +@@ -2266,6 +2265,7 @@ lpasscc: lpasscc@3000000 { + clocks = <&gcc GCC_CFG_NOC_LPASS_CLK>; + clock-names = "iface"; + #clock-cells = <1>; ++ status = "reserved"; /* Owned by ADSP firmware */ + }; + + lpass_rx_macro: codec@3200000 { +@@ -2417,6 +2417,7 @@ lpass_aon: clock-controller@3380000 { + clock-names = "bi_tcxo", "bi_tcxo_ao", "iface"; + #clock-cells = <1>; + #power-domain-cells = <1>; ++ status = "reserved"; /* Owned by ADSP firmware */ + }; + + lpass_core: clock-controller@3900000 { +@@ -2427,6 +2428,7 @@ lpass_core: clock-controller@3900000 { + power-domains = <&lpass_hm LPASS_CORE_CC_LPASS_CORE_HM_GDSC>; + #clock-cells = <1>; + #power-domain-cells = <1>; ++ status = "reserved"; /* Owned by ADSP firmware */ + }; + + lpass_cpu: audio@3987000 { +@@ -2497,6 +2499,7 @@ lpass_hm: clock-controller@3c00000 { + clock-names = "bi_tcxo"; + #clock-cells = <1>; + #power-domain-cells = <1>; ++ status = "reserved"; /* Owned by ADSP firmware */ + }; + + lpass_ag_noc: interconnect@3c40000 { +@@ -2565,7 +2568,8 @@ gpu: gpu@3d00000 { + "cx_mem", + "cx_dbgc"; + interrupts = ; +- iommus = <&adreno_smmu 0 0x401>; ++ iommus = <&adreno_smmu 0 0x400>, ++ <&adreno_smmu 1 0x400>; + operating-points-v2 = <&gpu_opp_table>; + qcom,gmu = <&gmu>; + interconnects = <&gem_noc MASTER_GFX3D 0 &mc_virt SLAVE_EBI1 0>; +@@ -2739,6 +2743,7 @@ adreno_smmu: iommu@3da0000 { + "gpu_cc_hub_aon_clk"; + + power-domains = <&gpucc GPU_CC_CX_GDSC>; ++ dma-coherent; + }; + + remoteproc_mpss: remoteproc@4080000 { +@@ -3296,6 +3301,7 @@ sdhc_2: mmc@8804000 { + operating-points-v2 = <&sdhc2_opp_table>; + + bus-width = <4>; ++ dma-coherent; + + qcom,dll-config = <0x0007642c>; + +@@ -3346,49 +3352,26 @@ usb_2_hsphy: phy@88e4000 { + resets = <&gcc GCC_QUSB2PHY_SEC_BCR>; + }; + +- usb_1_qmpphy: phy-wrapper@88e9000 { +- compatible = "qcom,sc7280-qmp-usb3-dp-phy", +- "qcom,sm8250-qmp-usb3-dp-phy"; +- reg = <0 0x088e9000 0 0x200>, +- <0 0x088e8000 0 0x40>, +- <0 0x088ea000 0 0x200>; ++ usb_1_qmpphy: phy@88e8000 { ++ compatible = "qcom,sc7280-qmp-usb3-dp-phy"; ++ reg = <0 0x088e8000 0 0x3000>; + status = "disabled"; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; + + clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>, + <&rpmhcc RPMH_CXO_CLK>, +- <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>; +- clock-names = "aux", "ref_clk_src", "com_aux"; ++ <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, ++ <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; ++ clock-names = "aux", ++ "ref", ++ "com_aux", ++ "usb3_pipe"; + + resets = <&gcc GCC_USB3_DP_PHY_PRIM_BCR>, + <&gcc GCC_USB3_PHY_PRIM_BCR>; + reset-names = "phy", "common"; + +- usb_1_ssphy: usb3-phy@88e9200 { +- reg = <0 0x088e9200 0 0x200>, +- <0 0x088e9400 0 0x200>, +- <0 0x088e9c00 0 0x400>, +- <0 0x088e9600 0 0x200>, +- <0 0x088e9800 0 0x200>, +- <0 0x088e9a00 0 0x100>; +- #clock-cells = <0>; +- #phy-cells = <0>; +- clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; +- clock-names = "pipe0"; +- clock-output-names = "usb3_phy_pipe_clk_src"; +- }; +- +- dp_phy: dp-phy@88ea200 { +- reg = <0 0x088ea200 0 0x200>, +- <0 0x088ea400 0 0x200>, +- <0 0x088eaa00 0 0x200>, +- <0 0x088ea600 0 0x200>, +- <0 0x088ea800 0 0x200>; +- #phy-cells = <0>; +- #clock-cells = <1>; +- }; ++ #clock-cells = <1>; ++ #phy-cells = <1>; + }; + + usb_2: usb@8cf8800 { +@@ -3416,8 +3399,8 @@ usb_2: usb@8cf8800 { + assigned-clock-rates = <19200000>, <200000000>; + + interrupts-extended = <&intc GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>, +- <&pdc 12 IRQ_TYPE_EDGE_RISING>, +- <&pdc 13 IRQ_TYPE_EDGE_RISING>; ++ <&pdc 12 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc 13 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hs_phy_irq", + "dp_hs_phy_irq", + "dm_hs_phy_irq"; +@@ -3624,6 +3607,8 @@ eud: eud@88e0000 { + <0 0x88e2000 0 0x1000>; + interrupts-extended = <&pdc 11 IRQ_TYPE_LEVEL_HIGH>; + ++ status = "disabled"; ++ + ports { + #address-cells = <1>; + #size-cells = <0>; +@@ -3634,13 +3619,6 @@ eud_ep: endpoint { + remote-endpoint = <&usb2_role_switch>; + }; + }; +- +- port@1 { +- reg = <1>; +- eud_con: endpoint { +- remote-endpoint = <&con_eud>; +- }; +- }; + }; + }; + +@@ -3676,9 +3654,9 @@ usb_1: usb@a6f8800 { + assigned-clock-rates = <19200000>, <200000000>; + + interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, +- <&pdc 14 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc 14 IRQ_TYPE_EDGE_BOTH>, + <&pdc 15 IRQ_TYPE_EDGE_BOTH>, +- <&pdc 17 IRQ_TYPE_EDGE_BOTH>; ++ <&pdc 17 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "hs_phy_irq", + "dp_hs_phy_irq", + "dm_hs_phy_irq", +@@ -3702,7 +3680,8 @@ usb_1_dwc3: usb@a600000 { + iommus = <&apps_smmu 0xe0 0x0>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; +- phys = <&usb_1_hsphy>, <&usb_1_ssphy>; ++ snps,parkmode-disable-ss-quirk; ++ phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>; + phy-names = "usb2-phy", "usb3-phy"; + maximum-speed = "super-speed"; + }; +@@ -3807,8 +3786,8 @@ dispcc: clock-controller@af00000 { + <&gcc GCC_DISP_GPLL0_CLK_SRC>, + <&mdss_dsi_phy 0>, + <&mdss_dsi_phy 1>, +- <&dp_phy 0>, +- <&dp_phy 1>, ++ <&usb_1_qmpphy QMP_USB43DP_DP_LINK_CLK>, ++ <&usb_1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>, + <&mdss_edp_phy 0>, + <&mdss_edp_phy 1>; + clock-names = "bi_tcxo", +@@ -4144,8 +4123,9 @@ mdss_dp: displayport-controller@ae90000 { + "stream_pixel"; + assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>; +- assigned-clock-parents = <&dp_phy 0>, <&dp_phy 1>; +- phys = <&dp_phy>; ++ assigned-clock-parents = <&usb_1_qmpphy QMP_USB43DP_DP_LINK_CLK>, ++ <&usb_1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; ++ phys = <&usb_1_qmpphy QMP_USB43DP_DP_PHY>; + phy-names = "dp"; + + operating-points-v2 = <&dp_opp_table>; +@@ -4215,6 +4195,7 @@ pdc_reset: reset-controller@b5e0000 { + compatible = "qcom,sc7280-pdc-global"; + reg = <0 0x0b5e0000 0 0x20000>; + #reset-cells = <1>; ++ status = "reserved"; /* Owned by firmware */ + }; + + tsens0: thermal-sensor@c263000 { +@@ -5211,11 +5192,12 @@ msi-controller@17a40000 { + }; + }; + +- watchdog@17c10000 { ++ watchdog: watchdog@17c10000 { + compatible = "qcom,apss-wdt-sc7280", "qcom,kpss-wdt"; + reg = <0 0x17c10000 0 0x1000>; + clocks = <&sleep_clk>; +- interrupts = ; ++ interrupts = ; ++ status = "reserved"; /* Owned by Gunyah hyp */ + }; + + timer@17c20000 { +@@ -5363,6 +5345,14 @@ cpufreq_hw: cpufreq@18591000 { + reg = <0 0x18591000 0 0x1000>, + <0 0x18592000 0 0x1000>, + <0 0x18593000 0 0x1000>; ++ ++ interrupts = , ++ , ++ ; ++ interrupt-names = "dcvsh-irq-0", ++ "dcvsh-irq-1", ++ "dcvsh-irq-2"; ++ + clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_GPLL0>; + clock-names = "xo", "alternate"; + #freq-domain-cells = <1>; +diff --git a/arch/arm64/boot/dts/qcom/sc8180x-primus.dts b/arch/arm64/boot/dts/qcom/sc8180x-primus.dts +index 834e6f9fb7c825..ae008c3b0aed93 100644 +--- a/arch/arm64/boot/dts/qcom/sc8180x-primus.dts ++++ b/arch/arm64/boot/dts/qcom/sc8180x-primus.dts +@@ -42,7 +42,7 @@ gpio-keys { + pinctrl-0 = <&hall_int_active_state>; + + lid-switch { +- gpios = <&tlmm 121 GPIO_ACTIVE_HIGH>; ++ gpios = <&tlmm 121 GPIO_ACTIVE_LOW>; + linux,input-type = ; + linux,code = ; + wakeup-source; +diff --git a/arch/arm64/boot/dts/qcom/sc8180x.dtsi b/arch/arm64/boot/dts/qcom/sc8180x.dtsi +index 486f7ffef43b2d..92b85de7706d39 100644 +--- a/arch/arm64/boot/dts/qcom/sc8180x.dtsi ++++ b/arch/arm64/boot/dts/qcom/sc8180x.dtsi +@@ -289,7 +289,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x40000004>; +- entry-latency-us = <241>; ++ entry-latency-us = <2411>; + exit-latency-us = <1461>; + min-residency-us = <4488>; + local-timer-stop; +@@ -297,7 +297,15 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + }; + + domain-idle-states { +- CLUSTER_SLEEP_0: cluster-sleep-0 { ++ CLUSTER_SLEEP_APSS_OFF: cluster-sleep-0 { ++ compatible = "domain-idle-state"; ++ arm,psci-suspend-param = <0x41000044>; ++ entry-latency-us = <3300>; ++ exit-latency-us = <3300>; ++ min-residency-us = <6000>; ++ }; ++ ++ CLUSTER_SLEEP_AOSS_SLEEP: cluster-sleep-1 { + compatible = "domain-idle-state"; + arm,psci-suspend-param = <0x4100a344>; + entry-latency-us = <3263>; +@@ -581,7 +589,7 @@ CPU_PD7: power-domain-cpu7 { + + CLUSTER_PD: power-domain-cpu-cluster0 { + #power-domain-cells = <0>; +- domain-idle-states = <&CLUSTER_SLEEP_0>; ++ domain-idle-states = <&CLUSTER_SLEEP_APSS_OFF &CLUSTER_SLEEP_AOSS_SLEEP>; + }; + }; + +@@ -781,6 +789,7 @@ gcc: clock-controller@100000 { + clock-names = "bi_tcxo", + "bi_tcxo_ao", + "sleep_clk"; ++ power-domains = <&rpmhpd SC8180X_CX>; + }; + + qupv3_id_0: geniqup@8c0000 { +@@ -1749,23 +1758,29 @@ pcie0: pci@1c00000 { + <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_PCIE_0 0>; + interconnect-names = "pcie-mem", "cpu-pcie"; + +- phys = <&pcie0_lane>; ++ phys = <&pcie0_phy>; + phy-names = "pciephy"; ++ dma-coherent; + + status = "disabled"; + }; + +- pcie0_phy: phy-wrapper@1c06000 { ++ pcie0_phy: phy@1c06000 { + compatible = "qcom,sc8180x-qmp-pcie-phy"; +- reg = <0 0x1c06000 0 0x1c0>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; ++ reg = <0 0x01c06000 0 0x1000>; + clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>, + <&gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&gcc GCC_PCIE_0_CLKREF_CLK>, +- <&gcc GCC_PCIE1_PHY_REFGEN_CLK>; +- clock-names = "aux", "cfg_ahb", "ref", "refgen"; ++ <&gcc GCC_PCIE0_PHY_REFGEN_CLK>, ++ <&gcc GCC_PCIE_0_PIPE_CLK>; ++ clock-names = "aux", ++ "cfg_ahb", ++ "ref", ++ "refgen", ++ "pipe"; ++ #clock-cells = <0>; ++ clock-output-names = "pcie_0_pipe_clk"; ++ #phy-cells = <0>; + + resets = <&gcc GCC_PCIE_0_PHY_BCR>; + reset-names = "phy"; +@@ -1774,21 +1789,6 @@ pcie0_phy: phy-wrapper@1c06000 { + assigned-clock-rates = <100000000>; + + status = "disabled"; +- +- pcie0_lane: phy@1c06200 { +- reg = <0 0x1c06200 0 0x170>, /* tx0 */ +- <0 0x1c06400 0 0x200>, /* rx0 */ +- <0 0x1c06a00 0 0x1f0>, /* pcs */ +- <0 0x1c06600 0 0x170>, /* tx1 */ +- <0 0x1c06800 0 0x200>, /* rx1 */ +- <0 0x1c06e00 0 0xf4>; /* pcs_com */ +- clocks = <&gcc GCC_PCIE_0_PIPE_CLK>; +- clock-names = "pipe0"; +- +- #clock-cells = <0>; +- clock-output-names = "pcie_0_pipe_clk"; +- #phy-cells = <0>; +- }; + }; + + pcie3: pci@1c08000 { +@@ -1853,26 +1853,33 @@ pcie3: pci@1c08000 { + power-domains = <&gcc PCIE_3_GDSC>; + + interconnects = <&aggre2_noc MASTER_PCIE_3 0 &mc_virt SLAVE_EBI_CH0 0>, +- <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_PCIE_0 0>; ++ <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_PCIE_3 0>; + interconnect-names = "pcie-mem", "cpu-pcie"; + +- phys = <&pcie3_lane>; ++ phys = <&pcie3_phy>; + phy-names = "pciephy"; ++ dma-coherent; + + status = "disabled"; + }; + +- pcie3_phy: phy-wrapper@1c0c000 { ++ pcie3_phy: phy@1c0c000 { + compatible = "qcom,sc8180x-qmp-pcie-phy"; +- reg = <0 0x1c0c000 0 0x1c0>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; ++ reg = <0 0x01c0c000 0 0x1000>; + clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>, + <&gcc GCC_PCIE_3_CFG_AHB_CLK>, + <&gcc GCC_PCIE_3_CLKREF_CLK>, +- <&gcc GCC_PCIE2_PHY_REFGEN_CLK>; +- clock-names = "aux", "cfg_ahb", "ref", "refgen"; ++ <&gcc GCC_PCIE3_PHY_REFGEN_CLK>, ++ <&gcc GCC_PCIE_3_PIPE_CLK>; ++ clock-names = "aux", ++ "cfg_ahb", ++ "ref", ++ "refgen", ++ "pipe"; ++ #clock-cells = <0>; ++ clock-output-names = "pcie_3_pipe_clk"; ++ ++ #phy-cells = <0>; + + resets = <&gcc GCC_PCIE_3_PHY_BCR>; + reset-names = "phy"; +@@ -1881,21 +1888,6 @@ pcie3_phy: phy-wrapper@1c0c000 { + assigned-clock-rates = <100000000>; + + status = "disabled"; +- +- pcie3_lane: phy@1c0c200 { +- reg = <0 0x1c0c200 0 0x170>, /* tx0 */ +- <0 0x1c0c400 0 0x200>, /* rx0 */ +- <0 0x1c0ca00 0 0x1f0>, /* pcs */ +- <0 0x1c0c600 0 0x170>, /* tx1 */ +- <0 0x1c0c800 0 0x200>, /* rx1 */ +- <0 0x1c0ce00 0 0xf4>; /* pcs_com */ +- clocks = <&gcc GCC_PCIE_3_PIPE_CLK>; +- clock-names = "pipe0"; +- +- #clock-cells = <0>; +- clock-output-names = "pcie_3_pipe_clk"; +- #phy-cells = <0>; +- }; + }; + + pcie1: pci@1c10000 { +@@ -1960,26 +1952,33 @@ pcie1: pci@1c10000 { + power-domains = <&gcc PCIE_1_GDSC>; + + interconnects = <&aggre2_noc MASTER_PCIE_1 0 &mc_virt SLAVE_EBI_CH0 0>, +- <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_PCIE_0 0>; ++ <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_PCIE_1 0>; + interconnect-names = "pcie-mem", "cpu-pcie"; + +- phys = <&pcie1_lane>; ++ phys = <&pcie1_phy>; + phy-names = "pciephy"; ++ dma-coherent; + + status = "disabled"; + }; + +- pcie1_phy: phy-wrapper@1c16000 { ++ pcie1_phy: phy@1c16000 { + compatible = "qcom,sc8180x-qmp-pcie-phy"; +- reg = <0 0x1c16000 0 0x1c0>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; ++ reg = <0 0x01c16000 0 0x1000>; + clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>, + <&gcc GCC_PCIE_1_CFG_AHB_CLK>, + <&gcc GCC_PCIE_1_CLKREF_CLK>, +- <&gcc GCC_PCIE1_PHY_REFGEN_CLK>; +- clock-names = "aux", "cfg_ahb", "ref", "refgen"; ++ <&gcc GCC_PCIE1_PHY_REFGEN_CLK>, ++ <&gcc GCC_PCIE_1_PIPE_CLK>; ++ clock-names = "aux", ++ "cfg_ahb", ++ "ref", ++ "refgen", ++ "pipe"; ++ #clock-cells = <0>; ++ clock-output-names = "pcie_1_pipe_clk"; ++ ++ #phy-cells = <0>; + + resets = <&gcc GCC_PCIE_1_PHY_BCR>; + reset-names = "phy"; +@@ -1988,21 +1987,6 @@ pcie1_phy: phy-wrapper@1c16000 { + assigned-clock-rates = <100000000>; + + status = "disabled"; +- +- pcie1_lane: phy@1c0e200 { +- reg = <0 0x1c16200 0 0x170>, /* tx0 */ +- <0 0x1c16400 0 0x200>, /* rx0 */ +- <0 0x1c16a00 0 0x1f0>, /* pcs */ +- <0 0x1c16600 0 0x170>, /* tx1 */ +- <0 0x1c16800 0 0x200>, /* rx1 */ +- <0 0x1c16e00 0 0xf4>; /* pcs_com */ +- clocks = <&gcc GCC_PCIE_1_PIPE_CLK>; +- clock-names = "pipe0"; +- #clock-cells = <0>; +- clock-output-names = "pcie_1_pipe_clk"; +- +- #phy-cells = <0>; +- }; + }; + + pcie2: pci@1c18000 { +@@ -2067,26 +2051,33 @@ pcie2: pci@1c18000 { + power-domains = <&gcc PCIE_2_GDSC>; + + interconnects = <&aggre2_noc MASTER_PCIE_2 0 &mc_virt SLAVE_EBI_CH0 0>, +- <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_PCIE_0 0>; ++ <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_PCIE_2 0>; + interconnect-names = "pcie-mem", "cpu-pcie"; + +- phys = <&pcie2_lane>; ++ phys = <&pcie2_phy>; + phy-names = "pciephy"; ++ dma-coherent; + + status = "disabled"; + }; + +- pcie2_phy: phy-wrapper@1c1c000 { ++ pcie2_phy: phy@1c1c000 { + compatible = "qcom,sc8180x-qmp-pcie-phy"; +- reg = <0 0x1c1c000 0 0x1c0>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; ++ reg = <0 0x01c1c000 0 0x1000>; + clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>, + <&gcc GCC_PCIE_2_CFG_AHB_CLK>, + <&gcc GCC_PCIE_2_CLKREF_CLK>, +- <&gcc GCC_PCIE2_PHY_REFGEN_CLK>; +- clock-names = "aux", "cfg_ahb", "ref", "refgen"; ++ <&gcc GCC_PCIE2_PHY_REFGEN_CLK>, ++ <&gcc GCC_PCIE_2_PIPE_CLK>; ++ clock-names = "aux", ++ "cfg_ahb", ++ "ref", ++ "refgen", ++ "pipe"; ++ #clock-cells = <0>; ++ clock-output-names = "pcie_2_pipe_clk"; ++ ++ #phy-cells = <0>; + + resets = <&gcc GCC_PCIE_2_PHY_BCR>; + reset-names = "phy"; +@@ -2095,22 +2086,6 @@ pcie2_phy: phy-wrapper@1c1c000 { + assigned-clock-rates = <100000000>; + + status = "disabled"; +- +- pcie2_lane: phy@1c0e200 { +- reg = <0 0x1c1c200 0 0x170>, /* tx0 */ +- <0 0x1c1c400 0 0x200>, /* rx0 */ +- <0 0x1c1ca00 0 0x1f0>, /* pcs */ +- <0 0x1c1c600 0 0x170>, /* tx1 */ +- <0 0x1c1c800 0 0x200>, /* rx1 */ +- <0 0x1c1ce00 0 0xf4>; /* pcs_com */ +- clocks = <&gcc GCC_PCIE_2_PIPE_CLK>; +- clock-names = "pipe0"; +- +- #clock-cells = <0>; +- clock-output-names = "pcie_2_pipe_clk"; +- +- #phy-cells = <0>; +- }; + }; + + ufs_mem_hc: ufshc@1d84000 { +@@ -2118,7 +2093,7 @@ ufs_mem_hc: ufshc@1d84000 { + "jedec,ufs-2.0"; + reg = <0 0x01d84000 0 0x2500>; + interrupts = ; +- phys = <&ufs_mem_phy_lanes>; ++ phys = <&ufs_mem_phy>; + phy-names = "ufsphy"; + lanes-per-direction = <2>; + #reset-cells = <1>; +@@ -2157,10 +2132,8 @@ ufs_mem_hc: ufshc@1d84000 { + + ufs_mem_phy: phy-wrapper@1d87000 { + compatible = "qcom,sc8180x-qmp-ufs-phy"; +- reg = <0 0x01d87000 0 0x1c0>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; ++ reg = <0 0x01d87000 0 0x1000>; ++ + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; + clock-names = "ref", +@@ -2168,16 +2141,12 @@ ufs_mem_phy: phy-wrapper@1d87000 { + + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; +- status = "disabled"; + +- ufs_mem_phy_lanes: phy@1d87400 { +- reg = <0 0x01d87400 0 0x108>, +- <0 0x01d87600 0 0x1e0>, +- <0 0x01d87c00 0 0x1dc>, +- <0 0x01d87800 0 0x108>, +- <0 0x01d87a00 0 0x1e0>; +- #phy-cells = <0>; +- }; ++ power-domains = <&gcc UFS_PHY_GDSC>; ++ ++ #phy-cells = <0>; ++ ++ status = "disabled"; + }; + + ipa_virt: interconnect@1e00000 { +@@ -2576,11 +2545,14 @@ usb_sec_dpphy: dp-phy@88ef200 { + + system-cache-controller@9200000 { + compatible = "qcom,sc8180x-llcc"; +- reg = <0 0x09200000 0 0x50000>, <0 0x09280000 0 0x50000>, +- <0 0x09300000 0 0x50000>, <0 0x09380000 0 0x50000>, +- <0 0x09600000 0 0x50000>; ++ reg = <0 0x09200000 0 0x58000>, <0 0x09280000 0 0x58000>, ++ <0 0x09300000 0 0x58000>, <0 0x09380000 0 0x58000>, ++ <0 0x09400000 0 0x58000>, <0 0x09480000 0 0x58000>, ++ <0 0x09500000 0 0x58000>, <0 0x09580000 0 0x58000>, ++ <0 0x09600000 0 0x58000>; + reg-names = "llcc0_base", "llcc1_base", "llcc2_base", +- "llcc3_base", "llcc_broadcast_base"; ++ "llcc3_base", "llcc4_base", "llcc5_base", ++ "llcc6_base", "llcc7_base", "llcc_broadcast_base"; + interrupts = ; + }; + +@@ -2594,10 +2566,10 @@ gem_noc: interconnect@9680000 { + usb_prim: usb@a6f8800 { + compatible = "qcom,sc8180x-dwc3", "qcom,dwc3"; + reg = <0 0x0a6f8800 0 0x400>; +- interrupts = , +- , +- , +- ; ++ interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc 8 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc 9 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hs_phy_irq", + "ss_phy_irq", + "dm_hs_phy_irq", +@@ -2668,10 +2640,10 @@ usb_sec: usb@a8f8800 { + "xo"; + resets = <&gcc GCC_USB30_SEC_BCR>; + power-domains = <&gcc USB30_SEC_GDSC>; +- interrupts = , +- , +- , +- ; ++ interrupts-extended = <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc 40 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc 10 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc 11 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hs_phy_irq", "ss_phy_irq", + "dm_hs_phy_irq", "dp_hs_phy_irq"; + +@@ -2756,10 +2728,8 @@ mdss_mdp: mdp@ae01000 { + "core", + "vsync"; + +- assigned-clocks = <&dispcc DISP_CC_MDSS_MDP_CLK>, +- <&dispcc DISP_CC_MDSS_VSYNC_CLK>; +- assigned-clock-rates = <460000000>, +- <19200000>; ++ assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>; ++ assigned-clock-rates = <19200000>; + + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmhpd SC8180X_MMCX>; +@@ -3219,7 +3189,7 @@ edp_phy: phy@aec2a00 { + <&dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "aux", "cfg_ahb"; + +- power-domains = <&dispcc MDSS_GDSC>; ++ power-domains = <&rpmhpd SC8180X_MX>; + + #clock-cells = <1>; + #phy-cells = <0>; +@@ -3245,6 +3215,7 @@ dispcc: clock-controller@af00000 { + "edp_phy_pll_link_clk", + "edp_phy_pll_vco_div_clk"; + power-domains = <&rpmhpd SC8180X_MMCX>; ++ required-opps = <&rpmhpd_opp_low_svs>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; +@@ -3283,7 +3254,7 @@ tsens1: thermal-sensor@c265000 { + + aoss_qmp: power-controller@c300000 { + compatible = "qcom,sc8180x-aoss-qmp", "qcom,aoss-qmp"; +- reg = <0x0 0x0c300000 0x0 0x100000>; ++ reg = <0x0 0x0c300000 0x0 0x400>; + interrupts = ; + mboxes = <&apss_shared 0>; + +diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts +index e4861c61a65bdc..ffc4406422ae2f 100644 +--- a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts ++++ b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts +@@ -458,6 +458,8 @@ mdss0_dp3_out: endpoint { + }; + + &mdss0_dp3_phy { ++ compatible = "qcom,sc8280xp-edp-phy"; ++ + vdda-phy-supply = <&vreg_l6b>; + vdda-pll-supply = <&vreg_l3b>; + +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 38edaf51aa3457..5c2894fcfa4a08 100644 +--- a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts ++++ b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts +@@ -82,6 +82,9 @@ switch-lid { + leds { + compatible = "gpio-leds"; + ++ pinctrl-names = "default"; ++ pinctrl-0 = <&cam_indicator_en>; ++ + led-camera-indicator { + label = "white:camera-indicator"; + function = LED_FUNCTION_INDICATOR; +@@ -601,6 +604,7 @@ mdss0_dp3_out: endpoint { + }; + + &mdss0_dp3_phy { ++ compatible = "qcom,sc8280xp-edp-phy"; + vdda-phy-supply = <&vreg_l6b>; + vdda-pll-supply = <&vreg_l3b>; + +@@ -615,15 +619,16 @@ &i2c4 { + + status = "okay"; + +- /* FIXME: verify */ + touchscreen@10 { +- compatible = "hid-over-i2c"; ++ compatible = "elan,ekth5015m", "elan,ekth6915"; + reg = <0x10>; + +- hid-descr-addr = <0x1>; + interrupts-extended = <&tlmm 175 IRQ_TYPE_LEVEL_LOW>; +- vdd-supply = <&vreg_misc_3p3>; +- vddl-supply = <&vreg_s10b>; ++ reset-gpios = <&tlmm 99 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>; ++ no-reset-on-power-off; ++ ++ vcc33-supply = <&vreg_misc_3p3>; ++ vccio-supply = <&vreg_misc_3p3>; + + pinctrl-names = "default"; + pinctrl-0 = <&ts0_default>; +@@ -717,6 +722,8 @@ &pcie3a_phy { + }; + + &pcie4 { ++ max-link-speed = <2>; ++ + perst-gpios = <&tlmm 141 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 139 GPIO_ACTIVE_LOW>; + +@@ -1277,6 +1284,13 @@ hstp-sw-ctrl-pins { + }; + }; + ++ cam_indicator_en: cam-indicator-en-state { ++ pins = "gpio28"; ++ function = "gpio"; ++ drive-strength = <2>; ++ bias-disable; ++ }; ++ + edp_reg_en: edp-reg-en-state { + pins = "gpio25"; + function = "gpio"; +@@ -1438,8 +1452,8 @@ int-n-pins { + reset-n-pins { + pins = "gpio99"; + function = "gpio"; +- output-high; +- drive-strength = <16>; ++ drive-strength = <2>; ++ bias-disable; + }; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi +index cad59af7ccef1b..6425c74edd60cc 100644 +--- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi ++++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi +@@ -1773,6 +1773,7 @@ pcie4: pcie@1c00000 { + reset-names = "pci"; + + power-domains = <&gcc PCIE_4_GDSC>; ++ required-opps = <&rpmhpd_opp_nom>; + + phys = <&pcie4_phy>; + phy-names = "pciephy"; +@@ -1797,6 +1798,7 @@ pcie4_phy: phy@1c06000 { + assigned-clock-rates = <100000000>; + + power-domains = <&gcc PCIE_4_GDSC>; ++ required-opps = <&rpmhpd_opp_nom>; + + resets = <&gcc GCC_PCIE_4_PHY_BCR>; + reset-names = "phy"; +@@ -1871,6 +1873,7 @@ pcie3b: pcie@1c08000 { + reset-names = "pci"; + + power-domains = <&gcc PCIE_3B_GDSC>; ++ required-opps = <&rpmhpd_opp_nom>; + + phys = <&pcie3b_phy>; + phy-names = "pciephy"; +@@ -1895,6 +1898,7 @@ pcie3b_phy: phy@1c0e000 { + assigned-clock-rates = <100000000>; + + power-domains = <&gcc PCIE_3B_GDSC>; ++ required-opps = <&rpmhpd_opp_nom>; + + resets = <&gcc GCC_PCIE_3B_PHY_BCR>; + reset-names = "phy"; +@@ -1969,6 +1973,7 @@ pcie3a: pcie@1c10000 { + reset-names = "pci"; + + power-domains = <&gcc PCIE_3A_GDSC>; ++ required-opps = <&rpmhpd_opp_nom>; + + phys = <&pcie3a_phy>; + phy-names = "pciephy"; +@@ -1994,6 +1999,7 @@ pcie3a_phy: phy@1c14000 { + assigned-clock-rates = <100000000>; + + power-domains = <&gcc PCIE_3A_GDSC>; ++ required-opps = <&rpmhpd_opp_nom>; + + resets = <&gcc GCC_PCIE_3A_PHY_BCR>; + reset-names = "phy"; +@@ -2070,6 +2076,7 @@ pcie2b: pcie@1c18000 { + reset-names = "pci"; + + power-domains = <&gcc PCIE_2B_GDSC>; ++ required-opps = <&rpmhpd_opp_nom>; + + phys = <&pcie2b_phy>; + phy-names = "pciephy"; +@@ -2094,6 +2101,7 @@ pcie2b_phy: phy@1c1e000 { + assigned-clock-rates = <100000000>; + + power-domains = <&gcc PCIE_2B_GDSC>; ++ required-opps = <&rpmhpd_opp_nom>; + + resets = <&gcc GCC_PCIE_2B_PHY_BCR>; + reset-names = "phy"; +@@ -2168,6 +2176,7 @@ pcie2a: pcie@1c20000 { + reset-names = "pci"; + + power-domains = <&gcc PCIE_2A_GDSC>; ++ required-opps = <&rpmhpd_opp_nom>; + + phys = <&pcie2a_phy>; + phy-names = "pciephy"; +@@ -2193,6 +2202,7 @@ pcie2a_phy: phy@1c24000 { + assigned-clock-rates = <100000000>; + + power-domains = <&gcc PCIE_2A_GDSC>; ++ required-opps = <&rpmhpd_opp_nom>; + + resets = <&gcc GCC_PCIE_2A_PHY_BCR>; + reset-names = "phy"; +@@ -4225,7 +4235,7 @@ watchdog@17c10000 { + compatible = "qcom,apss-wdt-sc8280xp", "qcom,kpss-wdt"; + reg = <0 0x17c10000 0 0x1000>; + clocks = <&sleep_clk>; +- interrupts = ; ++ interrupts = ; + }; + + timer@17c20000 { +diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi +index ec6003212c4d5f..0f3f57fb860ec8 100644 +--- a/arch/arm64/boot/dts/qcom/sdm630.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi +@@ -1258,6 +1258,7 @@ usb3_dwc3: usb@a800000 { + interrupts = ; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; ++ snps,parkmode-disable-ss-quirk; + + /* + * SDM630 technically supports USB3 but I +diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi +index 84cd2e39266fed..730c8351bcaa33 100644 +--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi +@@ -1295,10 +1295,10 @@ usb_1: usb@a6f8800 { + <&gcc GCC_USB30_PRIM_MASTER_CLK>; + assigned-clock-rates = <19200000>, <150000000>; + +- interrupts = , +- , +- , +- ; ++ interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc 8 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc 9 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hs_phy_irq", "ss_phy_irq", + "dm_hs_phy_irq", "dp_hs_phy_irq"; + +@@ -1328,7 +1328,8 @@ pdc: interrupt-controller@b220000 { + compatible = "qcom,sdm670-pdc", "qcom,pdc"; + reg = <0 0x0b220000 0 0x30000>; + qcom,pdc-ranges = <0 480 40>, <41 521 7>, <49 529 4>, +- <54 534 24>, <79 559 30>, <115 630 7>; ++ <54 534 24>, <79 559 15>, <94 609 15>, ++ <115 630 7>; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupt-controller; +diff --git a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi +index f86e7acdfd99f4..0ab5e8f53ac9f8 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi +@@ -143,16 +143,20 @@ panel_in_edp: endpoint { + }; + }; + ++&cpufreq_hw { ++ /delete-property/ interrupts-extended; /* reference to lmh_cluster[01] */ ++}; ++ + &psci { +- /delete-node/ cpu0; +- /delete-node/ cpu1; +- /delete-node/ cpu2; +- /delete-node/ cpu3; +- /delete-node/ cpu4; +- /delete-node/ cpu5; +- /delete-node/ cpu6; +- /delete-node/ cpu7; +- /delete-node/ cpu-cluster0; ++ /delete-node/ power-domain-cpu0; ++ /delete-node/ power-domain-cpu1; ++ /delete-node/ power-domain-cpu2; ++ /delete-node/ power-domain-cpu3; ++ /delete-node/ power-domain-cpu4; ++ /delete-node/ power-domain-cpu5; ++ /delete-node/ power-domain-cpu6; ++ /delete-node/ power-domain-cpu7; ++ /delete-node/ power-domain-cluster; + }; + + &cpus { +@@ -275,6 +279,14 @@ &BIG_CPU_SLEEP_1 + &CLUSTER_SLEEP_0>; + }; + ++&lmh_cluster0 { ++ status = "disabled"; ++}; ++ ++&lmh_cluster1 { ++ status = "disabled"; ++}; ++ + /* + * Reserved memory changes + * +@@ -338,6 +350,8 @@ flash@0 { + + + &apps_rsc { ++ /delete-property/ power-domains; ++ + regulators-0 { + compatible = "qcom,pm8998-rpmh-regulators"; + qcom,pmic-id = "a"; +diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +index c7eba6c491be2b..0a891a0122446c 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +@@ -67,8 +67,8 @@ led-0 { + function = LED_FUNCTION_INDICATOR; + color = ; + gpios = <&pm8998_gpios 13 GPIO_ACTIVE_HIGH>; +- linux,default-trigger = "panic-indicator"; + default-state = "off"; ++ panic-indicator; + }; + + led-1 { +@@ -580,7 +580,7 @@ &mss_pil { + &pcie0 { + status = "okay"; + perst-gpios = <&tlmm 35 GPIO_ACTIVE_LOW>; +- enable-gpio = <&tlmm 134 GPIO_ACTIVE_HIGH>; ++ wake-gpios = <&tlmm 134 GPIO_ACTIVE_HIGH>; + + vddpe-3v3-supply = <&pcie0_3p3v_dual>; + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts +index b3c27a5247429f..1516113391edc3 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts +@@ -716,6 +716,8 @@ &wifi { + vdd-1.8-xo-supply = <&vreg_l7a_1p8>; + vdd-1.3-rfa-supply = <&vreg_l17a_1p3>; + vdd-3.3-ch0-supply = <&vreg_l25a_3p3>; ++ ++ qcom,snoc-host-cap-8bit-quirk; + }; + + /* PINCTRL - additions to nodes defined in sdm845.dtsi */ +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index 122c7128dea9da..9322b92a1e6825 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -485,13 +485,13 @@ &pmi8998_charger { + }; + + &q6afedai { +- qi2s@22 { +- reg = <22>; ++ dai@22 { ++ reg = ; + qcom,sd-lines = <1>; + }; + +- qi2s@23 { +- reg = <23>; ++ dai@23 { ++ reg = ; + qcom,sd-lines = <0>; + }; + }; +diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi +index 055ca80c007578..dcdc8a0cd1819f 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2634,6 +2635,8 @@ ufs_mem_phy: phy@1d87000 { + clocks = <&gcc GCC_UFS_MEM_CLKREF_CLK>, + <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; + ++ power-domains = <&gcc UFS_PHY_GDSC>; ++ + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; + status = "disabled"; +@@ -3363,8 +3366,8 @@ slpi_pas: remoteproc@5c00000 { + + qcom,qmp = <&aoss_qmp>; + +- power-domains = <&rpmhpd SDM845_CX>, +- <&rpmhpd SDM845_MX>; ++ power-domains = <&rpmhpd SDM845_LCX>, ++ <&rpmhpd SDM845_LMX>; + power-domain-names = "lcx", "lmx"; + + memory-region = <&slpi_mem>; +@@ -3555,11 +3558,8 @@ etf_out: endpoint { + }; + + in-ports { +- #address-cells = <1>; +- #size-cells = <0>; + +- port@1 { +- reg = <1>; ++ port { + etf_in: endpoint { + remote-endpoint = + <&merge_funnel_out>; +@@ -3984,80 +3984,54 @@ usb_2_hsphy: phy@88e3000 { + nvmem-cells = <&qusb2s_hstx_trim>; + }; + +- usb_1_qmpphy: phy@88e9000 { ++ usb_1_qmpphy: phy@88e8000 { + compatible = "qcom,sdm845-qmp-usb3-dp-phy"; +- reg = <0 0x088e9000 0 0x18c>, +- <0 0x088e8000 0 0x38>, +- <0 0x088ea000 0 0x40>; ++ reg = <0 0x088e8000 0 0x3000>; + status = "disabled"; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; + + clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>, +- <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>, +- <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>; +- clock-names = "aux", "cfg_ahb", "ref", "com_aux"; ++ <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, ++ <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, ++ <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; ++ clock-names = "aux", ++ "ref", ++ "com_aux", ++ "usb3_pipe", ++ "cfg_ahb"; + + resets = <&gcc GCC_USB3_PHY_PRIM_BCR>, + <&gcc GCC_USB3_DP_PHY_PRIM_BCR>; + reset-names = "phy", "common"; + +- usb_1_ssphy: usb3-phy@88e9200 { +- reg = <0 0x088e9200 0 0x128>, +- <0 0x088e9400 0 0x200>, +- <0 0x088e9c00 0 0x218>, +- <0 0x088e9600 0 0x128>, +- <0 0x088e9800 0 0x200>, +- <0 0x088e9a00 0 0x100>; +- #clock-cells = <0>; +- #phy-cells = <0>; +- clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; +- clock-names = "pipe0"; +- clock-output-names = "usb3_phy_pipe_clk_src"; +- }; +- +- dp_phy: dp-phy@88ea200 { +- reg = <0 0x088ea200 0 0x200>, +- <0 0x088ea400 0 0x200>, +- <0 0x088eaa00 0 0x200>, +- <0 0x088ea600 0 0x200>, +- <0 0x088ea800 0 0x200>; +- #clock-cells = <1>; +- #phy-cells = <0>; +- }; ++ #clock-cells = <1>; ++ #phy-cells = <1>; + }; + + usb_2_qmpphy: phy@88eb000 { + compatible = "qcom,sdm845-qmp-usb3-uni-phy"; +- reg = <0 0x088eb000 0 0x18c>; +- status = "disabled"; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; ++ reg = <0 0x088eb000 0 0x1000>; + + clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>, + <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&gcc GCC_USB3_SEC_CLKREF_CLK>, +- <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>; +- clock-names = "aux", "cfg_ahb", "ref", "com_aux"; ++ <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>, ++ <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; ++ clock-names = "aux", ++ "cfg_ahb", ++ "ref", ++ "com_aux", ++ "pipe"; ++ clock-output-names = "usb3_uni_phy_pipe_clk_src"; ++ #clock-cells = <0>; ++ #phy-cells = <0>; + +- resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>, +- <&gcc GCC_USB3_PHY_SEC_BCR>; +- reset-names = "phy", "common"; ++ resets = <&gcc GCC_USB3_PHY_SEC_BCR>, ++ <&gcc GCC_USB3PHY_PHY_SEC_BCR>; ++ reset-names = "phy", ++ "phy_phy"; + +- usb_2_ssphy: phy@88eb200 { +- reg = <0 0x088eb200 0 0x128>, +- <0 0x088eb400 0 0x1fc>, +- <0 0x088eb800 0 0x218>, +- <0 0x088eb600 0 0x70>; +- #clock-cells = <0>; +- #phy-cells = <0>; +- clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; +- clock-names = "pipe0"; +- clock-output-names = "usb3_uni_phy_pipe_clk_src"; +- }; ++ status = "disabled"; + }; + + usb_1: usb@a6f8800 { +@@ -4084,10 +4058,10 @@ usb_1: usb@a6f8800 { + <&gcc GCC_USB30_PRIM_MASTER_CLK>; + assigned-clock-rates = <19200000>, <150000000>; + +- interrupts = , +- , +- , +- ; ++ interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc_intc 6 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc_intc 8 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc_intc 9 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hs_phy_irq", "ss_phy_irq", + "dm_hs_phy_irq", "dp_hs_phy_irq"; + +@@ -4106,7 +4080,8 @@ usb_1_dwc3: usb@a600000 { + iommus = <&apps_smmu 0x740 0>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; +- phys = <&usb_1_hsphy>, <&usb_1_ssphy>; ++ snps,parkmode-disable-ss-quirk; ++ phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>; + phy-names = "usb2-phy", "usb3-phy"; + }; + }; +@@ -4135,10 +4110,10 @@ usb_2: usb@a8f8800 { + <&gcc GCC_USB30_SEC_MASTER_CLK>; + assigned-clock-rates = <19200000>, <150000000>; + +- interrupts = , +- , +- , +- ; ++ interrupts-extended = <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc_intc 7 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc_intc 10 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc_intc 11 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hs_phy_irq", "ss_phy_irq", + "dm_hs_phy_irq", "dp_hs_phy_irq"; + +@@ -4157,7 +4132,8 @@ usb_2_dwc3: usb@a800000 { + iommus = <&apps_smmu 0x760 0>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; +- phys = <&usb_2_hsphy>, <&usb_2_ssphy>; ++ snps,parkmode-disable-ss-quirk; ++ phys = <&usb_2_hsphy>, <&usb_2_qmpphy>; + phy-names = "usb2-phy", "usb3-phy"; + }; + }; +@@ -4574,8 +4550,9 @@ mdss_dp: displayport-controller@ae90000 { + "ctrl_link_iface", "stream_pixel"; + assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>; +- assigned-clock-parents = <&dp_phy 0>, <&dp_phy 1>; +- phys = <&dp_phy>; ++ assigned-clock-parents = <&usb_1_qmpphy QMP_USB43DP_DP_LINK_CLK>, ++ <&usb_1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; ++ phys = <&usb_1_qmpphy QMP_USB43DP_DP_PHY>; + phy-names = "dp"; + + operating-points-v2 = <&dp_opp_table>; +@@ -4913,8 +4890,8 @@ dispcc: clock-controller@af00000 { + <&mdss_dsi0_phy 1>, + <&mdss_dsi1_phy 0>, + <&mdss_dsi1_phy 1>, +- <&dp_phy 0>, +- <&dp_phy 1>; ++ <&usb_1_qmpphy QMP_USB43DP_DP_LINK_CLK>, ++ <&usb_1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; + clock-names = "bi_tcxo", + "gcc_disp_gpll0_clk_src", + "gcc_disp_gpll0_div_clk_src", +@@ -5118,7 +5095,7 @@ watchdog@17980000 { + compatible = "qcom,apss-wdt-sdm845", "qcom,kpss-wdt"; + reg = <0 0x17980000 0 0x1000>; + clocks = <&sleep_clk>; +- interrupts = ; ++ interrupts = ; + }; + + apss_shared: mailbox@17990000 { +diff --git a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts +index 92a812b5f4238e..fe5c12da666e40 100644 +--- a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts ++++ b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts +@@ -488,6 +488,7 @@ ecsh: hid@5c { + &ipa { + qcom,gsi-loader = "self"; + memory-region = <&ipa_fw_mem>; ++ firmware-name = "qcom/sdm850/LENOVO/81JL/ipa_fws.elf"; + status = "okay"; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sdx75-idp.dts b/arch/arm64/boot/dts/qcom/sdx75-idp.dts +index 10d15871f2c48e..a14e0650c4a8aa 100644 +--- a/arch/arm64/boot/dts/qcom/sdx75-idp.dts ++++ b/arch/arm64/boot/dts/qcom/sdx75-idp.dts +@@ -44,7 +44,7 @@ vreg_bob_3p3: pmx75-bob { + }; + + &apps_rsc { +- pmx75-rpmh-regulators { ++ regulators-0 { + compatible = "qcom,pmx75-rpmh-regulators"; + qcom,pmic-id = "b"; + +diff --git a/arch/arm64/boot/dts/qcom/sm6115.dtsi b/arch/arm64/boot/dts/qcom/sm6115.dtsi +index 839c6035124034..821db9b8518557 100644 +--- a/arch/arm64/boot/dts/qcom/sm6115.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm6115.dtsi +@@ -591,6 +591,11 @@ tcsr_mutex: hwlock@340000 { + #hwlock-cells = <1>; + }; + ++ tcsr_regs: syscon@3c0000 { ++ compatible = "qcom,sm6115-tcsr", "syscon"; ++ reg = <0x0 0x003c0000 0x0 0x40000>; ++ }; ++ + tlmm: pinctrl@500000 { + compatible = "qcom,sm6115-tlmm"; + reg = <0x0 0x00500000 0x0 0x400000>, +@@ -856,6 +861,8 @@ usb_qmpphy: phy@1615000 { + + #phy-cells = <0>; + ++ qcom,tcsr-reg = <&tcsr_regs 0xb244>; ++ + status = "disabled"; + }; + +@@ -1036,6 +1043,8 @@ ufs_mem_phy: phy@4807000 { + clocks = <&gcc GCC_UFS_CLKREF_CLK>, <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; + clock-names = "ref", "ref_aux"; + ++ power-domains = <&gcc GCC_UFS_PHY_GDSC>; ++ + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; + status = "disabled"; +diff --git a/arch/arm64/boot/dts/qcom/sm6125.dtsi b/arch/arm64/boot/dts/qcom/sm6125.dtsi +index d7c1a40617c647..07081088ba1463 100644 +--- a/arch/arm64/boot/dts/qcom/sm6125.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm6125.dtsi +@@ -1165,6 +1165,10 @@ usb3: usb@4ef8800 { + <&gcc GCC_USB30_PRIM_MASTER_CLK>; + assigned-clock-rates = <19200000>, <66666667>; + ++ interrupts = , ++ ; ++ interrupt-names = "hs_phy_irq", "ss_phy_irq"; ++ + power-domains = <&gcc USB30_PRIM_GDSC>; + qcom,select-utmi-as-pipe-clk; + status = "disabled"; +@@ -1208,7 +1212,7 @@ spmi_bus: spmi@1c40000 { + + apps_smmu: iommu@c600000 { + compatible = "qcom,sm6125-smmu-500", "qcom,smmu-500", "arm,mmu-500"; +- reg = <0xc600000 0x80000>; ++ reg = <0x0c600000 0x80000>; + interrupts = , + , + , +diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi +index 8fd6f4d0349001..2efceb49a3218e 100644 +--- a/arch/arm64/boot/dts/qcom/sm6350.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi +@@ -1197,6 +1197,8 @@ ufs_mem_phy: phy@1d87000 { + clocks = <&gcc GCC_UFS_MEM_CLKREF_CLK>, + <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; + ++ power-domains = <&gcc UFS_PHY_GDSC>; ++ + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; + +@@ -1297,6 +1299,7 @@ fastrpc { + compatible = "qcom,fastrpc"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + label = "adsp"; ++ qcom,non-secure-domain; + #address-cells = <1>; + #size-cells = <0>; + +@@ -1557,6 +1560,7 @@ fastrpc { + compatible = "qcom,fastrpc"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + label = "cdsp"; ++ qcom,non-secure-domain; + #address-cells = <1>; + #size-cells = <0>; + +@@ -1864,6 +1868,7 @@ usb_1_dwc3: usb@a600000 { + snps,dis_enblslpm_quirk; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; ++ snps,parkmode-disable-ss-quirk; + phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>; + phy-names = "usb2-phy", "usb3-phy"; + }; +@@ -2524,7 +2529,7 @@ watchdog@17c10000 { + compatible = "qcom,apss-wdt-sm6350", "qcom,kpss-wdt"; + reg = <0 0x17c10000 0 0x1000>; + clocks = <&sleep_clk>; +- interrupts = ; ++ interrupts = ; + }; + + timer@17c20000 { +diff --git a/arch/arm64/boot/dts/qcom/sm6375.dtsi b/arch/arm64/boot/dts/qcom/sm6375.dtsi +index e7ff55443da702..e56f7ea4ebc6ae 100644 +--- a/arch/arm64/boot/dts/qcom/sm6375.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm6375.dtsi +@@ -311,6 +311,25 @@ scm { + }; + }; + ++ mpm: interrupt-controller { ++ compatible = "qcom,mpm"; ++ qcom,rpm-msg-ram = <&apss_mpm>; ++ interrupts = ; ++ mboxes = <&ipcc IPCC_CLIENT_AOP IPCC_MPROC_SIGNAL_SMP2P>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ #power-domain-cells = <0>; ++ interrupt-parent = <&intc>; ++ qcom,mpm-pin-count = <96>; ++ qcom,mpm-pin-map = <5 296>, /* Soundwire wake_irq */ ++ <12 422>, /* DWC3 ss_phy_irq */ ++ <86 183>, /* MPM wake, SPMI */ ++ <89 314>, /* TSENS0 0C */ ++ <90 315>, /* TSENS1 0C */ ++ <93 164>, /* DWC3 dm_hs_phy_irq */ ++ <94 165>; /* DWC3 dp_hs_phy_irq */ ++ }; ++ + memory@80000000 { + device_type = "memory"; + /* We expect the bootloader to fill in the size */ +@@ -486,6 +505,7 @@ CPU_PD7: power-domain-cpu7 { + + CLUSTER_PD: power-domain-cpu-cluster0 { + #power-domain-cells = <0>; ++ power-domains = <&mpm>; + domain-idle-states = <&CLUSTER_SLEEP_0>; + }; + }; +@@ -808,7 +828,7 @@ tlmm: pinctrl@500000 { + reg = <0 0x00500000 0 0x800000>; + interrupts = ; + gpio-ranges = <&tlmm 0 0 157>; +- /* TODO: Hook up MPM as wakeup-parent when it's there */ ++ wakeup-parent = <&mpm>; + interrupt-controller; + gpio-controller; + #interrupt-cells = <2>; +@@ -930,7 +950,7 @@ spmi_bus: spmi@1c40000 { + <0 0x01c0a000 0 0x26000>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; +- interrupts = ; ++ interrupts-extended = <&mpm 86 IRQ_TYPE_LEVEL_HIGH>; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <2>; +@@ -962,8 +982,15 @@ tsens1: thermal-sensor@4413000 { + }; + + rpm_msg_ram: sram@45f0000 { +- compatible = "qcom,rpm-msg-ram"; ++ compatible = "qcom,rpm-msg-ram", "mmio-sram"; + reg = <0 0x045f0000 0 0x7000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 0x0 0x045f0000 0x7000>; ++ ++ apss_mpm: sram@1b8 { ++ reg = <0x1b8 0x48>; ++ }; + }; + + sram@4690000 { +@@ -1360,10 +1387,10 @@ usb_1: usb@4ef8800 { + <&gcc GCC_USB30_PRIM_MASTER_CLK>; + assigned-clock-rates = <19200000>, <133333333>; + +- interrupts = , +- , +- , +- ; ++ interrupts-extended = <&intc GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>, ++ <&mpm 12 IRQ_TYPE_LEVEL_HIGH>, ++ <&mpm 93 IRQ_TYPE_EDGE_BOTH>, ++ <&mpm 94 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hs_phy_irq", + "ss_phy_irq", + "dm_hs_phy_irq", +diff --git a/arch/arm64/boot/dts/qcom/sm8150-hdk.dts b/arch/arm64/boot/dts/qcom/sm8150-hdk.dts +index bb161b536da466..f4c6e1309a7e99 100644 +--- a/arch/arm64/boot/dts/qcom/sm8150-hdk.dts ++++ b/arch/arm64/boot/dts/qcom/sm8150-hdk.dts +@@ -127,8 +127,6 @@ vdda_qrefs_0p875_5: + vdda_sp_sensor: + vdda_ufs_2ln_core_1: + vdda_ufs_2ln_core_2: +- vdda_usb_ss_dp_core_1: +- vdda_usb_ss_dp_core_2: + vdda_qlink_lv: + vdda_qlink_lv_ck: + vreg_l5a_0p875: ldo5 { +@@ -210,6 +208,12 @@ vreg_l17a_3p0: ldo17 { + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; ++ ++ vreg_l18a_0p8: ldo18 { ++ regulator-min-microvolt = <880000>; ++ regulator-max-microvolt = <880000>; ++ regulator-initial-mode = ; ++ }; + }; + + regulators-1 { +@@ -445,13 +449,13 @@ &usb_2_hsphy { + &usb_1_qmpphy { + status = "okay"; + vdda-phy-supply = <&vreg_l3c_1p2>; +- vdda-pll-supply = <&vdda_usb_ss_dp_core_1>; ++ vdda-pll-supply = <&vreg_l18a_0p8>; + }; + + &usb_2_qmpphy { + status = "okay"; + vdda-phy-supply = <&vreg_l3c_1p2>; +- vdda-pll-supply = <&vdda_usb_ss_dp_core_1>; ++ vdda-pll-supply = <&vreg_l5a_0p875>; + }; + + &usb_1 { +diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi +index 06c53000bb74d4..73ef228ff26891 100644 +--- a/arch/arm64/boot/dts/qcom/sm8150.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi +@@ -1876,8 +1876,8 @@ pcie0: pci@1c00000 { + phys = <&pcie0_lane>; + phy-names = "pciephy"; + +- perst-gpio = <&tlmm 35 GPIO_ACTIVE_HIGH>; +- enable-gpio = <&tlmm 37 GPIO_ACTIVE_HIGH>; ++ perst-gpios = <&tlmm 35 GPIO_ACTIVE_HIGH>; ++ wake-gpios = <&tlmm 37 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_default_state>; +@@ -1893,8 +1893,12 @@ pcie0_phy: phy@1c06000 { + ranges; + clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>, + <&gcc GCC_PCIE_0_CFG_AHB_CLK>, ++ <&gcc GCC_PCIE_0_CLKREF_CLK>, + <&gcc GCC_PCIE0_PHY_REFGEN_CLK>; +- clock-names = "aux", "cfg_ahb", "refgen"; ++ clock-names = "aux", ++ "cfg_ahb", ++ "ref", ++ "refgen"; + + resets = <&gcc GCC_PCIE_0_PHY_BCR>; + reset-names = "phy"; +@@ -1974,7 +1978,7 @@ pcie1: pci@1c08000 { + phys = <&pcie1_lane>; + phy-names = "pciephy"; + +- perst-gpio = <&tlmm 102 GPIO_ACTIVE_HIGH>; ++ perst-gpios = <&tlmm 102 GPIO_ACTIVE_HIGH>; + enable-gpio = <&tlmm 104 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; +@@ -1991,8 +1995,12 @@ pcie1_phy: phy@1c0e000 { + ranges; + clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>, + <&gcc GCC_PCIE_1_CFG_AHB_CLK>, ++ <&gcc GCC_PCIE_1_CLKREF_CLK>, + <&gcc GCC_PCIE1_PHY_REFGEN_CLK>; +- clock-names = "aux", "cfg_ahb", "refgen"; ++ clock-names = "aux", ++ "cfg_ahb", ++ "ref", ++ "refgen"; + + resets = <&gcc GCC_PCIE_1_PHY_BCR>; + reset-names = "phy"; +@@ -2965,11 +2973,8 @@ replicator1_out: endpoint { + }; + + in-ports { +- #address-cells = <1>; +- #size-cells = <0>; + +- port@1 { +- reg = <1>; ++ port { + replicator1_in: endpoint { + remote-endpoint = <&replicator_out1>; + }; +@@ -3584,10 +3589,10 @@ usb_1: usb@a6f8800 { + <&gcc GCC_USB30_PRIM_MASTER_CLK>; + assigned-clock-rates = <19200000>, <200000000>; + +- interrupts = , +- , +- , +- ; ++ interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc 8 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc 9 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hs_phy_irq", "ss_phy_irq", + "dm_hs_phy_irq", "dp_hs_phy_irq"; + +@@ -3637,10 +3642,10 @@ usb_2: usb@a8f8800 { + <&gcc GCC_USB30_SEC_MASTER_CLK>; + assigned-clock-rates = <19200000>, <200000000>; + +- interrupts = , +- , +- , +- ; ++ interrupts-extended = <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc 7 IRQ_TYPE_LEVEL_HIGH>, ++ <&pdc 10 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc 11 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hs_phy_irq", "ss_phy_irq", + "dm_hs_phy_irq", "dp_hs_phy_irq"; + +@@ -3951,6 +3956,7 @@ dispcc: clock-controller@af00000 { + "dp_phy_pll_link_clk", + "dp_phy_pll_vco_div_clk"; + power-domains = <&rpmhpd SM8150_MMCX>; ++ required-opps = <&rpmhpd_opp_low_svs>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; +@@ -4189,7 +4195,7 @@ watchdog@17c10000 { + compatible = "qcom,apss-wdt-sm8150", "qcom,kpss-wdt"; + reg = <0 0x17c10000 0 0x1000>; + clocks = <&sleep_clk>; +- interrupts = ; ++ interrupts = ; + }; + + timer@17c20000 { +diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi +index a4e58ad731c34f..b522d19f3a1327 100644 +--- a/arch/arm64/boot/dts/qcom/sm8250.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi +@@ -2169,7 +2169,7 @@ ufs_mem_hc: ufshc@1d84000 { + "jedec,ufs-2.0"; + reg = <0 0x01d84000 0 0x3000>; + interrupts = ; +- phys = <&ufs_mem_phy_lanes>; ++ phys = <&ufs_mem_phy>; + phy-names = "ufsphy"; + lanes-per-direction = <2>; + #reset-cells = <1>; +@@ -2217,10 +2217,8 @@ ufs_mem_hc: ufshc@1d84000 { + + ufs_mem_phy: phy@1d87000 { + compatible = "qcom,sm8250-qmp-ufs-phy"; +- reg = <0 0x01d87000 0 0x1c0>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; ++ reg = <0 0x01d87000 0 0x1000>; ++ + clock-names = "ref", + "ref_aux"; + clocks = <&rpmhcc RPMH_CXO_CLK>, +@@ -2228,16 +2226,12 @@ ufs_mem_phy: phy@1d87000 { + + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; +- status = "disabled"; + +- ufs_mem_phy_lanes: phy@1d87400 { +- reg = <0 0x01d87400 0 0x16c>, +- <0 0x01d87600 0 0x200>, +- <0 0x01d87c00 0 0x200>, +- <0 0x01d87800 0 0x16c>, +- <0 0x01d87a00 0 0x200>; +- #phy-cells = <0>; +- }; ++ power-domains = <&gcc UFS_PHY_GDSC>; ++ ++ #phy-cells = <0>; ++ ++ status = "disabled"; + }; + + cryptobam: dma-controller@1dc4000 { +@@ -2830,11 +2824,8 @@ tpda@6004000 { + clock-names = "apb_pclk"; + + out-ports { +- #address-cells = <1>; +- #size-cells = <0>; + +- port@0 { +- reg = <0>; ++ port { + tpda_out_funnel_qatb: endpoint { + remote-endpoint = <&funnel_qatb_in_tpda>; + }; +@@ -2877,11 +2868,7 @@ funnel_qatb_out_funnel_in0: endpoint { + }; + + in-ports { +- #address-cells = <1>; +- #size-cells = <0>; +- +- port@0 { +- reg = <0>; ++ port { + funnel_qatb_in_tpda: endpoint { + remote-endpoint = <&tpda_out_funnel_qatb>; + }; +@@ -3090,11 +3077,8 @@ etf_out: endpoint { + }; + + in-ports { +- #address-cells = <1>; +- #size-cells = <0>; + +- port@0 { +- reg = <0>; ++ port { + etf_in_funnel_swao_out: endpoint { + remote-endpoint = <&funnel_swao_out_etf>; + }; +@@ -3178,8 +3162,6 @@ funnel@6c2d000 { + clock-names = "apb_pclk"; + + out-ports { +- #address-cells = <1>; +- #size-cells = <0>; + port { + tpdm_mm_out_tpda9: endpoint { + remote-endpoint = <&tpda_9_in_tpdm_mm>; +@@ -3445,11 +3427,7 @@ funnel_apss_merg_out_funnel_in1: endpoint { + }; + + in-ports { +- #address-cells = <1>; +- #size-cells = <0>; +- +- port@0 { +- reg = <0>; ++ port { + funnel_apss_merg_in_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_out_funnel_apss_merg>; + }; +@@ -5664,7 +5642,7 @@ watchdog@17c10000 { + compatible = "qcom,apss-wdt-sm8250", "qcom,kpss-wdt"; + reg = <0 0x17c10000 0 0x1000>; + clocks = <&sleep_clk>; +- interrupts = ; ++ interrupts = ; + }; + + timer@17c20000 { +diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi +index 00604bf7724f42..d4f1b36c7aebe4 100644 +--- a/arch/arm64/boot/dts/qcom/sm8350.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi +@@ -918,9 +918,9 @@ spi19: spi@894000 { + }; + }; + +- gpi_dma0: dma-controller@9800000 { ++ gpi_dma0: dma-controller@900000 { + compatible = "qcom,sm8350-gpi-dma", "qcom,sm6350-gpi-dma"; +- reg = <0 0x09800000 0 0x60000>; ++ reg = <0 0x00900000 0 0x60000>; + interrupts = , + , + , +@@ -1731,6 +1731,8 @@ ufs_mem_phy: phy@1d87000 { + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; + ++ power-domains = <&gcc UFS_PHY_GDSC>; ++ + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; + status = "disabled"; +@@ -2020,7 +2022,7 @@ mpss: remoteproc@4080000 { + compatible = "qcom,sm8350-mpss-pas"; + reg = <0x0 0x04080000 0x0 0x4040>; + +- interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>, ++ interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 2 IRQ_TYPE_EDGE_RISING>, +@@ -2062,7 +2064,7 @@ slpi: remoteproc@5c00000 { + compatible = "qcom,sm8350-slpi-pas"; + reg = <0 0x05c00000 0 0x4000>; + +- interrupts-extended = <&pdc 9 IRQ_TYPE_LEVEL_HIGH>, ++ interrupts-extended = <&pdc 9 IRQ_TYPE_EDGE_RISING>, + <&smp2p_slpi_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_slpi_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_slpi_in 2 IRQ_TYPE_EDGE_RISING>, +@@ -2964,7 +2966,7 @@ qup_uart6_default: qup-uart6-default-state { + }; + + qup_uart18_default: qup-uart18-default-state { +- pins = "gpio58", "gpio59"; ++ pins = "gpio68", "gpio69"; + function = "qup18"; + drive-strength = <2>; + bias-disable; +@@ -3206,7 +3208,7 @@ adsp: remoteproc@17300000 { + compatible = "qcom,sm8350-adsp-pas"; + reg = <0 0x17300000 0 0x100>; + +- interrupts-extended = <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, ++ interrupts-extended = <&pdc 6 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>, +@@ -3511,7 +3513,7 @@ cdsp: remoteproc@98900000 { + compatible = "qcom,sm8350-cdsp-pas"; + reg = <0 0x98900000 0 0x1400000>; + +- interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_LEVEL_HIGH>, ++ interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_EDGE_RISING>, + <&smp2p_cdsp_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_cdsp_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_cdsp_in 2 IRQ_TYPE_EDGE_RISING>, +diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi +index 2a60cf8bd891c2..a34f460240a076 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi +@@ -1025,6 +1025,12 @@ uart20: serial@894000 { + pinctrl-names = "default"; + pinctrl-0 = <&qup_uart20_default>; + interrupts = ; ++ interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS ++ &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, ++ <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS ++ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; ++ interconnect-names = "qup-core", ++ "qup-config"; + status = "disabled"; + }; + +@@ -1417,6 +1423,12 @@ uart7: serial@99c000 { + pinctrl-names = "default"; + pinctrl-0 = <&qup_uart7_tx>, <&qup_uart7_rx>; + interrupts = ; ++ interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS ++ &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, ++ <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS ++ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; ++ interconnect-names = "qup-core", ++ "qup-config"; + status = "disabled"; + }; + }; +@@ -1762,12 +1774,8 @@ pcie0: pci@1c00000 { + ranges = <0x01000000 0x0 0x00000000 0x0 0x60200000 0x0 0x100000>, + <0x02000000 0x0 0x60300000 0x0 0x60300000 0x0 0x3d00000>; + +- /* +- * MSIs for BDF (1:0.0) only works with Device ID 0x5980. +- * Hence, the IDs are swapped. +- */ +- msi-map = <0x0 &gic_its 0x5981 0x1>, +- <0x100 &gic_its 0x5980 0x1>; ++ msi-map = <0x0 &gic_its 0x5980 0x1>, ++ <0x100 &gic_its 0x5981 0x1>; + msi-map-mask = <0xff00>; + interrupts = ; + interrupt-names = "msi"; +@@ -1876,12 +1884,8 @@ pcie1: pci@1c08000 { + ranges = <0x01000000 0x0 0x00000000 0x0 0x40200000 0x0 0x100000>, + <0x02000000 0x0 0x40300000 0x0 0x40300000 0x0 0x1fd00000>; + +- /* +- * MSIs for BDF (1:0.0) only works with Device ID 0x5a00. +- * Hence, the IDs are swapped. +- */ +- msi-map = <0x0 &gic_its 0x5a01 0x1>, +- <0x100 &gic_its 0x5a00 0x1>; ++ msi-map = <0x0 &gic_its 0x5a00 0x1>, ++ <0x100 &gic_its 0x5a01 0x1>; + msi-map-mask = <0xff00>; + interrupts = ; + interrupt-names = "msi"; +@@ -2176,7 +2180,7 @@ wsa2macro: codec@31e0000 { + #sound-dai-cells = <1>; + }; + +- swr4: soundwire-controller@31f0000 { ++ swr4: soundwire@31f0000 { + compatible = "qcom,soundwire-v1.7.0"; + reg = <0 0x031f0000 0 0x2000>; + interrupts = ; +@@ -2224,7 +2228,7 @@ rxmacro: codec@3200000 { + #sound-dai-cells = <1>; + }; + +- swr1: soundwire-controller@3210000 { ++ swr1: soundwire@3210000 { + compatible = "qcom,soundwire-v1.7.0"; + reg = <0 0x03210000 0 0x2000>; + interrupts = ; +@@ -2291,7 +2295,7 @@ wsamacro: codec@3240000 { + #sound-dai-cells = <1>; + }; + +- swr0: soundwire-controller@3250000 { ++ swr0: soundwire@3250000 { + compatible = "qcom,soundwire-v1.7.0"; + reg = <0 0x03250000 0 0x2000>; + interrupts = ; +@@ -2318,14 +2322,14 @@ swr0: soundwire-controller@3250000 { + status = "disabled"; + }; + +- swr2: soundwire-controller@33b0000 { ++ swr2: soundwire@33b0000 { + compatible = "qcom,soundwire-v1.7.0"; + reg = <0 0x033b0000 0 0x2000>; + interrupts = , + ; + interrupt-names = "core", "wakeup"; + +- clocks = <&vamacro>; ++ clocks = <&txmacro>; + clock-names = "iface"; + label = "TX"; + +@@ -4196,6 +4200,8 @@ ufs_mem_phy: phy@1d87000 { + <&gcc GCC_UFS_PHY_PHY_AUX_CLK>, + <&gcc GCC_UFS_0_CLKREF_EN>; + ++ power-domains = <&gcc UFS_PHY_GDSC>; ++ + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; + status = "disabled"; +diff --git a/arch/arm64/boot/dts/qcom/sm8550-mtp.dts b/arch/arm64/boot/dts/qcom/sm8550-mtp.dts +index f29cce5186acd5..c4bfe43471f7ca 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550-mtp.dts ++++ b/arch/arm64/boot/dts/qcom/sm8550-mtp.dts +@@ -743,7 +743,7 @@ &swr2 { + wcd_tx: codec@0,3 { + compatible = "sdw20217010d00"; + reg = <0 3>; +- qcom,tx-port-mapping = <1 1 2 3>; ++ qcom,tx-port-mapping = <2 2 3 4>; + }; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sm8550-qrd.dts b/arch/arm64/boot/dts/qcom/sm8550-qrd.dts +index 2c09ce8aeafd9b..7a70cc59427979 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550-qrd.dts ++++ b/arch/arm64/boot/dts/qcom/sm8550-qrd.dts +@@ -835,7 +835,7 @@ &swr2 { + wcd_tx: codec@0,3 { + compatible = "sdw20217010d00"; + reg = <0 3>; +- qcom,tx-port-mapping = <1 1 2 3>; ++ qcom,tx-port-mapping = <2 2 3 4>; + }; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index d115960bdeec8a..90e6cd239f5699 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -283,9 +283,9 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + compatible = "arm,idle-state"; + idle-state-name = "silver-rail-power-collapse"; + arm,psci-suspend-param = <0x40000004>; +- entry-latency-us = <800>; ++ entry-latency-us = <550>; + exit-latency-us = <750>; +- min-residency-us = <4090>; ++ min-residency-us = <6700>; + local-timer-stop; + }; + +@@ -294,8 +294,18 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + idle-state-name = "gold-rail-power-collapse"; + arm,psci-suspend-param = <0x40000004>; + entry-latency-us = <600>; +- exit-latency-us = <1550>; +- min-residency-us = <4791>; ++ exit-latency-us = <1300>; ++ min-residency-us = <8136>; ++ local-timer-stop; ++ }; ++ ++ PRIME_CPU_SLEEP_0: cpu-sleep-2-0 { ++ compatible = "arm,idle-state"; ++ idle-state-name = "goldplus-rail-power-collapse"; ++ arm,psci-suspend-param = <0x40000004>; ++ entry-latency-us = <500>; ++ exit-latency-us = <1350>; ++ min-residency-us = <7480>; + local-timer-stop; + }; + }; +@@ -304,17 +314,17 @@ domain-idle-states { + CLUSTER_SLEEP_0: cluster-sleep-0 { + compatible = "domain-idle-state"; + arm,psci-suspend-param = <0x41000044>; +- entry-latency-us = <1050>; +- exit-latency-us = <2500>; +- min-residency-us = <5309>; ++ entry-latency-us = <750>; ++ exit-latency-us = <2350>; ++ min-residency-us = <9144>; + }; + + CLUSTER_SLEEP_1: cluster-sleep-1 { + compatible = "domain-idle-state"; + arm,psci-suspend-param = <0x4100c344>; +- entry-latency-us = <2700>; +- exit-latency-us = <3500>; +- min-residency-us = <13959>; ++ entry-latency-us = <2800>; ++ exit-latency-us = <4400>; ++ min-residency-us = <10150>; + }; + }; + }; +@@ -398,7 +408,7 @@ CPU_PD6: power-domain-cpu6 { + CPU_PD7: power-domain-cpu7 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; +- domain-idle-states = <&BIG_CPU_SLEEP_0>; ++ domain-idle-states = <&PRIME_CPU_SLEEP_0>; + }; + + CLUSTER_PD: power-domain-cluster { +@@ -2034,7 +2044,7 @@ lpass_wsa2macro: codec@6aa0000 { + #sound-dai-cells = <1>; + }; + +- swr3: soundwire-controller@6ab0000 { ++ swr3: soundwire@6ab0000 { + compatible = "qcom,soundwire-v2.0.0"; + reg = <0 0x06ab0000 0 0x10000>; + interrupts = ; +@@ -2080,7 +2090,7 @@ lpass_rxmacro: codec@6ac0000 { + #sound-dai-cells = <1>; + }; + +- swr1: soundwire-controller@6ad0000 { ++ swr1: soundwire@6ad0000 { + compatible = "qcom,soundwire-v2.0.0"; + reg = <0 0x06ad0000 0 0x10000>; + interrupts = ; +@@ -2145,7 +2155,7 @@ lpass_wsamacro: codec@6b00000 { + #sound-dai-cells = <1>; + }; + +- swr0: soundwire-controller@6b10000 { ++ swr0: soundwire@6b10000 { + compatible = "qcom,soundwire-v2.0.0"; + reg = <0 0x06b10000 0 0x10000>; + interrupts = ; +@@ -2172,13 +2182,13 @@ swr0: soundwire-controller@6b10000 { + status = "disabled"; + }; + +- swr2: soundwire-controller@6d30000 { ++ swr2: soundwire@6d30000 { + compatible = "qcom,soundwire-v2.0.0"; + reg = <0 0x06d30000 0 0x10000>; + interrupts = , + ; + interrupt-names = "core", "wakeup"; +- clocks = <&lpass_vamacro>; ++ clocks = <&lpass_txmacro>; + clock-names = "iface"; + label = "TX"; + +@@ -2893,8 +2903,8 @@ usb_1: usb@a6f8800 { + + interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 17 IRQ_TYPE_LEVEL_HIGH>, +- <&pdc 15 IRQ_TYPE_EDGE_RISING>, +- <&pdc 14 IRQ_TYPE_EDGE_RISING>; ++ <&pdc 15 IRQ_TYPE_EDGE_BOTH>, ++ <&pdc 14 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hs_phy_irq", + "ss_phy_irq", + "dm_hs_phy_irq", +@@ -3007,7 +3017,7 @@ sram@c3f0000 { + spmi_bus: spmi@c400000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0 0x0c400000 0 0x3000>, +- <0 0x0c500000 0 0x4000000>, ++ <0 0x0c500000 0 0x400000>, + <0 0x0c440000 0 0x80000>, + <0 0x0c4c0000 0 0x20000>, + <0 0x0c42d000 0 0x4000>; +diff --git a/arch/arm64/boot/dts/renesas/r8a779a0.dtsi b/arch/arm64/boot/dts/renesas/r8a779a0.dtsi +index 4e67a03564971b..84e0eb48a1b8ac 100644 +--- a/arch/arm64/boot/dts/renesas/r8a779a0.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a779a0.dtsi +@@ -658,7 +658,7 @@ channel7 { + avb0: ethernet@e6800000 { + compatible = "renesas,etheravb-r8a779a0", + "renesas,etheravb-rcar-gen4"; +- reg = <0 0xe6800000 0 0x800>; ++ reg = <0 0xe6800000 0 0x1000>; + interrupts = , + , + , +@@ -706,7 +706,7 @@ avb0: ethernet@e6800000 { + avb1: ethernet@e6810000 { + compatible = "renesas,etheravb-r8a779a0", + "renesas,etheravb-rcar-gen4"; +- reg = <0 0xe6810000 0 0x800>; ++ reg = <0 0xe6810000 0 0x1000>; + interrupts = , + , + , +@@ -2910,6 +2910,9 @@ timer { + interrupts-extended = <&gic GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, +- <&gic GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; ++ <&gic GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>, ++ <&gic GIC_PPI 12 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "sec-phys", "phys", "virt", "hyp-phys", ++ "hyp-virt"; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/r8a779f0.dtsi b/arch/arm64/boot/dts/renesas/r8a779f0.dtsi +index ecdd5a523fa344..555fff9364e35c 100644 +--- a/arch/arm64/boot/dts/renesas/r8a779f0.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a779f0.dtsi +@@ -1181,7 +1181,10 @@ timer { + interrupts-extended = <&gic GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, +- <&gic GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; ++ <&gic GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>, ++ <&gic GIC_PPI 12 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "sec-phys", "phys", "virt", "hyp-phys", ++ "hyp-virt"; + }; + + ufs30_clk: ufs30-clk { +diff --git a/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi b/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi +index bb4a5270f71b6a..913f70fe6c5cd2 100644 +--- a/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi +@@ -187,6 +187,9 @@ &extalr_clk { + }; + + &hscif0 { ++ pinctrl-0 = <&hscif0_pins>; ++ pinctrl-names = "default"; ++ + status = "okay"; + }; + +diff --git a/arch/arm64/boot/dts/renesas/r8a779g0.dtsi b/arch/arm64/boot/dts/renesas/r8a779g0.dtsi +index d3d25e077c5d50..87fbc53316906c 100644 +--- a/arch/arm64/boot/dts/renesas/r8a779g0.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a779g0.dtsi +@@ -161,11 +161,6 @@ L3_CA76_1: cache-controller-1 { + }; + }; + +- psci { +- compatible = "arm,psci-1.0", "arm,psci-0.2"; +- method = "smc"; +- }; +- + extal_clk: extal { + compatible = "fixed-clock"; + #clock-cells = <0>; +@@ -185,13 +180,24 @@ pmu_a76 { + interrupts-extended = <&gic GIC_PPI 7 IRQ_TYPE_LEVEL_LOW>; + }; + +- /* External SCIF clock - to be overridden by boards that provide it */ ++ psci { ++ compatible = "arm,psci-1.0", "arm,psci-0.2"; ++ method = "smc"; ++ }; ++ ++ /* External SCIF clocks - to be overridden by boards that provide them */ + scif_clk: scif { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + ++ scif_clk2: scif2 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <0>; ++ }; ++ + soc: soc { + compatible = "simple-bus"; + interrupt-parent = <&gic>; +@@ -681,7 +687,7 @@ hscif2: serial@e6560000 { + interrupts = ; + clocks = <&cpg CPG_MOD 516>, + <&cpg CPG_CORE R8A779G0_CLK_SASYNCPERD1>, +- <&scif_clk>; ++ <&scif_clk2>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac0 0x35>, <&dmac0 0x34>, + <&dmac1 0x35>, <&dmac1 0x34>; +@@ -761,7 +767,7 @@ channel7 { + avb0: ethernet@e6800000 { + compatible = "renesas,etheravb-r8a779g0", + "renesas,etheravb-rcar-gen4"; +- reg = <0 0xe6800000 0 0x800>; ++ reg = <0 0xe6800000 0 0x1000>; + interrupts = , + , + , +@@ -808,7 +814,7 @@ avb0: ethernet@e6800000 { + avb1: ethernet@e6810000 { + compatible = "renesas,etheravb-r8a779g0", + "renesas,etheravb-rcar-gen4"; +- reg = <0 0xe6810000 0 0x800>; ++ reg = <0 0xe6810000 0 0x1000>; + interrupts = , + , + , +@@ -1057,7 +1063,7 @@ scif4: serial@e6c40000 { + interrupts = ; + clocks = <&cpg CPG_MOD 705>, + <&cpg CPG_CORE R8A779G0_CLK_SASYNCPERD1>, +- <&scif_clk>; ++ <&scif_clk2>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac0 0x59>, <&dmac0 0x58>, + <&dmac1 0x59>, <&dmac1 0x58>; +@@ -1777,6 +1783,37 @@ ssi0: ssi-0 { + }; + }; + ++ mmc0: mmc@ee140000 { ++ compatible = "renesas,sdhi-r8a779g0", ++ "renesas,rcar-gen4-sdhi"; ++ reg = <0 0xee140000 0 0x2000>; ++ interrupts = ; ++ clocks = <&cpg CPG_MOD 706>, ++ <&cpg CPG_CORE R8A779G0_CLK_SD0H>; ++ clock-names = "core", "clkh"; ++ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>; ++ resets = <&cpg 706>; ++ max-frequency = <200000000>; ++ iommus = <&ipmmu_ds0 32>; ++ status = "disabled"; ++ }; ++ ++ rpc: spi@ee200000 { ++ compatible = "renesas,r8a779g0-rpc-if", ++ "renesas,rcar-gen4-rpc-if"; ++ reg = <0 0xee200000 0 0x200>, ++ <0 0x08000000 0 0x04000000>, ++ <0 0xee208000 0 0x100>; ++ reg-names = "regs", "dirmap", "wbuf"; ++ interrupts = ; ++ clocks = <&cpg CPG_MOD 629>; ++ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>; ++ resets = <&cpg 629>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ + ipmmu_rt0: iommu@ee480000 { + compatible = "renesas,ipmmu-r8a779g0", + "renesas,rcar-gen4-ipmmu-vmsa"; +@@ -1886,37 +1923,6 @@ ipmmu_mm: iommu@eefc0000 { + #iommu-cells = <1>; + }; + +- mmc0: mmc@ee140000 { +- compatible = "renesas,sdhi-r8a779g0", +- "renesas,rcar-gen4-sdhi"; +- reg = <0 0xee140000 0 0x2000>; +- interrupts = ; +- clocks = <&cpg CPG_MOD 706>, +- <&cpg CPG_CORE R8A779G0_CLK_SD0H>; +- clock-names = "core", "clkh"; +- power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>; +- resets = <&cpg 706>; +- max-frequency = <200000000>; +- iommus = <&ipmmu_ds0 32>; +- status = "disabled"; +- }; +- +- rpc: spi@ee200000 { +- compatible = "renesas,r8a779g0-rpc-if", +- "renesas,rcar-gen4-rpc-if"; +- reg = <0 0xee200000 0 0x200>, +- <0 0x08000000 0 0x04000000>, +- <0 0xee208000 0 0x100>; +- reg-names = "regs", "dirmap", "wbuf"; +- interrupts = ; +- clocks = <&cpg CPG_MOD 629>; +- power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>; +- resets = <&cpg 629>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- + gic: interrupt-controller@f1000000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; +@@ -2344,6 +2350,9 @@ timer { + interrupts-extended = <&gic GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, +- <&gic GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; ++ <&gic GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>, ++ <&gic GIC_PPI 12 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "sec-phys", "phys", "virt", "hyp-phys", ++ "hyp-virt"; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/r9a07g043u.dtsi b/arch/arm64/boot/dts/renesas/r9a07g043u.dtsi +index 2ab231572d95ff..71d51febabc1e8 100644 +--- a/arch/arm64/boot/dts/renesas/r9a07g043u.dtsi ++++ b/arch/arm64/boot/dts/renesas/r9a07g043u.dtsi +@@ -50,7 +50,10 @@ timer { + interrupts-extended = <&gic GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, +- <&gic GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; ++ <&gic GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>, ++ <&gic GIC_PPI 12 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "sec-phys", "phys", "virt", "hyp-phys", ++ "hyp-virt"; + }; + }; + +@@ -109,7 +112,13 @@ irqc: interrupt-controller@110a0000 { + , + , + , +- ; ++ , ++ , ++ , ++ , ++ , ++ , ++ ; + interrupt-names = "nmi", + "irq0", "irq1", "irq2", "irq3", + "irq4", "irq5", "irq6", "irq7", +@@ -121,7 +130,9 @@ irqc: interrupt-controller@110a0000 { + "tint20", "tint21", "tint22", "tint23", + "tint24", "tint25", "tint26", "tint27", + "tint28", "tint29", "tint30", "tint31", +- "bus-err"; ++ "bus-err", "ec7tie1-0", "ec7tie2-0", ++ "ec7tiovf-0", "ec7tie1-1", "ec7tie2-1", ++ "ec7tiovf-1"; + clocks = <&cpg CPG_MOD R9A07G043_IA55_CLK>, + <&cpg CPG_MOD R9A07G043_IA55_PCLK>; + clock-names = "clk", "pclk"; +@@ -134,8 +145,8 @@ gic: interrupt-controller@11900000 { + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; +- reg = <0x0 0x11900000 0 0x40000>, +- <0x0 0x11940000 0 0x60000>; ++ reg = <0x0 0x11900000 0 0x20000>, ++ <0x0 0x11940000 0 0x40000>; + interrupts = ; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi +index 66f68fc2b24118..edc942c8463959 100644 +--- a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi ++++ b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi +@@ -905,7 +905,27 @@ irqc: interrupt-controller@110a0000 { + , + , + , +- ; ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ interrupt-names = "nmi", "irq0", "irq1", "irq2", "irq3", ++ "irq4", "irq5", "irq6", "irq7", ++ "tint0", "tint1", "tint2", "tint3", ++ "tint4", "tint5", "tint6", "tint7", ++ "tint8", "tint9", "tint10", "tint11", ++ "tint12", "tint13", "tint14", "tint15", ++ "tint16", "tint17", "tint18", "tint19", ++ "tint20", "tint21", "tint22", "tint23", ++ "tint24", "tint25", "tint26", "tint27", ++ "tint28", "tint29", "tint30", "tint31", ++ "bus-err", "ec7tie1-0", "ec7tie2-0", ++ "ec7tiovf-0", "ec7tie1-1", "ec7tie2-1", ++ "ec7tiovf-1"; + clocks = <&cpg CPG_MOD R9A07G044_IA55_CLK>, + <&cpg CPG_MOD R9A07G044_IA55_PCLK>; + clock-names = "clk", "pclk"; +@@ -977,8 +997,8 @@ gic: interrupt-controller@11900000 { + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; +- reg = <0x0 0x11900000 0 0x40000>, +- <0x0 0x11940000 0 0x60000>; ++ reg = <0x0 0x11900000 0 0x20000>, ++ <0x0 0x11940000 0 0x40000>; + interrupts = ; + }; + +@@ -1268,6 +1288,9 @@ timer { + interrupts-extended = <&gic GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, +- <&gic GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; ++ <&gic GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>, ++ <&gic GIC_PPI 12 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "sec-phys", "phys", "virt", "hyp-phys", ++ "hyp-virt"; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/r9a07g054.dtsi b/arch/arm64/boot/dts/renesas/r9a07g054.dtsi +index 1f1d481dc7830d..d61f7894e55cdd 100644 +--- a/arch/arm64/boot/dts/renesas/r9a07g054.dtsi ++++ b/arch/arm64/boot/dts/renesas/r9a07g054.dtsi +@@ -912,7 +912,27 @@ irqc: interrupt-controller@110a0000 { + , + , + , +- ; ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ interrupt-names = "nmi", "irq0", "irq1", "irq2", "irq3", ++ "irq4", "irq5", "irq6", "irq7", ++ "tint0", "tint1", "tint2", "tint3", ++ "tint4", "tint5", "tint6", "tint7", ++ "tint8", "tint9", "tint10", "tint11", ++ "tint12", "tint13", "tint14", "tint15", ++ "tint16", "tint17", "tint18", "tint19", ++ "tint20", "tint21", "tint22", "tint23", ++ "tint24", "tint25", "tint26", "tint27", ++ "tint28", "tint29", "tint30", "tint31", ++ "bus-err", "ec7tie1-0", "ec7tie2-0", ++ "ec7tiovf-0", "ec7tie1-1", "ec7tie2-1", ++ "ec7tiovf-1"; + clocks = <&cpg CPG_MOD R9A07G054_IA55_CLK>, + <&cpg CPG_MOD R9A07G054_IA55_PCLK>; + clock-names = "clk", "pclk"; +@@ -984,8 +1004,8 @@ gic: interrupt-controller@11900000 { + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; +- reg = <0x0 0x11900000 0 0x40000>, +- <0x0 0x11940000 0 0x60000>; ++ reg = <0x0 0x11900000 0 0x20000>, ++ <0x0 0x11940000 0 0x40000>; + interrupts = ; + }; + +@@ -1275,6 +1295,9 @@ timer { + interrupts-extended = <&gic GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>, + <&gic GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>, +- <&gic GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>; ++ <&gic GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>, ++ <&gic GIC_PPI 12 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-names = "sec-phys", "phys", "virt", "hyp-phys", ++ "hyp-virt"; + }; + }; +diff --git a/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi b/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi +index 3885ef3454ff6e..50de17e4fb3f25 100644 +--- a/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi ++++ b/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi +@@ -234,6 +234,7 @@ gpio_exp_74: gpio@74 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; ++ #interrupt-cells = <2>; + interrupt-parent = <&gpio6>; + interrupts = <8 IRQ_TYPE_EDGE_FALLING>; + +@@ -294,6 +295,7 @@ gpio_exp_75: gpio@75 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; ++ #interrupt-cells = <2>; + interrupt-parent = <&gpio6>; + interrupts = <4 IRQ_TYPE_EDGE_FALLING>; + }; +@@ -314,6 +316,7 @@ gpio_exp_76: gpio@76 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; ++ #interrupt-cells = <2>; + interrupt-parent = <&gpio7>; + interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + }; +@@ -324,6 +327,7 @@ gpio_exp_77: gpio@77 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; ++ #interrupt-cells = <2>; + interrupt-parent = <&gpio5>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi +index 42ce78beb4134d..20955556b624d0 100644 +--- a/arch/arm64/boot/dts/rockchip/px30.dtsi ++++ b/arch/arm64/boot/dts/rockchip/px30.dtsi +@@ -632,6 +632,7 @@ spi0: spi@ff1d0000 { + clock-names = "spiclk", "apb_pclk"; + dmas = <&dmac 12>, <&dmac 13>; + dma-names = "tx", "rx"; ++ num-cs = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&spi0_clk &spi0_csn &spi0_miso &spi0_mosi>; + #address-cells = <1>; +@@ -647,6 +648,7 @@ spi1: spi@ff1d8000 { + clock-names = "spiclk", "apb_pclk"; + dmas = <&dmac 14>, <&dmac 15>; + dma-names = "tx", "rx"; ++ num-cs = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&spi1_clk &spi1_csn0 &spi1_csn1 &spi1_miso &spi1_mosi>; + #address-cells = <1>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts b/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts +index e9810d2f04071c..5ca0cc19f92c84 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts +@@ -5,6 +5,8 @@ + */ + + /dts-v1/; ++ ++#include + #include "rk3308.dtsi" + + / { +@@ -15,6 +17,7 @@ aliases { + ethernet0 = &gmac; + mmc0 = &emmc; + mmc1 = &sdmmc; ++ mmc2 = &sdio; + }; + + chosen { +@@ -24,17 +27,21 @@ chosen { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; +- pinctrl-0 = <&green_led_gio>, <&heartbeat_led_gpio>; ++ pinctrl-0 = <&green_led>, <&heartbeat_led>; + + green-led { ++ color = ; + default-state = "on"; ++ function = LED_FUNCTION_POWER; + gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; + label = "rockpis:green:power"; + linux,default-trigger = "default-on"; + }; + + blue-led { ++ color = ; + default-state = "on"; ++ function = LED_FUNCTION_HEARTBEAT; + gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>; + label = "rockpis:blue:user"; + linux,default-trigger = "heartbeat"; +@@ -126,21 +133,37 @@ &cpu0 { + }; + + &emmc { +- bus-width = <4>; + cap-mmc-highspeed; +- mmc-hs200-1_8v; ++ cap-sd-highspeed; ++ no-sdio; + non-removable; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&emmc_bus8 &emmc_clk &emmc_cmd>; + vmmc-supply = <&vcc_io>; + status = "okay"; + }; + + &gmac { + clock_in_out = "output"; ++ phy-handle = <&rtl8201f>; + phy-supply = <&vcc_io>; +- snps,reset-gpio = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>; +- snps,reset-active-low; +- snps,reset-delays-us = <0 50000 50000>; + status = "okay"; ++ ++ mdio { ++ compatible = "snps,dwmac-mdio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ rtl8201f: ethernet-phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <1>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mac_rst>; ++ reset-assert-us = <20000>; ++ reset-deassert-us = <50000>; ++ reset-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>; ++ }; ++ }; + }; + + &i2c1 { +@@ -151,12 +174,32 @@ &pinctrl { + pinctrl-names = "default"; + pinctrl-0 = <&rtc_32k>; + ++ bluetooth { ++ bt_reg_on: bt-reg-on { ++ rockchip,pins = <4 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ ++ bt_wake_host: bt-wake-host { ++ rockchip,pins = <4 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>; ++ }; ++ ++ host_wake_bt: host-wake-bt { ++ rockchip,pins = <4 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++ ++ gmac { ++ mac_rst: mac-rst { ++ rockchip,pins = <0 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++ + leds { +- green_led_gio: green-led-gpio { ++ green_led: green-led { + rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- heartbeat_led_gpio: heartbeat-led-gpio { ++ heartbeat_led: heartbeat-led { + rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +@@ -194,15 +237,31 @@ &sdio { + cap-sd-highspeed; + cap-sdio-irq; + keep-power-in-suspend; +- max-frequency = <1000000>; ++ max-frequency = <100000000>; + mmc-pwrseq = <&sdio_pwrseq>; ++ no-mmc; ++ no-sd; + non-removable; +- sd-uhs-sdr104; ++ sd-uhs-sdr50; ++ vmmc-supply = <&vcc_io>; ++ vqmmc-supply = <&vcc_1v8>; + status = "okay"; ++ ++ rtl8723ds: wifi@1 { ++ reg = <1>; ++ interrupt-parent = <&gpio0>; ++ interrupts = ; ++ interrupt-names = "host-wake"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&wifi_host_wake>; ++ }; + }; + + &sdmmc { ++ cap-mmc-highspeed; + cap-sd-highspeed; ++ disable-wp; ++ vmmc-supply = <&vcc_io>; + status = "okay"; + }; + +@@ -221,16 +280,22 @@ u2phy_otg: otg-port { + }; + + &uart0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0_xfer>; + status = "okay"; + }; + + &uart4 { ++ uart-has-rtscts; + status = "okay"; + + bluetooth { +- compatible = "realtek,rtl8723bs-bt"; +- device-wake-gpios = <&gpio4 RK_PB3 GPIO_ACTIVE_HIGH>; ++ compatible = "realtek,rtl8723ds-bt"; ++ device-wake-gpios = <&gpio4 RK_PB2 GPIO_ACTIVE_HIGH>; ++ enable-gpios = <&gpio4 RK_PB3 GPIO_ACTIVE_HIGH>; + host-wake-gpios = <&gpio4 RK_PB4 GPIO_ACTIVE_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bt_reg_on &bt_wake_host &host_wake_bt>; + }; + }; + +diff --git a/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts b/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts +index 5d7d567283e525..4237f2ee8fee33 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts +@@ -26,9 +26,11 @@ yt8531c: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + ++ motorcomm,auto-sleep-disabled; + motorcomm,clk-out-frequency-hz = <125000000>; + motorcomm,keep-pll-enabled; +- motorcomm,auto-sleep-disabled; ++ motorcomm,rx-clk-drv-microamp = <5020>; ++ motorcomm,rx-data-drv-microamp = <5020>; + + pinctrl-0 = <ð_phy_reset_pin>; + pinctrl-names = "default"; +diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts +index 018a3a5075c72e..66443d52cd34d8 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts +@@ -186,8 +186,8 @@ &i2c1 { + rk805: pmic@18 { + compatible = "rockchip,rk805"; + reg = <0x18>; +- interrupt-parent = <&gpio2>; +- interrupts = <6 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-parent = <&gpio0>; ++ interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + #clock-cells = <1>; + clock-output-names = "xin32k", "rk805-clkout2"; + gpio-controller; +@@ -332,7 +332,7 @@ led_pin: led-pin { + + pmic { + pmic_int_l: pmic-int-l { +- rockchip,pins = <2 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>; ++ rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + +diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +index e729e7a22b23a6..126165ba1ea260 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +@@ -668,7 +668,7 @@ vpu_mmu: iommu@ff350800 { + + vdec: video-codec@ff360000 { + compatible = "rockchip,rk3328-vdec", "rockchip,rk3399-vdec"; +- reg = <0x0 0xff360000 0x0 0x400>; ++ reg = <0x0 0xff360000 0x0 0x480>; + interrupts = ; + clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>, + <&cru SCLK_VDEC_CABAC>, <&cru SCLK_VDEC_CORE>; +@@ -743,11 +743,20 @@ hdmi: hdmi@ff3c0000 { + status = "disabled"; + + ports { +- hdmi_in: port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ hdmi_in: port@0 { ++ reg = <0>; ++ + hdmi_in_vop: endpoint { + remote-endpoint = <&vop_out_hdmi>; + }; + }; ++ ++ hdmi_out: port@1 { ++ reg = <1>; ++ }; + }; + }; + +@@ -813,8 +822,8 @@ cru: clock-controller@ff440000 { + <0>, <24000000>, + <24000000>, <24000000>, + <15000000>, <15000000>, +- <100000000>, <100000000>, +- <100000000>, <100000000>, ++ <300000000>, <100000000>, ++ <400000000>, <100000000>, + <50000000>, <100000000>, + <100000000>, <100000000>, + <50000000>, <50000000>, +diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi +index a4c5aaf1f45794..cac58ad951b2e3 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi +@@ -790,6 +790,7 @@ spdif: spdif@ff880000 { + dma-names = "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&spdif_tx>; ++ #sound-dai-cells = <0>; + status = "disabled"; + }; + +@@ -801,6 +802,7 @@ i2s_2ch: i2s-2ch@ff890000 { + clocks = <&cru SCLK_I2S_2CH>, <&cru HCLK_I2S_2CH>; + dmas = <&dmac_bus 6>, <&dmac_bus 7>; + dma-names = "tx", "rx"; ++ #sound-dai-cells = <0>; + status = "disabled"; + }; + +@@ -814,6 +816,7 @@ i2s_8ch: i2s-8ch@ff898000 { + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&i2s_8ch_bus>; ++ #sound-dai-cells = <0>; + status = "disabled"; + }; + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi +index 5c1929d41cc0b7..cacbad35cfc854 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi +@@ -509,8 +509,7 @@ wacky_spi_audio: spi2@0 { + &pci_rootport { + mvl_wifi: wifi@0,0 { + compatible = "pci1b4b,2b42"; +- reg = <0x83010000 0x0 0x00000000 0x0 0x00100000 +- 0x83010000 0x0 0x00100000 0x0 0x00100000>; ++ reg = <0x0000 0x0 0x0 0x0 0x0>; + interrupt-parent = <&gpio0>; + interrupts = <8 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet-dumo.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet-dumo.dts +index 853e88455e750e..9e4b12ed62cbed 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet-dumo.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet-dumo.dts +@@ -34,8 +34,8 @@ &mipi_panel { + &pci_rootport { + wifi@0,0 { + compatible = "qcom,ath10k"; +- reg = <0x00010000 0x0 0x00000000 0x0 0x00000000>, +- <0x03010010 0x0 0x00000000 0x0 0x00200000>; ++ reg = <0x00000000 0x0 0x00000000 0x0 0x00000000>, ++ <0x03000010 0x0 0x00000000 0x0 0x00200000>; + qcom,ath10k-calibration-variant = "GO_DUMO"; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi +index c9bf1d5c3a4264..3cd63d1e8f15bb 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi +@@ -450,7 +450,7 @@ da7219_aad { + dlg,btn-cfg = <50>; + dlg,mic-det-thr = <500>; + dlg,jack-ins-deb = <20>; +- dlg,jack-det-rate = "32ms_64ms"; ++ dlg,jack-det-rate = "32_64"; + dlg,jack-rem-deb = <1>; + + dlg,a-d-btn-thr = <0xa>; +@@ -489,6 +489,7 @@ pci_rootport: pcie@0,0 { + #address-cells = <3>; + #size-cells = <2>; + ranges; ++ device_type = "pci"; + }; + }; + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts +index 054c6a4d1a45f7..f5e124b235c83c 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts +@@ -32,12 +32,12 @@ chosen { + backlight: edp-backlight { + compatible = "pwm-backlight"; + power-supply = <&vcc_12v>; +- pwms = <&pwm0 0 740740 0>; ++ pwms = <&pwm0 0 125000 0>; + }; + + bat: battery { + compatible = "simple-battery"; +- charge-full-design-microamp-hours = <9800000>; ++ charge-full-design-microamp-hours = <10000000>; + voltage-max-design-microvolt = <4350000>; + voltage-min-design-microvolt = <3000000>; + }; +@@ -779,7 +779,6 @@ &pcie_phy { + }; + + &pcie0 { +- bus-scan-delay-ms = <1000>; + ep-gpios = <&gpio2 RK_PD4 GPIO_ACTIVE_HIGH>; + num-lanes = <4>; + pinctrl-names = "default"; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi +index 20e3f41efe97fa..aba2748fe54c77 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi +@@ -119,6 +119,22 @@ &emmc_phy { + drive-impedance-ohm = <33>; + }; + ++&gpio3 { ++ /* ++ * The Qseven BIOS_DISABLE signal on the RK3399-Q7 keeps the on-module ++ * eMMC and SPI flash powered-down initially (in fact it keeps the ++ * reset signal asserted). BIOS_DISABLE_OVERRIDE pin allows to override ++ * that signal so that eMMC and SPI can be used regardless of the state ++ * of the signal. ++ */ ++ bios-disable-override-hog { ++ gpios = ; ++ gpio-hog; ++ line-name = "bios_disable_override"; ++ output-high; ++ }; ++}; ++ + &gmac { + assigned-clocks = <&cru SCLK_RMII_SRC>; + assigned-clock-parents = <&clkin_gmac>; +@@ -374,6 +390,7 @@ vdd_cpu_b: regulator@60 { + + &i2s0 { + pinctrl-0 = <&i2s0_2ch_bus>; ++ pinctrl-1 = <&i2s0_2ch_bus_bclk_off>; + rockchip,playback-channels = <2>; + rockchip,capture-channels = <2>; + status = "okay"; +@@ -382,8 +399,8 @@ &i2s0 { + /* + * As Q7 does not specify neither a global nor a RX clock for I2S these + * signals are not used. Furthermore I2S0_LRCK_RX is used as GPIO. +- * Therefore we have to redefine the i2s0_2ch_bus definition to prevent +- * conflicts. ++ * Therefore we have to redefine the i2s0_2ch_bus and i2s0_2ch_bus_bclk_off ++ * definitions to prevent conflicts. + */ + &i2s0_2ch_bus { + rockchip,pins = +@@ -393,6 +410,14 @@ &i2s0_2ch_bus { + <3 RK_PD7 1 &pcfg_pull_none>; + }; + ++&i2s0_2ch_bus_bclk_off { ++ rockchip,pins = ++ <3 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>, ++ <3 RK_PD2 1 &pcfg_pull_none>, ++ <3 RK_PD3 1 &pcfg_pull_none>, ++ <3 RK_PD7 1 &pcfg_pull_none>; ++}; ++ + &io_domains { + status = "okay"; + bt656-supply = <&vcc_1v8>; +@@ -401,16 +426,27 @@ &io_domains { + gpio1830-supply = <&vcc_1v8>; + }; + +-&pmu_io_domains { +- status = "okay"; +- pmu1830-supply = <&vcc_1v8>; +-}; +- +-&pwm2 { +- status = "okay"; ++&pcie_clkreqn_cpm { ++ rockchip,pins = ++ <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + &pinctrl { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&q7_thermal_pin &bios_disable_override_hog_pin>; ++ ++ gpios { ++ bios_disable_override_hog_pin: bios-disable-override-hog-pin { ++ rockchip,pins = ++ <3 RK_PD5 RK_FUNC_GPIO &pcfg_pull_down>; ++ }; ++ ++ q7_thermal_pin: q7-thermal-pin { ++ rockchip,pins = ++ <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ + i2c8 { + i2c8_xfer_a: i2c8-xfer { + rockchip,pins = +@@ -443,11 +479,20 @@ vcc5v0_host_en: vcc5v0-host-en { + usb3 { + usb3_id: usb3-id { + rockchip,pins = +- <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; ++ <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + }; + ++&pmu_io_domains { ++ status = "okay"; ++ pmu1830-supply = <&vcc_1v8>; ++}; ++ ++&pwm2 { ++ status = "okay"; ++}; ++ + &sdhci { + /* + * Signal integrity isn't great at 200MHz but 100MHz has proven stable +diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +index 5bc2d4faeea6df..fb1ea84c2b14fe 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -1109,7 +1109,9 @@ power-domain@RK3399_PD_VCODEC { + power-domain@RK3399_PD_VDU { + reg = ; + clocks = <&cru ACLK_VDU>, +- <&cru HCLK_VDU>; ++ <&cru HCLK_VDU>, ++ <&cru SCLK_VDU_CA>, ++ <&cru SCLK_VDU_CORE>; + pm_qos = <&qos_video_m1_r>, + <&qos_video_m1_w>; + #power-domain-cells = <0>; +@@ -1385,7 +1387,7 @@ vpu_mmu: iommu@ff650800 { + + vdec: video-codec@ff660000 { + compatible = "rockchip,rk3399-vdec"; +- reg = <0x0 0xff660000 0x0 0x400>; ++ reg = <0x0 0xff660000 0x0 0x480>; + interrupts = ; + clocks = <&cru ACLK_VDU>, <&cru HCLK_VDU>, + <&cru SCLK_VDU_CA>, <&cru SCLK_VDU_CORE>; +@@ -1951,6 +1953,7 @@ simple-audio-card,codec { + hdmi: hdmi@ff940000 { + compatible = "rockchip,rk3399-dw-hdmi"; + reg = <0x0 0xff940000 0x0 0x20000>; ++ reg-io-width = <4>; + interrupts = ; + clocks = <&cru PCLK_HDMI_CTRL>, + <&cru SCLK_HDMI_SFR>, +@@ -1959,13 +1962,16 @@ hdmi: hdmi@ff940000 { + <&cru PLL_VPLL>; + clock-names = "iahb", "isfr", "cec", "grf", "ref"; + power-domains = <&power RK3399_PD_HDCP>; +- reg-io-width = <4>; + rockchip,grf = <&grf>; + #sound-dai-cells = <0>; + status = "disabled"; + + ports { +- hdmi_in: port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ hdmi_in: port@0 { ++ reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + +@@ -1978,6 +1984,10 @@ hdmi_in_vopl: endpoint@1 { + remote-endpoint = <&vopl_out_hdmi>; + }; + }; ++ ++ hdmi_out: port@1 { ++ reg = <1>; ++ }; + }; + }; + +diff --git a/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts b/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts +index 1c6d83b47cd217..6ecdf5d283390a 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts +@@ -455,7 +455,7 @@ &pcie2x1 { + &pinctrl { + leds { + sys_led_pin: sys-status-led-pin { +- rockchip,pins = <0 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>; ++ rockchip,pins = <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + +diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts +index 2d92713be2a09f..6195937aa6dc5f 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts +@@ -289,7 +289,7 @@ vdd_gpu: DCDC_REG2 { + regulator-name = "vdd_gpu"; + regulator-always-on; + regulator-boot-on; +- regulator-min-microvolt = <900000>; ++ regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <6001>; + +diff --git a/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts b/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts +index 938092fce18661..68a72ac24cd4b4 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts +@@ -268,7 +268,7 @@ rk809: pmic@20 { + vcc9-supply = <&vcc3v3_sys>; + + codec { +- mic-in-differential; ++ rockchip,mic-in-differential; + }; + + regulators { +diff --git a/arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts b/arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts +index f9127ddfbb7dfd..dc5892d25c1000 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts +@@ -416,6 +416,8 @@ regulator-state-mem { + + vccio_sd: LDO_REG5 { + regulator-name = "vccio_sd"; ++ regulator-always-on; ++ regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + +@@ -525,9 +527,9 @@ &mdio0 { + #address-cells = <1>; + #size-cells = <0>; + +- switch@0 { ++ switch@1f { + compatible = "mediatek,mt7531"; +- reg = <0>; ++ reg = <0x1f>; + + ports { + #address-cells = <1>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts +index 19f8fc369b1308..8c3ab07d380797 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts +@@ -475,7 +475,7 @@ regulator-state-mem { + }; + + codec { +- mic-in-differential; ++ rockchip,mic-in-differential; + }; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r66s.dts b/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r66s.dts +index 58ab7e9971dbce..b5e67990dd0f8b 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r66s.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r66s.dts +@@ -11,6 +11,10 @@ aliases { + }; + }; + ++&pmu_io_domains { ++ vccio3-supply = <&vccio_sd>; ++}; ++ + &sdmmc0 { + bus-width = <4>; + cap-mmc-highspeed; +diff --git a/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r66s.dtsi b/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r66s.dtsi +index 89e84e3a92629a..25c49bdbadbcba 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r66s.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r66s.dtsi +@@ -39,9 +39,9 @@ status_led: led-status { + }; + }; + +- dc_12v: dc-12v-regulator { ++ vcc12v_dcin: vcc12v-dcin-regulator { + compatible = "regulator-fixed"; +- regulator-name = "dc_12v"; ++ regulator-name = "vcc12v_dcin"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <12000000>; +@@ -65,7 +65,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; +- vin-supply = <&dc_12v>; ++ vin-supply = <&vcc12v_dcin>; + }; + + vcc5v0_sys: vcc5v0-sys-regulator { +@@ -75,16 +75,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; +- vin-supply = <&dc_12v>; +- }; +- +- vcc5v0_usb_host: vcc5v0-usb-host-regulator { +- compatible = "regulator-fixed"; +- regulator-name = "vcc5v0_usb_host"; +- regulator-always-on; +- regulator-boot-on; +- regulator-min-microvolt = <5000000>; +- regulator-max-microvolt = <5000000>; ++ vin-supply = <&vcc12v_dcin>; + }; + + vcc5v0_usb_otg: vcc5v0-usb-otg-regulator { +@@ -94,8 +85,9 @@ vcc5v0_usb_otg: vcc5v0-usb-otg-regulator { + pinctrl-names = "default"; + pinctrl-0 = <&vcc5v0_usb_otg_en>; + regulator-name = "vcc5v0_usb_otg"; +- regulator-always-on; +- regulator-boot-on; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&vcc5v0_sys>; + }; + }; + +@@ -123,6 +115,10 @@ &cpu3 { + cpu-supply = <&vdd_cpu>; + }; + ++&display_subsystem { ++ status = "disabled"; ++}; ++ + &gpu { + mali-supply = <&vdd_gpu>; + status = "okay"; +@@ -405,8 +401,8 @@ vcc5v0_usb_otg_en: vcc5v0-usb-otg-en { + &pmu_io_domains { + pmuio1-supply = <&vcc3v3_pmu>; + pmuio2-supply = <&vcc3v3_pmu>; +- vccio1-supply = <&vccio_acodec>; +- vccio3-supply = <&vccio_sd>; ++ vccio1-supply = <&vcc_3v3>; ++ vccio2-supply = <&vcc_1v8>; + vccio4-supply = <&vcc_1v8>; + vccio5-supply = <&vcc_3v3>; + vccio6-supply = <&vcc_1v8>; +@@ -429,28 +425,12 @@ &uart2 { + status = "okay"; + }; + +-&usb_host0_ehci { +- status = "okay"; +-}; +- +-&usb_host0_ohci { +- status = "okay"; +-}; +- + &usb_host0_xhci { + dr_mode = "host"; + extcon = <&usb2phy0>; + status = "okay"; + }; + +-&usb_host1_ehci { +- status = "okay"; +-}; +- +-&usb_host1_ohci { +- status = "okay"; +-}; +- + &usb_host1_xhci { + status = "okay"; + }; +@@ -460,7 +440,7 @@ &usb2phy0 { + }; + + &usb2phy0_host { +- phy-supply = <&vcc5v0_usb_host>; ++ phy-supply = <&vcc5v0_sys>; + status = "okay"; + }; + +diff --git a/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r68s.dts b/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r68s.dts +index e1fe5e442689a0..ce2a5e1ccefc3f 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r68s.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r68s.dts +@@ -39,7 +39,7 @@ &gmac0_tx_bus2 + &gmac0_rx_bus2 + &gmac0_rgmii_clk + &gmac0_rgmii_bus>; +- snps,reset-gpio = <&gpio0 RK_PB0 GPIO_ACTIVE_LOW>; ++ snps,reset-gpio = <&gpio1 RK_PB0 GPIO_ACTIVE_LOW>; + snps,reset-active-low; + /* Reset time is 15ms, 50ms for rtl8211f */ + snps,reset-delays-us = <0 15000 50000>; +@@ -61,7 +61,7 @@ &gmac1m1_tx_bus2 + &gmac1m1_rx_bus2 + &gmac1m1_rgmii_clk + &gmac1m1_rgmii_bus>; +- snps,reset-gpio = <&gpio0 RK_PB1 GPIO_ACTIVE_LOW>; ++ snps,reset-gpio = <&gpio1 RK_PB1 GPIO_ACTIVE_LOW>; + snps,reset-active-low; + /* Reset time is 15ms, 50ms for rtl8211f */ + snps,reset-delays-us = <0 15000 50000>; +@@ -71,18 +71,18 @@ &gmac1m1_rgmii_clk + }; + + &mdio0 { +- rgmii_phy0: ethernet-phy@0 { ++ rgmii_phy0: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; +- reg = <0>; ++ reg = <0x1>; + pinctrl-0 = <ð_phy0_reset_pin>; + pinctrl-names = "default"; + }; + }; + + &mdio1 { +- rgmii_phy1: ethernet-phy@0 { ++ rgmii_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; +- reg = <0>; ++ reg = <0x1>; + pinctrl-0 = <ð_phy1_reset_pin>; + pinctrl-names = "default"; + }; +@@ -102,6 +102,10 @@ eth_phy1_reset_pin: eth-phy1-reset-pin { + }; + }; + ++&pmu_io_domains { ++ vccio3-supply = <&vcc_3v3>; ++}; ++ + &sdhci { + bus-width = <8>; + max-frequency = <200000000>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3568-odroid-m1.dts b/arch/arm64/boot/dts/rockchip/rk3568-odroid-m1.dts +index a337f547caf538..6a02db4f073f29 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3568-odroid-m1.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3568-odroid-m1.dts +@@ -13,7 +13,7 @@ + + / { + model = "Hardkernel ODROID-M1"; +- compatible = "rockchip,rk3568-odroid-m1", "rockchip,rk3568"; ++ compatible = "hardkernel,odroid-m1", "rockchip,rk3568"; + + aliases { + ethernet0 = &gmac0; +diff --git a/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts b/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts +index e05ab11981f554..17830e8c9a59be 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts +@@ -530,10 +530,6 @@ regulator-state-mem { + }; + }; + }; +- +- codec { +- mic-in-differential; +- }; + }; + }; + +diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi +index abee88911982d4..2f885bc3665b5c 100644 +--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi +@@ -597,6 +597,7 @@ vpu: video-codec@fdea0400 { + compatible = "rockchip,rk3568-vpu"; + reg = <0x0 0xfdea0000 0x0 0x800>; + interrupts = ; ++ interrupt-names = "vdpu"; + clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; + clock-names = "aclk", "hclk"; + iommus = <&vdpu_mmu>; +@@ -748,6 +749,7 @@ vop_mmu: iommu@fe043e00 { + clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>; + clock-names = "aclk", "iface"; + #iommu-cells = <0>; ++ power-domains = <&power RK3568_PD_VO>; + status = "disabled"; + }; + +@@ -970,7 +972,7 @@ pcie2x1: pcie@fe260000 { + , + , + ; +- interrupt-names = "sys", "pmc", "msi", "legacy", "err"; ++ interrupt-names = "sys", "pmc", "msg", "legacy", "err"; + bus-range = <0x0 0xf>; + clocks = <&cru ACLK_PCIE20_MST>, <&cru ACLK_PCIE20_SLV>, + <&cru ACLK_PCIE20_DBI>, <&cru PCLK_PCIE20>, +@@ -1116,7 +1118,7 @@ i2s2_2ch: i2s@fe420000 { + dmas = <&dmac1 4>, <&dmac1 5>; + dma-names = "tx", "rx"; + resets = <&cru SRST_M_I2S2_2CH>; +- reset-names = "m"; ++ reset-names = "tx-m"; + rockchip,grf = <&grf>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s2m0_sclktx +diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts +index 229a9111f5eb05..fa8286a325af74 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts +@@ -215,6 +215,7 @@ pmic@0 { + <&rk806_dvs2_null>, <&rk806_dvs3_null>; + pinctrl-names = "default"; + spi-max-frequency = <1000000>; ++ system-power-controller; + + vcc1-supply = <&vcc5v0_sys>; + vcc2-supply = <&vcc5v0_sys>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dts b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dts +index 0bd80e51575448..97af4f91282854 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dts +@@ -137,6 +137,18 @@ vbus5v0_typec: vbus5v0-typec-regulator { + vin-supply = <&vcc5v0_sys>; + }; + ++ vcc3v3_pcie2x1l0: vcc3v3-pcie2x1l0-regulator { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio4 RK_PC2 GPIO_ACTIVE_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie_m2_1_pwren>; ++ regulator-name = "vcc3v3_pcie2x1l0"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <&vcc5v0_sys>; ++ }; ++ + vcc3v3_pcie30: vcc3v3-pcie30-regulator { + compatible = "regulator-fixed"; + enable-active-high; +@@ -421,6 +433,14 @@ &pcie2x1l0 { + status = "okay"; + }; + ++&pcie2x1l1 { ++ reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; ++ vpcie3v3-supply = <&vcc3v3_pcie2x1l0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie2_1_rst>; ++ status = "okay"; ++}; ++ + &pcie2x1l2 { + reset-gpios = <&gpio4 RK_PA4 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc_3v3_pcie20>; +@@ -467,6 +487,10 @@ pcie2_0_rst: pcie2-0-rst { + rockchip,pins = <4 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + ++ pcie2_1_rst: pcie2-1-rst { ++ rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ + pcie2_2_rst: pcie2-2-rst { + rockchip,pins = <4 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>; + }; +@@ -474,6 +498,10 @@ pcie2_2_rst: pcie2-2-rst { + pcie_m2_0_pwren: pcie-m20-pwren { + rockchip,pins = <2 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; + }; ++ ++ pcie_m2_1_pwren: pcie-m21-pwren { ++ rockchip,pins = <4 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; + }; + + usb { +diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts b/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts +index d1503a4b233a39..9299fa7e3e2150 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts +@@ -163,13 +163,13 @@ &gpio0 { + + &gpio1 { + gpio-line-names = /* GPIO1 A0-A7 */ +- "HEADER_27_3v3", "HEADER_28_3v3", "", "", ++ "HEADER_27_3v3", "", "", "", + "HEADER_29_1v8", "", "HEADER_7_1v8", "", + /* GPIO1 B0-B7 */ + "", "HEADER_31_1v8", "HEADER_33_1v8", "", + "HEADER_11_1v8", "HEADER_13_1v8", "", "", + /* GPIO1 C0-C7 */ +- "", "", "", "", ++ "", "HEADER_28_3v3", "", "", + "", "", "", "", + /* GPIO1 D0-D7 */ + "", "", "", "", +@@ -193,11 +193,11 @@ &gpio3 { + + &gpio4 { + gpio-line-names = /* GPIO4 A0-A7 */ +- "", "", "HEADER_37_3v3", "HEADER_32_3v3", +- "HEADER_36_3v3", "", "HEADER_35_3v3", "HEADER_38_3v3", ++ "", "", "HEADER_37_3v3", "HEADER_8_3v3", ++ "HEADER_10_3v3", "", "HEADER_32_3v3", "HEADER_35_3v3", + /* GPIO4 B0-B7 */ + "", "", "", "HEADER_40_3v3", +- "HEADER_8_3v3", "HEADER_10_3v3", "", "", ++ "HEADER_38_3v3", "HEADER_36_3v3", "", "", + /* GPIO4 C0-C7 */ + "", "", "", "", + "", "", "", "", +diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-pinctrl.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-pinctrl.dtsi +index 48181671eacb0d..0933652bafc301 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588s-pinctrl.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3588s-pinctrl.dtsi +@@ -369,7 +369,7 @@ emmc_cmd: emmc-cmd { + emmc_data_strobe: emmc-data-strobe { + rockchip,pins = + /* emmc_data_strobe */ +- <2 RK_PA2 1 &pcfg_pull_none>; ++ <2 RK_PA2 1 &pcfg_pull_down>; + }; + }; + +diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts +index 8347adcbd00301..68763714f7f7bc 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts +@@ -390,6 +390,7 @@ pmic@0 { + pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, + <&rk806_dvs2_null>, <&rk806_dvs3_null>; + spi-max-frequency = <1000000>; ++ system-power-controller; + + vcc1-supply = <&vcc5v0_sys>; + vcc2-supply = <&vcc5v0_sys>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +index 5544f66c6ff411..aa18cf1d1afaa1 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +@@ -890,6 +890,7 @@ power-domain@RK3588_PD_USB { + reg = ; + clocks = <&cru PCLK_PHP_ROOT>, + <&cru ACLK_USB_ROOT>, ++ <&cru ACLK_USB>, + <&cru HCLK_USB_ROOT>, + <&cru HCLK_HOST0>, + <&cru HCLK_HOST_ARB0>, +@@ -1541,7 +1542,6 @@ i2s2_2ch: i2s@fe490000 { + dmas = <&dmac1 0>, <&dmac1 1>; + dma-names = "tx", "rx"; + power-domains = <&power RK3588_PD_AUDIO>; +- rockchip,trcm-sync-tx-only; + pinctrl-names = "default"; + pinctrl-0 = <&i2s2m1_lrck + &i2s2m1_sclk +@@ -1562,7 +1562,6 @@ i2s3_2ch: i2s@fe4a0000 { + dmas = <&dmac1 2>, <&dmac1 3>; + dma-names = "tx", "rx"; + power-domains = <&power RK3588_PD_AUDIO>; +- rockchip,trcm-sync-tx-only; + pinctrl-names = "default"; + pinctrl-0 = <&i2s3_lrck + &i2s3_sclk +diff --git a/arch/arm64/boot/dts/sprd/ums512.dtsi b/arch/arm64/boot/dts/sprd/ums512.dtsi +index 024be594c47d17..cc4459551e05e1 100644 +--- a/arch/arm64/boot/dts/sprd/ums512.dtsi ++++ b/arch/arm64/boot/dts/sprd/ums512.dtsi +@@ -96,7 +96,7 @@ CPU5: cpu@500 { + + CPU6: cpu@600 { + device_type = "cpu"; +- compatible = "arm,cortex-a55"; ++ compatible = "arm,cortex-a75"; + reg = <0x0 0x600>; + enable-method = "psci"; + cpu-idle-states = <&CORE_PD>; +@@ -104,7 +104,7 @@ CPU6: cpu@600 { + + CPU7: cpu@700 { + device_type = "cpu"; +- compatible = "arm,cortex-a55"; ++ compatible = "arm,cortex-a75"; + reg = <0x0 0x700>; + enable-method = "psci"; + cpu-idle-states = <&CORE_PD>; +@@ -113,7 +113,7 @@ CPU7: cpu@700 { + + idle-states { + entry-method = "psci"; +- CORE_PD: core-pd { ++ CORE_PD: cpu-pd { + compatible = "arm,idle-state"; + entry-latency-us = <4000>; + exit-latency-us = <4000>; +@@ -291,6 +291,7 @@ anlg_phy_gc_regs: syscon@323e0000 { + pll2: clock-controller@0 { + compatible = "sprd,ums512-gc-pll"; + reg = <0x0 0x100>; ++ clocks = <&ext_26m>; + clock-names = "ext-26m"; + #clock-cells = <1>; + }; +diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile +index e7b8e2e7f083db..8bd5acc6d68351 100644 +--- a/arch/arm64/boot/dts/ti/Makefile ++++ b/arch/arm64/boot/dts/ti/Makefile +@@ -9,6 +9,8 @@ + # alphabetically. + + # Boards with AM62x SoC ++k3-am625-sk-hdmi-audio-dtbs := k3-am625-sk.dtb k3-am62x-sk-hdmi-audio.dtbo ++k3-am62-lp-sk-hdmi-audio-dtbs := k3-am62-lp-sk.dtb k3-am62x-sk-hdmi-audio.dtbo + dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay.dtb + dtb-$(CONFIG_ARCH_K3) += k3-am625-phyboard-lyra-rdk.dtb + dtb-$(CONFIG_ARCH_K3) += k3-am625-sk.dtb +@@ -19,7 +21,8 @@ dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dahlia.dtb + dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dev.dtb + dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-yavia.dtb + dtb-$(CONFIG_ARCH_K3) += k3-am62-lp-sk.dtb +-dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-hdmi-audio.dtbo ++dtb-$(CONFIG_ARCH_K3) += k3-am625-sk-hdmi-audio.dtb ++dtb-$(CONFIG_ARCH_K3) += k3-am62-lp-sk-hdmi-audio.dtb + + # Boards with AM62Ax SoC + dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk.dtb +@@ -66,6 +69,8 @@ dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk.dtb + dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-base-board.dtb + dtb-$(CONFIG_ARCH_K3) += k3-j721s2-common-proc-board.dtb + dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm-gesi-exp-board.dtbo ++k3-j721s2-evm-dtbs := k3-j721s2-common-proc-board.dtb k3-j721s2-evm-gesi-exp-board.dtbo ++dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm.dtb + + # Boards with J784s4 SoC + dtb-$(CONFIG_ARCH_K3) += k3-am69-sk.dtb +diff --git a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi +index 284b90c94da8a2..a9b47ab92a02c7 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi +@@ -613,6 +613,8 @@ usb0: usb@31000000 { + interrupt-names = "host", "peripheral"; + maximum-speed = "high-speed"; + dr_mode = "otg"; ++ snps,usb2-gadget-lpm-disable; ++ snps,usb2-lpm-disable; + }; + }; + +@@ -636,6 +638,8 @@ usb1: usb@31100000 { + interrupt-names = "host", "peripheral"; + maximum-speed = "high-speed"; + dr_mode = "otg"; ++ snps,usb2-gadget-lpm-disable; ++ snps,usb2-lpm-disable; + }; + }; + +@@ -743,9 +747,10 @@ dss: dss@30200000 { + <0x00 0x30207000 0x00 0x1000>, /* ovr1 */ + <0x00 0x30208000 0x00 0x1000>, /* ovr2 */ + <0x00 0x3020a000 0x00 0x1000>, /* vp1: Used for OLDI */ +- <0x00 0x3020b000 0x00 0x1000>; /* vp2: Used as DPI Out */ ++ <0x00 0x3020b000 0x00 0x1000>, /* vp2: Used as DPI Out */ ++ <0x00 0x30201000 0x00 0x1000>; /* common1 */ + reg-names = "common", "vidl1", "vid", +- "ovr1", "ovr2", "vp1", "vp2"; ++ "ovr1", "ovr2", "vp1", "vp2", "common1"; + power-domains = <&k3_pds 186 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 186 6>, + <&dss_vp1_clk>, +diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi +index 40992e7e4c3084..0a5634ca005dfb 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi +@@ -60,7 +60,7 @@ verdin_key_wakeup: key-wakeup { + + memory@80000000 { + device_type = "memory"; +- reg = <0x00000000 0x80000000 0x00000000 0x40000000>; /* 1G RAM */ ++ reg = <0x00000000 0x80000000 0x00000000 0x80000000>; /* 2G RAM */ + }; + + opp-table { +@@ -1061,6 +1061,7 @@ dsi_bridge: dsi@e { + vddc-supply = <®_1v2_dsi>; + vddmipi-supply = <®_1v2_dsi>; + vddio-supply = <®_1v8_dsi>; ++ status = "disabled"; + + dsi_bridge_ports: ports { + #address-cells = <1>; +@@ -1308,8 +1309,6 @@ &mcasp0 { + 0 0 0 0 + >; + tdm-slots = <2>; +- rx-num-evt = <32>; +- tx-num-evt = <32>; + #sound-dai-cells = <0>; + status = "disabled"; + }; +@@ -1326,8 +1325,6 @@ &mcasp1 { + 0 0 0 0 + >; + tdm-slots = <2>; +- rx-num-evt = <32>; +- tx-num-evt = <32>; + #sound-dai-cells = <0>; + status = "disabled"; + }; +diff --git a/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts b/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts +index 7cfdf562b53bfe..3560349d630513 100644 +--- a/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts ++++ b/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts +@@ -58,7 +58,7 @@ reserved-memory { + + ramoops: ramoops@9ca00000 { + compatible = "ramoops"; +- reg = <0x00 0x9c700000 0x00 0x00100000>; ++ reg = <0x00 0x9ca00000 0x00 0x00100000>; + record-size = <0x8000>; + console-size = <0x8000>; + ftrace-size = <0x00>; +@@ -903,6 +903,4 @@ &mcasp1 { + 0 0 0 0 + 0 0 0 0 + >; +- tx-num-evt = <32>; +- rx-num-evt = <32>; + }; +diff --git a/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi +index 3198af08fb9fad..de36abb243f104 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi +@@ -462,7 +462,7 @@ main_gpio0: gpio@600000 { + <193>, <194>, <195>; + interrupt-controller; + #interrupt-cells = <2>; +- ti,ngpio = <87>; ++ ti,ngpio = <92>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 77 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 77 0>; +@@ -480,7 +480,7 @@ main_gpio1: gpio@601000 { + <183>, <184>, <185>; + interrupt-controller; + #interrupt-cells = <2>; +- ti,ngpio = <88>; ++ ti,ngpio = <52>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 78 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 78 0>; +diff --git a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts +index cff283c75f8ecd..99f2878de4c677 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts ++++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts +@@ -250,7 +250,7 @@ &main_i2c1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c1_pins_default>; +- clock-frequency = <400000>; ++ clock-frequency = <100000>; + + exp1: gpio@22 { + compatible = "ti,tca6424"; +diff --git a/arch/arm64/boot/dts/ti/k3-am62p.dtsi b/arch/arm64/boot/dts/ti/k3-am62p.dtsi +index 294ab73ec98b7b..dc0a8e94e9ace0 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62p.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am62p.dtsi +@@ -71,7 +71,7 @@ cbass_main: bus@f0000 { + <0x00 0x43600000 0x00 0x43600000 0x00 0x00010000>, /* SA3 sproxy data */ + <0x00 0x44043000 0x00 0x44043000 0x00 0x00000fe0>, /* TI SCI DEBUG */ + <0x00 0x44860000 0x00 0x44860000 0x00 0x00040000>, /* SA3 sproxy config */ +- <0x00 0x48000000 0x00 0x48000000 0x00 0x06400000>, /* DMSS */ ++ <0x00 0x48000000 0x00 0x48000000 0x00 0x06408000>, /* DMSS */ + <0x00 0x60000000 0x00 0x60000000 0x00 0x08000000>, /* FSS0 DAT1 */ + <0x00 0x70000000 0x00 0x70000000 0x00 0x00010000>, /* OCSRAM */ + <0x01 0x00000000 0x01 0x00000000 0x00 0x00310000>, /* A53 PERIPHBASE */ +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 677ff8de4b6ecf..0f8c0f6a0f573e 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi +@@ -481,8 +481,6 @@ &mcasp1 { + 0 0 0 0 + 0 0 0 0 + >; +- tx-num-evt = <32>; +- rx-num-evt = <32>; + }; + + &dss { +diff --git a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi +index 0df54a74182474..064eb062bb54a0 100644 +--- a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi +@@ -612,6 +612,10 @@ sdhci0: mmc@fa10000 { + ti,otap-del-sel-mmc-hs = <0x0>; + ti,otap-del-sel-ddr52 = <0x6>; + ti,otap-del-sel-hs200 = <0x7>; ++ ti,itap-del-sel-legacy = <0x10>; ++ ti,itap-del-sel-mmc-hs = <0xa>; ++ ti,itap-del-sel-ddr52 = <0x3>; ++ status = "disabled"; + }; + + sdhci1: mmc@fa00000 { +@@ -623,13 +627,18 @@ sdhci1: mmc@fa00000 { + clock-names = "clk_ahb", "clk_xin"; + ti,trm-icp = <0x2>; + ti,otap-del-sel-legacy = <0x0>; +- ti,otap-del-sel-sd-hs = <0xf>; ++ ti,otap-del-sel-sd-hs = <0x0>; + ti,otap-del-sel-sdr12 = <0xf>; + ti,otap-del-sel-sdr25 = <0xf>; + ti,otap-del-sel-sdr50 = <0xc>; + ti,otap-del-sel-sdr104 = <0x6>; + ti,otap-del-sel-ddr50 = <0x9>; ++ ti,itap-del-sel-legacy = <0x0>; ++ ti,itap-del-sel-sd-hs = <0x0>; ++ ti,itap-del-sel-sdr12 = <0x0>; ++ ti,itap-del-sel-sdr25 = <0x0>; + ti,clkbuf-sel = <0x7>; ++ status = "disabled"; + }; + + cpsw3g: ethernet@8000000 { +diff --git a/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi b/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi +index 1c2c8f0daca9ff..1dcbf1fe7fae47 100644 +--- a/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi +@@ -200,6 +200,7 @@ flash@0 { + }; + + &sdhci0 { ++ status = "okay"; + bus-width = <8>; + non-removable; + ti,driver-strength-ohm = <50>; +diff --git a/arch/arm64/boot/dts/ti/k3-am642-evm.dts b/arch/arm64/boot/dts/ti/k3-am642-evm.dts +index b4a1f73d4fb17a..91d726ef7594a3 100644 +--- a/arch/arm64/boot/dts/ti/k3-am642-evm.dts ++++ b/arch/arm64/boot/dts/ti/k3-am642-evm.dts +@@ -35,6 +35,7 @@ aliases { + }; + + memory@80000000 { ++ bootph-all; + device_type = "memory"; + /* 2G RAM */ + reg = <0x00000000 0x80000000 0x00000000 0x80000000>; +@@ -108,6 +109,7 @@ rtos_ipc_memory_region: ipc-memories@a5000000 { + + evm_12v0: regulator-0 { + /* main DC jack */ ++ bootph-all; + compatible = "regulator-fixed"; + regulator-name = "evm_12v0"; + regulator-min-microvolt = <12000000>; +@@ -129,6 +131,7 @@ vsys_5v0: regulator-1 { + + vsys_3v3: regulator-2 { + /* output of LM5140 */ ++ bootph-all; + compatible = "regulator-fixed"; + regulator-name = "vsys_3v3"; + regulator-min-microvolt = <3300000>; +@@ -140,6 +143,7 @@ vsys_3v3: regulator-2 { + + vdd_mmc1: regulator-3 { + /* TPS2051BD */ ++ bootph-all; + compatible = "regulator-fixed"; + regulator-name = "vdd_mmc1"; + regulator-min-microvolt = <3300000>; +@@ -161,6 +165,7 @@ vddb: regulator-4 { + }; + + vtt_supply: regulator-5 { ++ bootph-all; + compatible = "regulator-fixed"; + regulator-name = "vtt"; + pinctrl-names = "default"; +@@ -251,6 +256,7 @@ AM64X_IOPAD(0x0244, PIN_OUTPUT, 0) /* (E14) UART1_TXD */ + }; + + main_uart0_pins_default: main-uart0-default-pins { ++ bootph-all; + pinctrl-single,pins = < + AM64X_IOPAD(0x0238, PIN_INPUT, 0) /* (B16) UART0_CTSn */ + AM64X_IOPAD(0x023c, PIN_OUTPUT, 0) /* (A16) UART0_RTSn */ +@@ -269,6 +275,7 @@ AM64X_IOPAD(0x0218, PIN_INPUT, 0) /* (A14) SPI0_D1 */ + }; + + main_i2c0_pins_default: main-i2c0-default-pins { ++ bootph-all; + pinctrl-single,pins = < + AM64X_IOPAD(0x0260, PIN_INPUT_PULLUP, 0) /* (A18) I2C0_SCL */ + AM64X_IOPAD(0x0264, PIN_INPUT_PULLUP, 0) /* (B18) I2C0_SDA */ +@@ -276,6 +283,7 @@ AM64X_IOPAD(0x0264, PIN_INPUT_PULLUP, 0) /* (B18) I2C0_SDA */ + }; + + main_i2c1_pins_default: main-i2c1-default-pins { ++ bootph-all; + pinctrl-single,pins = < + AM64X_IOPAD(0x0268, PIN_INPUT_PULLUP, 0) /* (C18) I2C1_SCL */ + AM64X_IOPAD(0x026c, PIN_INPUT_PULLUP, 0) /* (B19) I2C1_SDA */ +@@ -283,6 +291,7 @@ AM64X_IOPAD(0x026c, PIN_INPUT_PULLUP, 0) /* (B19) I2C1_SDA */ + }; + + mdio1_pins_default: mdio1-default-pins { ++ bootph-all; + pinctrl-single,pins = < + AM64X_IOPAD(0x01fc, PIN_OUTPUT, 4) /* (R2) PRG0_PRU1_GPO19.MDIO0_MDC */ + AM64X_IOPAD(0x01f8, PIN_INPUT, 4) /* (P5) PRG0_PRU1_GPO18.MDIO0_MDIO */ +@@ -290,6 +299,7 @@ AM64X_IOPAD(0x01f8, PIN_INPUT, 4) /* (P5) PRG0_PRU1_GPO18.MDIO0_MDIO */ + }; + + rgmii1_pins_default: rgmii1-default-pins { ++ bootph-all; + pinctrl-single,pins = < + AM64X_IOPAD(0x01cc, PIN_INPUT, 4) /* (W5) PRG0_PRU1_GPO7.RGMII1_RD0 */ + AM64X_IOPAD(0x01d4, PIN_INPUT, 4) /* (Y5) PRG0_PRU1_GPO9.RGMII1_RD1 */ +@@ -307,6 +317,7 @@ AM64X_IOPAD(0x00dc, PIN_OUTPUT, 4) /* (U15) PRG1_PRU0_GPO9.RGMII1_TX_CTL */ + }; + + rgmii2_pins_default: rgmii2-default-pins { ++ bootph-all; + pinctrl-single,pins = < + AM64X_IOPAD(0x0108, PIN_INPUT, 4) /* (W11) PRG1_PRU1_GPO0.RGMII2_RD0 */ + AM64X_IOPAD(0x010c, PIN_INPUT, 4) /* (V11) PRG1_PRU1_GPO1.RGMII2_RD1 */ +@@ -324,6 +335,7 @@ AM64X_IOPAD(0x0144, PIN_OUTPUT, 4) /* (Y11) PRG1_PRU1_GPO15.RGMII2_TX_CTL */ + }; + + main_usb0_pins_default: main-usb0-default-pins { ++ bootph-all; + pinctrl-single,pins = < + AM64X_IOPAD(0x02a8, PIN_OUTPUT, 0) /* (E19) USB0_DRVVBUS */ + >; +@@ -366,6 +378,7 @@ AM64X_IOPAD(0x0258, PIN_OUTPUT, 0) /* (C17) MCAN1_TX */ + }; + + ddr_vtt_pins_default: ddr-vtt-default-pins { ++ bootph-all; + pinctrl-single,pins = < + AM64X_IOPAD(0x0030, PIN_OUTPUT_PULLUP, 7) /* (L18) OSPI0_CSN1.GPIO0_12 */ + >; +@@ -373,6 +386,7 @@ AM64X_IOPAD(0x0030, PIN_OUTPUT_PULLUP, 7) /* (L18) OSPI0_CSN1.GPIO0_12 */ + }; + + &main_uart0 { ++ bootph-all; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_uart0_pins_default>; +@@ -387,6 +401,7 @@ &main_uart1 { + }; + + &main_i2c0 { ++ bootph-all; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c0_pins_default>; +@@ -400,12 +415,14 @@ eeprom@50 { + }; + + &main_i2c1 { ++ bootph-all; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c1_pins_default>; + clock-frequency = <400000>; + + exp1: gpio@22 { ++ bootph-all; + compatible = "ti,tca6424"; + reg = <0x22>; + gpio-controller; +@@ -438,6 +455,10 @@ display@3c { + }; + }; + ++&main_gpio0 { ++ bootph-all; ++}; ++ + /* mcu_gpio0 is reserved for mcu firmware usage */ + &mcu_gpio0 { + status = "reserved"; +@@ -457,16 +478,19 @@ eeprom@0 { + }; + }; + ++/* eMMC */ + &sdhci0 { +- /* emmc */ ++ status = "okay"; + bus-width = <8>; + non-removable; + ti,driver-strength-ohm = <50>; + disable-wp; + }; + ++/* SD/MMC */ + &sdhci1 { +- /* SD/MMC */ ++ bootph-all; ++ status = "okay"; + vmmc-supply = <&vdd_mmc1>; + pinctrl-names = "default"; + bus-width = <4>; +@@ -476,11 +500,13 @@ &sdhci1 { + }; + + &usbss0 { ++ bootph-all; + ti,vbus-divider; + ti,usb2-only; + }; + + &usb0 { ++ bootph-all; + dr_mode = "otg"; + maximum-speed = "high-speed"; + pinctrl-names = "default"; +@@ -488,11 +514,13 @@ &usb0 { + }; + + &cpsw3g { ++ bootph-all; + pinctrl-names = "default"; + pinctrl-0 = <&rgmii1_pins_default>, <&rgmii2_pins_default>; + }; + + &cpsw_port1 { ++ bootph-all; + phy-mode = "rgmii-rxid"; + phy-handle = <&cpsw3g_phy0>; + }; +@@ -503,11 +531,13 @@ &cpsw_port2 { + }; + + &cpsw3g_mdio { ++ bootph-all; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mdio1_pins_default>; + + cpsw3g_phy0: ethernet-phy@0 { ++ bootph-all; + reg = <0>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; +diff --git a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts +index 9175e96842d821..53b64e55413f99 100644 +--- a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts ++++ b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts +@@ -264,6 +264,7 @@ &main_uart1 { + }; + + &sdhci1 { ++ status = "okay"; + vmmc-supply = <&vcc_3v3_mmc>; + pinctrl-names = "default"; + pinctrl-0 = <&main_mmc1_pins_default>; +diff --git a/arch/arm64/boot/dts/ti/k3-am642-sk.dts b/arch/arm64/boot/dts/ti/k3-am642-sk.dts +index 722fd285a34eca..bffbd234f715ad 100644 +--- a/arch/arm64/boot/dts/ti/k3-am642-sk.dts ++++ b/arch/arm64/boot/dts/ti/k3-am642-sk.dts +@@ -34,6 +34,7 @@ aliases { + }; + + memory@80000000 { ++ bootph-pre-ram; + device_type = "memory"; + /* 2G RAM */ + reg = <0x00000000 0x80000000 0x00000000 0x80000000>; +@@ -107,6 +108,7 @@ rtos_ipc_memory_region: ipc-memories@a5000000 { + + vusb_main: regulator-0 { + /* USB MAIN INPUT 5V DC */ ++ bootph-all; + compatible = "regulator-fixed"; + regulator-name = "vusb_main5v0"; + regulator-min-microvolt = <5000000>; +@@ -117,6 +119,7 @@ vusb_main: regulator-0 { + + vcc_3v3_sys: regulator-1 { + /* output of LP8733xx */ ++ bootph-all; + compatible = "regulator-fixed"; + regulator-name = "vcc_3v3_sys"; + regulator-min-microvolt = <3300000>; +@@ -128,6 +131,7 @@ vcc_3v3_sys: regulator-1 { + + vdd_mmc1: regulator-2 { + /* TPS2051BD */ ++ bootph-all; + compatible = "regulator-fixed"; + regulator-name = "vdd_mmc1"; + regulator-min-microvolt = <3300000>; +@@ -234,6 +238,7 @@ led-7 { + + &main_pmx0 { + main_mmc1_pins_default: main-mmc1-default-pins { ++ bootph-all; + pinctrl-single,pins = < + AM64X_IOPAD(0x029c, PIN_INPUT_PULLUP, 0) /* (C20) MMC1_SDWP */ + AM64X_IOPAD(0x0298, PIN_INPUT_PULLUP, 0) /* (D19) MMC1_SDCD */ +@@ -248,6 +253,7 @@ AM64X_IOPAD(0x027c, PIN_INPUT_PULLUP, 0) /* (K18) MMC1_DAT3 */ + }; + + main_uart0_pins_default: main-uart0-default-pins { ++ bootph-all; + pinctrl-single,pins = < + AM64X_IOPAD(0x0238, PIN_INPUT, 0) /* (B16) UART0_CTSn */ + AM64X_IOPAD(0x023c, PIN_OUTPUT, 0) /* (A16) UART0_RTSn */ +@@ -257,6 +263,7 @@ AM64X_IOPAD(0x0234, PIN_OUTPUT, 0) /* (C16) UART0_TXD */ + }; + + main_uart1_pins_default: main-uart1-default-pins { ++ bootph-pre-ram; + pinctrl-single,pins = < + AM64X_IOPAD(0x0248, PIN_INPUT, 0) /* (D16) UART1_CTSn */ + AM64X_IOPAD(0x024c, PIN_OUTPUT, 0) /* (E16) UART1_RTSn */ +@@ -266,12 +273,14 @@ AM64X_IOPAD(0x0244, PIN_OUTPUT, 0) /* (E14) UART1_TXD */ + }; + + main_usb0_pins_default: main-usb0-default-pins { ++ bootph-all; + pinctrl-single,pins = < + AM64X_IOPAD(0x02a8, PIN_OUTPUT, 0) /* (E19) USB0_DRVVBUS */ + >; + }; + + main_i2c0_pins_default: main-i2c0-default-pins { ++ bootph-all; + pinctrl-single,pins = < + AM64X_IOPAD(0x0260, PIN_INPUT_PULLUP, 0) /* (A18) I2C0_SCL */ + AM64X_IOPAD(0x0264, PIN_INPUT_PULLUP, 0) /* (B18) I2C0_SDA */ +@@ -279,6 +288,7 @@ AM64X_IOPAD(0x0264, PIN_INPUT_PULLUP, 0) /* (B18) I2C0_SDA */ + }; + + main_i2c1_pins_default: main-i2c1-default-pins { ++ bootph-all; + pinctrl-single,pins = < + AM64X_IOPAD(0x0268, PIN_INPUT_PULLUP, 0) /* (C18) I2C1_SCL */ + AM64X_IOPAD(0x026c, PIN_INPUT_PULLUP, 0) /* (B19) I2C1_SDA */ +@@ -367,6 +377,7 @@ AM64X_IOPAD(0x00bc, PIN_INPUT, 7) /* (U8) GPIO0_46 */ + }; + + &main_uart0 { ++ bootph-all; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_uart0_pins_default>; +@@ -375,12 +386,14 @@ &main_uart0 { + + &main_uart1 { + /* main_uart1 is reserved for firmware usage */ ++ bootph-pre-ram; + status = "reserved"; + pinctrl-names = "default"; + pinctrl-0 = <&main_uart1_pins_default>; + }; + + &main_i2c0 { ++ bootph-all; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c0_pins_default>; +@@ -393,12 +406,14 @@ eeprom@51 { + }; + + &main_i2c1 { ++ bootph-all; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c1_pins_default>; + clock-frequency = <400000>; + + exp1: gpio@70 { ++ bootph-all; + compatible = "nxp,pca9538"; + reg = <0x70>; + gpio-controller; +@@ -424,6 +439,7 @@ &mcu_gpio0 { + }; + + &sdhci0 { ++ status = "okay"; + vmmc-supply = <&wlan_en>; + bus-width = <4>; + non-removable; +@@ -443,8 +459,10 @@ wlcore: wlcore@2 { + }; + }; + ++/* SD/MMC */ + &sdhci1 { +- /* SD/MMC */ ++ bootph-all; ++ status = "okay"; + vmmc-supply = <&vdd_mmc1>; + pinctrl-names = "default"; + bus-width = <4>; +@@ -454,11 +472,22 @@ &sdhci1 { + }; + + &serdes_ln_ctrl { ++ bootph-all; + idle-states = ; + }; + ++&serdes_refclk { ++ bootph-all; ++}; ++ ++&serdes_wiz0 { ++ bootph-all; ++}; ++ + &serdes0 { ++ bootph-all; + serdes0_usb_link: phy@0 { ++ bootph-all; + reg = <0>; + cdns,num-lanes = <1>; + #phy-cells = <0>; +@@ -468,10 +497,12 @@ serdes0_usb_link: phy@0 { + }; + + &usbss0 { ++ bootph-all; + ti,vbus-divider; + }; + + &usb0 { ++ bootph-all; + dr_mode = "host"; + maximum-speed = "super-speed"; + pinctrl-names = "default"; +diff --git a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts +index 04c15b64f0b776..76ff44e71ec177 100644 +--- a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts ++++ b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts +@@ -420,7 +420,6 @@ &sdhci1 { + ti,driver-strength-ohm = <50>; + ti,fails-without-test-cd; + /* Enabled by overlay */ +- status = "disabled"; + }; + + &tscadc0 { +diff --git a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi +index 6229849b5d9682..65dbbff64ed961 100644 +--- a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi +@@ -207,6 +207,7 @@ partitions { + }; + + &sdhci0 { ++ status = "okay"; + non-removable; + disable-wp; + no-sdio; +diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +index ba1c14a54acf48..b849648d51f91b 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +@@ -14,6 +14,16 @@ + + / { + aliases { ++ serial0 = &wkup_uart0; ++ serial1 = &mcu_uart0; ++ serial2 = &main_uart0; ++ serial3 = &main_uart1; ++ i2c0 = &wkup_i2c0; ++ i2c1 = &mcu_i2c0; ++ i2c2 = &main_i2c0; ++ i2c3 = &main_i2c1; ++ i2c4 = &main_i2c2; ++ i2c5 = &main_i2c3; + spi0 = &mcu_spi0; + mmc0 = &sdhci1; + mmc1 = &sdhci0; +diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +index bc460033a37a86..57befcce93b976 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +@@ -1013,9 +1013,10 @@ dss: dss@4a00000 { + <0x0 0x04a07000 0x0 0x1000>, /* ovr1 */ + <0x0 0x04a08000 0x0 0x1000>, /* ovr2 */ + <0x0 0x04a0a000 0x0 0x1000>, /* vp1 */ +- <0x0 0x04a0b000 0x0 0x1000>; /* vp2 */ ++ <0x0 0x04a0b000 0x0 0x1000>, /* vp2 */ ++ <0x0 0x04a01000 0x0 0x1000>; /* common1 */ + reg-names = "common", "vidl1", "vid", +- "ovr1", "ovr2", "vp1", "vp2"; ++ "ovr1", "ovr2", "vp1", "vp2", "common1"; + + ti,am65x-oldi-io-ctrl = <&dss_oldi_io_ctrl>; + +@@ -1034,7 +1035,7 @@ dss: dss@4a00000 { + assigned-clocks = <&k3_clks 67 2>; + assigned-clock-parents = <&k3_clks 67 5>; + +- interrupts = ; ++ interrupts = ; + + dma-coherent; + +diff --git a/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts +index cee2b4b0eb87da..7a0c599f2b1c35 100644 +--- a/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts ++++ b/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts +@@ -91,24 +91,25 @@ vdd_sd_dv: gpio-regulator-TLV71033 { + }; + + &wkup_pmx0 { ++}; ++ ++&wkup_pmx2 { + mcu_uart0_pins_default: mcu-uart0-default-pins { + pinctrl-single,pins = < +- J721E_WKUP_IOPAD(0xf4, PIN_INPUT, 0) /* (D20) MCU_UART0_RXD */ +- J721E_WKUP_IOPAD(0xf0, PIN_OUTPUT, 0) /* (D19) MCU_UART0_TXD */ +- J721E_WKUP_IOPAD(0xf8, PIN_INPUT, 0) /* (E20) MCU_UART0_CTSn */ +- J721E_WKUP_IOPAD(0xfc, PIN_OUTPUT, 0) /* (E21) MCU_UART0_RTSn */ ++ J721E_WKUP_IOPAD(0x90, PIN_INPUT, 0) /* (E20) MCU_UART0_CTSn */ ++ J721E_WKUP_IOPAD(0x94, PIN_OUTPUT, 0) /* (E21) MCU_UART0_RTSn */ ++ J721E_WKUP_IOPAD(0x8c, PIN_INPUT, 0) /* (D20) MCU_UART0_RXD */ ++ J721E_WKUP_IOPAD(0x88, PIN_OUTPUT, 0) /* (D19) MCU_UART0_TXD */ + >; + }; + + wkup_uart0_pins_default: wkup-uart0-default-pins { + pinctrl-single,pins = < +- J721E_WKUP_IOPAD(0xb0, PIN_INPUT, 0) /* (B14) WKUP_UART0_RXD */ +- J721E_WKUP_IOPAD(0xb4, PIN_OUTPUT, 0) /* (A14) WKUP_UART0_TXD */ ++ J721E_WKUP_IOPAD(0x48, PIN_INPUT, 0) /* (B14) WKUP_UART0_RXD */ ++ J721E_WKUP_IOPAD(0x4c, PIN_OUTPUT, 0) /* (A14) WKUP_UART0_TXD */ + >; + }; +-}; + +-&wkup_pmx2 { + mcu_cpsw_pins_default: mcu-cpsw-default-pins { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x0000, PIN_OUTPUT, 0) /* MCU_RGMII1_TX_CTL */ +@@ -210,7 +211,6 @@ &mcu_uart0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_uart0_pins_default>; +- clock-frequency = <96000000>; + }; + + &main_uart0 { +diff --git a/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64.dts b/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64.dts +index 2f954729f35338..7897323376a5b9 100644 +--- a/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64.dts ++++ b/arch/arm64/boot/dts/ti/k3-j721e-beagleboneai64.dts +@@ -123,7 +123,7 @@ main_r5fss1_core1_memory_region: r5f-memory@a5100000 { + no-map; + }; + +- c66_1_dma_memory_region: c66-dma-memory@a6000000 { ++ c66_0_dma_memory_region: c66-dma-memory@a6000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa6000000 0x00 0x100000>; + no-map; +@@ -135,7 +135,7 @@ c66_0_memory_region: c66-memory@a6100000 { + no-map; + }; + +- c66_0_dma_memory_region: c66-dma-memory@a7000000 { ++ c66_1_dma_memory_region: c66-dma-memory@a7000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa7000000 0x00 0x100000>; + no-map; +diff --git a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts +index 42fe8eee9ec8c7..ccacb65683b5b0 100644 +--- a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts ++++ b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts +@@ -119,7 +119,7 @@ main_r5fss1_core1_memory_region: r5f-memory@a5100000 { + no-map; + }; + +- c66_1_dma_memory_region: c66-dma-memory@a6000000 { ++ c66_0_dma_memory_region: c66-dma-memory@a6000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa6000000 0x00 0x100000>; + no-map; +@@ -131,7 +131,7 @@ c66_0_memory_region: c66-memory@a6100000 { + no-map; + }; + +- c66_0_dma_memory_region: c66-dma-memory@a7000000 { ++ c66_1_dma_memory_region: c66-dma-memory@a7000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa7000000 0x00 0x100000>; + no-map; +diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts +index c6b85bbf9a179b..1ba1f53c72d03b 100644 +--- a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts ++++ b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts +@@ -190,8 +190,6 @@ J721S2_IOPAD(0x038, PIN_OUTPUT, 0) /* (AB28) MCASP0_ACLKX.MCAN5_TX */ + &wkup_pmx2 { + wkup_uart0_pins_default: wkup-uart0-default-pins { + pinctrl-single,pins = < +- J721S2_WKUP_IOPAD(0x070, PIN_INPUT, 0) /* (E25) WKUP_GPIO0_6.WKUP_UART0_CTSn */ +- J721S2_WKUP_IOPAD(0x074, PIN_OUTPUT, 0) /* (F28) WKUP_GPIO0_7.WKUP_UART0_RTSn */ + J721S2_WKUP_IOPAD(0x048, PIN_INPUT, 0) /* (D28) WKUP_UART0_RXD */ + J721S2_WKUP_IOPAD(0x04c, PIN_OUTPUT, 0) /* (D27) WKUP_UART0_TXD */ + >; +diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi +index 2ddad931855416..71324fec415ae2 100644 +--- a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi +@@ -652,7 +652,7 @@ wkup_vtm0: temperature-sensor@42040000 { + compatible = "ti,j7200-vtm"; + reg = <0x00 0x42040000 0x0 0x350>, + <0x00 0x42050000 0x0 0x350>; +- power-domains = <&k3_pds 154 TI_SCI_PD_SHARED>; ++ power-domains = <&k3_pds 180 TI_SCI_PD_SHARED>; + #thermal-sensor-cells = <1>; + }; + }; +diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts b/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts +index 5991c2e1d994c8..39f99ee39dab99 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts +@@ -296,8 +296,6 @@ &wkup_pmx2 { + wkup_uart0_pins_default: wkup-uart0-default-pins { + bootph-all; + pinctrl-single,pins = < +- J721S2_WKUP_IOPAD(0x070, PIN_INPUT, 0) /* (L37) WKUP_GPIO0_6.WKUP_UART0_CTSn */ +- J721S2_WKUP_IOPAD(0x074, PIN_INPUT, 0) /* (L36) WKUP_GPIO0_7.WKUP_UART0_RTSn */ + J721S2_WKUP_IOPAD(0x048, PIN_INPUT, 0) /* (K35) WKUP_UART0_RXD */ + J721S2_WKUP_IOPAD(0x04c, PIN_INPUT, 0) /* (K34) WKUP_UART0_TXD */ + >; +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 4ab4018d369538..8d26daf7fa3d12 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi +@@ -616,7 +616,7 @@ wkup_vtm0: temperature-sensor@42040000 { + compatible = "ti,j7200-vtm"; + reg = <0x00 0x42040000 0x00 0x350>, + <0x00 0x42050000 0x00 0x350>; +- power-domains = <&k3_pds 154 TI_SCI_PD_SHARED>; ++ power-domains = <&k3_pds 243 TI_SCI_PD_SHARED>; + #thermal-sensor-cells = <1>; + }; + +diff --git a/arch/arm64/boot/dts/xilinx/Makefile b/arch/arm64/boot/dts/xilinx/Makefile +index 5e40c0b4fa0a90..1068b0fa8e9847 100644 +--- a/arch/arm64/boot/dts/xilinx/Makefile ++++ b/arch/arm64/boot/dts/xilinx/Makefile +@@ -22,11 +22,10 @@ dtb-$(CONFIG_ARCH_ZYNQMP) += zynqmp-sm-k26-revA.dtb + dtb-$(CONFIG_ARCH_ZYNQMP) += zynqmp-smk-k26-revA.dtb + + zynqmp-sm-k26-revA-sck-kv-g-revA-dtbs := zynqmp-sm-k26-revA.dtb zynqmp-sck-kv-g-revA.dtbo ++dtb-$(CONFIG_ARCH_ZYNQMP) += zynqmp-sm-k26-revA-sck-kv-g-revA.dtb + zynqmp-sm-k26-revA-sck-kv-g-revB-dtbs := zynqmp-sm-k26-revA.dtb zynqmp-sck-kv-g-revB.dtbo ++dtb-$(CONFIG_ARCH_ZYNQMP) += zynqmp-sm-k26-revA-sck-kv-g-revB.dtb + zynqmp-smk-k26-revA-sck-kv-g-revA-dtbs := zynqmp-smk-k26-revA.dtb zynqmp-sck-kv-g-revA.dtbo ++dtb-$(CONFIG_ARCH_ZYNQMP) += zynqmp-smk-k26-revA-sck-kv-g-revA.dtb + zynqmp-smk-k26-revA-sck-kv-g-revB-dtbs := zynqmp-smk-k26-revA.dtb zynqmp-sck-kv-g-revB.dtbo +- +-zynqmp-sm-k26-revA-sck-kr-g-revA-dtbs := zynqmp-sm-k26-revA.dtb zynqmp-sck-kr-g-revA.dtbo +-zynqmp-sm-k26-revA-sck-kr-g-revB-dtbs := zynqmp-sm-k26-revA.dtb zynqmp-sck-kr-g-revB.dtbo +-zynqmp-smk-k26-revA-sck-kr-g-revA-dtbs := zynqmp-smk-k26-revA.dtb zynqmp-sck-kr-g-revA.dtbo +-zynqmp-smk-k26-revA-sck-kr-g-revB-dtbs := zynqmp-smk-k26-revA.dtb zynqmp-sck-kr-g-revB.dtbo ++dtb-$(CONFIG_ARCH_ZYNQMP) += zynqmp-smk-k26-revA-sck-kv-g-revB.dtb +diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso +index ae1b9b2bdbee27..92f4190d564db1 100644 +--- a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso ++++ b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso +@@ -21,57 +21,57 @@ + /dts-v1/; + /plugin/; + +-&i2c1 { /* I2C_SCK C23/C24 - MIO from SOM */ +- #address-cells = <1>; +- #size-cells = <0>; +- pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&pinctrl_i2c1_default>; +- pinctrl-1 = <&pinctrl_i2c1_gpio>; +- scl-gpios = <&gpio 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; +- sda-gpios = <&gpio 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; +- +- /* u14 - 0x40 - ina260 */ +- /* u27 - 0xe0 - STDP4320 DP/HDMI splitter */ +-}; +- +-&amba { +- si5332_0: si5332_0 { /* u17 */ ++&{/} { ++ si5332_0: si5332-0 { /* u17 */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <125000000>; + }; + +- si5332_1: si5332_1 { /* u17 */ ++ si5332_1: si5332-1 { /* u17 */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; + +- si5332_2: si5332_2 { /* u17 */ ++ si5332_2: si5332-2 { /* u17 */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <48000000>; + }; + +- si5332_3: si5332_3 { /* u17 */ ++ si5332_3: si5332-3 { /* u17 */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; + +- si5332_4: si5332_4 { /* u17 */ ++ si5332_4: si5332-4 { /* u17 */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + }; + +- si5332_5: si5332_5 { /* u17 */ ++ si5332_5: si5332-5 { /* u17 */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; + }; + ++&i2c1 { /* I2C_SCK C23/C24 - MIO from SOM */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ pinctrl-names = "default", "gpio"; ++ pinctrl-0 = <&pinctrl_i2c1_default>; ++ pinctrl-1 = <&pinctrl_i2c1_gpio>; ++ scl-gpios = <&gpio 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ ++ /* u14 - 0x40 - ina260 */ ++ /* u27 - 0xe0 - STDP4320 DP/HDMI splitter */ ++}; ++ + /* DP/USB 3.0 and SATA */ + &psgtr { + status = "okay"; +diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso +index b59e48be6465a5..f88b71f5b07a63 100644 +--- a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso ++++ b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso +@@ -16,58 +16,58 @@ + /dts-v1/; + /plugin/; + +-&i2c1 { /* I2C_SCK C23/C24 - MIO from SOM */ +- #address-cells = <1>; +- #size-cells = <0>; +- pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&pinctrl_i2c1_default>; +- pinctrl-1 = <&pinctrl_i2c1_gpio>; +- scl-gpios = <&gpio 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; +- sda-gpios = <&gpio 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; +- +- /* u14 - 0x40 - ina260 */ +- /* u43 - 0x2d - usb5744 */ +- /* u27 - 0xe0 - STDP4320 DP/HDMI splitter */ +-}; +- +-&amba { +- si5332_0: si5332_0 { /* u17 */ ++&{/} { ++ si5332_0: si5332-0 { /* u17 */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <125000000>; + }; + +- si5332_1: si5332_1 { /* u17 */ ++ si5332_1: si5332-1 { /* u17 */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; + +- si5332_2: si5332_2 { /* u17 */ ++ si5332_2: si5332-2 { /* u17 */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <48000000>; + }; + +- si5332_3: si5332_3 { /* u17 */ ++ si5332_3: si5332-3 { /* u17 */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; + +- si5332_4: si5332_4 { /* u17 */ ++ si5332_4: si5332-4 { /* u17 */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + }; + +- si5332_5: si5332_5 { /* u17 */ ++ si5332_5: si5332-5 { /* u17 */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; + }; + ++&i2c1 { /* I2C_SCK C23/C24 - MIO from SOM */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ pinctrl-names = "default", "gpio"; ++ pinctrl-0 = <&pinctrl_i2c1_default>; ++ pinctrl-1 = <&pinctrl_i2c1_gpio>; ++ scl-gpios = <&gpio 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ ++ /* u14 - 0x40 - ina260 */ ++ /* u43 - 0x2d - usb5744 */ ++ /* u27 - 0xe0 - STDP4320 DP/HDMI splitter */ ++}; ++ + /* DP/USB 3.0 */ + &psgtr { + status = "okay"; +diff --git a/arch/arm64/boot/install.sh b/arch/arm64/boot/install.sh +index 7399d706967a4f..9b7a09808a3dda 100755 +--- a/arch/arm64/boot/install.sh ++++ b/arch/arm64/boot/install.sh +@@ -17,7 +17,8 @@ + # $3 - kernel map file + # $4 - default install path (blank if root directory) + +-if [ "$(basename $2)" = "Image.gz" ]; then ++if [ "$(basename $2)" = "Image.gz" ] || [ "$(basename $2)" = "vmlinuz.efi" ] ++then + # Compressed install + echo "Installing compressed kernel" + base=vmlinuz +diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig +index a789119e6483b5..60af93c04b45a7 100644 +--- a/arch/arm64/configs/defconfig ++++ b/arch/arm64/configs/defconfig +@@ -623,6 +623,7 @@ CONFIG_GPIO_RCAR=y + CONFIG_GPIO_UNIPHIER=y + CONFIG_GPIO_VISCONTI=y + CONFIG_GPIO_WCD934X=m ++CONFIG_GPIO_VF610=y + CONFIG_GPIO_XGENE=y + CONFIG_GPIO_XGENE_SB=y + CONFIG_GPIO_MAX732X=y +diff --git a/arch/arm64/crypto/aes-neonbs-glue.c b/arch/arm64/crypto/aes-neonbs-glue.c +index bac4cabef6073e..467ac2f768ac2b 100644 +--- a/arch/arm64/crypto/aes-neonbs-glue.c ++++ b/arch/arm64/crypto/aes-neonbs-glue.c +@@ -227,8 +227,19 @@ static int ctr_encrypt(struct skcipher_request *req) + src += blocks * AES_BLOCK_SIZE; + } + if (nbytes && walk.nbytes == walk.total) { ++ u8 buf[AES_BLOCK_SIZE]; ++ u8 *d = dst; ++ ++ if (unlikely(nbytes < AES_BLOCK_SIZE)) ++ src = dst = memcpy(buf + sizeof(buf) - nbytes, ++ src, nbytes); ++ + neon_aes_ctr_encrypt(dst, src, ctx->enc, ctx->key.rounds, + nbytes, walk.iv); ++ ++ if (unlikely(nbytes < AES_BLOCK_SIZE)) ++ memcpy(d, dst, nbytes); ++ + nbytes = 0; + } + kernel_neon_end(); +diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h +index 6792a1f83f2ad4..a407f9cd549edc 100644 +--- a/arch/arm64/include/asm/acpi.h ++++ b/arch/arm64/include/asm/acpi.h +@@ -119,6 +119,18 @@ static inline u32 get_acpi_id_for_cpu(unsigned int cpu) + return acpi_cpu_get_madt_gicc(cpu)->uid; + } + ++static inline int get_cpu_for_acpi_id(u32 uid) ++{ ++ int cpu; ++ ++ for (cpu = 0; cpu < nr_cpu_ids; cpu++) ++ if (acpi_cpu_get_madt_gicc(cpu) && ++ uid == get_acpi_id_for_cpu(cpu)) ++ return cpu; ++ ++ return -EINVAL; ++} ++ + static inline void arch_fix_phys_package_id(int num, u32 slot) { } + void __init acpi_init_cpus(void); + int apei_claim_sea(struct pt_regs *regs); +diff --git a/arch/arm64/include/asm/alternative-macros.h b/arch/arm64/include/asm/alternative-macros.h +index 94b486192e1f15..a3652b6bb740d9 100644 +--- a/arch/arm64/include/asm/alternative-macros.h ++++ b/arch/arm64/include/asm/alternative-macros.h +@@ -229,7 +229,7 @@ alternative_has_cap_likely(const unsigned long cpucap) + compiletime_assert(cpucap < ARM64_NCAPS, + "cpucap must be < ARM64_NCAPS"); + +- asm_volatile_goto( ++ asm goto( + ALTERNATIVE_CB("b %l[l_no]", %[cpucap], alt_cb_patch_nops) + : + : [cpucap] "i" (cpucap) +@@ -247,7 +247,7 @@ alternative_has_cap_unlikely(const unsigned long cpucap) + compiletime_assert(cpucap < ARM64_NCAPS, + "cpucap must be < ARM64_NCAPS"); + +- asm_volatile_goto( ++ asm goto( + ALTERNATIVE("nop", "b %l[l_yes]", %[cpucap]) + : + : [cpucap] "i" (cpucap) +diff --git a/arch/arm64/include/asm/arm_pmuv3.h b/arch/arm64/include/asm/arm_pmuv3.h +index 18dc2fb3d7b7b2..c27404fa4418ad 100644 +--- a/arch/arm64/include/asm/arm_pmuv3.h ++++ b/arch/arm64/include/asm/arm_pmuv3.h +@@ -46,12 +46,12 @@ static inline u32 read_pmuver(void) + ID_AA64DFR0_EL1_PMUVer_SHIFT); + } + +-static inline void write_pmcr(u32 val) ++static inline void write_pmcr(u64 val) + { + write_sysreg(val, pmcr_el0); + } + +-static inline u32 read_pmcr(void) ++static inline u64 read_pmcr(void) + { + return read_sysreg(pmcr_el0); + } +@@ -71,21 +71,6 @@ static inline u64 read_pmccntr(void) + return read_sysreg(pmccntr_el0); + } + +-static inline void write_pmxevcntr(u32 val) +-{ +- write_sysreg(val, pmxevcntr_el0); +-} +- +-static inline u32 read_pmxevcntr(void) +-{ +- return read_sysreg(pmxevcntr_el0); +-} +- +-static inline void write_pmxevtyper(u32 val) +-{ +- write_sysreg(val, pmxevtyper_el0); +-} +- + static inline void write_pmcntenset(u32 val) + { + write_sysreg(val, pmcntenset_el0); +@@ -106,7 +91,7 @@ static inline void write_pmintenclr(u32 val) + write_sysreg(val, pmintenclr_el1); + } + +-static inline void write_pmccfiltr(u32 val) ++static inline void write_pmccfiltr(u64 val) + { + write_sysreg(val, pmccfiltr_el0); + } +@@ -126,12 +111,12 @@ static inline void write_pmuserenr(u32 val) + write_sysreg(val, pmuserenr_el0); + } + +-static inline u32 read_pmceid0(void) ++static inline u64 read_pmceid0(void) + { + return read_sysreg(pmceid0_el0); + } + +-static inline u32 read_pmceid1(void) ++static inline u64 read_pmceid1(void) + { + return read_sysreg(pmceid1_el0); + } +diff --git a/arch/arm64/include/asm/asm-bug.h b/arch/arm64/include/asm/asm-bug.h +index c762038ba40093..6e73809f6492a2 100644 +--- a/arch/arm64/include/asm/asm-bug.h ++++ b/arch/arm64/include/asm/asm-bug.h +@@ -28,6 +28,7 @@ + 14470: .long 14471f - .; \ + _BUGVERBOSE_LOCATION(__FILE__, __LINE__) \ + .short flags; \ ++ .align 2; \ + .popsection; \ + 14471: + #else +diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h +index cf2987464c1860..1ca947d5c93963 100644 +--- a/arch/arm64/include/asm/barrier.h ++++ b/arch/arm64/include/asm/barrier.h +@@ -40,6 +40,10 @@ + */ + #define dgh() asm volatile("hint #6" : : : "memory") + ++#define spec_bar() asm volatile(ALTERNATIVE("dsb nsh\nisb\n", \ ++ SB_BARRIER_INSN"nop\n", \ ++ ARM64_HAS_SB)) ++ + #ifdef CONFIG_ARM64_PSEUDO_NMI + #define pmr_sync() \ + do { \ +diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h +index 74d00feb62f03e..488f8e75134959 100644 +--- a/arch/arm64/include/asm/cputype.h ++++ b/arch/arm64/include/asm/cputype.h +@@ -61,6 +61,7 @@ + #define ARM_CPU_IMP_HISI 0x48 + #define ARM_CPU_IMP_APPLE 0x61 + #define ARM_CPU_IMP_AMPERE 0xC0 ++#define ARM_CPU_IMP_MICROSOFT 0x6D + + #define ARM_CPU_PART_AEM_V8 0xD0F + #define ARM_CPU_PART_FOUNDATION 0xD00 +@@ -85,8 +86,18 @@ + #define ARM_CPU_PART_CORTEX_X2 0xD48 + #define ARM_CPU_PART_NEOVERSE_N2 0xD49 + #define ARM_CPU_PART_CORTEX_A78C 0xD4B +- +-#define APM_CPU_PART_POTENZA 0x000 ++#define ARM_CPU_PART_CORTEX_X1C 0xD4C ++#define ARM_CPU_PART_CORTEX_X3 0xD4E ++#define ARM_CPU_PART_NEOVERSE_V2 0xD4F ++#define ARM_CPU_PART_CORTEX_A720 0xD81 ++#define ARM_CPU_PART_CORTEX_X4 0xD82 ++#define ARM_CPU_PART_NEOVERSE_V3 0xD84 ++#define ARM_CPU_PART_CORTEX_X925 0xD85 ++#define ARM_CPU_PART_CORTEX_A725 0xD87 ++#define ARM_CPU_PART_NEOVERSE_N3 0xD8E ++ ++#define APM_CPU_PART_XGENE 0x000 ++#define APM_CPU_VAR_POTENZA 0x00 + + #define CAVIUM_CPU_PART_THUNDERX 0x0A1 + #define CAVIUM_CPU_PART_THUNDERX_81XX 0x0A2 +@@ -133,6 +144,9 @@ + #define APPLE_CPU_PART_M2_AVALANCHE_MAX 0x039 + + #define AMPERE_CPU_PART_AMPERE1 0xAC3 ++#define AMPERE_CPU_PART_AMPERE1A 0xAC4 ++ ++#define MICROSOFT_CPU_PART_AZURE_COBALT_100 0xD49 /* Based on r0p0 of ARM Neoverse N2 */ + + #define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) + #define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) +@@ -155,6 +169,15 @@ + #define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2) + #define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2) + #define MIDR_CORTEX_A78C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78C) ++#define MIDR_CORTEX_X1C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1C) ++#define MIDR_CORTEX_X3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X3) ++#define MIDR_NEOVERSE_V2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V2) ++#define MIDR_CORTEX_A720 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A720) ++#define MIDR_CORTEX_X4 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X4) ++#define MIDR_NEOVERSE_V3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3) ++#define MIDR_CORTEX_X925 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X925) ++#define MIDR_CORTEX_A725 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A725) ++#define MIDR_NEOVERSE_N3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N3) + #define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX) + #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX) + #define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX) +@@ -192,6 +215,8 @@ + #define MIDR_APPLE_M2_BLIZZARD_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_MAX) + #define MIDR_APPLE_M2_AVALANCHE_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_MAX) + #define MIDR_AMPERE1 MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1) ++#define MIDR_AMPERE1A MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1A) ++#define MIDR_MICROSOFT_AZURE_COBALT_100 MIDR_CPU_MODEL(ARM_CPU_IMP_MICROSOFT, MICROSOFT_CPU_PART_AZURE_COBALT_100) + + /* Fujitsu Erratum 010001 affects A64FX 1.0 and 1.1, (v0r0 and v1r0) */ + #define MIDR_FUJITSU_ERRATUM_010001 MIDR_FUJITSU_A64FX +diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h +index ae35939f395bb1..1cdae1b4f03bee 100644 +--- a/arch/arm64/include/asm/esr.h ++++ b/arch/arm64/include/asm/esr.h +@@ -10,63 +10,63 @@ + #include + #include + +-#define ESR_ELx_EC_UNKNOWN (0x00) +-#define ESR_ELx_EC_WFx (0x01) ++#define ESR_ELx_EC_UNKNOWN UL(0x00) ++#define ESR_ELx_EC_WFx UL(0x01) + /* Unallocated EC: 0x02 */ +-#define ESR_ELx_EC_CP15_32 (0x03) +-#define ESR_ELx_EC_CP15_64 (0x04) +-#define ESR_ELx_EC_CP14_MR (0x05) +-#define ESR_ELx_EC_CP14_LS (0x06) +-#define ESR_ELx_EC_FP_ASIMD (0x07) +-#define ESR_ELx_EC_CP10_ID (0x08) /* EL2 only */ +-#define ESR_ELx_EC_PAC (0x09) /* EL2 and above */ ++#define ESR_ELx_EC_CP15_32 UL(0x03) ++#define ESR_ELx_EC_CP15_64 UL(0x04) ++#define ESR_ELx_EC_CP14_MR UL(0x05) ++#define ESR_ELx_EC_CP14_LS UL(0x06) ++#define ESR_ELx_EC_FP_ASIMD UL(0x07) ++#define ESR_ELx_EC_CP10_ID UL(0x08) /* EL2 only */ ++#define ESR_ELx_EC_PAC UL(0x09) /* EL2 and above */ + /* Unallocated EC: 0x0A - 0x0B */ +-#define ESR_ELx_EC_CP14_64 (0x0C) +-#define ESR_ELx_EC_BTI (0x0D) +-#define ESR_ELx_EC_ILL (0x0E) ++#define ESR_ELx_EC_CP14_64 UL(0x0C) ++#define ESR_ELx_EC_BTI UL(0x0D) ++#define ESR_ELx_EC_ILL UL(0x0E) + /* Unallocated EC: 0x0F - 0x10 */ +-#define ESR_ELx_EC_SVC32 (0x11) +-#define ESR_ELx_EC_HVC32 (0x12) /* EL2 only */ +-#define ESR_ELx_EC_SMC32 (0x13) /* EL2 and above */ ++#define ESR_ELx_EC_SVC32 UL(0x11) ++#define ESR_ELx_EC_HVC32 UL(0x12) /* EL2 only */ ++#define ESR_ELx_EC_SMC32 UL(0x13) /* EL2 and above */ + /* Unallocated EC: 0x14 */ +-#define ESR_ELx_EC_SVC64 (0x15) +-#define ESR_ELx_EC_HVC64 (0x16) /* EL2 and above */ +-#define ESR_ELx_EC_SMC64 (0x17) /* EL2 and above */ +-#define ESR_ELx_EC_SYS64 (0x18) +-#define ESR_ELx_EC_SVE (0x19) +-#define ESR_ELx_EC_ERET (0x1a) /* EL2 only */ ++#define ESR_ELx_EC_SVC64 UL(0x15) ++#define ESR_ELx_EC_HVC64 UL(0x16) /* EL2 and above */ ++#define ESR_ELx_EC_SMC64 UL(0x17) /* EL2 and above */ ++#define ESR_ELx_EC_SYS64 UL(0x18) ++#define ESR_ELx_EC_SVE UL(0x19) ++#define ESR_ELx_EC_ERET UL(0x1a) /* EL2 only */ + /* Unallocated EC: 0x1B */ +-#define ESR_ELx_EC_FPAC (0x1C) /* EL1 and above */ +-#define ESR_ELx_EC_SME (0x1D) ++#define ESR_ELx_EC_FPAC UL(0x1C) /* EL1 and above */ ++#define ESR_ELx_EC_SME UL(0x1D) + /* Unallocated EC: 0x1E */ +-#define ESR_ELx_EC_IMP_DEF (0x1f) /* EL3 only */ +-#define ESR_ELx_EC_IABT_LOW (0x20) +-#define ESR_ELx_EC_IABT_CUR (0x21) +-#define ESR_ELx_EC_PC_ALIGN (0x22) ++#define ESR_ELx_EC_IMP_DEF UL(0x1f) /* EL3 only */ ++#define ESR_ELx_EC_IABT_LOW UL(0x20) ++#define ESR_ELx_EC_IABT_CUR UL(0x21) ++#define ESR_ELx_EC_PC_ALIGN UL(0x22) + /* Unallocated EC: 0x23 */ +-#define ESR_ELx_EC_DABT_LOW (0x24) +-#define ESR_ELx_EC_DABT_CUR (0x25) +-#define ESR_ELx_EC_SP_ALIGN (0x26) +-#define ESR_ELx_EC_MOPS (0x27) +-#define ESR_ELx_EC_FP_EXC32 (0x28) ++#define ESR_ELx_EC_DABT_LOW UL(0x24) ++#define ESR_ELx_EC_DABT_CUR UL(0x25) ++#define ESR_ELx_EC_SP_ALIGN UL(0x26) ++#define ESR_ELx_EC_MOPS UL(0x27) ++#define ESR_ELx_EC_FP_EXC32 UL(0x28) + /* Unallocated EC: 0x29 - 0x2B */ +-#define ESR_ELx_EC_FP_EXC64 (0x2C) ++#define ESR_ELx_EC_FP_EXC64 UL(0x2C) + /* Unallocated EC: 0x2D - 0x2E */ +-#define ESR_ELx_EC_SERROR (0x2F) +-#define ESR_ELx_EC_BREAKPT_LOW (0x30) +-#define ESR_ELx_EC_BREAKPT_CUR (0x31) +-#define ESR_ELx_EC_SOFTSTP_LOW (0x32) +-#define ESR_ELx_EC_SOFTSTP_CUR (0x33) +-#define ESR_ELx_EC_WATCHPT_LOW (0x34) +-#define ESR_ELx_EC_WATCHPT_CUR (0x35) ++#define ESR_ELx_EC_SERROR UL(0x2F) ++#define ESR_ELx_EC_BREAKPT_LOW UL(0x30) ++#define ESR_ELx_EC_BREAKPT_CUR UL(0x31) ++#define ESR_ELx_EC_SOFTSTP_LOW UL(0x32) ++#define ESR_ELx_EC_SOFTSTP_CUR UL(0x33) ++#define ESR_ELx_EC_WATCHPT_LOW UL(0x34) ++#define ESR_ELx_EC_WATCHPT_CUR UL(0x35) + /* Unallocated EC: 0x36 - 0x37 */ +-#define ESR_ELx_EC_BKPT32 (0x38) ++#define ESR_ELx_EC_BKPT32 UL(0x38) + /* Unallocated EC: 0x39 */ +-#define ESR_ELx_EC_VECTOR32 (0x3A) /* EL2 only */ ++#define ESR_ELx_EC_VECTOR32 UL(0x3A) /* EL2 only */ + /* Unallocated EC: 0x3B */ +-#define ESR_ELx_EC_BRK64 (0x3C) ++#define ESR_ELx_EC_BRK64 UL(0x3C) + /* Unallocated EC: 0x3D - 0x3F */ +-#define ESR_ELx_EC_MAX (0x3F) ++#define ESR_ELx_EC_MAX UL(0x3F) + + #define ESR_ELx_EC_SHIFT (26) + #define ESR_ELx_EC_WIDTH (6) +diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h +index 8df46f186c64b8..7415c63b41874d 100644 +--- a/arch/arm64/include/asm/fpsimd.h ++++ b/arch/arm64/include/asm/fpsimd.h +@@ -36,13 +36,13 @@ + * When we defined the maximum SVE vector length we defined the ABI so + * that the maximum vector length included all the reserved for future + * expansion bits in ZCR rather than those just currently defined by +- * the architecture. While SME follows a similar pattern the fact that +- * it includes a square matrix means that any allocations that attempt +- * to cover the maximum potential vector length (such as happen with +- * the regset used for ptrace) end up being extremely large. Define +- * the much lower actual limit for use in such situations. ++ * the architecture. Using this length to allocate worst size buffers ++ * results in excessively large allocations, and this effect is even ++ * more pronounced for SME due to ZA. Define more suitable VLs for ++ * these situations. + */ +-#define SME_VQ_MAX 16 ++#define ARCH_SVE_VQ_MAX ((ZCR_ELx_LEN_MASK >> ZCR_ELx_LEN_SHIFT) + 1) ++#define SME_VQ_MAX ((SMCR_ELx_LEN_MASK >> SMCR_ELx_LEN_SHIFT) + 1) + + struct task_struct; + +@@ -360,6 +360,7 @@ extern void sme_alloc(struct task_struct *task, bool flush); + extern unsigned int sme_get_vl(void); + extern int sme_set_current_vl(unsigned long arg); + extern int sme_get_current_vl(void); ++extern void sme_suspend_exit(void); + + /* + * Return how many bytes of memory are required to store the full SME +@@ -395,6 +396,7 @@ static inline int sme_max_vl(void) { return 0; } + static inline int sme_max_virtualisable_vl(void) { return 0; } + static inline int sme_set_current_vl(unsigned long arg) { return -EINVAL; } + static inline int sme_get_current_vl(void) { return -EINVAL; } ++static inline void sme_suspend_exit(void) { } + + static inline size_t sme_state_size(struct task_struct const *task) + { +diff --git a/arch/arm64/include/asm/irq_work.h b/arch/arm64/include/asm/irq_work.h +index 81bbfa3a035bd2..a1020285ea7504 100644 +--- a/arch/arm64/include/asm/irq_work.h ++++ b/arch/arm64/include/asm/irq_work.h +@@ -2,8 +2,6 @@ + #ifndef __ASM_IRQ_WORK_H + #define __ASM_IRQ_WORK_H + +-extern void arch_irq_work_raise(void); +- + static inline bool arch_irq_work_has_interrupt(void) + { + return true; +diff --git a/arch/arm64/include/asm/jump_label.h b/arch/arm64/include/asm/jump_label.h +index 48ddc0f45d2283..4b99159150829b 100644 +--- a/arch/arm64/include/asm/jump_label.h ++++ b/arch/arm64/include/asm/jump_label.h +@@ -13,12 +13,13 @@ + #include + #include + ++#define HAVE_JUMP_LABEL_BATCH + #define JUMP_LABEL_NOP_SIZE AARCH64_INSN_SIZE + + static __always_inline bool arch_static_branch(struct static_key * const key, + const bool branch) + { +- asm_volatile_goto( ++ asm goto( + "1: nop \n\t" + " .pushsection __jump_table, \"aw\" \n\t" + " .align 3 \n\t" +@@ -35,7 +36,7 @@ static __always_inline bool arch_static_branch(struct static_key * const key, + static __always_inline bool arch_static_branch_jump(struct static_key * const key, + const bool branch) + { +- asm_volatile_goto( ++ asm goto( + "1: b %l[l_yes] \n\t" + " .pushsection __jump_table, \"aw\" \n\t" + " .align 3 \n\t" +diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h +index 7f7d9b1df4e5ad..07bdf5dd8ebef5 100644 +--- a/arch/arm64/include/asm/pgtable.h ++++ b/arch/arm64/include/asm/pgtable.h +@@ -826,6 +826,12 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) + pte = set_pte_bit(pte, __pgprot(PTE_DIRTY)); + + pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); ++ /* ++ * If we end up clearing hw dirtiness for a sw-dirty PTE, set hardware ++ * dirtiness again. ++ */ ++ if (pte_sw_dirty(pte)) ++ pte = pte_mkdirty(pte); + return pte; + } + +diff --git a/arch/arm64/include/asm/setup.h b/arch/arm64/include/asm/setup.h +index f4af547ef54caa..2e4d7da74fb87a 100644 +--- a/arch/arm64/include/asm/setup.h ++++ b/arch/arm64/include/asm/setup.h +@@ -21,9 +21,22 @@ static inline bool arch_parse_debug_rodata(char *arg) + extern bool rodata_enabled; + extern bool rodata_full; + +- if (arg && !strcmp(arg, "full")) { ++ if (!arg) ++ return false; ++ ++ if (!strcmp(arg, "full")) { ++ rodata_enabled = rodata_full = true; ++ return true; ++ } ++ ++ if (!strcmp(arg, "off")) { ++ rodata_enabled = rodata_full = false; ++ return true; ++ } ++ ++ if (!strcmp(arg, "on")) { + rodata_enabled = true; +- rodata_full = true; ++ rodata_full = false; + return true; + } + +diff --git a/arch/arm64/include/asm/syscall_wrapper.h b/arch/arm64/include/asm/syscall_wrapper.h +index 17f687510c4851..7a0e7b59be9b9f 100644 +--- a/arch/arm64/include/asm/syscall_wrapper.h ++++ b/arch/arm64/include/asm/syscall_wrapper.h +@@ -44,9 +44,6 @@ + return sys_ni_syscall(); \ + } + +-#define COMPAT_SYS_NI(name) \ +- SYSCALL_ALIAS(__arm64_compat_sys_##name, sys_ni_posix_timers); +- + #endif /* CONFIG_COMPAT */ + + #define __SYSCALL_DEFINEx(x, name, ...) \ +@@ -82,6 +79,5 @@ + } + + asmlinkage long __arm64_sys_ni_syscall(const struct pt_regs *__unused); +-#define SYS_NI(name) SYSCALL_ALIAS(__arm64_sys_##name, sys_ni_posix_timers); + + #endif /* __ASM_SYSCALL_WRAPPER_H */ +diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h +index b149cf9f91bc96..b73baaf8ae47be 100644 +--- a/arch/arm64/include/asm/tlbflush.h ++++ b/arch/arm64/include/asm/tlbflush.h +@@ -152,12 +152,18 @@ static inline unsigned long get_trans_granule(void) + #define MAX_TLBI_RANGE_PAGES __TLBI_RANGE_PAGES(31, 3) + + /* +- * Generate 'num' values from -1 to 30 with -1 rejected by the +- * __flush_tlb_range() loop below. ++ * Generate 'num' values from -1 to 31 with -1 rejected by the ++ * __flush_tlb_range() loop below. Its return value is only ++ * significant for a maximum of MAX_TLBI_RANGE_PAGES pages. If ++ * 'pages' is more than that, you must iterate over the overall ++ * range. + */ +-#define TLBI_RANGE_MASK GENMASK_ULL(4, 0) +-#define __TLBI_RANGE_NUM(pages, scale) \ +- ((((pages) >> (5 * (scale) + 1)) & TLBI_RANGE_MASK) - 1) ++#define __TLBI_RANGE_NUM(pages, scale) \ ++ ({ \ ++ int __pages = min((pages), \ ++ __TLBI_RANGE_PAGES(31, (scale))); \ ++ (__pages >> (5 * (scale) + 1)) - 1; \ ++ }) + + /* + * TLB Invalidation +@@ -351,29 +357,25 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch) + * entries one by one at the granularity of 'stride'. If the TLB + * range ops are supported, then: + * +- * 1. If 'pages' is odd, flush the first page through non-range +- * operations; +- * +- * 2. For remaining pages: the minimum range granularity is decided +- * by 'scale', so multiple range TLBI operations may be required. +- * Start from scale = 0, flush the corresponding number of pages +- * ((num+1)*2^(5*scale+1) starting from 'addr'), then increase it +- * until no pages left. ++ * 1. The minimum range granularity is decided by 'scale', so multiple range ++ * TLBI operations may be required. Start from scale = 3, flush the largest ++ * possible number of pages ((num+1)*2^(5*scale+1)) that fit into the ++ * requested range, then decrement scale and continue until one or zero pages ++ * are left. + * +- * Note that certain ranges can be represented by either num = 31 and +- * scale or num = 0 and scale + 1. The loop below favours the latter +- * since num is limited to 30 by the __TLBI_RANGE_NUM() macro. ++ * 2. If there is 1 page remaining, flush it through non-range operations. Range ++ * operations can only span an even number of pages. + */ + #define __flush_tlb_range_op(op, start, pages, stride, \ + asid, tlb_level, tlbi_user) \ + do { \ + int num = 0; \ +- int scale = 0; \ ++ int scale = 3; \ + unsigned long addr; \ + \ + while (pages > 0) { \ + if (!system_supports_tlb_range() || \ +- pages % 2 == 1) { \ ++ pages == 1) { \ + addr = __TLBI_VADDR(start, asid); \ + __tlbi_level(op, addr, tlb_level); \ + if (tlbi_user) \ +@@ -393,7 +395,7 @@ do { \ + start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; \ + pages -= __TLBI_RANGE_PAGES(num, scale); \ + } \ +- scale++; \ ++ scale--; \ + } \ + } while (0) + +diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h +index 78b68311ec8192..545a4a7b5371ce 100644 +--- a/arch/arm64/include/asm/unistd32.h ++++ b/arch/arm64/include/asm/unistd32.h +@@ -840,7 +840,7 @@ __SYSCALL(__NR_pselect6_time64, compat_sys_pselect6_time64) + #define __NR_ppoll_time64 414 + __SYSCALL(__NR_ppoll_time64, compat_sys_ppoll_time64) + #define __NR_io_pgetevents_time64 416 +-__SYSCALL(__NR_io_pgetevents_time64, sys_io_pgetevents) ++__SYSCALL(__NR_io_pgetevents_time64, compat_sys_io_pgetevents_time64) + #define __NR_recvmmsg_time64 417 + __SYSCALL(__NR_recvmmsg_time64, compat_sys_recvmmsg_time64) + #define __NR_mq_timedsend_time64 418 +diff --git a/arch/arm64/include/asm/uprobes.h b/arch/arm64/include/asm/uprobes.h +index 2b09495499c618..014b02897f8e22 100644 +--- a/arch/arm64/include/asm/uprobes.h ++++ b/arch/arm64/include/asm/uprobes.h +@@ -10,11 +10,9 @@ + #include + #include + +-#define MAX_UINSN_BYTES AARCH64_INSN_SIZE +- + #define UPROBE_SWBP_INSN cpu_to_le32(BRK64_OPCODE_UPROBES) + #define UPROBE_SWBP_INSN_SIZE AARCH64_INSN_SIZE +-#define UPROBE_XOL_SLOT_BYTES MAX_UINSN_BYTES ++#define UPROBE_XOL_SLOT_BYTES AARCH64_INSN_SIZE + + typedef __le32 uprobe_opcode_t; + +@@ -23,8 +21,8 @@ struct arch_uprobe_task { + + struct arch_uprobe { + union { +- u8 insn[MAX_UINSN_BYTES]; +- u8 ixol[MAX_UINSN_BYTES]; ++ __le32 insn; ++ __le32 ixol; + }; + struct arch_probe_insn api; + bool simulate; +diff --git a/arch/arm64/include/uapi/asm/sigcontext.h b/arch/arm64/include/uapi/asm/sigcontext.h +index f23c1dc3f002fe..8f003db7a6967a 100644 +--- a/arch/arm64/include/uapi/asm/sigcontext.h ++++ b/arch/arm64/include/uapi/asm/sigcontext.h +@@ -312,10 +312,10 @@ struct zt_context { + ((sizeof(struct za_context) + (__SVE_VQ_BYTES - 1)) \ + / __SVE_VQ_BYTES * __SVE_VQ_BYTES) + +-#define ZA_SIG_REGS_SIZE(vq) ((vq * __SVE_VQ_BYTES) * (vq * __SVE_VQ_BYTES)) ++#define ZA_SIG_REGS_SIZE(vq) (((vq) * __SVE_VQ_BYTES) * ((vq) * __SVE_VQ_BYTES)) + + #define ZA_SIG_ZAV_OFFSET(vq, n) (ZA_SIG_REGS_OFFSET + \ +- (SVE_SIG_ZREG_SIZE(vq) * n)) ++ (SVE_SIG_ZREG_SIZE(vq) * (n))) + + #define ZA_SIG_CONTEXT_SIZE(vq) \ + (ZA_SIG_REGS_OFFSET + ZA_SIG_REGS_SIZE(vq)) +@@ -326,7 +326,7 @@ struct zt_context { + + #define ZT_SIG_REGS_OFFSET sizeof(struct zt_context) + +-#define ZT_SIG_REGS_SIZE(n) (ZT_SIG_REG_BYTES * n) ++#define ZT_SIG_REGS_SIZE(n) (ZT_SIG_REG_BYTES * (n)) + + #define ZT_SIG_CONTEXT_SIZE(n) \ + (sizeof(struct zt_context) + ZT_SIG_REGS_SIZE(n)) +diff --git a/arch/arm64/kernel/acpi_numa.c b/arch/arm64/kernel/acpi_numa.c +index e51535a5f939a9..2465f291c7e17c 100644 +--- a/arch/arm64/kernel/acpi_numa.c ++++ b/arch/arm64/kernel/acpi_numa.c +@@ -27,24 +27,13 @@ + + #include + +-static int acpi_early_node_map[NR_CPUS] __initdata = { NUMA_NO_NODE }; ++static int acpi_early_node_map[NR_CPUS] __initdata = { [0 ... NR_CPUS - 1] = NUMA_NO_NODE }; + + int __init acpi_numa_get_nid(unsigned int cpu) + { + return acpi_early_node_map[cpu]; + } + +-static inline int get_cpu_for_acpi_id(u32 uid) +-{ +- int cpu; +- +- for (cpu = 0; cpu < nr_cpu_ids; cpu++) +- if (uid == get_acpi_id_for_cpu(cpu)) +- return cpu; +- +- return -EINVAL; +-} +- + static int __init acpi_parse_gicc_pxm(union acpi_subtable_headers *header, + const unsigned long end) + { +diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c +index e459cfd3371171..d6b711e56df972 100644 +--- a/arch/arm64/kernel/armv8_deprecated.c ++++ b/arch/arm64/kernel/armv8_deprecated.c +@@ -464,6 +464,9 @@ static int run_all_insn_set_hw_mode(unsigned int cpu) + for (int i = 0; i < ARRAY_SIZE(insn_emulations); i++) { + struct insn_emulation *insn = insn_emulations[i]; + bool enable = READ_ONCE(insn->current_mode) == INSN_HW; ++ if (insn->status == INSN_UNAVAILABLE) ++ continue; ++ + if (insn->set_hw_mode && insn->set_hw_mode(enable)) { + pr_warn("CPU[%u] cannot support the emulation of %s", + cpu, insn->name); +diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c +index 5706e74c55786a..463b48d0f92500 100644 +--- a/arch/arm64/kernel/cpu_errata.c ++++ b/arch/arm64/kernel/cpu_errata.c +@@ -390,6 +390,7 @@ static const struct midr_range erratum_1463225[] = { + static const struct midr_range trbe_overwrite_fill_mode_cpus[] = { + #ifdef CONFIG_ARM64_ERRATUM_2139208 + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), ++ MIDR_ALL_VERSIONS(MIDR_MICROSOFT_AZURE_COBALT_100), + #endif + #ifdef CONFIG_ARM64_ERRATUM_2119858 + MIDR_ALL_VERSIONS(MIDR_CORTEX_A710), +@@ -403,6 +404,7 @@ static const struct midr_range trbe_overwrite_fill_mode_cpus[] = { + static const struct midr_range tsb_flush_fail_cpus[] = { + #ifdef CONFIG_ARM64_ERRATUM_2067961 + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), ++ MIDR_ALL_VERSIONS(MIDR_MICROSOFT_AZURE_COBALT_100), + #endif + #ifdef CONFIG_ARM64_ERRATUM_2054223 + MIDR_ALL_VERSIONS(MIDR_CORTEX_A710), +@@ -415,6 +417,7 @@ static const struct midr_range tsb_flush_fail_cpus[] = { + static struct midr_range trbe_write_out_of_range_cpus[] = { + #ifdef CONFIG_ARM64_ERRATUM_2253138 + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), ++ MIDR_ALL_VERSIONS(MIDR_MICROSOFT_AZURE_COBALT_100), + #endif + #ifdef CONFIG_ARM64_ERRATUM_2224489 + MIDR_ALL_VERSIONS(MIDR_CORTEX_A710), +@@ -432,6 +435,54 @@ static struct midr_range broken_aarch32_aes[] = { + }; + #endif /* CONFIG_ARM64_WORKAROUND_TRBE_WRITE_OUT_OF_RANGE */ + ++#ifdef CONFIG_ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD ++static const struct midr_range erratum_spec_unpriv_load_list[] = { ++#ifdef CONFIG_ARM64_ERRATUM_3117295 ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A510), ++#endif ++#ifdef CONFIG_ARM64_ERRATUM_2966298 ++ /* Cortex-A520 r0p0 to r0p1 */ ++ MIDR_REV_RANGE(MIDR_CORTEX_A520, 0, 0, 1), ++#endif ++ {}, ++}; ++#endif ++ ++#ifdef CONFIG_ARM64_ERRATUM_3194386 ++static const struct midr_range erratum_spec_ssbs_list[] = { ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A76), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A77), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A78), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A78C), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A710), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A715), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A720), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_A725), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_X1), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_X1C), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_X2), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_X3), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_X4), ++ MIDR_ALL_VERSIONS(MIDR_CORTEX_X925), ++ MIDR_ALL_VERSIONS(MIDR_MICROSOFT_AZURE_COBALT_100), ++ MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1), ++ MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), ++ MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N3), ++ MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1), ++ MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V2), ++ MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V3), ++ {} ++}; ++#endif ++ ++#ifdef CONFIG_AMPERE_ERRATUM_AC03_CPU_38 ++static const struct midr_range erratum_ac03_cpu_38_list[] = { ++ MIDR_ALL_VERSIONS(MIDR_AMPERE1), ++ MIDR_ALL_VERSIONS(MIDR_AMPERE1A), ++ {}, ++}; ++#endif ++ + const struct arm64_cpu_capabilities arm64_errata[] = { + #ifdef CONFIG_ARM64_WORKAROUND_CLEAN_CACHE + { +@@ -730,19 +781,26 @@ const struct arm64_cpu_capabilities arm64_errata[] = { + .cpu_enable = cpu_clear_bf16_from_user_emulation, + }, + #endif +-#ifdef CONFIG_ARM64_ERRATUM_2966298 ++#ifdef CONFIG_ARM64_ERRATUM_3194386 ++ { ++ .desc = "SSBS not fully self-synchronizing", ++ .capability = ARM64_WORKAROUND_SPECULATIVE_SSBS, ++ ERRATA_MIDR_RANGE_LIST(erratum_spec_ssbs_list), ++ }, ++#endif ++#ifdef CONFIG_ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD + { +- .desc = "ARM erratum 2966298", +- .capability = ARM64_WORKAROUND_2966298, ++ .desc = "ARM errata 2966298, 3117295", ++ .capability = ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD, + /* Cortex-A520 r0p0 - r0p1 */ +- ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A520, 0, 0, 1), ++ ERRATA_MIDR_RANGE_LIST(erratum_spec_unpriv_load_list), + }, + #endif + #ifdef CONFIG_AMPERE_ERRATUM_AC03_CPU_38 + { + .desc = "AmpereOne erratum AC03_CPU_38", + .capability = ARM64_WORKAROUND_AMPERE_AC03_CPU_38, +- ERRATA_MIDR_ALL_VERSIONS(MIDR_AMPERE1), ++ ERRATA_MIDR_RANGE_LIST(erratum_ac03_cpu_38_list), + }, + #endif + { +diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c +index 444a73c2e63858..7e96604559004b 100644 +--- a/arch/arm64/kernel/cpufeature.c ++++ b/arch/arm64/kernel/cpufeature.c +@@ -2190,6 +2190,17 @@ static void cpu_enable_mte(struct arm64_cpu_capabilities const *cap) + } + #endif /* CONFIG_ARM64_MTE */ + ++static void user_feature_fixup(void) ++{ ++ if (cpus_have_cap(ARM64_WORKAROUND_SPECULATIVE_SSBS)) { ++ struct arm64_ftr_reg *regp; ++ ++ regp = get_arm64_ftr_reg(SYS_ID_AA64PFR1_EL1); ++ if (regp) ++ regp->user_mask &= ~ID_AA64PFR1_EL1_SSBS_MASK; ++ } ++} ++ + static void elf_hwcap_fixup(void) + { + #ifdef CONFIG_ARM64_ERRATUM_1742098 +@@ -3345,6 +3356,7 @@ void __init setup_cpu_features(void) + u32 cwg; + + setup_system_capabilities(); ++ user_feature_fixup(); + setup_elf_hwcaps(arm64_elf_hwcaps); + + if (system_supports_32bit_el0()) { +diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S +index a6030913cd58c4..7fcbee0f6c0e4e 100644 +--- a/arch/arm64/kernel/entry.S ++++ b/arch/arm64/kernel/entry.S +@@ -428,16 +428,9 @@ alternative_else_nop_endif + ldp x28, x29, [sp, #16 * 14] + + .if \el == 0 +-alternative_if ARM64_WORKAROUND_2966298 +- tlbi vale1, xzr +- dsb nsh +-alternative_else_nop_endif +-alternative_if_not ARM64_UNMAP_KERNEL_AT_EL0 +- ldr lr, [sp, #S_LR] +- add sp, sp, #PT_REGS_SIZE // restore sp +- eret +-alternative_else_nop_endif + #ifdef CONFIG_UNMAP_KERNEL_AT_EL0 ++ alternative_insn "b .L_skip_tramp_exit_\@", nop, ARM64_UNMAP_KERNEL_AT_EL0 ++ + msr far_el1, x29 + + ldr_this_cpu x30, this_cpu_vector, x29 +@@ -446,7 +439,18 @@ alternative_else_nop_endif + ldr lr, [sp, #S_LR] // restore x30 + add sp, sp, #PT_REGS_SIZE // restore sp + br x29 ++ ++.L_skip_tramp_exit_\@: + #endif ++ ldr lr, [sp, #S_LR] ++ add sp, sp, #PT_REGS_SIZE // restore sp ++ ++ /* This must be after the last explicit memory access */ ++alternative_if ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD ++ tlbi vale1, xzr ++ dsb nsh ++alternative_else_nop_endif ++ eret + .else + ldr lr, [sp, #S_LR] + add sp, sp, #PT_REGS_SIZE // restore sp +diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c +index 91e44ac7150f90..5cdfcc9e3e54b9 100644 +--- a/arch/arm64/kernel/fpsimd.c ++++ b/arch/arm64/kernel/fpsimd.c +@@ -1280,8 +1280,10 @@ void fpsimd_release_task(struct task_struct *dead_task) + */ + void sme_alloc(struct task_struct *task, bool flush) + { +- if (task->thread.sme_state && flush) { +- memset(task->thread.sme_state, 0, sme_state_size(task)); ++ if (task->thread.sme_state) { ++ if (flush) ++ memset(task->thread.sme_state, 0, ++ sme_state_size(task)); + return; + } + +@@ -1404,6 +1406,22 @@ void __init sme_setup(void) + get_sme_default_vl()); + } + ++void sme_suspend_exit(void) ++{ ++ u64 smcr = 0; ++ ++ if (!system_supports_sme()) ++ return; ++ ++ if (system_supports_fa64()) ++ smcr |= SMCR_ELx_FA64; ++ if (system_supports_sme2()) ++ smcr |= SMCR_ELx_EZT0; ++ ++ write_sysreg_s(smcr, SYS_SMCR_EL1); ++ write_sysreg_s(0, SYS_SMPRI_EL1); ++} ++ + #endif /* CONFIG_ARM64_SME */ + + static void sve_init_regs(void) +@@ -1684,7 +1702,7 @@ void fpsimd_preserve_current_state(void) + void fpsimd_signal_preserve_current_state(void) + { + fpsimd_preserve_current_state(); +- if (test_thread_flag(TIF_SVE)) ++ if (current->thread.fp_type == FP_STATE_SVE) + sve_to_fpsimd(current); + } + +diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S +index 7b236994f0e150..6517bf2644a08b 100644 +--- a/arch/arm64/kernel/head.S ++++ b/arch/arm64/kernel/head.S +@@ -569,6 +569,11 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL) + adr_l x1, __hyp_text_end + adr_l x2, dcache_clean_poc + blr x2 ++ ++ mov_q x0, INIT_SCTLR_EL2_MMU_OFF ++ pre_disable_mmu_workaround ++ msr sctlr_el2, x0 ++ isb + 0: + mov_q x0, HCR_HOST_NVHE_FLAGS + msr hcr_el2, x0 +diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c +index 6ad5c6ef532962..85087e2df56498 100644 +--- a/arch/arm64/kernel/irq.c ++++ b/arch/arm64/kernel/irq.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -47,17 +48,17 @@ static void init_irq_scs(void) + + for_each_possible_cpu(cpu) + per_cpu(irq_shadow_call_stack_ptr, cpu) = +- scs_alloc(cpu_to_node(cpu)); ++ scs_alloc(early_cpu_to_node(cpu)); + } + + #ifdef CONFIG_VMAP_STACK +-static void init_irq_stacks(void) ++static void __init init_irq_stacks(void) + { + int cpu; + unsigned long *p; + + for_each_possible_cpu(cpu) { +- p = arch_alloc_vmap_stack(IRQ_STACK_SIZE, cpu_to_node(cpu)); ++ p = arch_alloc_vmap_stack(IRQ_STACK_SIZE, early_cpu_to_node(cpu)); + per_cpu(irq_stack_ptr, cpu) = p; + } + } +diff --git a/arch/arm64/kernel/jump_label.c b/arch/arm64/kernel/jump_label.c +index faf88ec9c48e8a..f63ea915d6ad25 100644 +--- a/arch/arm64/kernel/jump_label.c ++++ b/arch/arm64/kernel/jump_label.c +@@ -7,11 +7,12 @@ + */ + #include + #include ++#include + #include + #include + +-void arch_jump_label_transform(struct jump_entry *entry, +- enum jump_label_type type) ++bool arch_jump_label_transform_queue(struct jump_entry *entry, ++ enum jump_label_type type) + { + void *addr = (void *)jump_entry_code(entry); + u32 insn; +@@ -25,4 +26,10 @@ void arch_jump_label_transform(struct jump_entry *entry, + } + + aarch64_insn_patch_text_nosync(addr, insn); ++ return true; ++} ++ ++void arch_jump_label_transform_apply(void) ++{ ++ kick_all_cpus_sync(); + } +diff --git a/arch/arm64/kernel/module-plts.c b/arch/arm64/kernel/module-plts.c +index bd69a4e7cd6055..79200f21e12393 100644 +--- a/arch/arm64/kernel/module-plts.c ++++ b/arch/arm64/kernel/module-plts.c +@@ -167,9 +167,6 @@ static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num, + switch (ELF64_R_TYPE(rela[i].r_info)) { + case R_AARCH64_JUMP26: + case R_AARCH64_CALL26: +- if (!IS_ENABLED(CONFIG_RANDOMIZE_BASE)) +- break; +- + /* + * We only have to consider branch targets that resolve + * to symbols that are defined in a different section. +@@ -269,9 +266,6 @@ static int partition_branch_plt_relas(Elf64_Sym *syms, Elf64_Rela *rela, + { + int i = 0, j = numrels - 1; + +- if (!IS_ENABLED(CONFIG_RANDOMIZE_BASE)) +- return 0; +- + while (i < j) { + if (branch_rela_needs_plt(syms, &rela[i], dstidx)) + i++; +diff --git a/arch/arm64/kernel/probes/decode-insn.c b/arch/arm64/kernel/probes/decode-insn.c +index 968d5fffe23302..3496d6169e59b2 100644 +--- a/arch/arm64/kernel/probes/decode-insn.c ++++ b/arch/arm64/kernel/probes/decode-insn.c +@@ -99,10 +99,6 @@ arm_probe_decode_insn(probe_opcode_t insn, struct arch_probe_insn *api) + aarch64_insn_is_blr(insn) || + aarch64_insn_is_ret(insn)) { + api->handler = simulate_br_blr_ret; +- } else if (aarch64_insn_is_ldr_lit(insn)) { +- api->handler = simulate_ldr_literal; +- } else if (aarch64_insn_is_ldrsw_lit(insn)) { +- api->handler = simulate_ldrsw_literal; + } else { + /* + * Instruction cannot be stepped out-of-line and we don't +@@ -140,6 +136,17 @@ arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi) + probe_opcode_t insn = le32_to_cpu(*addr); + probe_opcode_t *scan_end = NULL; + unsigned long size = 0, offset = 0; ++ struct arch_probe_insn *api = &asi->api; ++ ++ if (aarch64_insn_is_ldr_lit(insn)) { ++ api->handler = simulate_ldr_literal; ++ decoded = INSN_GOOD_NO_SLOT; ++ } else if (aarch64_insn_is_ldrsw_lit(insn)) { ++ api->handler = simulate_ldrsw_literal; ++ decoded = INSN_GOOD_NO_SLOT; ++ } else { ++ decoded = arm_probe_decode_insn(insn, &asi->api); ++ } + + /* + * If there's a symbol defined in front of and near enough to +@@ -157,7 +164,6 @@ arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi) + else + scan_end = addr - MAX_ATOMIC_CONTEXT_SIZE; + } +- decoded = arm_probe_decode_insn(insn, &asi->api); + + if (decoded != INSN_REJECTED && scan_end) + if (is_probed_address_atomic(addr - 1, scan_end)) +diff --git a/arch/arm64/kernel/probes/simulate-insn.c b/arch/arm64/kernel/probes/simulate-insn.c +index 22d0b32524763e..b65334ab79d2b0 100644 +--- a/arch/arm64/kernel/probes/simulate-insn.c ++++ b/arch/arm64/kernel/probes/simulate-insn.c +@@ -171,17 +171,15 @@ simulate_tbz_tbnz(u32 opcode, long addr, struct pt_regs *regs) + void __kprobes + simulate_ldr_literal(u32 opcode, long addr, struct pt_regs *regs) + { +- u64 *load_addr; ++ unsigned long load_addr; + int xn = opcode & 0x1f; +- int disp; + +- disp = ldr_displacement(opcode); +- load_addr = (u64 *) (addr + disp); ++ load_addr = addr + ldr_displacement(opcode); + + if (opcode & (1 << 30)) /* x0-x30 */ +- set_x_reg(regs, xn, *load_addr); ++ set_x_reg(regs, xn, READ_ONCE(*(u64 *)load_addr)); + else /* w0-w30 */ +- set_w_reg(regs, xn, *load_addr); ++ set_w_reg(regs, xn, READ_ONCE(*(u32 *)load_addr)); + + instruction_pointer_set(regs, instruction_pointer(regs) + 4); + } +@@ -189,14 +187,12 @@ simulate_ldr_literal(u32 opcode, long addr, struct pt_regs *regs) + void __kprobes + simulate_ldrsw_literal(u32 opcode, long addr, struct pt_regs *regs) + { +- s32 *load_addr; ++ unsigned long load_addr; + int xn = opcode & 0x1f; +- int disp; + +- disp = ldr_displacement(opcode); +- load_addr = (s32 *) (addr + disp); ++ load_addr = addr + ldr_displacement(opcode); + +- set_x_reg(regs, xn, *load_addr); ++ set_x_reg(regs, xn, READ_ONCE(*(s32 *)load_addr)); + + instruction_pointer_set(regs, instruction_pointer(regs) + 4); + } +diff --git a/arch/arm64/kernel/probes/uprobes.c b/arch/arm64/kernel/probes/uprobes.c +index d49aef2657cdf7..a2f137a595fc1c 100644 +--- a/arch/arm64/kernel/probes/uprobes.c ++++ b/arch/arm64/kernel/probes/uprobes.c +@@ -42,7 +42,7 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, + else if (!IS_ALIGNED(addr, AARCH64_INSN_SIZE)) + return -EINVAL; + +- insn = *(probe_opcode_t *)(&auprobe->insn[0]); ++ insn = le32_to_cpu(auprobe->insn); + + switch (arm_probe_decode_insn(insn, &auprobe->api)) { + case INSN_REJECTED: +@@ -108,7 +108,7 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) + if (!auprobe->simulate) + return false; + +- insn = *(probe_opcode_t *)(&auprobe->insn[0]); ++ insn = le32_to_cpu(auprobe->insn); + addr = instruction_pointer(regs); + + if (auprobe->api.handler) +diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c +index 05f40c4e18fda2..57503dc4b22faf 100644 +--- a/arch/arm64/kernel/proton-pack.c ++++ b/arch/arm64/kernel/proton-pack.c +@@ -558,6 +558,18 @@ static enum mitigation_state spectre_v4_enable_hw_mitigation(void) + + /* SCTLR_EL1.DSSBS was initialised to 0 during boot */ + set_pstate_ssbs(0); ++ ++ /* ++ * SSBS is self-synchronizing and is intended to affect subsequent ++ * speculative instructions, but some CPUs can speculate with a stale ++ * value of SSBS. ++ * ++ * Mitigate this with an unconditional speculation barrier, as CPUs ++ * could mis-speculate branches and bypass a conditional barrier. ++ */ ++ if (IS_ENABLED(CONFIG_ARM64_ERRATUM_3194386)) ++ spec_bar(); ++ + return SPECTRE_MITIGATED; + } + +diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c +index 20d7ef82de90aa..d95416b93a9dd5 100644 +--- a/arch/arm64/kernel/ptrace.c ++++ b/arch/arm64/kernel/ptrace.c +@@ -728,7 +728,6 @@ static void sve_init_header_from_task(struct user_sve_header *header, + { + unsigned int vq; + bool active; +- bool fpsimd_only; + enum vec_type task_type; + + memset(header, 0, sizeof(*header)); +@@ -744,12 +743,10 @@ static void sve_init_header_from_task(struct user_sve_header *header, + case ARM64_VEC_SVE: + if (test_tsk_thread_flag(target, TIF_SVE_VL_INHERIT)) + header->flags |= SVE_PT_VL_INHERIT; +- fpsimd_only = !test_tsk_thread_flag(target, TIF_SVE); + break; + case ARM64_VEC_SME: + if (test_tsk_thread_flag(target, TIF_SME_VL_INHERIT)) + header->flags |= SVE_PT_VL_INHERIT; +- fpsimd_only = false; + break; + default: + WARN_ON_ONCE(1); +@@ -757,7 +754,7 @@ static void sve_init_header_from_task(struct user_sve_header *header, + } + + if (active) { +- if (fpsimd_only) { ++ if (target->thread.fp_type == FP_STATE_FPSIMD) { + header->flags |= SVE_PT_REGS_FPSIMD; + } else { + header->flags |= SVE_PT_REGS_SVE; +@@ -1107,12 +1104,13 @@ static int za_set(struct task_struct *target, + } + } + +- /* Allocate/reinit ZA storage */ +- sme_alloc(target, true); +- if (!target->thread.sme_state) { +- ret = -ENOMEM; +- goto out; +- } ++ /* ++ * Only flush the storage if PSTATE.ZA was not already set, ++ * otherwise preserve any existing data. ++ */ ++ sme_alloc(target, !thread_za_enabled(&target->thread)); ++ if (!target->thread.sme_state) ++ return -ENOMEM; + + /* If there is no data then disable ZA */ + if (!count) { +@@ -1498,7 +1496,8 @@ static const struct user_regset aarch64_regsets[] = { + #ifdef CONFIG_ARM64_SVE + [REGSET_SVE] = { /* Scalable Vector Extension */ + .core_note_type = NT_ARM_SVE, +- .n = DIV_ROUND_UP(SVE_PT_SIZE(SVE_VQ_MAX, SVE_PT_REGS_SVE), ++ .n = DIV_ROUND_UP(SVE_PT_SIZE(ARCH_SVE_VQ_MAX, ++ SVE_PT_REGS_SVE), + SVE_VQ_BYTES), + .size = SVE_VQ_BYTES, + .align = SVE_VQ_BYTES, +diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c +index 417a8a86b2db59..c583d1f335f8c7 100644 +--- a/arch/arm64/kernel/setup.c ++++ b/arch/arm64/kernel/setup.c +@@ -371,9 +371,6 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p) + smp_init_cpus(); + smp_build_mpidr_hash(); + +- /* Init percpu seeds for random tags after cpus are set up. */ +- kasan_init_sw_tags(); +- + #ifdef CONFIG_ARM64_SW_TTBR0_PAN + /* + * Make sure init_thread_info.ttbr0 always generates translation +diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c +index 0e8beb3349ea2a..425b1bc17a3f6d 100644 +--- a/arch/arm64/kernel/signal.c ++++ b/arch/arm64/kernel/signal.c +@@ -242,7 +242,7 @@ static int preserve_sve_context(struct sve_context __user *ctx) + vl = task_get_sme_vl(current); + vq = sve_vq_from_vl(vl); + flags |= SVE_SIG_FLAG_SM; +- } else if (test_thread_flag(TIF_SVE)) { ++ } else if (current->thread.fp_type == FP_STATE_SVE) { + vq = sve_vq_from_vl(vl); + } + +@@ -878,7 +878,7 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user, + if (system_supports_sve() || system_supports_sme()) { + unsigned int vq = 0; + +- if (add_all || test_thread_flag(TIF_SVE) || ++ if (add_all || current->thread.fp_type == FP_STATE_SVE || + thread_sm_enabled(¤t->thread)) { + int vl = max(sve_max_vl(), sme_max_vl()); + +diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c +index 960b98b43506dd..14365ef8424402 100644 +--- a/arch/arm64/kernel/smp.c ++++ b/arch/arm64/kernel/smp.c +@@ -459,6 +459,8 @@ void __init smp_prepare_boot_cpu(void) + init_gic_priority_masking(); + + kasan_init_hw_tags(); ++ /* Init percpu seeds for random tags after cpus are set up. */ ++ kasan_init_sw_tags(); + } + + /* +diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c +index 0fbdf5fe64d8da..045af2bfd656a0 100644 +--- a/arch/arm64/kernel/suspend.c ++++ b/arch/arm64/kernel/suspend.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -80,6 +81,8 @@ void notrace __cpu_suspend_exit(void) + */ + spectre_v4_enable_mitigation(NULL); + ++ sme_suspend_exit(); ++ + /* Restore additional feature-specific configuration */ + ptrauth_suspend_exit(); + } +diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c +index 9a70d9746b661b..f090e39f69bc4a 100644 +--- a/arch/arm64/kernel/syscall.c ++++ b/arch/arm64/kernel/syscall.c +@@ -56,17 +56,15 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno, + syscall_set_return_value(current, regs, 0, ret); + + /* +- * Ultimately, this value will get limited by KSTACK_OFFSET_MAX(), +- * but not enough for arm64 stack utilization comfort. To keep +- * reasonable stack head room, reduce the maximum offset to 9 bits. ++ * This value will get limited by KSTACK_OFFSET_MAX(), which is 10 ++ * bits. The actual entropy will be further reduced by the compiler ++ * when applying stack alignment constraints: the AAPCS mandates a ++ * 16-byte aligned SP at function boundaries, which will remove the ++ * 4 low bits from any entropy chosen here. + * +- * The actual entropy will be further reduced by the compiler when +- * applying stack alignment constraints: the AAPCS mandates a +- * 16-byte (i.e. 4-bit) aligned SP at function boundaries. +- * +- * The resulting 5 bits of entropy is seen in SP[8:4]. ++ * The resulting 6 bits of entropy is seen in SP[9:4]. + */ +- choose_random_kstack_offset(get_random_u16() & 0x1FF); ++ choose_random_kstack_offset(get_random_u16()); + } + + static inline bool has_syscall_work(unsigned long flags) +diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile +index fe7a53c6781f15..8818287f10955c 100644 +--- a/arch/arm64/kernel/vdso/Makefile ++++ b/arch/arm64/kernel/vdso/Makefile +@@ -78,13 +78,3 @@ include/generated/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE + # Actual build commands + quiet_cmd_vdsold_and_vdso_check = LD $@ + cmd_vdsold_and_vdso_check = $(cmd_ld); $(cmd_vdso_check) +- +-# Install commands for the unstripped file +-quiet_cmd_vdso_install = INSTALL $@ +- cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ +- +-vdso.so: $(obj)/vdso.so.dbg +- @mkdir -p $(MODLIB)/vdso +- $(call cmd,vdso_install) +- +-vdso_install: vdso.so +diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile +index 2f73e5bca213f8..1f911a76c5af39 100644 +--- a/arch/arm64/kernel/vdso32/Makefile ++++ b/arch/arm64/kernel/vdso32/Makefile +@@ -172,13 +172,3 @@ gen-vdsosym := $(srctree)/$(src)/../vdso/gen_vdso_offsets.sh + quiet_cmd_vdsosym = VDSOSYM $@ + # The AArch64 nm should be able to read an AArch32 binary + cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ +- +-# Install commands for the unstripped file +-quiet_cmd_vdso_install = INSTALL32 $@ +- cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/vdso32.so +- +-vdso.so: $(obj)/vdso.so.dbg +- @mkdir -p $(MODLIB)/vdso +- $(call cmd,vdso_install) +- +-vdso_install: vdso.so +diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c +index 4866b3f7b4ea38..685cc436146a5a 100644 +--- a/arch/arm64/kvm/arm.c ++++ b/arch/arm64/kvm/arm.c +@@ -407,7 +407,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) + kvm_mmu_free_memory_cache(&vcpu->arch.mmu_page_cache); + kvm_timer_vcpu_terminate(vcpu); + kvm_pmu_vcpu_destroy(vcpu); +- ++ kvm_vgic_vcpu_destroy(vcpu); + kvm_arm_vcpu_destroy(vcpu); + } + +diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c +index 95f6945c443252..efe82cc86bd1f3 100644 +--- a/arch/arm64/kvm/guest.c ++++ b/arch/arm64/kvm/guest.c +@@ -251,6 +251,7 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) + case PSR_AA32_MODE_SVC: + case PSR_AA32_MODE_ABT: + case PSR_AA32_MODE_UND: ++ case PSR_AA32_MODE_SYS: + if (!vcpu_el1_is_32bit(vcpu)) + return -EINVAL; + break; +@@ -276,7 +277,7 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) + if (*vcpu_cpsr(vcpu) & PSR_MODE32_BIT) { + int i, nr_reg; + +- switch (*vcpu_cpsr(vcpu)) { ++ switch (*vcpu_cpsr(vcpu) & PSR_AA32_MODE_MASK) { + /* + * Either we are dealing with user mode, and only the + * first 15 registers (+ PC) must be narrowed to 32bit. +@@ -874,7 +875,7 @@ u32 __attribute_const__ kvm_target_cpu(void) + break; + case ARM_CPU_IMP_APM: + switch (part_number) { +- case APM_CPU_PART_POTENZA: ++ case APM_CPU_PART_XGENE: + return KVM_ARM_TARGET_XGENE_POTENZA; + } + break; +diff --git a/arch/arm64/kvm/hyp/aarch32.c b/arch/arm64/kvm/hyp/aarch32.c +index f98cbe2626a1cb..19efb41aab805d 100644 +--- a/arch/arm64/kvm/hyp/aarch32.c ++++ b/arch/arm64/kvm/hyp/aarch32.c +@@ -50,9 +50,23 @@ bool kvm_condition_valid32(const struct kvm_vcpu *vcpu) + u32 cpsr_cond; + int cond; + +- /* Top two bits non-zero? Unconditional. */ +- if (kvm_vcpu_get_esr(vcpu) >> 30) ++ /* ++ * These are the exception classes that could fire with a ++ * conditional instruction. ++ */ ++ switch (kvm_vcpu_trap_get_class(vcpu)) { ++ case ESR_ELx_EC_CP15_32: ++ case ESR_ELx_EC_CP15_64: ++ case ESR_ELx_EC_CP14_MR: ++ case ESR_ELx_EC_CP14_LS: ++ case ESR_ELx_EC_FP_ASIMD: ++ case ESR_ELx_EC_CP10_ID: ++ case ESR_ELx_EC_CP14_64: ++ case ESR_ELx_EC_SVC32: ++ break; ++ default: + return true; ++ } + + /* Is condition field valid? */ + cond = kvm_vcpu_get_condition(vcpu); +diff --git a/arch/arm64/kvm/hyp/include/nvhe/gfp.h b/arch/arm64/kvm/hyp/include/nvhe/gfp.h +index fe5472a184a37d..97c527ef53c2ad 100644 +--- a/arch/arm64/kvm/hyp/include/nvhe/gfp.h ++++ b/arch/arm64/kvm/hyp/include/nvhe/gfp.h +@@ -16,7 +16,7 @@ struct hyp_pool { + * API at EL2. + */ + hyp_spinlock_t lock; +- struct list_head free_area[MAX_ORDER + 1]; ++ struct list_head free_area[NR_PAGE_ORDERS]; + phys_addr_t range_start; + phys_addr_t range_end; + unsigned short max_order; +diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c +index 6e4dba9eadef52..8d21ab904f1a98 100644 +--- a/arch/arm64/kvm/hyp/nvhe/ffa.c ++++ b/arch/arm64/kvm/hyp/nvhe/ffa.c +@@ -415,9 +415,9 @@ static void do_ffa_mem_frag_tx(struct arm_smccc_res *res, + return; + } + +-static __always_inline void do_ffa_mem_xfer(const u64 func_id, +- struct arm_smccc_res *res, +- struct kvm_cpu_context *ctxt) ++static void __do_ffa_mem_xfer(const u64 func_id, ++ struct arm_smccc_res *res, ++ struct kvm_cpu_context *ctxt) + { + DECLARE_REG(u32, len, ctxt, 1); + DECLARE_REG(u32, fraglen, ctxt, 2); +@@ -428,9 +428,6 @@ static __always_inline void do_ffa_mem_xfer(const u64 func_id, + u32 offset, nr_ranges; + int ret = 0; + +- BUILD_BUG_ON(func_id != FFA_FN64_MEM_SHARE && +- func_id != FFA_FN64_MEM_LEND); +- + if (addr_mbz || npages_mbz || fraglen > len || + fraglen > KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE) { + ret = FFA_RET_INVALID_PARAMETERS; +@@ -449,6 +446,11 @@ static __always_inline void do_ffa_mem_xfer(const u64 func_id, + goto out_unlock; + } + ++ if (len > ffa_desc_buf.len) { ++ ret = FFA_RET_NO_MEMORY; ++ goto out_unlock; ++ } ++ + buf = hyp_buffers.tx; + memcpy(buf, host_buffers.tx, fraglen); + +@@ -498,6 +500,13 @@ static __always_inline void do_ffa_mem_xfer(const u64 func_id, + goto out_unlock; + } + ++#define do_ffa_mem_xfer(fid, res, ctxt) \ ++ do { \ ++ BUILD_BUG_ON((fid) != FFA_FN64_MEM_SHARE && \ ++ (fid) != FFA_FN64_MEM_LEND); \ ++ __do_ffa_mem_xfer((fid), (res), (ctxt)); \ ++ } while (0); ++ + static void do_ffa_mem_reclaim(struct arm_smccc_res *res, + struct kvm_cpu_context *ctxt) + { +diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c +index f155b8c9e98c7f..ca0bf0b92ca09e 100644 +--- a/arch/arm64/kvm/hyp/pgtable.c ++++ b/arch/arm64/kvm/hyp/pgtable.c +@@ -523,7 +523,7 @@ static int hyp_unmap_walker(const struct kvm_pgtable_visit_ctx *ctx, + + kvm_clear_pte(ctx->ptep); + dsb(ishst); +- __tlbi_level(vae2is, __TLBI_VADDR(ctx->addr, 0), ctx->level); ++ __tlbi_level(vae2is, __TLBI_VADDR(ctx->addr, 0), 0); + } else { + if (ctx->end - ctx->addr < granule) + return -EINVAL; +@@ -805,12 +805,15 @@ static bool stage2_try_break_pte(const struct kvm_pgtable_visit_ctx *ctx, + * Perform the appropriate TLB invalidation based on the + * evicted pte value (if any). + */ +- if (kvm_pte_table(ctx->old, ctx->level)) +- kvm_tlb_flush_vmid_range(mmu, ctx->addr, +- kvm_granule_size(ctx->level)); +- else if (kvm_pte_valid(ctx->old)) ++ if (kvm_pte_table(ctx->old, ctx->level)) { ++ u64 size = kvm_granule_size(ctx->level); ++ u64 addr = ALIGN_DOWN(ctx->addr, size); ++ ++ kvm_tlb_flush_vmid_range(mmu, addr, size); ++ } else if (kvm_pte_valid(ctx->old)) { + kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, mmu, + ctx->addr, ctx->level); ++ } + } + + if (stage2_pte_is_counted(ctx->old)) +@@ -858,9 +861,13 @@ static void stage2_unmap_put_pte(const struct kvm_pgtable_visit_ctx *ctx, + if (kvm_pte_valid(ctx->old)) { + kvm_clear_pte(ctx->ptep); + +- if (!stage2_unmap_defer_tlb_flush(pgt)) +- kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, mmu, +- ctx->addr, ctx->level); ++ if (kvm_pte_table(ctx->old, ctx->level)) { ++ kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, mmu, ctx->addr, ++ 0); ++ } else if (!stage2_unmap_defer_tlb_flush(pgt)) { ++ kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, mmu, ctx->addr, ++ ctx->level); ++ } + } + + mm_ops->put_page(ctx->ptep); +diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c +index 6ff3ec18c92584..b2c8084cdb95de 100644 +--- a/arch/arm64/kvm/pkvm.c ++++ b/arch/arm64/kvm/pkvm.c +@@ -101,6 +101,17 @@ void __init kvm_hyp_reserve(void) + hyp_mem_base); + } + ++static void __pkvm_destroy_hyp_vm(struct kvm *host_kvm) ++{ ++ if (host_kvm->arch.pkvm.handle) { ++ WARN_ON(kvm_call_hyp_nvhe(__pkvm_teardown_vm, ++ host_kvm->arch.pkvm.handle)); ++ } ++ ++ host_kvm->arch.pkvm.handle = 0; ++ free_hyp_memcache(&host_kvm->arch.pkvm.teardown_mc); ++} ++ + /* + * Allocates and donates memory for hypervisor VM structs at EL2. + * +@@ -181,7 +192,7 @@ static int __pkvm_create_hyp_vm(struct kvm *host_kvm) + return 0; + + destroy_vm: +- pkvm_destroy_hyp_vm(host_kvm); ++ __pkvm_destroy_hyp_vm(host_kvm); + return ret; + free_vm: + free_pages_exact(hyp_vm, hyp_vm_sz); +@@ -194,23 +205,19 @@ int pkvm_create_hyp_vm(struct kvm *host_kvm) + { + int ret = 0; + +- mutex_lock(&host_kvm->lock); ++ mutex_lock(&host_kvm->arch.config_lock); + if (!host_kvm->arch.pkvm.handle) + ret = __pkvm_create_hyp_vm(host_kvm); +- mutex_unlock(&host_kvm->lock); ++ mutex_unlock(&host_kvm->arch.config_lock); + + return ret; + } + + void pkvm_destroy_hyp_vm(struct kvm *host_kvm) + { +- if (host_kvm->arch.pkvm.handle) { +- WARN_ON(kvm_call_hyp_nvhe(__pkvm_teardown_vm, +- host_kvm->arch.pkvm.handle)); +- } +- +- host_kvm->arch.pkvm.handle = 0; +- free_hyp_memcache(&host_kvm->arch.pkvm.teardown_mc); ++ mutex_lock(&host_kvm->arch.config_lock); ++ __pkvm_destroy_hyp_vm(host_kvm); ++ mutex_unlock(&host_kvm->arch.config_lock); + } + + int pkvm_init_host_vm(struct kvm *host_kvm) +diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c +index 0afd6136e2759c..b233a64df2956a 100644 +--- a/arch/arm64/kvm/sys_regs.c ++++ b/arch/arm64/kvm/sys_regs.c +@@ -32,6 +32,7 @@ + #include + + #include "sys_regs.h" ++#include "vgic/vgic.h" + + #include "trace.h" + +@@ -301,6 +302,11 @@ static bool access_gic_sgi(struct kvm_vcpu *vcpu, + { + bool g1; + ++ if (!kvm_has_gicv3(vcpu->kvm)) { ++ kvm_inject_undefined(vcpu); ++ return false; ++ } ++ + if (!p->is_write) + return read_from_write_only(vcpu, p, r); + +diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c +index c8c3cb81278321..a2b439ad387c80 100644 +--- a/arch/arm64/kvm/vgic/vgic-init.c ++++ b/arch/arm64/kvm/vgic/vgic-init.c +@@ -355,7 +355,7 @@ static void kvm_vgic_dist_destroy(struct kvm *kvm) + + if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) { + list_for_each_entry_safe(rdreg, next, &dist->rd_regions, list) +- vgic_v3_free_redist_region(rdreg); ++ vgic_v3_free_redist_region(kvm, rdreg); + INIT_LIST_HEAD(&dist->rd_regions); + } else { + dist->vgic_cpu_base = VGIC_ADDR_UNDEF; +@@ -368,7 +368,7 @@ static void kvm_vgic_dist_destroy(struct kvm *kvm) + vgic_v4_teardown(kvm); + } + +-void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu) ++static void __kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu) + { + struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; + +@@ -379,29 +379,39 @@ void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu) + vgic_flush_pending_lpis(vcpu); + + INIT_LIST_HEAD(&vgic_cpu->ap_list_head); +- vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF; ++ if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) { ++ vgic_unregister_redist_iodev(vcpu); ++ vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF; ++ } + } + +-static void __kvm_vgic_destroy(struct kvm *kvm) ++void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu) ++{ ++ struct kvm *kvm = vcpu->kvm; ++ ++ mutex_lock(&kvm->slots_lock); ++ __kvm_vgic_vcpu_destroy(vcpu); ++ mutex_unlock(&kvm->slots_lock); ++} ++ ++void kvm_vgic_destroy(struct kvm *kvm) + { + struct kvm_vcpu *vcpu; + unsigned long i; + +- lockdep_assert_held(&kvm->arch.config_lock); ++ mutex_lock(&kvm->slots_lock); + + vgic_debug_destroy(kvm); + + kvm_for_each_vcpu(i, vcpu, kvm) +- kvm_vgic_vcpu_destroy(vcpu); ++ __kvm_vgic_vcpu_destroy(vcpu); ++ ++ mutex_lock(&kvm->arch.config_lock); + + kvm_vgic_dist_destroy(kvm); +-} + +-void kvm_vgic_destroy(struct kvm *kvm) +-{ +- mutex_lock(&kvm->arch.config_lock); +- __kvm_vgic_destroy(kvm); + mutex_unlock(&kvm->arch.config_lock); ++ mutex_unlock(&kvm->slots_lock); + } + + /** +@@ -469,25 +479,26 @@ int kvm_vgic_map_resources(struct kvm *kvm) + type = VGIC_V3; + } + +- if (ret) { +- __kvm_vgic_destroy(kvm); ++ if (ret) + goto out; +- } ++ + dist->ready = true; + dist_base = dist->vgic_dist_base; + mutex_unlock(&kvm->arch.config_lock); + + ret = vgic_register_dist_iodev(kvm, dist_base, type); +- if (ret) { ++ if (ret) + kvm_err("Unable to register VGIC dist MMIO regions\n"); +- kvm_vgic_destroy(kvm); +- } +- mutex_unlock(&kvm->slots_lock); +- return ret; + ++ goto out_slots; + out: + mutex_unlock(&kvm->arch.config_lock); ++out_slots: + mutex_unlock(&kvm->slots_lock); ++ ++ if (ret) ++ kvm_vgic_destroy(kvm); ++ + return ret; + } + +diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c +index 5fe2365a629f25..4f9084ba7949c0 100644 +--- a/arch/arm64/kvm/vgic/vgic-its.c ++++ b/arch/arm64/kvm/vgic/vgic-its.c +@@ -462,6 +462,9 @@ static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu) + } + + irq = vgic_get_irq(vcpu->kvm, NULL, intids[i]); ++ if (!irq) ++ continue; ++ + raw_spin_lock_irqsave(&irq->irq_lock, flags); + irq->pending_latch = pendmask & (1U << bit_nr); + vgic_queue_irq_unlock(vcpu->kvm, irq, flags); +@@ -584,7 +587,11 @@ static struct vgic_irq *vgic_its_check_cache(struct kvm *kvm, phys_addr_t db, + unsigned long flags; + + raw_spin_lock_irqsave(&dist->lpi_list_lock, flags); ++ + irq = __vgic_its_check_cache(dist, db, devid, eventid); ++ if (irq) ++ vgic_get_irq_kref(irq); ++ + raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags); + + return irq; +@@ -763,6 +770,7 @@ int vgic_its_inject_cached_translation(struct kvm *kvm, struct kvm_msi *msi) + raw_spin_lock_irqsave(&irq->irq_lock, flags); + irq->pending_latch = true; + vgic_queue_irq_unlock(kvm, irq, flags); ++ vgic_put_irq(kvm, irq); + + return 0; + } +@@ -1422,6 +1430,8 @@ static int vgic_its_cmd_handle_movall(struct kvm *kvm, struct vgic_its *its, + + for (i = 0; i < irq_count; i++) { + irq = vgic_get_irq(kvm, NULL, intids[i]); ++ if (!irq) ++ continue; + + update_affinity(irq, vcpu2); + +diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c +index 212b73a715c1c2..2f9e8c611f6421 100644 +--- a/arch/arm64/kvm/vgic/vgic-kvm-device.c ++++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c +@@ -337,16 +337,12 @@ int kvm_register_vgic_device(unsigned long type) + int vgic_v2_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr, + struct vgic_reg_attr *reg_attr) + { +- int cpuid; ++ int cpuid = FIELD_GET(KVM_DEV_ARM_VGIC_CPUID_MASK, attr->attr); + +- cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >> +- KVM_DEV_ARM_VGIC_CPUID_SHIFT; +- +- if (cpuid >= atomic_read(&dev->kvm->online_vcpus)) +- return -EINVAL; +- +- reg_attr->vcpu = kvm_get_vcpu(dev->kvm, cpuid); + reg_attr->addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK; ++ reg_attr->vcpu = kvm_get_vcpu_by_id(dev->kvm, cpuid); ++ if (!reg_attr->vcpu) ++ return -EINVAL; + + return 0; + } +diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c +index 188d2187eede93..48e8b60ff1e338 100644 +--- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c ++++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c +@@ -365,19 +365,26 @@ static int vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu, + struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + + raw_spin_lock_irqsave(&irq->irq_lock, flags); +- if (test_bit(i, &val)) { +- /* +- * pending_latch is set irrespective of irq type +- * (level or edge) to avoid dependency that VM should +- * restore irq config before pending info. +- */ +- irq->pending_latch = true; +- vgic_queue_irq_unlock(vcpu->kvm, irq, flags); +- } else { ++ ++ /* ++ * pending_latch is set irrespective of irq type ++ * (level or edge) to avoid dependency that VM should ++ * restore irq config before pending info. ++ */ ++ irq->pending_latch = test_bit(i, &val); ++ ++ if (irq->hw && vgic_irq_is_sgi(irq->intid)) { ++ irq_set_irqchip_state(irq->host_irq, ++ IRQCHIP_STATE_PENDING, ++ irq->pending_latch); + irq->pending_latch = false; +- raw_spin_unlock_irqrestore(&irq->irq_lock, flags); + } + ++ if (irq->pending_latch) ++ vgic_queue_irq_unlock(vcpu->kvm, irq, flags); ++ else ++ raw_spin_unlock_irqrestore(&irq->irq_lock, flags); ++ + vgic_put_irq(vcpu->kvm, irq); + } + +@@ -820,7 +827,7 @@ int vgic_register_redist_iodev(struct kvm_vcpu *vcpu) + return ret; + } + +-static void vgic_unregister_redist_iodev(struct kvm_vcpu *vcpu) ++void vgic_unregister_redist_iodev(struct kvm_vcpu *vcpu) + { + struct vgic_io_device *rd_dev = &vcpu->arch.vgic_cpu.rd_iodev; + +@@ -935,8 +942,19 @@ static int vgic_v3_alloc_redist_region(struct kvm *kvm, uint32_t index, + return ret; + } + +-void vgic_v3_free_redist_region(struct vgic_redist_region *rdreg) ++void vgic_v3_free_redist_region(struct kvm *kvm, struct vgic_redist_region *rdreg) + { ++ struct kvm_vcpu *vcpu; ++ unsigned long c; ++ ++ lockdep_assert_held(&kvm->arch.config_lock); ++ ++ /* Garbage collect the region */ ++ kvm_for_each_vcpu(c, vcpu, kvm) { ++ if (vcpu->arch.vgic_cpu.rdreg == rdreg) ++ vcpu->arch.vgic_cpu.rdreg = NULL; ++ } ++ + list_del(&rdreg->list); + kfree(rdreg); + } +@@ -961,7 +979,7 @@ int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count) + + mutex_lock(&kvm->arch.config_lock); + rdreg = vgic_v3_rdist_region_from_index(kvm, index); +- vgic_v3_free_redist_region(rdreg); ++ vgic_v3_free_redist_region(kvm, rdreg); + mutex_unlock(&kvm->arch.config_lock); + return ret; + } +diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h +index 0ab09b0d44404b..07e48f8a4f23b3 100644 +--- a/arch/arm64/kvm/vgic/vgic.h ++++ b/arch/arm64/kvm/vgic/vgic.h +@@ -241,6 +241,7 @@ int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq); + int vgic_v3_save_pending_tables(struct kvm *kvm); + int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count); + int vgic_register_redist_iodev(struct kvm_vcpu *vcpu); ++void vgic_unregister_redist_iodev(struct kvm_vcpu *vcpu); + bool vgic_v3_check_base(struct kvm *kvm); + + void vgic_v3_load(struct kvm_vcpu *vcpu); +@@ -309,7 +310,7 @@ vgic_v3_rd_region_size(struct kvm *kvm, struct vgic_redist_region *rdreg) + + struct vgic_redist_region *vgic_v3_rdist_region_from_index(struct kvm *kvm, + u32 index); +-void vgic_v3_free_redist_region(struct vgic_redist_region *rdreg); ++void vgic_v3_free_redist_region(struct kvm *kvm, struct vgic_redist_region *rdreg); + + bool vgic_v3_rdist_overlap(struct kvm *kvm, gpa_t base, size_t size); + +@@ -342,4 +343,11 @@ void vgic_v4_configure_vsgis(struct kvm *kvm); + void vgic_v4_get_vlpi_state(struct vgic_irq *irq, bool *val); + int vgic_v4_request_vpe_irq(struct kvm_vcpu *vcpu, int irq); + ++static inline bool kvm_has_gicv3(struct kvm *kvm) ++{ ++ return (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) && ++ irqchip_in_kernel(kvm) && ++ kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3); ++} ++ + #endif +diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c +index 8e2017ba5f1b11..0a62f458c5cb02 100644 +--- a/arch/arm64/mm/pageattr.c ++++ b/arch/arm64/mm/pageattr.c +@@ -29,8 +29,8 @@ bool can_set_direct_map(void) + * + * KFENCE pool requires page-granular mapping if initialized late. + */ +- return (rodata_enabled && rodata_full) || debug_pagealloc_enabled() || +- arm64_kfence_can_set_direct_map(); ++ return rodata_full || debug_pagealloc_enabled() || ++ arm64_kfence_can_set_direct_map(); + } + + static int change_page_range(pte_t *ptep, unsigned long addr, void *data) +@@ -105,8 +105,7 @@ static int change_memory_common(unsigned long addr, int numpages, + * If we are manipulating read-only permissions, apply the same + * change to the linear mapping of the pages that back this VM area. + */ +- if (rodata_enabled && +- rodata_full && (pgprot_val(set_mask) == PTE_RDONLY || ++ if (rodata_full && (pgprot_val(set_mask) == PTE_RDONLY || + pgprot_val(clear_mask) == PTE_RDONLY)) { + for (i = 0; i < area->nr_pages; i++) { + __change_memory_common((u64)page_address(area->pages[i]), +@@ -220,9 +219,6 @@ bool kernel_page_present(struct page *page) + pte_t *ptep; + unsigned long addr = (unsigned long)page_address(page); + +- if (!can_set_direct_map()) +- return true; +- + pgdp = pgd_offset_k(addr); + if (pgd_none(READ_ONCE(*pgdp))) + return false; +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index 150d1c6543f7f1..166619348b98e4 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -876,7 +876,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, + emit(A64_UXTH(is64, dst, dst), ctx); + break; + case 32: +- emit(A64_REV32(is64, dst, dst), ctx); ++ emit(A64_REV32(0, dst, dst), ctx); + /* upper 32 bits already cleared */ + break; + case 64: +@@ -1189,7 +1189,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, + } else { + emit_a64_mov_i(1, tmp, off, ctx); + if (sign_extend) +- emit(A64_LDRSW(dst, src_adj, off_adj), ctx); ++ emit(A64_LDRSW(dst, src, tmp), ctx); + else + emit(A64_LDR32(dst, src, tmp), ctx); + } +@@ -1738,15 +1738,15 @@ static void invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_link *l, + + emit_call(enter_prog, ctx); + ++ /* save return value to callee saved register x20 */ ++ emit(A64_MOV(1, A64_R(20), A64_R(0)), ctx); ++ + /* if (__bpf_prog_enter(prog) == 0) + * goto skip_exec_of_prog; + */ + branch = ctx->image + ctx->idx; + emit(A64_NOP, ctx); + +- /* save return value to callee saved register x20 */ +- emit(A64_MOV(1, A64_R(20), A64_R(0)), ctx); +- + emit(A64_ADD_I(1, A64_R(0), A64_SP, args_off), ctx); + if (!p->jited) + emit_addr_mov_i64(A64_R(1), (const u64)p->insnsi, ctx); +diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps +index dea3dc89234b02..c251ef3caae560 100644 +--- a/arch/arm64/tools/cpucaps ++++ b/arch/arm64/tools/cpucaps +@@ -84,7 +84,6 @@ WORKAROUND_2077057 + WORKAROUND_2457168 + WORKAROUND_2645198 + WORKAROUND_2658417 +-WORKAROUND_2966298 + WORKAROUND_AMPERE_AC03_CPU_38 + WORKAROUND_TRBE_OVERWRITE_FILL_MODE + WORKAROUND_TSB_FLUSH_FAILURE +@@ -100,3 +99,5 @@ WORKAROUND_NVIDIA_CARMEL_CNP + WORKAROUND_QCOM_FALKOR_E1003 + WORKAROUND_REPEAT_TLBI + WORKAROUND_SPECULATIVE_AT ++WORKAROUND_SPECULATIVE_SSBS ++WORKAROUND_SPECULATIVE_UNPRIV_LOAD +diff --git a/arch/csky/abiv1/inc/abi/cacheflush.h b/arch/csky/abiv1/inc/abi/cacheflush.h +index 908d8b0bc4fdc6..d011a81575d21e 100644 +--- a/arch/csky/abiv1/inc/abi/cacheflush.h ++++ b/arch/csky/abiv1/inc/abi/cacheflush.h +@@ -43,6 +43,7 @@ static inline void flush_anon_page(struct vm_area_struct *vma, + */ + extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); + #define flush_cache_vmap(start, end) cache_wbinv_all() ++#define flush_cache_vmap_early(start, end) do { } while (0) + #define flush_cache_vunmap(start, end) cache_wbinv_all() + + #define flush_icache_range(start, end) cache_wbinv_range(start, end) +diff --git a/arch/csky/abiv2/inc/abi/cacheflush.h b/arch/csky/abiv2/inc/abi/cacheflush.h +index 40be16907267d6..6513ac5d257888 100644 +--- a/arch/csky/abiv2/inc/abi/cacheflush.h ++++ b/arch/csky/abiv2/inc/abi/cacheflush.h +@@ -41,6 +41,7 @@ void flush_icache_mm_range(struct mm_struct *mm, + void flush_icache_deferred(struct mm_struct *mm); + + #define flush_cache_vmap(start, end) do { } while (0) ++#define flush_cache_vmap_early(start, end) do { } while (0) + #define flush_cache_vunmap(start, end) do { } while (0) + + #define copy_to_user_page(vma, page, vaddr, dst, src, len) \ +diff --git a/arch/csky/include/asm/irq_work.h b/arch/csky/include/asm/irq_work.h +index 33aaf39d6f94f6..d39fcc1f5395f6 100644 +--- a/arch/csky/include/asm/irq_work.h ++++ b/arch/csky/include/asm/irq_work.h +@@ -7,5 +7,5 @@ static inline bool arch_irq_work_has_interrupt(void) + { + return true; + } +-extern void arch_irq_work_raise(void); ++ + #endif /* __ASM_CSKY_IRQ_WORK_H */ +diff --git a/arch/csky/include/asm/jump_label.h b/arch/csky/include/asm/jump_label.h +index d488ba6084bc6b..ef2e37a10a0feb 100644 +--- a/arch/csky/include/asm/jump_label.h ++++ b/arch/csky/include/asm/jump_label.h +@@ -12,7 +12,7 @@ + static __always_inline bool arch_static_branch(struct static_key *key, + bool branch) + { +- asm_volatile_goto( ++ asm goto( + "1: nop32 \n" + " .pushsection __jump_table, \"aw\" \n" + " .align 2 \n" +@@ -29,7 +29,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, + static __always_inline bool arch_static_branch_jump(struct static_key *key, + bool branch) + { +- asm_volatile_goto( ++ asm goto( + "1: bsr32 %l[label] \n" + " .pushsection __jump_table, \"aw\" \n" + " .align 2 \n" +@@ -43,5 +43,10 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, + return true; + } + ++enum jump_label_type; ++void arch_jump_label_transform_static(struct jump_entry *entry, ++ enum jump_label_type type); ++#define arch_jump_label_transform_static arch_jump_label_transform_static ++ + #endif /* __ASSEMBLY__ */ + #endif /* __ASM_CSKY_JUMP_LABEL_H */ +diff --git a/arch/csky/include/uapi/asm/unistd.h b/arch/csky/include/uapi/asm/unistd.h +index 7ff6a2466af10d..e0594b6370a658 100644 +--- a/arch/csky/include/uapi/asm/unistd.h ++++ b/arch/csky/include/uapi/asm/unistd.h +@@ -6,6 +6,7 @@ + #define __ARCH_WANT_SYS_CLONE3 + #define __ARCH_WANT_SET_GET_RLIMIT + #define __ARCH_WANT_TIME32_SYSCALLS ++#define __ARCH_WANT_SYNC_FILE_RANGE2 + #include + + #define __NR_set_thread_area (__NR_arch_specific_syscall + 0) +diff --git a/arch/csky/kernel/probes/ftrace.c b/arch/csky/kernel/probes/ftrace.c +index 834cffcfbce320..7ba4b98076de1e 100644 +--- a/arch/csky/kernel/probes/ftrace.c ++++ b/arch/csky/kernel/probes/ftrace.c +@@ -12,6 +12,9 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, + struct kprobe_ctlblk *kcb; + struct pt_regs *regs; + ++ if (unlikely(kprobe_ftrace_disabled)) ++ return; ++ + bit = ftrace_test_recursion_trylock(ip, parent_ip); + if (bit < 0) + return; +diff --git a/arch/hexagon/include/asm/syscalls.h b/arch/hexagon/include/asm/syscalls.h +new file mode 100644 +index 00000000000000..40f2d08bec92cc +--- /dev/null ++++ b/arch/hexagon/include/asm/syscalls.h +@@ -0,0 +1,6 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++#include ++ ++asmlinkage long sys_hexagon_fadvise64_64(int fd, int advice, ++ u32 a2, u32 a3, u32 a4, u32 a5); +diff --git a/arch/hexagon/include/uapi/asm/unistd.h b/arch/hexagon/include/uapi/asm/unistd.h +index 432c4db1b62392..21ae22306b5dce 100644 +--- a/arch/hexagon/include/uapi/asm/unistd.h ++++ b/arch/hexagon/include/uapi/asm/unistd.h +@@ -36,5 +36,6 @@ + #define __ARCH_WANT_SYS_VFORK + #define __ARCH_WANT_SYS_FORK + #define __ARCH_WANT_TIME32_SYSCALLS ++#define __ARCH_WANT_SYNC_FILE_RANGE2 + + #include +diff --git a/arch/hexagon/kernel/syscalltab.c b/arch/hexagon/kernel/syscalltab.c +index 0fadd582cfc77f..5d98bdc494ec29 100644 +--- a/arch/hexagon/kernel/syscalltab.c ++++ b/arch/hexagon/kernel/syscalltab.c +@@ -14,6 +14,13 @@ + #undef __SYSCALL + #define __SYSCALL(nr, call) [nr] = (call), + ++SYSCALL_DEFINE6(hexagon_fadvise64_64, int, fd, int, advice, ++ SC_ARG64(offset), SC_ARG64(len)) ++{ ++ return ksys_fadvise64_64(fd, SC_VAL64(loff_t, offset), SC_VAL64(loff_t, len), advice); ++} ++#define sys_fadvise64_64 sys_hexagon_fadvise64_64 ++ + void *sys_call_table[__NR_syscalls] = { + #include + }; +diff --git a/arch/hexagon/kernel/vmlinux.lds.S b/arch/hexagon/kernel/vmlinux.lds.S +index 1140051a0c455d..1150b77fa281ce 100644 +--- a/arch/hexagon/kernel/vmlinux.lds.S ++++ b/arch/hexagon/kernel/vmlinux.lds.S +@@ -63,6 +63,7 @@ SECTIONS + STABS_DEBUG + DWARF_DEBUG + ELF_DETAILS ++ .hexagon.attributes 0 : { *(.hexagon.attributes) } + + DISCARDS + } +diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c +index 5a55ac82c13a47..d2c66efdde560e 100644 +--- a/arch/ia64/kernel/setup.c ++++ b/arch/ia64/kernel/setup.c +@@ -86,9 +86,13 @@ EXPORT_SYMBOL(local_per_cpu_offset); + #endif + unsigned long ia64_cycles_per_usec; + struct ia64_boot_param *ia64_boot_param; ++#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_EFI) + struct screen_info screen_info; ++#endif ++#ifdef CONFIG_VGA_CONSOLE + unsigned long vga_console_iobase; + unsigned long vga_console_membase; ++#endif + + static struct resource data_resource = { + .name = "Kernel data", +@@ -497,6 +501,7 @@ early_console_setup (char *cmdline) + static void __init + screen_info_setup(void) + { ++#ifdef CONFIG_VGA_CONSOLE + unsigned int orig_x, orig_y, num_cols, num_rows, font_height; + + memset(&screen_info, 0, sizeof(screen_info)); +@@ -525,6 +530,7 @@ screen_info_setup(void) + screen_info.orig_video_mode = 3; /* XXX fake */ + screen_info.orig_video_isVGA = 1; /* XXX fake */ + screen_info.orig_video_ega_bx = 3; /* XXX fake */ ++#endif + } + + static inline void +diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig +index e14396a2ddcbfc..9fd8644a9a4c6a 100644 +--- a/arch/loongarch/Kconfig ++++ b/arch/loongarch/Kconfig +@@ -11,6 +11,7 @@ config LOONGARCH + select ARCH_DISABLE_KASAN_INLINE + select ARCH_ENABLE_MEMORY_HOTPLUG + select ARCH_ENABLE_MEMORY_HOTREMOVE ++ select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE + select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI + select ARCH_HAS_CPU_FINALIZE_INIT + select ARCH_HAS_FORTIFY_SOURCE +@@ -97,6 +98,7 @@ config LOONGARCH + select HAVE_ARCH_KFENCE + select HAVE_ARCH_KGDB if PERF_EVENTS + select HAVE_ARCH_MMAP_RND_BITS if MMU ++ select HAVE_ARCH_SECCOMP + select HAVE_ARCH_SECCOMP_FILTER + select HAVE_ARCH_TRACEHOOK + select HAVE_ARCH_TRANSPARENT_HUGEPAGE +@@ -603,23 +605,6 @@ config RANDOMIZE_BASE_MAX_OFFSET + + This is limited by the size of the lower address memory, 256MB. + +-config SECCOMP +- bool "Enable seccomp to safely compute untrusted bytecode" +- depends on PROC_FS +- default y +- help +- This kernel feature is useful for number crunching applications +- that may need to compute untrusted bytecode during their +- execution. By using pipes or other transports made available to +- the process as file descriptors supporting the read/write +- syscalls, it's possible to isolate those applications in +- their own address space using seccomp. Once seccomp is +- enabled via /proc//seccomp, it cannot be disabled +- and the task is only allowed to execute a few safe syscalls +- defined by each seccomp mode. +- +- If unsure, say Y. Only embedded should say N here. +- + endmenu + + config ARCH_SELECT_MEMORY_MODEL +@@ -638,10 +623,6 @@ config ARCH_SPARSEMEM_ENABLE + or have huge holes in the physical address space for other reasons. + See for more. + +-config ARCH_ENABLE_THP_MIGRATION +- def_bool y +- depends on TRANSPARENT_HUGEPAGE +- + config ARCH_MEMORY_PROBE + def_bool y + depends on MEMORY_HOTPLUG +diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile +index fb0fada43197e4..81e8089c9c4f18 100644 +--- a/arch/loongarch/Makefile ++++ b/arch/loongarch/Makefile +@@ -80,7 +80,7 @@ endif + + ifeq ($(CONFIG_RELOCATABLE),y) + KBUILD_CFLAGS_KERNEL += -fPIE +-LDFLAGS_vmlinux += -static -pie --no-dynamic-linker -z notext ++LDFLAGS_vmlinux += -static -pie --no-dynamic-linker -z notext $(call ld-option, --apply-dynamic-relocs) + endif + + cflags-y += $(call cc-option, -mno-check-zero-division) +@@ -136,12 +136,12 @@ vdso_prepare: prepare0 + $(Q)$(MAKE) $(build)=arch/loongarch/vdso include/generated/vdso-offsets.h + endif + +-PHONY += vdso_install +-vdso_install: +- $(Q)$(MAKE) $(build)=arch/loongarch/vdso $@ ++vdso-install-y += arch/loongarch/vdso/vdso.so.dbg + + all: $(notdir $(KBUILD_IMAGE)) + ++vmlinuz.efi: vmlinux.efi ++ + vmlinux.elf vmlinux.efi vmlinuz.efi: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(bootvars-y) $(boot)/$@ + +diff --git a/arch/loongarch/configs/loongson3_defconfig b/arch/loongarch/configs/loongson3_defconfig +index a3b52aaa83b336..e5f70642ed2062 100644 +--- a/arch/loongarch/configs/loongson3_defconfig ++++ b/arch/loongarch/configs/loongson3_defconfig +@@ -83,7 +83,6 @@ CONFIG_ZPOOL=y + CONFIG_ZSWAP=y + CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD=y + CONFIG_ZBUD=y +-CONFIG_Z3FOLD=y + CONFIG_ZSMALLOC=m + # CONFIG_COMPAT_BRK is not set + CONFIG_MEMORY_HOTPLUG=y +diff --git a/arch/loongarch/crypto/crc32-loongarch.c b/arch/loongarch/crypto/crc32-loongarch.c +index 1f2a2c3839bcbf..1e8ff57a46ca6d 100644 +--- a/arch/loongarch/crypto/crc32-loongarch.c ++++ b/arch/loongarch/crypto/crc32-loongarch.c +@@ -44,7 +44,6 @@ static u32 crc32_loongarch_hw(u32 crc_, const u8 *p, unsigned int len) + + CRC32(crc, value, w); + p += sizeof(u32); +- len -= sizeof(u32); + } + + if (len & sizeof(u16)) { +@@ -80,7 +79,6 @@ static u32 crc32c_loongarch_hw(u32 crc_, const u8 *p, unsigned int len) + + CRC32C(crc, value, w); + p += sizeof(u32); +- len -= sizeof(u32); + } + + if (len & sizeof(u16)) { +diff --git a/arch/loongarch/include/asm/Kbuild b/arch/loongarch/include/asm/Kbuild +index 93783fa24f6e9b..dede0b422cfb91 100644 +--- a/arch/loongarch/include/asm/Kbuild ++++ b/arch/loongarch/include/asm/Kbuild +@@ -4,6 +4,7 @@ generic-y += mcs_spinlock.h + generic-y += parport.h + generic-y += early_ioremap.h + generic-y += qrwlock.h ++generic-y += qspinlock.h + generic-y += rwsem.h + generic-y += segment.h + generic-y += user.h +diff --git a/arch/loongarch/include/asm/acpi.h b/arch/loongarch/include/asm/acpi.h +index 8de6c4b83a61a8..49e29b29996f0f 100644 +--- a/arch/loongarch/include/asm/acpi.h ++++ b/arch/loongarch/include/asm/acpi.h +@@ -32,8 +32,10 @@ static inline bool acpi_has_cpu_in_madt(void) + return true; + } + ++#define MAX_CORE_PIC 256 ++ + extern struct list_head acpi_wakeup_device_list; +-extern struct acpi_madt_core_pic acpi_core_pic[NR_CPUS]; ++extern struct acpi_madt_core_pic acpi_core_pic[MAX_CORE_PIC]; + + extern int __init parse_acpi_topology(void); + +diff --git a/arch/loongarch/include/asm/asmmacro.h b/arch/loongarch/include/asm/asmmacro.h +index c9544f358c3399..655db7d7a42796 100644 +--- a/arch/loongarch/include/asm/asmmacro.h ++++ b/arch/loongarch/include/asm/asmmacro.h +@@ -609,8 +609,7 @@ + lu32i.d \reg, 0 + lu52i.d \reg, \reg, 0 + .pushsection ".la_abs", "aw", %progbits +- 768: +- .dword 768b-766b ++ .dword 766b + .dword \sym + .popsection + #endif +diff --git a/arch/loongarch/include/asm/dma-direct.h b/arch/loongarch/include/asm/dma-direct.h +deleted file mode 100644 +index 75ccd808a2af39..00000000000000 +--- a/arch/loongarch/include/asm/dma-direct.h ++++ /dev/null +@@ -1,11 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * Copyright (C) 2020-2022 Loongson Technology Corporation Limited +- */ +-#ifndef _LOONGARCH_DMA_DIRECT_H +-#define _LOONGARCH_DMA_DIRECT_H +- +-dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr); +-phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr); +- +-#endif /* _LOONGARCH_DMA_DIRECT_H */ +diff --git a/arch/loongarch/include/asm/efi.h b/arch/loongarch/include/asm/efi.h +index 091897d40b0375..eddc8e79b3fae7 100644 +--- a/arch/loongarch/include/asm/efi.h ++++ b/arch/loongarch/include/asm/efi.h +@@ -32,6 +32,4 @@ static inline unsigned long efi_get_kimg_min_align(void) + + #define EFI_KIMG_PREFERRED_ADDRESS PHYSADDR(VMLINUX_LOAD_ADDRESS) + +-unsigned long kernel_entry_address(void); +- + #endif /* _ASM_LOONGARCH_EFI_H */ +diff --git a/arch/loongarch/include/asm/elf.h b/arch/loongarch/include/asm/elf.h +index b9a4ab54285c11..f16bd42456e4cc 100644 +--- a/arch/loongarch/include/asm/elf.h ++++ b/arch/loongarch/include/asm/elf.h +@@ -241,8 +241,6 @@ void loongarch_dump_regs64(u64 *uregs, const struct pt_regs *regs); + do { \ + current->thread.vdso = &vdso_info; \ + \ +- loongarch_set_personality_fcsr(state); \ +- \ + if (personality(current->personality) != PER_LINUX) \ + set_personality(PER_LINUX); \ + } while (0) +@@ -259,7 +257,6 @@ do { \ + clear_thread_flag(TIF_32BIT_ADDR); \ + \ + current->thread.vdso = &vdso_info; \ +- loongarch_set_personality_fcsr(state); \ + \ + p = personality(current->personality); \ + if (p != PER_LINUX32 && p != PER_LINUX) \ +@@ -293,7 +290,7 @@ extern const char *__elf_platform; + #define ELF_PLAT_INIT(_r, load_addr) do { \ + _r->regs[1] = _r->regs[2] = _r->regs[3] = _r->regs[4] = 0; \ + _r->regs[5] = _r->regs[6] = _r->regs[7] = _r->regs[8] = 0; \ +- _r->regs[9] = _r->regs[10] = _r->regs[11] = _r->regs[12] = 0; \ ++ _r->regs[9] = _r->regs[10] /* syscall n */ = _r->regs[12] = 0; \ + _r->regs[13] = _r->regs[14] = _r->regs[15] = _r->regs[16] = 0; \ + _r->regs[17] = _r->regs[18] = _r->regs[19] = _r->regs[20] = 0; \ + _r->regs[21] = _r->regs[22] = _r->regs[23] = _r->regs[24] = 0; \ +@@ -340,6 +337,4 @@ extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf, + extern int arch_check_elf(void *ehdr, bool has_interpreter, void *interp_ehdr, + struct arch_elf_state *state); + +-extern void loongarch_set_personality_fcsr(struct arch_elf_state *state); +- + #endif /* _ASM_ELF_H */ +diff --git a/arch/loongarch/include/asm/hw_breakpoint.h b/arch/loongarch/include/asm/hw_breakpoint.h +index 21447fb1efc778..d78330916bd18a 100644 +--- a/arch/loongarch/include/asm/hw_breakpoint.h ++++ b/arch/loongarch/include/asm/hw_breakpoint.h +@@ -75,6 +75,8 @@ do { \ + #define CSR_MWPC_NUM 0x3f + + #define CTRL_PLV_ENABLE 0x1e ++#define CTRL_PLV0_ENABLE 0x02 ++#define CTRL_PLV3_ENABLE 0x10 + + #define MWPnCFG3_LoadEn 8 + #define MWPnCFG3_StoreEn 9 +@@ -101,7 +103,7 @@ struct perf_event; + struct perf_event_attr; + + extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, +- int *gen_len, int *gen_type, int *offset); ++ int *gen_len, int *gen_type); + extern int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw); + extern int hw_breakpoint_arch_parse(struct perf_event *bp, + const struct perf_event_attr *attr, +diff --git a/arch/loongarch/include/asm/hw_irq.h b/arch/loongarch/include/asm/hw_irq.h +index af4f4e8fbd858f..8156ffb6741591 100644 +--- a/arch/loongarch/include/asm/hw_irq.h ++++ b/arch/loongarch/include/asm/hw_irq.h +@@ -9,6 +9,8 @@ + + extern atomic_t irq_err_count; + ++#define ARCH_IRQ_INIT_FLAGS IRQ_NOPROBE ++ + /* + * interrupt-retrigger: NOP for now. This may not be appropriate for all + * machines, we'll see ... +diff --git a/arch/loongarch/include/asm/io.h b/arch/loongarch/include/asm/io.h +index c486c2341b6623..4a8adcca329b81 100644 +--- a/arch/loongarch/include/asm/io.h ++++ b/arch/loongarch/include/asm/io.h +@@ -71,6 +71,8 @@ extern void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t + #define memcpy_fromio(a, c, l) __memcpy_fromio((a), (c), (l)) + #define memcpy_toio(c, a, l) __memcpy_toio((c), (a), (l)) + ++#define __io_aw() mmiowb() ++ + #include + + #define ARCH_HAS_VALID_PHYS_ADDR_RANGE +diff --git a/arch/loongarch/include/asm/jump_label.h b/arch/loongarch/include/asm/jump_label.h +index 3cea299a5ef583..29acfe3de3faae 100644 +--- a/arch/loongarch/include/asm/jump_label.h ++++ b/arch/loongarch/include/asm/jump_label.h +@@ -22,7 +22,7 @@ + + static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch) + { +- asm_volatile_goto( ++ asm goto( + "1: nop \n\t" + JUMP_TABLE_ENTRY + : : "i"(&((char *)key)[branch]) : : l_yes); +@@ -35,7 +35,7 @@ static __always_inline bool arch_static_branch(struct static_key * const key, co + + static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch) + { +- asm_volatile_goto( ++ asm goto( + "1: b %l[l_yes] \n\t" + JUMP_TABLE_ENTRY + : : "i"(&((char *)key)[branch]) : : l_yes); +diff --git a/arch/loongarch/include/asm/numa.h b/arch/loongarch/include/asm/numa.h +index 27f319b4986257..b5f9de9f102e44 100644 +--- a/arch/loongarch/include/asm/numa.h ++++ b/arch/loongarch/include/asm/numa.h +@@ -56,6 +56,7 @@ extern int early_cpu_to_node(int cpu); + static inline void early_numa_add_cpu(int cpuid, s16 node) { } + static inline void numa_add_cpu(unsigned int cpu) { } + static inline void numa_remove_cpu(unsigned int cpu) { } ++static inline void set_cpuid_to_node(int cpuid, s16 node) { } + + static inline int early_cpu_to_node(int cpu) + { +diff --git a/arch/loongarch/include/asm/percpu.h b/arch/loongarch/include/asm/percpu.h +index b9f567e6601668..7e804140500f15 100644 +--- a/arch/loongarch/include/asm/percpu.h ++++ b/arch/loongarch/include/asm/percpu.h +@@ -29,10 +29,15 @@ static inline void set_my_cpu_offset(unsigned long off) + __my_cpu_offset = off; + csr_write64(off, PERCPU_BASE_KS); + } +-#define __my_cpu_offset __my_cpu_offset ++ ++#define __my_cpu_offset \ ++({ \ ++ __asm__ __volatile__("":"+r"(__my_cpu_offset)); \ ++ __my_cpu_offset; \ ++}) + + #define PERCPU_OP(op, asm_op, c_op) \ +-static inline unsigned long __percpu_##op(void *ptr, \ ++static __always_inline unsigned long __percpu_##op(void *ptr, \ + unsigned long val, int size) \ + { \ + unsigned long ret; \ +@@ -63,7 +68,7 @@ PERCPU_OP(and, and, &) + PERCPU_OP(or, or, |) + #undef PERCPU_OP + +-static inline unsigned long __percpu_read(void *ptr, int size) ++static __always_inline unsigned long __percpu_read(void *ptr, int size) + { + unsigned long ret; + +@@ -100,7 +105,7 @@ static inline unsigned long __percpu_read(void *ptr, int size) + return ret; + } + +-static inline void __percpu_write(void *ptr, unsigned long val, int size) ++static __always_inline void __percpu_write(void *ptr, unsigned long val, int size) + { + switch (size) { + case 1: +@@ -132,8 +137,8 @@ static inline void __percpu_write(void *ptr, unsigned long val, int size) + } + } + +-static inline unsigned long __percpu_xchg(void *ptr, unsigned long val, +- int size) ++static __always_inline unsigned long __percpu_xchg(void *ptr, unsigned long val, ++ int size) + { + switch (size) { + case 1: +diff --git a/arch/loongarch/include/asm/perf_event.h b/arch/loongarch/include/asm/perf_event.h +index 2a35a0bc2aaabf..f948a0676daf80 100644 +--- a/arch/loongarch/include/asm/perf_event.h ++++ b/arch/loongarch/include/asm/perf_event.h +@@ -7,6 +7,13 @@ + #ifndef __LOONGARCH_PERF_EVENT_H__ + #define __LOONGARCH_PERF_EVENT_H__ + ++#include ++ + #define perf_arch_bpf_user_pt_regs(regs) (struct user_pt_regs *)regs + ++#define perf_arch_fetch_caller_regs(regs, __ip) { \ ++ (regs)->csr_era = (__ip); \ ++ (regs)->regs[3] = (unsigned long) __builtin_frame_address(0); \ ++} ++ + #endif /* __LOONGARCH_PERF_EVENT_H__ */ +diff --git a/arch/loongarch/include/asm/qspinlock.h b/arch/loongarch/include/asm/qspinlock.h +deleted file mode 100644 +index 34f43f8ad5912b..00000000000000 +--- a/arch/loongarch/include/asm/qspinlock.h ++++ /dev/null +@@ -1,18 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-#ifndef _ASM_QSPINLOCK_H +-#define _ASM_QSPINLOCK_H +- +-#include +- +-#define queued_spin_unlock queued_spin_unlock +- +-static inline void queued_spin_unlock(struct qspinlock *lock) +-{ +- compiletime_assert_atomic_type(lock->locked); +- c_sync(); +- WRITE_ONCE(lock->locked, 0); +-} +- +-#include +- +-#endif /* _ASM_QSPINLOCK_H */ +diff --git a/arch/loongarch/include/asm/setup.h b/arch/loongarch/include/asm/setup.h +index a0bc159ce8bdc0..ee52fb1e996316 100644 +--- a/arch/loongarch/include/asm/setup.h ++++ b/arch/loongarch/include/asm/setup.h +@@ -25,7 +25,7 @@ extern void set_merr_handler(unsigned long offset, void *addr, unsigned long len + #ifdef CONFIG_RELOCATABLE + + struct rela_la_abs { +- long offset; ++ long pc; + long symvalue; + }; + +diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h +index 4fb1e6408b982a..efc8c42290d019 100644 +--- a/arch/loongarch/include/asm/stackframe.h ++++ b/arch/loongarch/include/asm/stackframe.h +@@ -41,7 +41,7 @@ + .macro JUMP_VIRT_ADDR temp1 temp2 + li.d \temp1, CACHE_BASE + pcaddi \temp2, 0 +- or \temp1, \temp1, \temp2 ++ bstrins.d \temp1, \temp2, (DMW_PABITS - 1), 0 + jirl zero, \temp1, 0xc + .endm + +diff --git a/arch/loongarch/include/uapi/asm/unistd.h b/arch/loongarch/include/uapi/asm/unistd.h +index fcb668984f0336..b344b1f917153b 100644 +--- a/arch/loongarch/include/uapi/asm/unistd.h ++++ b/arch/loongarch/include/uapi/asm/unistd.h +@@ -1,4 +1,5 @@ + /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++#define __ARCH_WANT_NEW_STAT + #define __ARCH_WANT_SYS_CLONE + #define __ARCH_WANT_SYS_CLONE3 + +diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c +index 8e00a754e54894..55d6a48c76a821 100644 +--- a/arch/loongarch/kernel/acpi.c ++++ b/arch/loongarch/kernel/acpi.c +@@ -29,11 +29,9 @@ int disabled_cpus; + + u64 acpi_saved_sp; + +-#define MAX_CORE_PIC 256 +- + #define PREFIX "ACPI: " + +-struct acpi_madt_core_pic acpi_core_pic[NR_CPUS]; ++struct acpi_madt_core_pic acpi_core_pic[MAX_CORE_PIC]; + + void __init __iomem * __acpi_map_table(unsigned long phys, unsigned long size) + { +diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c +index 9fc10cea21e10e..de4f3def4af0b9 100644 +--- a/arch/loongarch/kernel/efi.c ++++ b/arch/loongarch/kernel/efi.c +@@ -66,6 +66,12 @@ void __init efi_runtime_init(void) + set_bit(EFI_RUNTIME_SERVICES, &efi.flags); + } + ++bool efi_poweroff_required(void) ++{ ++ return efi_enabled(EFI_RUNTIME_SERVICES) && ++ (acpi_gbl_reduced_hardware || acpi_no_s5); ++} ++ + unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR; + + static void __init init_screen_info(void) +diff --git a/arch/loongarch/kernel/elf.c b/arch/loongarch/kernel/elf.c +index 183e94fc9c69ce..0fa81ced28dcdd 100644 +--- a/arch/loongarch/kernel/elf.c ++++ b/arch/loongarch/kernel/elf.c +@@ -23,8 +23,3 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, void *_interp_ehdr, + { + return 0; + } +- +-void loongarch_set_personality_fcsr(struct arch_elf_state *state) +-{ +- current->thread.fpu.fcsr = boot_cpu_data.fpu_csr0; +-} +diff --git a/arch/loongarch/kernel/ftrace_dyn.c b/arch/loongarch/kernel/ftrace_dyn.c +index 73858c9029cc9e..bff058317062e3 100644 +--- a/arch/loongarch/kernel/ftrace_dyn.c ++++ b/arch/loongarch/kernel/ftrace_dyn.c +@@ -287,6 +287,9 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, + struct kprobe *p; + struct kprobe_ctlblk *kcb; + ++ if (unlikely(kprobe_ftrace_disabled)) ++ return; ++ + bit = ftrace_test_recursion_trylock(ip, parent_ip); + if (bit < 0) + return; +diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S +index 53b883db078620..e336fbc4eb9675 100644 +--- a/arch/loongarch/kernel/head.S ++++ b/arch/loongarch/kernel/head.S +@@ -22,7 +22,7 @@ + _head: + .word MZ_MAGIC /* "MZ", MS-DOS header */ + .org 0x8 +- .dword kernel_entry /* Kernel entry point */ ++ .dword _kernel_entry /* Kernel entry point (physical address) */ + .dword _kernel_asize /* Kernel image effective size */ + .quad PHYS_LINK_KADDR /* Kernel image load offset from start of RAM */ + .org 0x38 /* 0x20 ~ 0x37 reserved */ +@@ -34,7 +34,6 @@ pe_header: + + SYM_DATA(kernel_asize, .long _kernel_asize); + SYM_DATA(kernel_fsize, .long _kernel_fsize); +-SYM_DATA(kernel_offset, .long _kernel_offset); + + #endif + +diff --git a/arch/loongarch/kernel/hw_breakpoint.c b/arch/loongarch/kernel/hw_breakpoint.c +index fc55c4de2a11ff..a6e4b605bfa8d6 100644 +--- a/arch/loongarch/kernel/hw_breakpoint.c ++++ b/arch/loongarch/kernel/hw_breakpoint.c +@@ -174,11 +174,21 @@ void flush_ptrace_hw_breakpoint(struct task_struct *tsk) + static int hw_breakpoint_control(struct perf_event *bp, + enum hw_breakpoint_ops ops) + { +- u32 ctrl; ++ u32 ctrl, privilege; + int i, max_slots, enable; ++ struct pt_regs *regs; + struct perf_event **slots; + struct arch_hw_breakpoint *info = counter_arch_bp(bp); + ++ if (arch_check_bp_in_kernelspace(info)) ++ privilege = CTRL_PLV0_ENABLE; ++ else ++ privilege = CTRL_PLV3_ENABLE; ++ ++ /* Whether bp belongs to a task. */ ++ if (bp->hw.target) ++ regs = task_pt_regs(bp->hw.target); ++ + if (info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) { + /* Breakpoint */ + slots = this_cpu_ptr(bp_on_reg); +@@ -197,31 +207,38 @@ static int hw_breakpoint_control(struct perf_event *bp, + switch (ops) { + case HW_BREAKPOINT_INSTALL: + /* Set the FWPnCFG/MWPnCFG 1~4 register. */ +- write_wb_reg(CSR_CFG_ADDR, i, 0, info->address); +- write_wb_reg(CSR_CFG_ADDR, i, 1, info->address); +- write_wb_reg(CSR_CFG_MASK, i, 0, info->mask); +- write_wb_reg(CSR_CFG_MASK, i, 1, info->mask); +- write_wb_reg(CSR_CFG_ASID, i, 0, 0); +- write_wb_reg(CSR_CFG_ASID, i, 1, 0); + if (info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) { +- write_wb_reg(CSR_CFG_CTRL, i, 0, CTRL_PLV_ENABLE); ++ write_wb_reg(CSR_CFG_ADDR, i, 0, info->address); ++ write_wb_reg(CSR_CFG_MASK, i, 0, info->mask); ++ write_wb_reg(CSR_CFG_ASID, i, 0, 0); ++ write_wb_reg(CSR_CFG_CTRL, i, 0, privilege); + } else { ++ write_wb_reg(CSR_CFG_ADDR, i, 1, info->address); ++ write_wb_reg(CSR_CFG_MASK, i, 1, info->mask); ++ write_wb_reg(CSR_CFG_ASID, i, 1, 0); + ctrl = encode_ctrl_reg(info->ctrl); +- write_wb_reg(CSR_CFG_CTRL, i, 1, ctrl | CTRL_PLV_ENABLE); ++ write_wb_reg(CSR_CFG_CTRL, i, 1, ctrl | privilege); + } + enable = csr_read64(LOONGARCH_CSR_CRMD); + csr_write64(CSR_CRMD_WE | enable, LOONGARCH_CSR_CRMD); ++ if (bp->hw.target && test_tsk_thread_flag(bp->hw.target, TIF_LOAD_WATCH)) ++ regs->csr_prmd |= CSR_PRMD_PWE; + break; + case HW_BREAKPOINT_UNINSTALL: + /* Reset the FWPnCFG/MWPnCFG 1~4 register. */ +- write_wb_reg(CSR_CFG_ADDR, i, 0, 0); +- write_wb_reg(CSR_CFG_ADDR, i, 1, 0); +- write_wb_reg(CSR_CFG_MASK, i, 0, 0); +- write_wb_reg(CSR_CFG_MASK, i, 1, 0); +- write_wb_reg(CSR_CFG_CTRL, i, 0, 0); +- write_wb_reg(CSR_CFG_CTRL, i, 1, 0); +- write_wb_reg(CSR_CFG_ASID, i, 0, 0); +- write_wb_reg(CSR_CFG_ASID, i, 1, 0); ++ if (info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) { ++ write_wb_reg(CSR_CFG_ADDR, i, 0, 0); ++ write_wb_reg(CSR_CFG_MASK, i, 0, 0); ++ write_wb_reg(CSR_CFG_CTRL, i, 0, 0); ++ write_wb_reg(CSR_CFG_ASID, i, 0, 0); ++ } else { ++ write_wb_reg(CSR_CFG_ADDR, i, 1, 0); ++ write_wb_reg(CSR_CFG_MASK, i, 1, 0); ++ write_wb_reg(CSR_CFG_CTRL, i, 1, 0); ++ write_wb_reg(CSR_CFG_ASID, i, 1, 0); ++ } ++ if (bp->hw.target) ++ regs->csr_prmd &= ~CSR_PRMD_PWE; + break; + } + +@@ -283,7 +300,7 @@ int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw) + * to generic breakpoint descriptions. + */ + int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, +- int *gen_len, int *gen_type, int *offset) ++ int *gen_len, int *gen_type) + { + /* Type */ + switch (ctrl.type) { +@@ -303,11 +320,6 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, + return -EINVAL; + } + +- if (!ctrl.len) +- return -EINVAL; +- +- *offset = __ffs(ctrl.len); +- + /* Len */ + switch (ctrl.len) { + case LOONGARCH_BREAKPOINT_LEN_1: +@@ -386,21 +398,17 @@ int hw_breakpoint_arch_parse(struct perf_event *bp, + struct arch_hw_breakpoint *hw) + { + int ret; +- u64 alignment_mask, offset; ++ u64 alignment_mask; + + /* Build the arch_hw_breakpoint. */ + ret = arch_build_bp_info(bp, attr, hw); + if (ret) + return ret; + +- if (hw->ctrl.type != LOONGARCH_BREAKPOINT_EXECUTE) +- alignment_mask = 0x7; +- else ++ if (hw->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) { + alignment_mask = 0x3; +- offset = hw->address & alignment_mask; +- +- hw->address &= ~alignment_mask; +- hw->ctrl.len <<= offset; ++ hw->address &= ~alignment_mask; ++ } + + return 0; + } +@@ -471,12 +479,15 @@ void breakpoint_handler(struct pt_regs *regs) + slots = this_cpu_ptr(bp_on_reg); + + for (i = 0; i < boot_cpu_data.watch_ireg_count; ++i) { +- bp = slots[i]; +- if (bp == NULL) +- continue; +- perf_bp_event(bp, regs); ++ if ((csr_read32(LOONGARCH_CSR_FWPS) & (0x1 << i))) { ++ bp = slots[i]; ++ if (bp == NULL) ++ continue; ++ perf_bp_event(bp, regs); ++ csr_write32(0x1 << i, LOONGARCH_CSR_FWPS); ++ update_bp_registers(regs, 0, 0); ++ } + } +- update_bp_registers(regs, 0, 0); + } + NOKPROBE_SYMBOL(breakpoint_handler); + +@@ -488,12 +499,15 @@ void watchpoint_handler(struct pt_regs *regs) + slots = this_cpu_ptr(wp_on_reg); + + for (i = 0; i < boot_cpu_data.watch_dreg_count; ++i) { +- wp = slots[i]; +- if (wp == NULL) +- continue; +- perf_bp_event(wp, regs); ++ if ((csr_read32(LOONGARCH_CSR_MWPS) & (0x1 << i))) { ++ wp = slots[i]; ++ if (wp == NULL) ++ continue; ++ perf_bp_event(wp, regs); ++ csr_write32(0x1 << i, LOONGARCH_CSR_MWPS); ++ update_bp_registers(regs, 0, 1); ++ } + } +- update_bp_registers(regs, 0, 1); + } + NOKPROBE_SYMBOL(watchpoint_handler); + +diff --git a/arch/loongarch/kernel/image-vars.h b/arch/loongarch/kernel/image-vars.h +index e561989d02de93..b12f8810f19916 100644 +--- a/arch/loongarch/kernel/image-vars.h ++++ b/arch/loongarch/kernel/image-vars.h +@@ -11,7 +11,6 @@ __efistub_strcmp = strcmp; + __efistub_kernel_entry = kernel_entry; + __efistub_kernel_asize = kernel_asize; + __efistub_kernel_fsize = kernel_fsize; +-__efistub_kernel_offset = kernel_offset; + __efistub_screen_info = screen_info; + + #endif +diff --git a/arch/loongarch/kernel/irq.c b/arch/loongarch/kernel/irq.c +index 883e5066ae445f..df42c063f6c430 100644 +--- a/arch/loongarch/kernel/irq.c ++++ b/arch/loongarch/kernel/irq.c +@@ -122,9 +122,6 @@ void __init init_IRQ(void) + panic("IPI IRQ request failed\n"); + #endif + +- for (i = 0; i < NR_IRQS; i++) +- irq_set_noprobe(i); +- + for_each_possible_cpu(i) { + page = alloc_pages_node(cpu_to_node(i), GFP_KERNEL, order); + +diff --git a/arch/loongarch/kernel/perf_event.c b/arch/loongarch/kernel/perf_event.c +index 0491bf453cd496..cac7cba81b65f7 100644 +--- a/arch/loongarch/kernel/perf_event.c ++++ b/arch/loongarch/kernel/perf_event.c +@@ -884,4 +884,4 @@ static int __init init_hw_perf_events(void) + + return 0; + } +-early_initcall(init_hw_perf_events); ++pure_initcall(init_hw_perf_events); +diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/process.c +index 767d94cce0de07..f2ff8b5d591e4f 100644 +--- a/arch/loongarch/kernel/process.c ++++ b/arch/loongarch/kernel/process.c +@@ -85,6 +85,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) + regs->csr_euen = euen; + lose_fpu(0); + lose_lbt(0); ++ current->thread.fpu.fcsr = boot_cpu_data.fpu_csr0; + + clear_thread_flag(TIF_LSX_CTX_LIVE); + clear_thread_flag(TIF_LASX_CTX_LIVE); +diff --git a/arch/loongarch/kernel/ptrace.c b/arch/loongarch/kernel/ptrace.c +index c114c5ef13325a..19dc6eff45ccc8 100644 +--- a/arch/loongarch/kernel/ptrace.c ++++ b/arch/loongarch/kernel/ptrace.c +@@ -494,28 +494,14 @@ static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type, + struct arch_hw_breakpoint_ctrl ctrl, + struct perf_event_attr *attr) + { +- int err, len, type, offset; ++ int err, len, type; + +- err = arch_bp_generic_fields(ctrl, &len, &type, &offset); ++ err = arch_bp_generic_fields(ctrl, &len, &type); + if (err) + return err; + +- switch (note_type) { +- case NT_LOONGARCH_HW_BREAK: +- if ((type & HW_BREAKPOINT_X) != type) +- return -EINVAL; +- break; +- case NT_LOONGARCH_HW_WATCH: +- if ((type & HW_BREAKPOINT_RW) != type) +- return -EINVAL; +- break; +- default: +- return -EINVAL; +- } +- + attr->bp_len = len; + attr->bp_type = type; +- attr->bp_addr += offset; + + return 0; + } +@@ -603,16 +589,36 @@ static int ptrace_hbp_set_ctrl(unsigned int note_type, + struct perf_event *bp; + struct perf_event_attr attr; + struct arch_hw_breakpoint_ctrl ctrl; ++ struct thread_info *ti = task_thread_info(tsk); + + bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx); + if (IS_ERR(bp)) + return PTR_ERR(bp); + + attr = bp->attr; +- decode_ctrl_reg(uctrl, &ctrl); +- err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr); +- if (err) +- return err; ++ ++ switch (note_type) { ++ case NT_LOONGARCH_HW_BREAK: ++ ctrl.type = LOONGARCH_BREAKPOINT_EXECUTE; ++ ctrl.len = LOONGARCH_BREAKPOINT_LEN_4; ++ break; ++ case NT_LOONGARCH_HW_WATCH: ++ decode_ctrl_reg(uctrl, &ctrl); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (uctrl & CTRL_PLV_ENABLE) { ++ err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr); ++ if (err) ++ return err; ++ attr.disabled = 0; ++ set_ti_thread_flag(ti, TIF_LOAD_WATCH); ++ } else { ++ attr.disabled = 1; ++ clear_ti_thread_flag(ti, TIF_LOAD_WATCH); ++ } + + return modify_user_hw_breakpoint(bp, &attr); + } +@@ -643,6 +649,10 @@ static int ptrace_hbp_set_addr(unsigned int note_type, + struct perf_event *bp; + struct perf_event_attr attr; + ++ /* Kernel-space address cannot be monitored by user-space */ ++ if ((unsigned long)addr >= XKPRANGE) ++ return -EINVAL; ++ + bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx); + if (IS_ERR(bp)) + return PTR_ERR(bp); +diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c +index 6c3eff9af9fb1e..0eddd4a66b8745 100644 +--- a/arch/loongarch/kernel/relocate.c ++++ b/arch/loongarch/kernel/relocate.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -52,7 +53,7 @@ static inline void __init relocate_absolute(long random_offset) + for (p = begin; (void *)p < end; p++) { + long v = p->symvalue; + uint32_t lu12iw, ori, lu32id, lu52id; +- union loongarch_instruction *insn = (void *)p - p->offset; ++ union loongarch_instruction *insn = (void *)p->pc; + + lu12iw = (v >> 12) & 0xfffff; + ori = v & 0xfff; +@@ -102,6 +103,14 @@ static inline __init unsigned long get_random_boot(void) + return hash; + } + ++static int __init nokaslr(char *p) ++{ ++ pr_info("KASLR is disabled.\n"); ++ ++ return 0; /* Print a notice and silence the boot warning */ ++} ++early_param("nokaslr", nokaslr); ++ + static inline __init bool kaslr_disabled(void) + { + char *str; +@@ -162,7 +171,7 @@ unsigned long __init relocate_kernel(void) + unsigned long kernel_length; + unsigned long random_offset = 0; + void *location_new = _text; /* Default to original kernel start */ +- char *cmdline = early_ioremap(fw_arg1, COMMAND_LINE_SIZE); /* Boot command line is passed in fw_arg1 */ ++ char *cmdline = early_memremap_ro(fw_arg1, COMMAND_LINE_SIZE); /* Boot command line is passed in fw_arg1 */ + + strscpy(boot_command_line, cmdline, COMMAND_LINE_SIZE); + +@@ -174,6 +183,7 @@ unsigned long __init relocate_kernel(void) + random_offset = (unsigned long)location_new - (unsigned long)(_text); + #endif + reloc_offset = (unsigned long)_text - VMLINUX_LOAD_ADDRESS; ++ early_memunmap(cmdline, COMMAND_LINE_SIZE); + + if (random_offset) { + kernel_length = (long)(_end) - (long)(_text); +diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c +index aed65915e932e2..6748d7f3f22198 100644 +--- a/arch/loongarch/kernel/setup.c ++++ b/arch/loongarch/kernel/setup.c +@@ -57,7 +57,9 @@ + #define SMBIOS_CORE_PACKAGE_OFFSET 0x23 + #define LOONGSON_EFI_ENABLE (1 << 3) + ++#ifdef CONFIG_EFI + struct screen_info screen_info __section(".data"); ++#endif + + unsigned long fw_arg0, fw_arg1, fw_arg2; + DEFINE_PER_CPU(unsigned long, kernelsp); +@@ -367,6 +369,8 @@ void __init platform_init(void) + acpi_gbl_use_default_register_widths = false; + acpi_boot_table_init(); + #endif ++ ++ early_init_fdt_scan_reserved_mem(); + unflatten_and_copy_device_tree(); + + #ifdef CONFIG_NUMA +@@ -400,8 +404,6 @@ static void __init arch_mem_init(char **cmdline_p) + + check_kernel_sections_mem(); + +- early_init_fdt_scan_reserved_mem(); +- + /* + * In order to reduce the possibility of kernel panic when failed to + * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate +diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c +index ef35c871244f08..d74dfe1206ed04 100644 +--- a/arch/loongarch/kernel/smp.c ++++ b/arch/loongarch/kernel/smp.c +@@ -88,6 +88,73 @@ void show_ipi_list(struct seq_file *p, int prec) + } + } + ++static inline void set_cpu_core_map(int cpu) ++{ ++ int i; ++ ++ cpumask_set_cpu(cpu, &cpu_core_setup_map); ++ ++ for_each_cpu(i, &cpu_core_setup_map) { ++ if (cpu_data[cpu].package == cpu_data[i].package) { ++ cpumask_set_cpu(i, &cpu_core_map[cpu]); ++ cpumask_set_cpu(cpu, &cpu_core_map[i]); ++ } ++ } ++} ++ ++static inline void set_cpu_sibling_map(int cpu) ++{ ++ int i; ++ ++ cpumask_set_cpu(cpu, &cpu_sibling_setup_map); ++ ++ for_each_cpu(i, &cpu_sibling_setup_map) { ++ if (cpus_are_siblings(cpu, i)) { ++ cpumask_set_cpu(i, &cpu_sibling_map[cpu]); ++ cpumask_set_cpu(cpu, &cpu_sibling_map[i]); ++ } ++ } ++} ++ ++static inline void clear_cpu_sibling_map(int cpu) ++{ ++ int i; ++ ++ for_each_cpu(i, &cpu_sibling_setup_map) { ++ if (cpus_are_siblings(cpu, i)) { ++ cpumask_clear_cpu(i, &cpu_sibling_map[cpu]); ++ cpumask_clear_cpu(cpu, &cpu_sibling_map[i]); ++ } ++ } ++ ++ cpumask_clear_cpu(cpu, &cpu_sibling_setup_map); ++} ++ ++/* ++ * Calculate a new cpu_foreign_map mask whenever a ++ * new cpu appears or disappears. ++ */ ++void calculate_cpu_foreign_map(void) ++{ ++ int i, k, core_present; ++ cpumask_t temp_foreign_map; ++ ++ /* Re-calculate the mask */ ++ cpumask_clear(&temp_foreign_map); ++ for_each_online_cpu(i) { ++ core_present = 0; ++ for_each_cpu(k, &temp_foreign_map) ++ if (cpus_are_siblings(i, k)) ++ core_present = 1; ++ if (!core_present) ++ cpumask_set_cpu(i, &temp_foreign_map); ++ } ++ ++ for_each_online_cpu(i) ++ cpumask_andnot(&cpu_foreign_map[i], ++ &temp_foreign_map, &cpu_sibling_map[i]); ++} ++ + /* Send mailbox buffer via Mail_Send */ + static void csr_mail_send(uint64_t data, int cpu, int mailbox) + { +@@ -195,7 +262,6 @@ static void __init fdt_smp_setup(void) + + if (cpuid == loongson_sysconf.boot_cpu_id) { + cpu = 0; +- numa_add_cpu(cpu); + } else { + cpu = cpumask_next_zero(-1, cpu_present_mask); + } +@@ -205,6 +271,9 @@ static void __init fdt_smp_setup(void) + set_cpu_present(cpu, true); + __cpu_number_map[cpuid] = cpu; + __cpu_logical_map[cpu] = cpuid; ++ ++ early_numa_add_cpu(cpu, 0); ++ set_cpuid_to_node(cpuid, 0); + } + + loongson_sysconf.nr_cpus = num_processors; +@@ -300,6 +369,7 @@ int loongson_cpu_disable(void) + numa_remove_cpu(cpu); + #endif + set_cpu_online(cpu, false); ++ clear_cpu_sibling_map(cpu); + calculate_cpu_foreign_map(); + local_irq_save(flags); + irq_migrate_all_off_this_cpu(); +@@ -334,6 +404,7 @@ void __noreturn arch_cpu_idle_dead(void) + addr = iocsr_read64(LOONGARCH_IOCSR_MBUF0); + } while (addr == 0); + ++ local_irq_disable(); + init_fn = (void *)TO_CACHE(addr); + iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_CLEAR); + +@@ -376,59 +447,6 @@ static int __init ipi_pm_init(void) + core_initcall(ipi_pm_init); + #endif + +-static inline void set_cpu_sibling_map(int cpu) +-{ +- int i; +- +- cpumask_set_cpu(cpu, &cpu_sibling_setup_map); +- +- for_each_cpu(i, &cpu_sibling_setup_map) { +- if (cpus_are_siblings(cpu, i)) { +- cpumask_set_cpu(i, &cpu_sibling_map[cpu]); +- cpumask_set_cpu(cpu, &cpu_sibling_map[i]); +- } +- } +-} +- +-static inline void set_cpu_core_map(int cpu) +-{ +- int i; +- +- cpumask_set_cpu(cpu, &cpu_core_setup_map); +- +- for_each_cpu(i, &cpu_core_setup_map) { +- if (cpu_data[cpu].package == cpu_data[i].package) { +- cpumask_set_cpu(i, &cpu_core_map[cpu]); +- cpumask_set_cpu(cpu, &cpu_core_map[i]); +- } +- } +-} +- +-/* +- * Calculate a new cpu_foreign_map mask whenever a +- * new cpu appears or disappears. +- */ +-void calculate_cpu_foreign_map(void) +-{ +- int i, k, core_present; +- cpumask_t temp_foreign_map; +- +- /* Re-calculate the mask */ +- cpumask_clear(&temp_foreign_map); +- for_each_online_cpu(i) { +- core_present = 0; +- for_each_cpu(k, &temp_foreign_map) +- if (cpus_are_siblings(i, k)) +- core_present = 1; +- if (!core_present) +- cpumask_set_cpu(i, &temp_foreign_map); +- } +- +- for_each_online_cpu(i) +- cpumask_andnot(&cpu_foreign_map[i], +- &temp_foreign_map, &cpu_sibling_map[i]); +-} +- + /* Preload SMP state for boot cpu */ + void smp_prepare_boot_cpu(void) + { +@@ -437,6 +455,7 @@ void smp_prepare_boot_cpu(void) + set_cpu_possible(0, true); + set_cpu_online(0, true); + set_my_cpu_offset(per_cpu_offset(0)); ++ numa_add_cpu(0); + + rr_node = first_node(node_online_map); + for_each_possible_cpu(cpu) { +@@ -504,7 +523,7 @@ asmlinkage void start_secondary(void) + unsigned int cpu; + + sync_counter(); +- cpu = smp_processor_id(); ++ cpu = raw_smp_processor_id(); + set_my_cpu_offset(per_cpu_offset(cpu)); + + cpu_probe(); +diff --git a/arch/loongarch/kernel/stacktrace.c b/arch/loongarch/kernel/stacktrace.c +index 92270f14db9482..f623feb2129f12 100644 +--- a/arch/loongarch/kernel/stacktrace.c ++++ b/arch/loongarch/kernel/stacktrace.c +@@ -32,7 +32,7 @@ void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, + } + + for (unwind_start(&state, task, regs); +- !unwind_done(&state) && !unwind_error(&state); unwind_next_frame(&state)) { ++ !unwind_done(&state); unwind_next_frame(&state)) { + addr = unwind_get_return_address(&state); + if (!addr || !consume_entry(cookie, addr)) + break; +diff --git a/arch/loongarch/kernel/time.c b/arch/loongarch/kernel/time.c +index 3064af94db9c2e..e7015f7b70e37c 100644 +--- a/arch/loongarch/kernel/time.c ++++ b/arch/loongarch/kernel/time.c +@@ -58,14 +58,16 @@ static int constant_set_state_oneshot(struct clock_event_device *evt) + return 0; + } + +-static int constant_set_state_oneshot_stopped(struct clock_event_device *evt) ++static int constant_set_state_periodic(struct clock_event_device *evt) + { ++ unsigned long period; + unsigned long timer_config; + + raw_spin_lock(&state_lock); + +- timer_config = csr_read64(LOONGARCH_CSR_TCFG); +- timer_config &= ~CSR_TCFG_EN; ++ period = const_clock_freq / HZ; ++ timer_config = period & CSR_TCFG_VAL; ++ timer_config |= (CSR_TCFG_PERIOD | CSR_TCFG_EN); + csr_write64(timer_config, LOONGARCH_CSR_TCFG); + + raw_spin_unlock(&state_lock); +@@ -73,16 +75,14 @@ static int constant_set_state_oneshot_stopped(struct clock_event_device *evt) + return 0; + } + +-static int constant_set_state_periodic(struct clock_event_device *evt) ++static int constant_set_state_shutdown(struct clock_event_device *evt) + { +- unsigned long period; + unsigned long timer_config; + + raw_spin_lock(&state_lock); + +- period = const_clock_freq / HZ; +- timer_config = period & CSR_TCFG_VAL; +- timer_config |= (CSR_TCFG_PERIOD | CSR_TCFG_EN); ++ timer_config = csr_read64(LOONGARCH_CSR_TCFG); ++ timer_config &= ~CSR_TCFG_EN; + csr_write64(timer_config, LOONGARCH_CSR_TCFG); + + raw_spin_unlock(&state_lock); +@@ -90,11 +90,6 @@ static int constant_set_state_periodic(struct clock_event_device *evt) + return 0; + } + +-static int constant_set_state_shutdown(struct clock_event_device *evt) +-{ +- return 0; +-} +- + static int constant_timer_next_event(unsigned long delta, struct clock_event_device *evt) + { + unsigned long timer_config; +@@ -161,7 +156,7 @@ int constant_clockevent_init(void) + cd->rating = 320; + cd->cpumask = cpumask_of(cpu); + cd->set_state_oneshot = constant_set_state_oneshot; +- cd->set_state_oneshot_stopped = constant_set_state_oneshot_stopped; ++ cd->set_state_oneshot_stopped = constant_set_state_shutdown; + cd->set_state_periodic = constant_set_state_periodic; + cd->set_state_shutdown = constant_set_state_shutdown; + cd->set_next_event = constant_timer_next_event; +diff --git a/arch/loongarch/kernel/unwind.c b/arch/loongarch/kernel/unwind.c +index ba324ba76fa156..a463d6961344c0 100644 +--- a/arch/loongarch/kernel/unwind.c ++++ b/arch/loongarch/kernel/unwind.c +@@ -28,6 +28,5 @@ bool default_next_frame(struct unwind_state *state) + + } while (!get_stack_info(state->sp, state->task, info)); + +- state->error = true; + return false; + } +diff --git a/arch/loongarch/kernel/unwind_prologue.c b/arch/loongarch/kernel/unwind_prologue.c +index 55afc27320e12a..929ae240280a5f 100644 +--- a/arch/loongarch/kernel/unwind_prologue.c ++++ b/arch/loongarch/kernel/unwind_prologue.c +@@ -227,7 +227,7 @@ static bool next_frame(struct unwind_state *state) + } while (!get_stack_info(state->sp, state->task, info)); + + out: +- state->error = true; ++ state->stack_info.type = STACK_TYPE_UNKNOWN; + return false; + } + +diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S +index bb2ec86f37a8eb..d5afd0c80a4999 100644 +--- a/arch/loongarch/kernel/vmlinux.lds.S ++++ b/arch/loongarch/kernel/vmlinux.lds.S +@@ -5,6 +5,7 @@ + + #define PAGE_SIZE _PAGE_SIZE + #define RO_EXCEPTION_TABLE_ALIGN 4 ++#define PHYSADDR_MASK 0xffffffffffff /* 48-bit */ + + /* + * Put .bss..swapper_pg_dir as the first thing in .bss. This will +@@ -139,11 +140,11 @@ SECTIONS + + #ifdef CONFIG_EFI_STUB + /* header symbols */ +- _kernel_asize = _end - _text; +- _kernel_fsize = _edata - _text; +- _kernel_vsize = _end - __initdata_begin; +- _kernel_rsize = _edata - __initdata_begin; +- _kernel_offset = kernel_offset - _text; ++ _kernel_entry = ABSOLUTE(kernel_entry & PHYSADDR_MASK); ++ _kernel_asize = ABSOLUTE(_end - _text); ++ _kernel_fsize = ABSOLUTE(_edata - _text); ++ _kernel_vsize = ABSOLUTE(_end - __initdata_begin); ++ _kernel_rsize = ABSOLUTE(_edata - __initdata_begin); + #endif + + .gptab.sdata : { +diff --git a/arch/loongarch/mm/fault.c b/arch/loongarch/mm/fault.c +index 1fc2f6813ea027..97b40defde0608 100644 +--- a/arch/loongarch/mm/fault.c ++++ b/arch/loongarch/mm/fault.c +@@ -202,10 +202,10 @@ static void __kprobes __do_page_fault(struct pt_regs *regs, + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + } else { +- if (!(vma->vm_flags & VM_READ) && address != exception_era(regs)) +- goto bad_area; + if (!(vma->vm_flags & VM_EXEC) && address == exception_era(regs)) + goto bad_area; ++ if (!(vma->vm_flags & (VM_READ | VM_WRITE)) && address != exception_era(regs)) ++ goto bad_area; + } + + /* +diff --git a/arch/loongarch/mm/kasan_init.c b/arch/loongarch/mm/kasan_init.c +index cc3e81fe0186f4..c608adc9984581 100644 +--- a/arch/loongarch/mm/kasan_init.c ++++ b/arch/loongarch/mm/kasan_init.c +@@ -44,6 +44,9 @@ void *kasan_mem_to_shadow(const void *addr) + unsigned long xrange = (maddr >> XRANGE_SHIFT) & 0xffff; + unsigned long offset = 0; + ++ if (maddr >= FIXADDR_START) ++ return (void *)(kasan_early_shadow_page); ++ + maddr &= XRANGE_SHADOW_MASK; + switch (xrange) { + case XKPRANGE_CC_SEG: +diff --git a/arch/loongarch/mm/pgtable.c b/arch/loongarch/mm/pgtable.c +index 71d0539e2d0b02..2aae72e638713a 100644 +--- a/arch/loongarch/mm/pgtable.c ++++ b/arch/loongarch/mm/pgtable.c +@@ -13,13 +13,13 @@ struct page *dmw_virt_to_page(unsigned long kaddr) + { + return pfn_to_page(virt_to_pfn(kaddr)); + } +-EXPORT_SYMBOL_GPL(dmw_virt_to_page); ++EXPORT_SYMBOL(dmw_virt_to_page); + + struct page *tlb_virt_to_page(unsigned long kaddr) + { + return pfn_to_page(pte_pfn(*virt_to_kpte(kaddr))); + } +-EXPORT_SYMBOL_GPL(tlb_virt_to_page); ++EXPORT_SYMBOL(tlb_virt_to_page); + + pgd_t *pgd_alloc(struct mm_struct *mm) + { +diff --git a/arch/loongarch/mm/tlb.c b/arch/loongarch/mm/tlb.c +index 2c0a411f23aa77..56bf1dd5358aa1 100644 +--- a/arch/loongarch/mm/tlb.c ++++ b/arch/loongarch/mm/tlb.c +@@ -284,12 +284,16 @@ static void setup_tlb_handler(int cpu) + set_handler(EXCCODE_TLBNR * VECSIZE, handle_tlb_protect, VECSIZE); + set_handler(EXCCODE_TLBNX * VECSIZE, handle_tlb_protect, VECSIZE); + set_handler(EXCCODE_TLBPE * VECSIZE, handle_tlb_protect, VECSIZE); +- } ++ } else { ++ int vec_sz __maybe_unused; ++ void *addr __maybe_unused; ++ struct page *page __maybe_unused; ++ ++ /* Avoid lockdep warning */ ++ rcu_cpu_starting(cpu); ++ + #ifdef CONFIG_NUMA +- else { +- void *addr; +- struct page *page; +- const int vec_sz = sizeof(exception_handlers); ++ vec_sz = sizeof(exception_handlers); + + if (pcpu_handlers[cpu]) + return; +@@ -305,8 +309,8 @@ static void setup_tlb_handler(int cpu) + csr_write64(pcpu_handlers[cpu], LOONGARCH_CSR_EENTRY); + csr_write64(pcpu_handlers[cpu], LOONGARCH_CSR_MERRENTRY); + csr_write64(pcpu_handlers[cpu] + 80*VECSIZE, LOONGARCH_CSR_TLBRENTRY); +- } + #endif ++ } + } + + void tlb_init(int cpu) +diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c +index db9342b2d0e660..9eb7753d117dfb 100644 +--- a/arch/loongarch/net/bpf_jit.c ++++ b/arch/loongarch/net/bpf_jit.c +@@ -461,7 +461,6 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext + const u8 dst = regmap[insn->dst_reg]; + const s16 off = insn->off; + const s32 imm = insn->imm; +- const u64 imm64 = (u64)(insn + 1)->imm << 32 | (u32)insn->imm; + const bool is32 = BPF_CLASS(insn->code) == BPF_ALU || BPF_CLASS(insn->code) == BPF_JMP32; + + switch (code) { +@@ -855,8 +854,6 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext + + /* function return */ + case BPF_JMP | BPF_EXIT: +- emit_sext_32(ctx, regmap[BPF_REG_0], true); +- + if (i == ctx->prog->len - 1) + break; + +@@ -867,8 +864,12 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext + + /* dst = imm64 */ + case BPF_LD | BPF_IMM | BPF_DW: ++ { ++ const u64 imm64 = (u64)(insn + 1)->imm << 32 | (u32)insn->imm; ++ + move_imm(ctx, dst, imm64, is32); + return 1; ++ } + + /* dst = *(size *)(src + off) */ + case BPF_LDX | BPF_MEM | BPF_B: +@@ -907,14 +908,8 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext + } + break; + case BPF_DW: +- if (is_signed_imm12(off)) { +- emit_insn(ctx, ldd, dst, src, off); +- } else if (is_signed_imm14(off)) { +- emit_insn(ctx, ldptrd, dst, src, off); +- } else { +- move_imm(ctx, t1, off, is32); +- emit_insn(ctx, ldxd, dst, src, t1); +- } ++ move_imm(ctx, t1, off, is32); ++ emit_insn(ctx, ldxd, dst, src, t1); + break; + } + +diff --git a/arch/loongarch/pci/acpi.c b/arch/loongarch/pci/acpi.c +index 365f7de771cbb9..1da4dc46df43e5 100644 +--- a/arch/loongarch/pci/acpi.c ++++ b/arch/loongarch/pci/acpi.c +@@ -225,6 +225,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) + if (bus) { + memcpy(bus->sysdata, info->cfg, sizeof(struct pci_config_window)); + kfree(info); ++ kfree(root_ops); + } else { + struct pci_bus *child; + +diff --git a/arch/loongarch/vdso/Makefile b/arch/loongarch/vdso/Makefile +index 5c97d146332821..f597cd08a96be0 100644 +--- a/arch/loongarch/vdso/Makefile ++++ b/arch/loongarch/vdso/Makefile +@@ -2,6 +2,7 @@ + # Objects to go into the VDSO. + + KASAN_SANITIZE := n ++UBSAN_SANITIZE := n + KCOV_INSTRUMENT := n + + # Include the generic Makefile to check the built vdso. +@@ -83,13 +84,3 @@ $(obj)/vdso.so: $(obj)/vdso.so.dbg FORCE + obj-y += vdso.o + + $(obj)/vdso.o : $(obj)/vdso.so +- +-# install commands for the unstripped file +-quiet_cmd_vdso_install = INSTALL $@ +- cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ +- +-vdso.so: $(obj)/vdso.so.dbg +- @mkdir -p $(MODLIB)/vdso +- $(call cmd,vdso_install) +- +-vdso_install: vdso.so +diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c +index 3137b45750dfce..b7cb28f5ee290a 100644 +--- a/arch/m68k/amiga/config.c ++++ b/arch/m68k/amiga/config.c +@@ -180,6 +180,15 @@ int __init amiga_parse_bootinfo(const struct bi_record *record) + dev->slotsize = be16_to_cpu(cd->cd_SlotSize); + dev->boardaddr = be32_to_cpu(cd->cd_BoardAddr); + dev->boardsize = be32_to_cpu(cd->cd_BoardSize); ++ ++ /* CS-LAB Warp 1260 workaround */ ++ if (be16_to_cpu(dev->rom.er_Manufacturer) == ZORRO_MANUF(ZORRO_PROD_CSLAB_WARP_1260) && ++ dev->rom.er_Product == ZORRO_PROD(ZORRO_PROD_CSLAB_WARP_1260)) { ++ ++ /* turn off all interrupts */ ++ pr_info("Warp 1260 card detected: applying interrupt storm workaround\n"); ++ *(uint32_t *)(dev->boardaddr + 0x1000) = 0xfff; ++ } + } else + pr_warn("amiga_parse_bootinfo: too many AutoConfig devices\n"); + #endif /* CONFIG_ZORRO */ +diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c +index 56f02ea2c248d8..715d1e0d973e61 100644 +--- a/arch/m68k/atari/ataints.c ++++ b/arch/m68k/atari/ataints.c +@@ -302,11 +302,7 @@ void __init atari_init_IRQ(void) + + if (ATARIHW_PRESENT(SCU)) { + /* init the SCU if present */ +- tt_scu.sys_mask = 0x10; /* enable VBL (for the cursor) and +- * disable HSYNC interrupts (who +- * needs them?) MFP and SCC are +- * enabled in VME mask +- */ ++ tt_scu.sys_mask = 0x0; /* disable all interrupts */ + tt_scu.vme_mask = 0x60; /* enable MFP and SCC ints */ + } else { + /* If no SCU and no Hades, the HSYNC interrupt needs to be +diff --git a/arch/m68k/include/asm/cacheflush_mm.h b/arch/m68k/include/asm/cacheflush_mm.h +index ed12358c4783b4..9a71b0148461a4 100644 +--- a/arch/m68k/include/asm/cacheflush_mm.h ++++ b/arch/m68k/include/asm/cacheflush_mm.h +@@ -191,6 +191,7 @@ extern void cache_push_v(unsigned long vaddr, int len); + #define flush_cache_all() __flush_cache_all() + + #define flush_cache_vmap(start, end) flush_cache_all() ++#define flush_cache_vmap_early(start, end) do { } while (0) + #define flush_cache_vunmap(start, end) flush_cache_all() + + static inline void flush_cache_mm(struct mm_struct *mm) +diff --git a/arch/m68k/include/asm/cmpxchg.h b/arch/m68k/include/asm/cmpxchg.h +index d7f3de9c5d6f79..4ba14f3535fcbe 100644 +--- a/arch/m68k/include/asm/cmpxchg.h ++++ b/arch/m68k/include/asm/cmpxchg.h +@@ -32,7 +32,7 @@ static inline unsigned long __arch_xchg(unsigned long x, volatile void * ptr, in + x = tmp; + break; + default: +- tmp = __invalid_xchg_size(x, ptr, size); ++ x = __invalid_xchg_size(x, ptr, size); + break; + } + +diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S +index 4dd2fd7acba9ea..2e1e9ad4f98ca7 100644 +--- a/arch/m68k/kernel/entry.S ++++ b/arch/m68k/kernel/entry.S +@@ -433,7 +433,9 @@ resume: + movec %a0,%dfc + + /* restore status register */ +- movew %a1@(TASK_THREAD+THREAD_SR),%sr ++ movew %a1@(TASK_THREAD+THREAD_SR),%d0 ++ oriw #0x0700,%d0 ++ movew %d0,%sr + + rts + +diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c +index e06ce147c0b7fc..fb87219fc3b469 100644 +--- a/arch/m68k/kernel/process.c ++++ b/arch/m68k/kernel/process.c +@@ -116,7 +116,7 @@ asmlinkage int m68k_clone(struct pt_regs *regs) + { + /* regs will be equal to current_pt_regs() */ + struct kernel_clone_args args = { +- .flags = regs->d1 & ~CSIGNAL, ++ .flags = (u32)(regs->d1) & ~CSIGNAL, + .pidfd = (int __user *)regs->d3, + .child_tid = (int __user *)regs->d4, + .parent_tid = (int __user *)regs->d3, +diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c +index c7cb29f0ff0163..29e06f46ab511f 100644 +--- a/arch/m68k/mac/misc.c ++++ b/arch/m68k/mac/misc.c +@@ -451,30 +451,18 @@ void mac_poweroff(void) + + void mac_reset(void) + { +- if (macintosh_config->adb_type == MAC_ADB_II && +- macintosh_config->ident != MAC_MODEL_SE30) { +- /* need ROMBASE in booter */ +- /* indeed, plus need to MAP THE ROM !! */ +- +- if (mac_bi_data.rombase == 0) +- mac_bi_data.rombase = 0x40800000; +- +- /* works on some */ +- rom_reset = (void *) (mac_bi_data.rombase + 0xa); +- +- local_irq_disable(); +- rom_reset(); + #ifdef CONFIG_ADB_CUDA +- } else if (macintosh_config->adb_type == MAC_ADB_EGRET || +- macintosh_config->adb_type == MAC_ADB_CUDA) { ++ if (macintosh_config->adb_type == MAC_ADB_EGRET || ++ macintosh_config->adb_type == MAC_ADB_CUDA) { + cuda_restart(); ++ } else + #endif + #ifdef CONFIG_ADB_PMU +- } else if (macintosh_config->adb_type == MAC_ADB_PB2) { ++ if (macintosh_config->adb_type == MAC_ADB_PB2) { + pmu_restart(); ++ } else + #endif +- } else if (CPU_IS_030) { +- ++ if (CPU_IS_030) { + /* 030-specific reset routine. The idea is general, but the + * specific registers to reset are '030-specific. Until I + * have a non-030 machine, I can't test anything else. +@@ -522,6 +510,18 @@ void mac_reset(void) + "jmp %/a0@\n\t" /* jump to the reset vector */ + ".chip 68k" + : : "r" (offset), "a" (rombase) : "a0"); ++ } else { ++ /* need ROMBASE in booter */ ++ /* indeed, plus need to MAP THE ROM !! */ ++ ++ if (mac_bi_data.rombase == 0) ++ mac_bi_data.rombase = 0x40800000; ++ ++ /* works on some */ ++ rom_reset = (void *)(mac_bi_data.rombase + 0xa); ++ ++ local_irq_disable(); ++ rom_reset(); + } + + /* should never get here */ +diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile +index 4393bee64eaf80..85c4d29ef43e9e 100644 +--- a/arch/microblaze/kernel/Makefile ++++ b/arch/microblaze/kernel/Makefile +@@ -7,7 +7,6 @@ ifdef CONFIG_FUNCTION_TRACER + # Do not trace early boot code and low level code + CFLAGS_REMOVE_timer.o = -pg + CFLAGS_REMOVE_intc.o = -pg +-CFLAGS_REMOVE_early_printk.o = -pg + CFLAGS_REMOVE_ftrace.o = -pg + CFLAGS_REMOVE_process.o = -pg + endif +diff --git a/arch/microblaze/kernel/cpu/cpuinfo-static.c b/arch/microblaze/kernel/cpu/cpuinfo-static.c +index 85dbda4a08a81f..03da36dc6d9c92 100644 +--- a/arch/microblaze/kernel/cpu/cpuinfo-static.c ++++ b/arch/microblaze/kernel/cpu/cpuinfo-static.c +@@ -18,7 +18,7 @@ static const char family_string[] = CONFIG_XILINX_MICROBLAZE0_FAMILY; + static const char cpu_ver_string[] = CONFIG_XILINX_MICROBLAZE0_HW_VER; + + #define err_printk(x) \ +- early_printk("ERROR: Microblaze " x "-different for kernel and DTS\n"); ++ pr_err("ERROR: Microblaze " x "-different for kernel and DTS\n"); + + void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu) + { +diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c +index 3827dc76edd823..4520c57415797f 100644 +--- a/arch/microblaze/mm/init.c ++++ b/arch/microblaze/mm/init.c +@@ -193,11 +193,6 @@ asmlinkage void __init mmu_init(void) + { + unsigned int kstart, ksize; + +- if (!memblock.reserved.cnt) { +- pr_emerg("Error memory count\n"); +- machine_restart(NULL); +- } +- + if ((u32) memblock.memory.regions[0].size < 0x400000) { + pr_emerg("Memory must be greater than 4MB\n"); + machine_restart(NULL); +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index bc8421859006fa..91c3a502156b31 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -482,6 +482,7 @@ config MACH_LOONGSON2EF + + config MACH_LOONGSON64 + bool "Loongson 64-bit family of machines" ++ select ARCH_DMA_DEFAULT_COHERENT + select ARCH_SPARSEMEM_ENABLE + select ARCH_MIGHT_HAVE_PC_PARPORT + select ARCH_MIGHT_HAVE_PC_SERIO +@@ -1273,6 +1274,7 @@ config CPU_LOONGSON64 + select CPU_SUPPORTS_MSA + select CPU_DIEI_BROKEN if !LOONGSON3_ENHANCEMENT + select CPU_MIPSR2_IRQ_VI ++ select DMA_NONCOHERENT + select WEAK_ORDERING + select WEAK_REORDERING_BEYOND_LLSC + select MIPS_ASID_BITS_VARIABLE +diff --git a/arch/mips/alchemy/devboards/db1200.c b/arch/mips/alchemy/devboards/db1200.c +index f521874ebb07b2..67f067706af273 100644 +--- a/arch/mips/alchemy/devboards/db1200.c ++++ b/arch/mips/alchemy/devboards/db1200.c +@@ -847,7 +847,7 @@ int __init db1200_dev_setup(void) + i2c_register_board_info(0, db1200_i2c_devs, + ARRAY_SIZE(db1200_i2c_devs)); + spi_register_board_info(db1200_spi_devs, +- ARRAY_SIZE(db1200_i2c_devs)); ++ ARRAY_SIZE(db1200_spi_devs)); + + /* SWITCHES: S6.8 I2C/SPI selector (OFF=I2C ON=SPI) + * S6.7 AC97/I2S selector (OFF=AC97 ON=I2S) +diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c +index fd91d9c9a2525d..6c6837181f5555 100644 +--- a/arch/mips/alchemy/devboards/db1550.c ++++ b/arch/mips/alchemy/devboards/db1550.c +@@ -589,7 +589,7 @@ int __init db1550_dev_setup(void) + i2c_register_board_info(0, db1550_i2c_devs, + ARRAY_SIZE(db1550_i2c_devs)); + spi_register_board_info(db1550_spi_devs, +- ARRAY_SIZE(db1550_i2c_devs)); ++ ARRAY_SIZE(db1550_spi_devs)); + + c = clk_get(NULL, "psc0_intclk"); + if (!IS_ERR(c)) { +diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c +index ec180ab92eaa83..66a8ba19c28722 100644 +--- a/arch/mips/bmips/setup.c ++++ b/arch/mips/bmips/setup.c +@@ -110,7 +110,8 @@ static void bcm6358_quirks(void) + * RAC flush causes kernel panics on BCM6358 when booting from TP1 + * because the bootloader is not initializing it properly. + */ +- bmips_rac_flush_disable = !!(read_c0_brcm_cmt_local() & (1 << 31)); ++ bmips_rac_flush_disable = !!(read_c0_brcm_cmt_local() & (1 << 31)) || ++ !!BMIPS_GET_CBR(); + } + + static void bcm6368_quirks(void) +diff --git a/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi b/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi +index f878f47e4501bc..cc7747c5f21f35 100644 +--- a/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi ++++ b/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi +@@ -23,14 +23,6 @@ cpu0: cpu@0 { + }; + }; + +- memory@200000 { +- compatible = "memory"; +- device_type = "memory"; +- reg = <0x00000000 0x00200000 0x00000000 0x0ee00000>, /* 238 MB at 2 MB */ +- <0x00000000 0x20000000 0x00000000 0x1f000000>, /* 496 MB at 512 MB */ +- <0x00000001 0x10000000 0x00000001 0xb0000000>; /* 6912 MB at 4352MB */ +- }; +- + cpu_clk: cpu_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; +@@ -52,6 +44,13 @@ package0: bus@10000000 { + 0 0x40000000 0 0x40000000 0 0x40000000 + 0xfe 0x00000000 0xfe 0x00000000 0 0x40000000>; + ++ isa@18000000 { ++ compatible = "isa"; ++ #size-cells = <1>; ++ #address-cells = <2>; ++ ranges = <1 0x0 0x0 0x18000000 0x4000>; ++ }; ++ + pm: reset-controller@1fe07000 { + compatible = "loongson,ls2k-pm"; + reg = <0 0x1fe07000 0 0x422>; +@@ -100,8 +99,8 @@ liointc1: interrupt-controller@1fe11440 { + rtc0: rtc@1fe07800 { + compatible = "loongson,ls2k1000-rtc"; + reg = <0 0x1fe07800 0 0x78>; +- interrupt-parent = <&liointc0>; +- interrupts = <60 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-parent = <&liointc1>; ++ interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; + }; + + uart0: serial@1fe00000 { +@@ -109,7 +108,7 @@ uart0: serial@1fe00000 { + reg = <0 0x1fe00000 0 0x8>; + clock-frequency = <125000000>; + interrupt-parent = <&liointc0>; +- interrupts = <0 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + no-loopback-test; + }; + +@@ -118,7 +117,6 @@ pci@1a000000 { + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; +- #interrupt-cells = <2>; + + reg = <0 0x1a000000 0 0x02000000>, + <0xfe 0x00000000 0 0x20000000>; +@@ -130,15 +128,15 @@ gmac@3,0 { + compatible = "pci0014,7a03.0", + "pci0014,7a03", + "pciclass0c0320", +- "pciclass0c03", +- "loongson, pci-gmac"; ++ "pciclass0c03"; + + reg = <0x1800 0x0 0x0 0x0 0x0>; +- interrupts = <12 IRQ_TYPE_LEVEL_LOW>, +- <13 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <12 IRQ_TYPE_LEVEL_HIGH>, ++ <13 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq", "eth_lpi"; + interrupt-parent = <&liointc0>; +- phy-mode = "rgmii"; ++ phy-mode = "rgmii-id"; ++ phy-handle = <&phy1>; + mdio { + #address-cells = <1>; + #size-cells = <0>; +@@ -157,11 +155,12 @@ gmac@3,1 { + "loongson, pci-gmac"; + + reg = <0x1900 0x0 0x0 0x0 0x0>; +- interrupts = <14 IRQ_TYPE_LEVEL_LOW>, +- <15 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <14 IRQ_TYPE_LEVEL_HIGH>, ++ <15 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq", "eth_lpi"; + interrupt-parent = <&liointc0>; +- phy-mode = "rgmii"; ++ phy-mode = "rgmii-id"; ++ phy-handle = <&phy1>; + mdio { + #address-cells = <1>; + #size-cells = <0>; +@@ -179,7 +178,7 @@ ehci@4,1 { + "pciclass0c03"; + + reg = <0x2100 0x0 0x0 0x0 0x0>; +- interrupts = <18 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <18 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + }; + +@@ -190,7 +189,7 @@ ohci@4,2 { + "pciclass0c03"; + + reg = <0x2200 0x0 0x0 0x0 0x0>; +- interrupts = <19 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + }; + +@@ -201,97 +200,121 @@ sata@8,0 { + "pciclass0106"; + + reg = <0x4000 0x0 0x0 0x0 0x0>; +- interrupts = <19 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc0>; + }; + +- pci_bridge@9,0 { ++ pcie@9,0 { + compatible = "pci0014,7a19.0", + "pci0014,7a19", + "pciclass060400", + "pciclass0604"; + + reg = <0x4800 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <0 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 0 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 0 IRQ_TYPE_LEVEL_HIGH>; ++ ranges; + external-facing; + }; + +- pci_bridge@a,0 { ++ pcie@a,0 { + compatible = "pci0014,7a09.0", + "pci0014,7a09", + "pciclass060400", + "pciclass0604"; + + reg = <0x5000 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <1 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 1 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 1 IRQ_TYPE_LEVEL_HIGH>; ++ ranges; + external-facing; + }; + +- pci_bridge@b,0 { ++ pcie@b,0 { + compatible = "pci0014,7a09.0", + "pci0014,7a09", + "pciclass060400", + "pciclass0604"; + + reg = <0x5800 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <2 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 2 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 2 IRQ_TYPE_LEVEL_HIGH>; ++ ranges; + external-facing; + }; + +- pci_bridge@c,0 { ++ pcie@c,0 { + compatible = "pci0014,7a09.0", + "pci0014,7a09", + "pciclass060400", + "pciclass0604"; + + reg = <0x6000 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <3 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 3 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 3 IRQ_TYPE_LEVEL_HIGH>; ++ ranges; + external-facing; + }; + +- pci_bridge@d,0 { ++ pcie@d,0 { + compatible = "pci0014,7a19.0", + "pci0014,7a19", + "pciclass060400", + "pciclass0604"; + + reg = <0x6800 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <4 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 4 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 4 IRQ_TYPE_LEVEL_HIGH>; ++ ranges; + external-facing; + }; + +- pci_bridge@e,0 { ++ pcie@e,0 { + compatible = "pci0014,7a09.0", + "pci0014,7a09", + "pciclass060400", + "pciclass0604"; + + reg = <0x7000 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <5 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 5 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 5 IRQ_TYPE_LEVEL_HIGH>; ++ ranges; + external-facing; + }; + +diff --git a/arch/mips/boot/dts/loongson/ls7a-pch.dtsi b/arch/mips/boot/dts/loongson/ls7a-pch.dtsi +index 7c69e8245c2f10..cce9428afc41fc 100644 +--- a/arch/mips/boot/dts/loongson/ls7a-pch.dtsi ++++ b/arch/mips/boot/dts/loongson/ls7a-pch.dtsi +@@ -193,8 +193,7 @@ gmac@3,0 { + compatible = "pci0014,7a03.0", + "pci0014,7a03", + "pciclass020000", +- "pciclass0200", +- "loongson, pci-gmac"; ++ "pciclass0200"; + + reg = <0x1800 0x0 0x0 0x0 0x0>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH>, +diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h +index f36c2519ed9768..1f14132b3fc98a 100644 +--- a/arch/mips/include/asm/cacheflush.h ++++ b/arch/mips/include/asm/cacheflush.h +@@ -97,6 +97,8 @@ static inline void flush_cache_vmap(unsigned long start, unsigned long end) + __flush_cache_vmap(); + } + ++#define flush_cache_vmap_early(start, end) do { } while (0) ++ + extern void (*__flush_cache_vunmap)(void); + + static inline void flush_cache_vunmap(unsigned long start, unsigned long end) +diff --git a/arch/mips/include/asm/checksum.h b/arch/mips/include/asm/checksum.h +index 4044eaf989ac7d..0921ddda11a4b3 100644 +--- a/arch/mips/include/asm/checksum.h ++++ b/arch/mips/include/asm/checksum.h +@@ -241,7 +241,8 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, + " .set pop" + : "=&r" (sum), "=&r" (tmp) + : "r" (saddr), "r" (daddr), +- "0" (htonl(len)), "r" (htonl(proto)), "r" (sum)); ++ "0" (htonl(len)), "r" (htonl(proto)), "r" (sum) ++ : "memory"); + + return csum_fold(sum); + } +diff --git a/arch/mips/include/asm/dmi.h b/arch/mips/include/asm/dmi.h +index 27415a288adf56..dc397f630c6608 100644 +--- a/arch/mips/include/asm/dmi.h ++++ b/arch/mips/include/asm/dmi.h +@@ -5,7 +5,7 @@ + #include + #include + +-#define dmi_early_remap(x, l) ioremap_cache(x, l) ++#define dmi_early_remap(x, l) ioremap(x, l) + #define dmi_early_unmap(x, l) iounmap(x) + #define dmi_remap(x, l) ioremap_cache(x, l) + #define dmi_unmap(x) iounmap(x) +diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h +index c5c6864e64bc43..405c85173f2c16 100644 +--- a/arch/mips/include/asm/jump_label.h ++++ b/arch/mips/include/asm/jump_label.h +@@ -36,7 +36,7 @@ + + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\t" B_INSN " 2f\n\t" ++ asm goto("1:\t" B_INSN " 2f\n\t" + "2:\t.insn\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + WORD_INSN " 1b, %l[l_yes], %0\n\t" +@@ -50,7 +50,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran + + static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\t" J_INSN " %l[l_yes]\n\t" ++ asm goto("1:\t" J_INSN " %l[l_yes]\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + WORD_INSN " 1b, %l[l_yes], %0\n\t" + ".popsection\n\t" +diff --git a/arch/mips/include/asm/mach-loongson64/boot_param.h b/arch/mips/include/asm/mach-loongson64/boot_param.h +index 035b1a69e2d00d..9218b3ae338322 100644 +--- a/arch/mips/include/asm/mach-loongson64/boot_param.h ++++ b/arch/mips/include/asm/mach-loongson64/boot_param.h +@@ -14,7 +14,11 @@ + #define ADAPTER_ROM 8 + #define ACPI_TABLE 9 + #define SMBIOS_TABLE 10 +-#define MAX_MEMORY_TYPE 11 ++#define UMA_VIDEO_RAM 11 ++#define VUMA_VIDEO_RAM 12 ++#define MAX_MEMORY_TYPE 13 ++ ++#define MEM_SIZE_IS_IN_BYTES (1 << 31) + + #define LOONGSON3_BOOT_MEM_MAP_MAX 128 + struct efi_memory_map_loongson { +@@ -38,12 +42,14 @@ enum loongson_cpu_type { + Legacy_1B = 0x5, + Legacy_2G = 0x6, + Legacy_2H = 0x7, ++ Legacy_2K = 0x8, + Loongson_1A = 0x100, + Loongson_1B = 0x101, + Loongson_2E = 0x200, + Loongson_2F = 0x201, + Loongson_2G = 0x202, + Loongson_2H = 0x203, ++ Loongson_2K = 0x204, + Loongson_3A = 0x300, + Loongson_3B = 0x301 + }; +@@ -117,7 +123,8 @@ struct irq_source_routing_table { + u64 pci_io_start_addr; + u64 pci_io_end_addr; + u64 pci_config_addr; +- u32 dma_mask_bits; ++ u16 dma_mask_bits; ++ u16 dma_noncoherent; + } __packed; + + struct interface_info { +diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h +index 23c67c0871b17c..696b40beb774f5 100644 +--- a/arch/mips/include/asm/mips-cm.h ++++ b/arch/mips/include/asm/mips-cm.h +@@ -228,6 +228,10 @@ GCR_ACCESSOR_RO(32, 0x0d0, gic_status) + GCR_ACCESSOR_RO(32, 0x0f0, cpc_status) + #define CM_GCR_CPC_STATUS_EX BIT(0) + ++/* GCR_ACCESS - Controls core/IOCU access to GCRs */ ++GCR_ACCESSOR_RW(32, 0x120, access_cm3) ++#define CM_GCR_ACCESS_ACCESSEN GENMASK(7, 0) ++ + /* GCR_L2_CONFIG - Indicates L2 cache configuration when Config5.L2C=1 */ + GCR_ACCESSOR_RW(32, 0x130, l2_config) + #define CM_GCR_L2_CONFIG_BYPASS BIT(20) +diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h +index daf3cf244ea972..4a2b40ce39e091 100644 +--- a/arch/mips/include/asm/ptrace.h ++++ b/arch/mips/include/asm/ptrace.h +@@ -60,6 +60,7 @@ static inline void instruction_pointer_set(struct pt_regs *regs, + unsigned long val) + { + regs->cp0_epc = val; ++ regs->cp0_cause &= ~CAUSEF_BD; + } + + /* Query offset/name of register from its name/offset */ +@@ -154,9 +155,11 @@ static inline long regs_return_value(struct pt_regs *regs) + } + + #define instruction_pointer(regs) ((regs)->cp0_epc) ++extern unsigned long exception_ip(struct pt_regs *regs); ++#define exception_ip(regs) exception_ip(regs) + #define profile_pc(regs) instruction_pointer(regs) + +-extern asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall); ++extern asmlinkage long syscall_trace_enter(struct pt_regs *regs); + extern asmlinkage void syscall_trace_leave(struct pt_regs *regs); + + extern void die(const char *, struct pt_regs *) __noreturn; +diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c +index d1b11f66f748f0..cb1045ebab0621 100644 +--- a/arch/mips/kernel/asm-offsets.c ++++ b/arch/mips/kernel/asm-offsets.c +@@ -101,6 +101,7 @@ void output_thread_info_defines(void) + OFFSET(TI_CPU, thread_info, cpu); + OFFSET(TI_PRE_COUNT, thread_info, preempt_count); + OFFSET(TI_REGS, thread_info, regs); ++ OFFSET(TI_SYSCALL, thread_info, syscall); + DEFINE(_THREAD_SIZE, THREAD_SIZE); + DEFINE(_THREAD_MASK, THREAD_MASK); + DEFINE(_IRQ_STACK_SIZE, IRQ_STACK_SIZE); +diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c +index 368e8475870f08..5f6e9e2ebbdbb8 100644 +--- a/arch/mips/kernel/cevt-r4k.c ++++ b/arch/mips/kernel/cevt-r4k.c +@@ -303,13 +303,6 @@ int r4k_clockevent_init(void) + if (!c0_compare_int_usable()) + return -ENXIO; + +- /* +- * With vectored interrupts things are getting platform specific. +- * get_c0_compare_int is a hook to allow a platform to return the +- * interrupt number of its liking. +- */ +- irq = get_c0_compare_int(); +- + cd = &per_cpu(mips_clockevent_device, cpu); + + cd->name = "MIPS"; +@@ -320,7 +313,6 @@ int r4k_clockevent_init(void) + min_delta = calculate_min_delta(); + + cd->rating = 300; +- cd->irq = irq; + cd->cpumask = cpumask_of(cpu); + cd->set_next_event = mips_next_event; + cd->event_handler = mips_event_handler; +@@ -332,6 +324,13 @@ int r4k_clockevent_init(void) + + cp0_timer_irq_installed = 1; + ++ /* ++ * With vectored interrupts things are getting platform specific. ++ * get_c0_compare_int is a hook to allow a platform to return the ++ * interrupt number of its liking. ++ */ ++ irq = get_c0_compare_int(); ++ + if (request_irq(irq, c0_compare_interrupt, flags, "timer", + c0_compare_interrupt)) + pr_err("Failed to request irq %d (timer)\n", irq); +diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c +index b406d8bfb15a36..c7fee72ea60679 100644 +--- a/arch/mips/kernel/cpu-probe.c ++++ b/arch/mips/kernel/cpu-probe.c +@@ -1725,12 +1725,16 @@ static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu) + c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_CAM | + MIPS_ASE_LOONGSON_EXT | MIPS_ASE_LOONGSON_EXT2); + c->ases &= ~MIPS_ASE_VZ; /* VZ of Loongson-3A2000/3000 is incomplete */ ++ change_c0_config6(LOONGSON_CONF6_EXTIMER | LOONGSON_CONF6_INTIMER, ++ LOONGSON_CONF6_INTIMER); + break; + case PRID_IMP_LOONGSON_64G: + __cpu_name[cpu] = "ICT Loongson-3"; + set_elf_platform(cpu, "loongson3a"); + set_isa(c, MIPS_CPU_ISA_M64R2); + decode_cpucfg(c); ++ change_c0_config6(LOONGSON_CONF6_EXTIMER | LOONGSON_CONF6_INTIMER, ++ LOONGSON_CONF6_INTIMER); + break; + default: + panic("Unknown Loongson Processor ID!"); +diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c +index 5582a4ca1e9e36..7aa2c2360ff602 100644 +--- a/arch/mips/kernel/elf.c ++++ b/arch/mips/kernel/elf.c +@@ -11,6 +11,7 @@ + + #include + #include ++#include + + #ifdef CONFIG_MIPS_FP_SUPPORT + +@@ -309,6 +310,11 @@ void mips_set_personality_nan(struct arch_elf_state *state) + struct cpuinfo_mips *c = &boot_cpu_data; + struct task_struct *t = current; + ++ /* Do this early so t->thread.fpu.fcr31 won't be clobbered in case ++ * we are preempted before the lose_fpu(0) in start_thread. ++ */ ++ lose_fpu(0); ++ + t->thread.fpu.fcr31 = c->fpu_csr31; + switch (state->nan_2008) { + case 0: +diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c +index 5387ed0a51862b..b630604c577f9f 100644 +--- a/arch/mips/kernel/process.c ++++ b/arch/mips/kernel/process.c +@@ -121,6 +121,19 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) + /* Put the stack after the struct pt_regs. */ + childksp = (unsigned long) childregs; + p->thread.cp0_status = (read_c0_status() & ~(ST0_CU2|ST0_CU1)) | ST0_KERNEL_CUMASK; ++ ++ /* ++ * New tasks lose permission to use the fpu. This accelerates context ++ * switching for most programs since they don't use the fpu. ++ */ ++ clear_tsk_thread_flag(p, TIF_USEDFPU); ++ clear_tsk_thread_flag(p, TIF_USEDMSA); ++ clear_tsk_thread_flag(p, TIF_MSA_CTX_LIVE); ++ ++#ifdef CONFIG_MIPS_MT_FPAFF ++ clear_tsk_thread_flag(p, TIF_FPUBOUND); ++#endif /* CONFIG_MIPS_MT_FPAFF */ ++ + if (unlikely(args->fn)) { + /* kernel thread */ + unsigned long status = p->thread.cp0_status; +@@ -149,20 +162,8 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) + p->thread.reg29 = (unsigned long) childregs; + p->thread.reg31 = (unsigned long) ret_from_fork; + +- /* +- * New tasks lose permission to use the fpu. This accelerates context +- * switching for most programs since they don't use the fpu. +- */ + childregs->cp0_status &= ~(ST0_CU2|ST0_CU1); + +- clear_tsk_thread_flag(p, TIF_USEDFPU); +- clear_tsk_thread_flag(p, TIF_USEDMSA); +- clear_tsk_thread_flag(p, TIF_MSA_CTX_LIVE); +- +-#ifdef CONFIG_MIPS_MT_FPAFF +- clear_tsk_thread_flag(p, TIF_FPUBOUND); +-#endif /* CONFIG_MIPS_MT_FPAFF */ +- + #ifdef CONFIG_MIPS_FP_SUPPORT + atomic_set(&p->thread.bd_emu_frame, BD_EMUFRAME_NONE); + #endif +diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c +index d9df543f7e2c4c..61503a36067e9e 100644 +--- a/arch/mips/kernel/ptrace.c ++++ b/arch/mips/kernel/ptrace.c +@@ -31,6 +31,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -48,6 +49,12 @@ + #define CREATE_TRACE_POINTS + #include + ++unsigned long exception_ip(struct pt_regs *regs) ++{ ++ return exception_epc(regs); ++} ++EXPORT_SYMBOL(exception_ip); ++ + /* + * Called by kernel/ptrace.c when detaching.. + * +@@ -1310,16 +1317,13 @@ long arch_ptrace(struct task_struct *child, long request, + * Notification of system call entry/exit + * - triggered by current->work.syscall_trace + */ +-asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall) ++asmlinkage long syscall_trace_enter(struct pt_regs *regs) + { + user_exit(); + +- current_thread_info()->syscall = syscall; +- + if (test_thread_flag(TIF_SYSCALL_TRACE)) { + if (ptrace_report_syscall_entry(regs)) + return -1; +- syscall = current_thread_info()->syscall; + } + + #ifdef CONFIG_SECCOMP +@@ -1328,7 +1332,7 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall) + struct seccomp_data sd; + unsigned long args[6]; + +- sd.nr = syscall; ++ sd.nr = current_thread_info()->syscall; + sd.arch = syscall_get_arch(current); + syscall_get_arguments(current, regs, args); + for (i = 0; i < 6; i++) +@@ -1338,23 +1342,23 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall) + ret = __secure_computing(&sd); + if (ret == -1) + return ret; +- syscall = current_thread_info()->syscall; + } + #endif + + if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) + trace_sys_enter(regs, regs->regs[2]); + +- audit_syscall_entry(syscall, regs->regs[4], regs->regs[5], ++ audit_syscall_entry(current_thread_info()->syscall, ++ regs->regs[4], regs->regs[5], + regs->regs[6], regs->regs[7]); + + /* + * Negative syscall numbers are mistaken for rejected syscalls, but + * won't have had the return value set appropriately, so we do so now. + */ +- if (syscall < 0) ++ if (current_thread_info()->syscall < 0) + syscall_set_return_value(current, regs, -ENOSYS, 0); +- return syscall; ++ return current_thread_info()->syscall; + } + + /* +diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S +index 18dc9b34505614..2c604717e63080 100644 +--- a/arch/mips/kernel/scall32-o32.S ++++ b/arch/mips/kernel/scall32-o32.S +@@ -77,6 +77,18 @@ loads_done: + PTR_WD load_a7, bad_stack_a7 + .previous + ++ /* ++ * syscall number is in v0 unless we called syscall(__NR_###) ++ * where the real syscall number is in a0 ++ */ ++ subu t2, v0, __NR_O32_Linux ++ bnez t2, 1f /* __NR_syscall at offset 0 */ ++ LONG_S a0, TI_SYSCALL($28) # Save a0 as syscall number ++ b 2f ++1: ++ LONG_S v0, TI_SYSCALL($28) # Save v0 as syscall number ++2: ++ + lw t0, TI_FLAGS($28) # syscall tracing enabled? + li t1, _TIF_WORK_SYSCALL_ENTRY + and t0, t1 +@@ -114,16 +126,7 @@ syscall_trace_entry: + SAVE_STATIC + move a0, sp + +- /* +- * syscall number is in v0 unless we called syscall(__NR_###) +- * where the real syscall number is in a0 +- */ +- move a1, v0 +- subu t2, v0, __NR_O32_Linux +- bnez t2, 1f /* __NR_syscall at offset 0 */ +- lw a1, PT_R4(sp) +- +-1: jal syscall_trace_enter ++ jal syscall_trace_enter + + bltz v0, 1f # seccomp failed? Skip syscall + +diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S +index 97456b2ca7dc32..97788859238c34 100644 +--- a/arch/mips/kernel/scall64-n32.S ++++ b/arch/mips/kernel/scall64-n32.S +@@ -44,6 +44,8 @@ NESTED(handle_sysn32, PT_SIZE, sp) + + sd a3, PT_R26(sp) # save a3 for syscall restarting + ++ LONG_S v0, TI_SYSCALL($28) # Store syscall number ++ + li t1, _TIF_WORK_SYSCALL_ENTRY + LONG_L t0, TI_FLAGS($28) # syscall tracing enabled? + and t0, t1, t0 +@@ -72,7 +74,6 @@ syscall_common: + n32_syscall_trace_entry: + SAVE_STATIC + move a0, sp +- move a1, v0 + jal syscall_trace_enter + + bltz v0, 1f # seccomp failed? Skip syscall +diff --git a/arch/mips/kernel/scall64-n64.S b/arch/mips/kernel/scall64-n64.S +index e6264aa62e457f..be11ea5cc67e04 100644 +--- a/arch/mips/kernel/scall64-n64.S ++++ b/arch/mips/kernel/scall64-n64.S +@@ -46,6 +46,8 @@ NESTED(handle_sys64, PT_SIZE, sp) + + sd a3, PT_R26(sp) # save a3 for syscall restarting + ++ LONG_S v0, TI_SYSCALL($28) # Store syscall number ++ + li t1, _TIF_WORK_SYSCALL_ENTRY + LONG_L t0, TI_FLAGS($28) # syscall tracing enabled? + and t0, t1, t0 +@@ -82,7 +84,6 @@ n64_syscall_exit: + syscall_trace_entry: + SAVE_STATIC + move a0, sp +- move a1, v0 + jal syscall_trace_enter + + bltz v0, 1f # seccomp failed? Skip syscall +diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S +index d3c2616cba2269..7a5abb73e53127 100644 +--- a/arch/mips/kernel/scall64-o32.S ++++ b/arch/mips/kernel/scall64-o32.S +@@ -79,6 +79,22 @@ loads_done: + PTR_WD load_a7, bad_stack_a7 + .previous + ++ /* ++ * absolute syscall number is in v0 unless we called syscall(__NR_###) ++ * where the real syscall number is in a0 ++ * note: NR_syscall is the first O32 syscall but the macro is ++ * only defined when compiling with -mabi=32 (CONFIG_32BIT) ++ * therefore __NR_O32_Linux is used (4000) ++ */ ++ ++ subu t2, v0, __NR_O32_Linux ++ bnez t2, 1f /* __NR_syscall at offset 0 */ ++ LONG_S a0, TI_SYSCALL($28) # Save a0 as syscall number ++ b 2f ++1: ++ LONG_S v0, TI_SYSCALL($28) # Save v0 as syscall number ++2: ++ + li t1, _TIF_WORK_SYSCALL_ENTRY + LONG_L t0, TI_FLAGS($28) # syscall tracing enabled? + and t0, t1, t0 +@@ -113,22 +129,7 @@ trace_a_syscall: + sd a7, PT_R11(sp) # For indirect syscalls + + move a0, sp +- /* +- * absolute syscall number is in v0 unless we called syscall(__NR_###) +- * where the real syscall number is in a0 +- * note: NR_syscall is the first O32 syscall but the macro is +- * only defined when compiling with -mabi=32 (CONFIG_32BIT) +- * therefore __NR_O32_Linux is used (4000) +- */ +- .set push +- .set reorder +- subu t1, v0, __NR_O32_Linux +- move a1, v0 +- bnez t1, 1f /* __NR_syscall at offset 0 */ +- ld a1, PT_R4(sp) /* Arg1 for __NR_syscall case */ +- .set pop +- +-1: jal syscall_trace_enter ++ jal syscall_trace_enter + + bltz v0, 1f # seccomp failed? Skip syscall + +diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c +index cb871eb784a7c1..3f45b72561db9c 100644 +--- a/arch/mips/kernel/setup.c ++++ b/arch/mips/kernel/setup.c +@@ -54,7 +54,7 @@ struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly; + + EXPORT_SYMBOL(cpu_data); + +-#ifdef CONFIG_VT ++#ifdef CONFIG_VGA_CONSOLE + struct screen_info screen_info; + #endif + +@@ -326,11 +326,11 @@ static void __init bootmem_init(void) + panic("Incorrect memory mapping !!!"); + + if (max_pfn > PFN_DOWN(HIGHMEM_START)) { ++ max_low_pfn = PFN_DOWN(HIGHMEM_START); + #ifdef CONFIG_HIGHMEM +- highstart_pfn = PFN_DOWN(HIGHMEM_START); ++ highstart_pfn = max_low_pfn; + highend_pfn = max_pfn; + #else +- max_low_pfn = PFN_DOWN(HIGHMEM_START); + max_pfn = max_low_pfn; + #endif + } +diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c +index dd55d59b88db34..d445f8e849abdc 100644 +--- a/arch/mips/kernel/smp-cps.c ++++ b/arch/mips/kernel/smp-cps.c +@@ -222,7 +222,10 @@ static void boot_core(unsigned int core, unsigned int vpe_id) + write_gcr_co_reset_ext_base(CM_GCR_Cx_RESET_EXT_BASE_UEB); + + /* Ensure the core can access the GCRs */ +- set_gcr_access(1 << core); ++ if (mips_cm_revision() < CM_REV_CM3) ++ set_gcr_access(1 << core); ++ else ++ set_gcr_access_cm3(1 << core); + + if (mips_cpc_present()) { + /* Reset the core */ +diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c +index 8fbef537fb8859..81f6c4f8fbc154 100644 +--- a/arch/mips/kernel/smp.c ++++ b/arch/mips/kernel/smp.c +@@ -351,10 +351,11 @@ early_initcall(mips_smp_ipi_init); + */ + asmlinkage void start_secondary(void) + { +- unsigned int cpu; ++ unsigned int cpu = raw_smp_processor_id(); + + cpu_probe(); + per_cpu_trap_init(false); ++ rcu_cpu_starting(cpu); + mips_clockevent_init(); + mp_ops->init_secondary(); + cpu_report(); +@@ -366,7 +367,6 @@ asmlinkage void start_secondary(void) + */ + + calibrate_delay(); +- cpu = smp_processor_id(); + cpu_data[cpu].udelay_val = loops_per_jiffy; + + set_cpu_sibling_map(cpu); +diff --git a/arch/mips/kernel/syscalls/syscall_n32.tbl b/arch/mips/kernel/syscalls/syscall_n32.tbl +index 152034b8e0a0f3..4a296124604a15 100644 +--- a/arch/mips/kernel/syscalls/syscall_n32.tbl ++++ b/arch/mips/kernel/syscalls/syscall_n32.tbl +@@ -354,7 +354,7 @@ + 412 n32 utimensat_time64 sys_utimensat + 413 n32 pselect6_time64 compat_sys_pselect6_time64 + 414 n32 ppoll_time64 compat_sys_ppoll_time64 +-416 n32 io_pgetevents_time64 sys_io_pgetevents ++416 n32 io_pgetevents_time64 compat_sys_io_pgetevents_time64 + 417 n32 recvmmsg_time64 compat_sys_recvmmsg_time64 + 418 n32 mq_timedsend_time64 sys_mq_timedsend + 419 n32 mq_timedreceive_time64 sys_mq_timedreceive +diff --git a/arch/mips/kernel/syscalls/syscall_o32.tbl b/arch/mips/kernel/syscalls/syscall_o32.tbl +index 1a646813afdca4..1ee62a861380a2 100644 +--- a/arch/mips/kernel/syscalls/syscall_o32.tbl ++++ b/arch/mips/kernel/syscalls/syscall_o32.tbl +@@ -27,7 +27,7 @@ + 17 o32 break sys_ni_syscall + # 18 was sys_stat + 18 o32 unused18 sys_ni_syscall +-19 o32 lseek sys_lseek ++19 o32 lseek sys_lseek compat_sys_lseek + 20 o32 getpid sys_getpid + 21 o32 mount sys_mount + 22 o32 umount sys_oldumount +@@ -403,7 +403,7 @@ + 412 o32 utimensat_time64 sys_utimensat sys_utimensat + 413 o32 pselect6_time64 sys_pselect6 compat_sys_pselect6_time64 + 414 o32 ppoll_time64 sys_ppoll compat_sys_ppoll_time64 +-416 o32 io_pgetevents_time64 sys_io_pgetevents sys_io_pgetevents ++416 o32 io_pgetevents_time64 sys_io_pgetevents compat_sys_io_pgetevents_time64 + 417 o32 recvmmsg_time64 sys_recvmmsg compat_sys_recvmmsg_time64 + 418 o32 mq_timedsend_time64 sys_mq_timedsend sys_mq_timedsend + 419 o32 mq_timedreceive_time64 sys_mq_timedreceive sys_mq_timedreceive +diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c +index 246c6a6b02614c..5b778995d44831 100644 +--- a/arch/mips/kernel/traps.c ++++ b/arch/mips/kernel/traps.c +@@ -2007,7 +2007,13 @@ unsigned long vi_handlers[64]; + + void reserve_exception_space(phys_addr_t addr, unsigned long size) + { +- memblock_reserve(addr, size); ++ /* ++ * reserve exception space on CPUs other than CPU0 ++ * is too late, since memblock is unavailable when APs ++ * up ++ */ ++ if (smp_processor_id() == 0) ++ memblock_reserve(addr, size); + } + + void __init *set_except_vector(int n, void *addr) +diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c +index a3cf293658581e..0c45767eacf674 100644 +--- a/arch/mips/lantiq/prom.c ++++ b/arch/mips/lantiq/prom.c +@@ -108,10 +108,9 @@ void __init prom_init(void) + prom_init_cmdline(); + + #if defined(CONFIG_MIPS_MT_SMP) +- if (cpu_has_mipsmt) { +- lantiq_smp_ops = vsmp_smp_ops; ++ lantiq_smp_ops = vsmp_smp_ops; ++ if (cpu_has_mipsmt) + lantiq_smp_ops.init_secondary = lantiq_init_secondary; +- register_smp_ops(&lantiq_smp_ops); +- } ++ register_smp_ops(&lantiq_smp_ops); + #endif + } +diff --git a/arch/mips/loongson64/env.c b/arch/mips/loongson64/env.c +index c961e2999f15ac..09ff052698614d 100644 +--- a/arch/mips/loongson64/env.c ++++ b/arch/mips/loongson64/env.c +@@ -13,6 +13,8 @@ + * Copyright (C) 2009 Lemote Inc. + * Author: Wu Zhangjin, wuzhangjin@gmail.com + */ ++ ++#include + #include + #include + #include +@@ -86,6 +88,12 @@ void __init prom_lefi_init_env(void) + cpu_clock_freq = ecpu->cpu_clock_freq; + loongson_sysconf.cputype = ecpu->cputype; + switch (ecpu->cputype) { ++ case Legacy_2K: ++ case Loongson_2K: ++ smp_group[0] = 0x900000001fe11000; ++ loongson_sysconf.cores_per_node = 2; ++ loongson_sysconf.cores_per_package = 2; ++ break; + case Legacy_3A: + case Loongson_3A: + loongson_sysconf.cores_per_node = 4; +@@ -147,8 +155,14 @@ void __init prom_lefi_init_env(void) + + loongson_sysconf.dma_mask_bits = eirq_source->dma_mask_bits; + if (loongson_sysconf.dma_mask_bits < 32 || +- loongson_sysconf.dma_mask_bits > 64) ++ loongson_sysconf.dma_mask_bits > 64) { + loongson_sysconf.dma_mask_bits = 32; ++ dma_default_coherent = true; ++ } else { ++ dma_default_coherent = !eirq_source->dma_noncoherent; ++ } ++ ++ pr_info("Firmware: Coherent DMA: %s\n", dma_default_coherent ? "on" : "off"); + + loongson_sysconf.restart_addr = boot_p->reset_system.ResetWarm; + loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown; +@@ -213,6 +227,8 @@ void __init prom_lefi_init_env(void) + default: + break; + } ++ } else if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64R) { ++ loongson_fdt_blob = __dtb_loongson64_2core_2k1000_begin; + } else if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64G) { + if (loongson_sysconf.bridgetype == LS7A) + loongson_fdt_blob = __dtb_loongson64g_4core_ls7a_begin; +diff --git a/arch/mips/loongson64/init.c b/arch/mips/loongson64/init.c +index ee8de1735b7c04..f25caa6aa9d306 100644 +--- a/arch/mips/loongson64/init.c ++++ b/arch/mips/loongson64/init.c +@@ -49,8 +49,7 @@ void virtual_early_config(void) + void __init szmem(unsigned int node) + { + u32 i, mem_type; +- static unsigned long num_physpages; +- u64 node_id, node_psize, start_pfn, end_pfn, mem_start, mem_size; ++ phys_addr_t node_id, mem_start, mem_size; + + /* Otherwise come from DTB */ + if (loongson_sysconf.fw_interface != LOONGSON_LEFI) +@@ -64,30 +63,46 @@ void __init szmem(unsigned int node) + + mem_type = loongson_memmap->map[i].mem_type; + mem_size = loongson_memmap->map[i].mem_size; +- mem_start = loongson_memmap->map[i].mem_start; ++ ++ /* Memory size comes in MB if MEM_SIZE_IS_IN_BYTES not set */ ++ if (mem_size & MEM_SIZE_IS_IN_BYTES) ++ mem_size &= ~MEM_SIZE_IS_IN_BYTES; ++ else ++ mem_size = mem_size << 20; ++ ++ mem_start = (node_id << 44) | loongson_memmap->map[i].mem_start; + + switch (mem_type) { + case SYSTEM_RAM_LOW: + case SYSTEM_RAM_HIGH: +- start_pfn = ((node_id << 44) + mem_start) >> PAGE_SHIFT; +- node_psize = (mem_size << 20) >> PAGE_SHIFT; +- end_pfn = start_pfn + node_psize; +- num_physpages += node_psize; +- pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n", +- (u32)node_id, mem_type, mem_start, mem_size); +- pr_info(" start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n", +- start_pfn, end_pfn, num_physpages); +- memblock_add_node(PFN_PHYS(start_pfn), +- PFN_PHYS(node_psize), node, ++ case UMA_VIDEO_RAM: ++ pr_info("Node %d, mem_type:%d\t[%pa], %pa bytes usable\n", ++ (u32)node_id, mem_type, &mem_start, &mem_size); ++ memblock_add_node(mem_start, mem_size, node, + MEMBLOCK_NONE); + break; + case SYSTEM_RAM_RESERVED: +- pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n", +- (u32)node_id, mem_type, mem_start, mem_size); +- memblock_reserve(((node_id << 44) + mem_start), mem_size << 20); ++ case VIDEO_ROM: ++ case ADAPTER_ROM: ++ case ACPI_TABLE: ++ case SMBIOS_TABLE: ++ pr_info("Node %d, mem_type:%d\t[%pa], %pa bytes reserved\n", ++ (u32)node_id, mem_type, &mem_start, &mem_size); ++ memblock_reserve(mem_start, mem_size); ++ break; ++ /* We should not reserve VUMA_VIDEO_RAM as it overlaps with MMIO */ ++ case VUMA_VIDEO_RAM: ++ default: ++ pr_info("Node %d, mem_type:%d\t[%pa], %pa bytes unhandled\n", ++ (u32)node_id, mem_type, &mem_start, &mem_size); + break; + } + } ++ ++ /* Reserve vgabios if it comes from firmware */ ++ if (loongson_sysconf.vgabios_addr) ++ memblock_reserve(virt_to_phys((void *)loongson_sysconf.vgabios_addr), ++ SZ_256K); + } + + #ifndef CONFIG_NUMA +diff --git a/arch/mips/loongson64/reset.c b/arch/mips/loongson64/reset.c +index e420800043b089..2a8e4cd72605d0 100644 +--- a/arch/mips/loongson64/reset.c ++++ b/arch/mips/loongson64/reset.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -21,36 +22,21 @@ + #include + #include + +-static void loongson_restart(char *command) ++static int firmware_restart(struct sys_off_data *unusedd) + { + + void (*fw_restart)(void) = (void *)loongson_sysconf.restart_addr; + + fw_restart(); +- while (1) { +- if (cpu_wait) +- cpu_wait(); +- } ++ return NOTIFY_DONE; + } + +-static void loongson_poweroff(void) ++static int firmware_poweroff(struct sys_off_data *unused) + { + void (*fw_poweroff)(void) = (void *)loongson_sysconf.poweroff_addr; + + fw_poweroff(); +- while (1) { +- if (cpu_wait) +- cpu_wait(); +- } +-} +- +-static void loongson_halt(void) +-{ +- pr_notice("\n\n** You can safely turn off the power now **\n\n"); +- while (1) { +- if (cpu_wait) +- cpu_wait(); +- } ++ return NOTIFY_DONE; + } + + #ifdef CONFIG_KEXEC +@@ -154,9 +140,17 @@ static void loongson_crash_shutdown(struct pt_regs *regs) + + static int __init mips_reboot_setup(void) + { +- _machine_restart = loongson_restart; +- _machine_halt = loongson_halt; +- pm_power_off = loongson_poweroff; ++ if (loongson_sysconf.restart_addr) { ++ register_sys_off_handler(SYS_OFF_MODE_RESTART, ++ SYS_OFF_PRIO_FIRMWARE, ++ firmware_restart, NULL); ++ } ++ ++ if (loongson_sysconf.poweroff_addr) { ++ register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, ++ SYS_OFF_PRIO_FIRMWARE, ++ firmware_poweroff, NULL); ++ } + + #ifdef CONFIG_KEXEC + kexec_argv = kmalloc(KEXEC_ARGV_SIZE, GFP_KERNEL); +diff --git a/arch/mips/loongson64/smp.c b/arch/mips/loongson64/smp.c +index e015a26a40f7a5..979993679d913e 100644 +--- a/arch/mips/loongson64/smp.c ++++ b/arch/mips/loongson64/smp.c +@@ -466,12 +466,25 @@ static void loongson3_smp_finish(void) + static void __init loongson3_smp_setup(void) + { + int i = 0, num = 0; /* i: physical id, num: logical id */ ++ int max_cpus = 0; + + init_cpu_possible(cpu_none_mask); + ++ for (i = 0; i < ARRAY_SIZE(smp_group); i++) { ++ if (!smp_group[i]) ++ break; ++ max_cpus += loongson_sysconf.cores_per_node; ++ } ++ ++ if (max_cpus < loongson_sysconf.nr_cpus) { ++ pr_err("SMP Groups are less than the number of CPUs\n"); ++ loongson_sysconf.nr_cpus = max_cpus ? max_cpus : 1; ++ } ++ + /* For unified kernel, NR_CPUS is the maximum possible value, + * loongson_sysconf.nr_cpus is the really present value + */ ++ i = 0; + while (i < loongson_sysconf.nr_cpus) { + if (loongson_sysconf.reserved_cpus_mask & (1< PAGE_SHIFT)); + +-#ifdef CONFIG_HIGHMEM +- max_mapnr = highend_pfn ? highend_pfn : max_low_pfn; +-#else +- max_mapnr = max_low_pfn; +-#endif +- high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT); +- + maar_init(); + memblock_free_all(); + setup_zero_pages(); /* Setup zeroed pages. */ +diff --git a/arch/mips/pci/ops-rc32434.c b/arch/mips/pci/ops-rc32434.c +index 874ed6df97683a..34b9323bdabb0e 100644 +--- a/arch/mips/pci/ops-rc32434.c ++++ b/arch/mips/pci/ops-rc32434.c +@@ -112,8 +112,8 @@ static int read_config_dword(struct pci_bus *bus, unsigned int devfn, + * gives them time to settle + */ + if (where == PCI_VENDOR_ID) { +- if (ret == 0xffffffff || ret == 0x00000000 || +- ret == 0x0000ffff || ret == 0xffff0000) { ++ if (*val == 0xffffffff || *val == 0x00000000 || ++ *val == 0x0000ffff || *val == 0xffff0000) { + if (delay > 4) + return 0; + delay *= 2; +diff --git a/arch/mips/pci/pcie-octeon.c b/arch/mips/pci/pcie-octeon.c +index c9edd3fb380df5..9eaacd3d338805 100644 +--- a/arch/mips/pci/pcie-octeon.c ++++ b/arch/mips/pci/pcie-octeon.c +@@ -230,12 +230,18 @@ static inline uint64_t __cvmx_pcie_build_config_addr(int pcie_port, int bus, + { + union cvmx_pcie_address pcie_addr; + union cvmx_pciercx_cfg006 pciercx_cfg006; ++ union cvmx_pciercx_cfg032 pciercx_cfg032; + + pciercx_cfg006.u32 = + cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG006(pcie_port)); + if ((bus <= pciercx_cfg006.s.pbnum) && (dev != 0)) + return 0; + ++ pciercx_cfg032.u32 = ++ cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); ++ if ((pciercx_cfg032.s.dlla == 0) || (pciercx_cfg032.s.lt == 1)) ++ return 0; ++ + pcie_addr.u64 = 0; + pcie_addr.config.upper = 2; + pcie_addr.config.io = 1; +diff --git a/arch/mips/sgi-ip30/ip30-console.c b/arch/mips/sgi-ip30/ip30-console.c +index b91f8c4fdc7860..a087b7ebe12936 100644 +--- a/arch/mips/sgi-ip30/ip30-console.c ++++ b/arch/mips/sgi-ip30/ip30-console.c +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + + #include ++#include + + #include + +diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c +index 76683993cdd3ad..37df504d3ecbb0 100644 +--- a/arch/mips/sibyte/swarm/setup.c ++++ b/arch/mips/sibyte/swarm/setup.c +@@ -129,7 +129,7 @@ void __init plat_mem_setup(void) + if (m41t81_probe()) + swarm_rtc_type = RTC_M41T81; + +-#ifdef CONFIG_VT ++#ifdef CONFIG_VGA_CONSOLE + screen_info = (struct screen_info) { + .orig_video_page = 52, + .orig_video_mode = 3, +diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c +index efad85c8c823b9..9984cf91be7d04 100644 +--- a/arch/mips/sni/setup.c ++++ b/arch/mips/sni/setup.c +@@ -38,7 +38,7 @@ extern void sni_machine_power_off(void); + + static void __init sni_display_setup(void) + { +-#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) && defined(CONFIG_FW_ARC) ++#if defined(CONFIG_VGA_CONSOLE) && defined(CONFIG_FW_ARC) + struct screen_info *si = &screen_info; + DISPLAY_STATUS *di; + +diff --git a/arch/nios2/include/asm/cacheflush.h b/arch/nios2/include/asm/cacheflush.h +index 348cea0977927a..81484a776b333a 100644 +--- a/arch/nios2/include/asm/cacheflush.h ++++ b/arch/nios2/include/asm/cacheflush.h +@@ -38,6 +38,7 @@ void flush_icache_pages(struct vm_area_struct *vma, struct page *page, + #define flush_icache_pages flush_icache_pages + + #define flush_cache_vmap(start, end) flush_dcache_range(start, end) ++#define flush_cache_vmap_early(start, end) do { } while (0) + #define flush_cache_vunmap(start, end) flush_dcache_range(start, end) + + extern void copy_to_user_page(struct vm_area_struct *vma, struct page *page, +diff --git a/arch/openrisc/kernel/setup.c b/arch/openrisc/kernel/setup.c +index 9cf7fb60441f89..be56eaafc8b957 100644 +--- a/arch/openrisc/kernel/setup.c ++++ b/arch/openrisc/kernel/setup.c +@@ -255,6 +255,9 @@ void calibrate_delay(void) + + void __init setup_arch(char **cmdline_p) + { ++ /* setup memblock allocator */ ++ setup_memory(); ++ + unflatten_and_copy_device_tree(); + + setup_cpuinfo(); +@@ -278,9 +281,6 @@ void __init setup_arch(char **cmdline_p) + } + #endif + +- /* setup memblock allocator */ +- setup_memory(); +- + /* paging_init() sets up the MMU and marks all pages as reserved */ + paging_init(); + +diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c +index 9370888c9a7e31..90554a5558fbca 100644 +--- a/arch/openrisc/kernel/traps.c ++++ b/arch/openrisc/kernel/traps.c +@@ -180,29 +180,39 @@ asmlinkage void unhandled_exception(struct pt_regs *regs, int ea, int vector) + + asmlinkage void do_fpe_trap(struct pt_regs *regs, unsigned long address) + { +- int code = FPE_FLTUNK; +- unsigned long fpcsr = regs->fpcsr; +- +- if (fpcsr & SPR_FPCSR_IVF) +- code = FPE_FLTINV; +- else if (fpcsr & SPR_FPCSR_OVF) +- code = FPE_FLTOVF; +- else if (fpcsr & SPR_FPCSR_UNF) +- code = FPE_FLTUND; +- else if (fpcsr & SPR_FPCSR_DZF) +- code = FPE_FLTDIV; +- else if (fpcsr & SPR_FPCSR_IXF) +- code = FPE_FLTRES; +- +- /* Clear all flags */ +- regs->fpcsr &= ~SPR_FPCSR_ALLF; +- +- force_sig_fault(SIGFPE, code, (void __user *)regs->pc); ++ if (user_mode(regs)) { ++ int code = FPE_FLTUNK; ++ unsigned long fpcsr = regs->fpcsr; ++ ++ if (fpcsr & SPR_FPCSR_IVF) ++ code = FPE_FLTINV; ++ else if (fpcsr & SPR_FPCSR_OVF) ++ code = FPE_FLTOVF; ++ else if (fpcsr & SPR_FPCSR_UNF) ++ code = FPE_FLTUND; ++ else if (fpcsr & SPR_FPCSR_DZF) ++ code = FPE_FLTDIV; ++ else if (fpcsr & SPR_FPCSR_IXF) ++ code = FPE_FLTRES; ++ ++ /* Clear all flags */ ++ regs->fpcsr &= ~SPR_FPCSR_ALLF; ++ ++ force_sig_fault(SIGFPE, code, (void __user *)regs->pc); ++ } else { ++ pr_emerg("KERNEL: Illegal fpe exception 0x%.8lx\n", regs->pc); ++ die("Die:", regs, SIGFPE); ++ } + } + + asmlinkage void do_trap(struct pt_regs *regs, unsigned long address) + { +- force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc); ++ if (user_mode(regs)) { ++ force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc); ++ } else { ++ pr_emerg("KERNEL: Illegal trap exception 0x%.8lx\n", regs->pc); ++ die("Die:", regs, SIGILL); ++ } + } + + asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address) +diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig +index a15ab147af2e07..a077e6bf9475f5 100644 +--- a/arch/parisc/Kconfig ++++ b/arch/parisc/Kconfig +@@ -14,9 +14,11 @@ config PARISC + select ARCH_HAS_UBSAN_SANITIZE_ALL + select ARCH_HAS_PTE_SPECIAL + select ARCH_NO_SG_CHAIN ++ select ARCH_SPLIT_ARG64 if !64BIT + select ARCH_SUPPORTS_HUGETLBFS if PA20 + select ARCH_SUPPORTS_MEMORY_FAILURE + select ARCH_STACKWALK ++ select ARCH_HAS_CACHE_LINE_SIZE + select ARCH_HAS_DEBUG_VM_PGTABLE + select HAVE_RELIABLE_STACKTRACE + select DMA_OPS +@@ -24,7 +26,6 @@ config PARISC + select RTC_DRV_GENERIC + select INIT_ALL_POSSIBLE + select BUG +- select BUILDTIME_TABLE_SORT + select HAVE_PCI + select HAVE_PERF_EVENTS + select HAVE_KERNEL_BZIP2 +@@ -83,6 +84,7 @@ config PARISC + select HAVE_SOFTIRQ_ON_OWN_STACK if IRQSTACKS + select TRACE_IRQFLAGS_SUPPORT + select HAVE_FUNCTION_DESCRIPTORS if 64BIT ++ select PCI_MSI_ARCH_FALLBACKS if PCI_MSI + + help + The PA-RISC microprocessor is designed by Hewlett-Packard and used +@@ -113,9 +115,12 @@ config ARCH_HAS_ILOG2_U64 + default n + + config GENERIC_BUG +- bool +- default y ++ def_bool y + depends on BUG ++ select GENERIC_BUG_RELATIVE_POINTERS if 64BIT ++ ++config GENERIC_BUG_RELATIVE_POINTERS ++ bool + + config GENERIC_HWEIGHT + bool +@@ -138,11 +143,11 @@ config ARCH_MMAP_RND_COMPAT_BITS_MIN + default 8 + + config ARCH_MMAP_RND_BITS_MAX +- default 24 if 64BIT +- default 17 ++ default 18 if 64BIT ++ default 13 + + config ARCH_MMAP_RND_COMPAT_BITS_MAX +- default 17 ++ default 13 + + # unless you want to implement ACPI on PA-RISC ... ;-) + config PM +diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile +index 968ebe17494c5f..920db57b6b4cc8 100644 +--- a/arch/parisc/Makefile ++++ b/arch/parisc/Makefile +@@ -177,12 +177,8 @@ vdso_prepare: prepare0 + $(Q)$(MAKE) $(build)=arch/parisc/kernel/vdso32 include/generated/vdso32-offsets.h + endif + +-PHONY += vdso_install +- +-vdso_install: +- $(Q)$(MAKE) $(build)=arch/parisc/kernel/vdso $@ +- $(if $(CONFIG_COMPAT_VDSO), \ +- $(Q)$(MAKE) $(build)=arch/parisc/kernel/vdso32 $@) ++vdso-install-y += arch/parisc/kernel/vdso32/vdso32.so ++vdso-install-$(CONFIG_64BIT) += arch/parisc/kernel/vdso64/vdso64.so + + install: KBUILD_IMAGE := vmlinux + zinstall: KBUILD_IMAGE := vmlinuz +diff --git a/arch/parisc/include/asm/alternative.h b/arch/parisc/include/asm/alternative.h +index 1ed45fd085d3b8..1eb488f25b8380 100644 +--- a/arch/parisc/include/asm/alternative.h ++++ b/arch/parisc/include/asm/alternative.h +@@ -34,7 +34,8 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end, + + /* Alternative SMP implementation. */ + #define ALTERNATIVE(cond, replacement) "!0:" \ +- ".section .altinstructions, \"aw\" !" \ ++ ".section .altinstructions, \"a\" !" \ ++ ".align 4 !" \ + ".word (0b-4-.) !" \ + ".hword 1, " __stringify(cond) " !" \ + ".word " __stringify(replacement) " !" \ +@@ -44,7 +45,8 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end, + + /* to replace one single instructions by a new instruction */ + #define ALTERNATIVE(from, to, cond, replacement)\ +- .section .altinstructions, "aw" ! \ ++ .section .altinstructions, "a" ! \ ++ .align 4 ! \ + .word (from - .) ! \ + .hword (to - from)/4, cond ! \ + .word replacement ! \ +@@ -52,7 +54,8 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end, + + /* to replace multiple instructions by new code */ + #define ALTERNATIVE_CODE(from, num_instructions, cond, new_instr_ptr)\ +- .section .altinstructions, "aw" ! \ ++ .section .altinstructions, "a" ! \ ++ .align 4 ! \ + .word (from - .) ! \ + .hword -num_instructions, cond ! \ + .word (new_instr_ptr - .) ! \ +diff --git a/arch/parisc/include/asm/assembly.h b/arch/parisc/include/asm/assembly.h +index 75677b526b2bb7..000a28e1c5e8d4 100644 +--- a/arch/parisc/include/asm/assembly.h ++++ b/arch/parisc/include/asm/assembly.h +@@ -97,26 +97,28 @@ + * version takes two arguments: a src and destination register. + * However, the source and destination registers can not be + * the same register. ++ * ++ * We use add,l to avoid clobbering the C/B bits in the PSW. + */ + + .macro tophys grvirt, grphys +- ldil L%(__PAGE_OFFSET), \grphys +- sub \grvirt, \grphys, \grphys ++ ldil L%(-__PAGE_OFFSET), \grphys ++ addl \grvirt, \grphys, \grphys + .endm +- ++ + .macro tovirt grphys, grvirt + ldil L%(__PAGE_OFFSET), \grvirt +- add \grphys, \grvirt, \grvirt ++ addl \grphys, \grvirt, \grvirt + .endm + + .macro tophys_r1 gr +- ldil L%(__PAGE_OFFSET), %r1 +- sub \gr, %r1, \gr ++ ldil L%(-__PAGE_OFFSET), %r1 ++ addl \gr, %r1, \gr + .endm +- ++ + .macro tovirt_r1 gr + ldil L%(__PAGE_OFFSET), %r1 +- add \gr, %r1, \gr ++ addl \gr, %r1, \gr + .endm + + .macro delay value +@@ -574,7 +576,9 @@ + */ + #define ASM_EXCEPTIONTABLE_ENTRY(fault_addr, except_addr) \ + .section __ex_table,"aw" ! \ ++ .align 4 ! \ + .word (fault_addr - .), (except_addr - .) ! \ ++ or %r0,%r0,%r0 ! \ + .previous + + +diff --git a/arch/parisc/include/asm/bug.h b/arch/parisc/include/asm/bug.h +index 4b6d60b941247e..833555f74ffa72 100644 +--- a/arch/parisc/include/asm/bug.h ++++ b/arch/parisc/include/asm/bug.h +@@ -17,24 +17,27 @@ + #define PARISC_BUG_BREAK_ASM "break 0x1f, 0x1fff" + #define PARISC_BUG_BREAK_INSN 0x03ffe01f /* PARISC_BUG_BREAK_ASM */ + +-#if defined(CONFIG_64BIT) +-#define ASM_WORD_INSN ".dword\t" ++#ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS ++# define __BUG_REL(val) ".word " __stringify(val) " - ." + #else +-#define ASM_WORD_INSN ".word\t" ++# define __BUG_REL(val) ".word " __stringify(val) + #endif + ++ + #ifdef CONFIG_DEBUG_BUGVERBOSE + #define BUG() \ + do { \ + asm volatile("\n" \ + "1:\t" PARISC_BUG_BREAK_ASM "\n" \ +- "\t.pushsection __bug_table,\"aw\"\n" \ +- "2:\t" ASM_WORD_INSN "1b, %c0\n" \ +- "\t.short %c1, %c2\n" \ +- "\t.org 2b+%c3\n" \ ++ "\t.pushsection __bug_table,\"a\"\n" \ ++ "\t.align 4\n" \ ++ "2:\t" __BUG_REL(1b) "\n" \ ++ "\t" __BUG_REL(%c0) "\n" \ ++ "\t.short %1, %2\n" \ ++ "\t.blockz %3-2*4-2*2\n" \ + "\t.popsection" \ + : : "i" (__FILE__), "i" (__LINE__), \ +- "i" (0), "i" (sizeof(struct bug_entry)) ); \ ++ "i" (0), "i" (sizeof(struct bug_entry)) ); \ + unreachable(); \ + } while(0) + +@@ -51,10 +54,12 @@ + do { \ + asm volatile("\n" \ + "1:\t" PARISC_BUG_BREAK_ASM "\n" \ +- "\t.pushsection __bug_table,\"aw\"\n" \ +- "2:\t" ASM_WORD_INSN "1b, %c0\n" \ +- "\t.short %c1, %c2\n" \ +- "\t.org 2b+%c3\n" \ ++ "\t.pushsection __bug_table,\"a\"\n" \ ++ "\t.align 4\n" \ ++ "2:\t" __BUG_REL(1b) "\n" \ ++ "\t" __BUG_REL(%c0) "\n" \ ++ "\t.short %1, %2\n" \ ++ "\t.blockz %3-2*4-2*2\n" \ + "\t.popsection" \ + : : "i" (__FILE__), "i" (__LINE__), \ + "i" (BUGFLAG_WARNING|(flags)), \ +@@ -65,10 +70,11 @@ + do { \ + asm volatile("\n" \ + "1:\t" PARISC_BUG_BREAK_ASM "\n" \ +- "\t.pushsection __bug_table,\"aw\"\n" \ +- "2:\t" ASM_WORD_INSN "1b\n" \ +- "\t.short %c0\n" \ +- "\t.org 2b+%c1\n" \ ++ "\t.pushsection __bug_table,\"a\"\n" \ ++ "\t.align 4\n" \ ++ "2:\t" __BUG_REL(1b) "\n" \ ++ "\t.short %0\n" \ ++ "\t.blockz %1-4-2\n" \ + "\t.popsection" \ + : : "i" (BUGFLAG_WARNING|(flags)), \ + "i" (sizeof(struct bug_entry)) ); \ +diff --git a/arch/parisc/include/asm/cache.h b/arch/parisc/include/asm/cache.h +index 2a60d7a72f1fa8..a3f0f100f21949 100644 +--- a/arch/parisc/include/asm/cache.h ++++ b/arch/parisc/include/asm/cache.h +@@ -20,7 +20,16 @@ + + #define SMP_CACHE_BYTES L1_CACHE_BYTES + +-#define ARCH_DMA_MINALIGN L1_CACHE_BYTES ++#ifdef CONFIG_PA20 ++#define ARCH_DMA_MINALIGN 128 ++#else ++#define ARCH_DMA_MINALIGN 32 ++#endif ++#define ARCH_KMALLOC_MINALIGN 16 /* ldcw requires 16-byte alignment */ ++ ++#define arch_slab_minalign() ((unsigned)dcache_stride) ++#define cache_line_size() dcache_stride ++#define dma_get_cache_alignment cache_line_size + + #define __read_mostly __section(".data..read_mostly") + +diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h +index b4006f2a97052d..8394718870e1a2 100644 +--- a/arch/parisc/include/asm/cacheflush.h ++++ b/arch/parisc/include/asm/cacheflush.h +@@ -31,17 +31,17 @@ void flush_cache_all_local(void); + void flush_cache_all(void); + void flush_cache_mm(struct mm_struct *mm); + +-void flush_kernel_dcache_page_addr(const void *addr); +- + #define flush_kernel_dcache_range(start,size) \ + flush_kernel_dcache_range_asm((start), (start)+(size)); + ++/* The only way to flush a vmap range is to flush whole cache */ + #define ARCH_IMPLEMENTS_FLUSH_KERNEL_VMAP_RANGE 1 + void flush_kernel_vmap_range(void *vaddr, int size); + void invalidate_kernel_vmap_range(void *vaddr, int size); + +-#define flush_cache_vmap(start, end) flush_cache_all() +-#define flush_cache_vunmap(start, end) flush_cache_all() ++void flush_cache_vmap(unsigned long start, unsigned long end); ++#define flush_cache_vmap_early(start, end) do { } while (0) ++void flush_cache_vunmap(unsigned long start, unsigned long end); + + void flush_dcache_folio(struct folio *folio); + #define flush_dcache_folio flush_dcache_folio +@@ -76,17 +76,11 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, + void flush_cache_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end); + +-/* defined in pacache.S exported in cache.c used by flush_anon_page */ +-void flush_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr); +- + #define ARCH_HAS_FLUSH_ANON_PAGE + void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr); + + #define ARCH_HAS_FLUSH_ON_KUNMAP +-static inline void kunmap_flush_on_unmap(const void *addr) +-{ +- flush_kernel_dcache_page_addr(addr); +-} ++void kunmap_flush_on_unmap(const void *addr); + + #endif /* _PARISC_CACHEFLUSH_H */ + +diff --git a/arch/parisc/include/asm/checksum.h b/arch/parisc/include/asm/checksum.h +index 3c43baca7b397d..2aceebcd695c80 100644 +--- a/arch/parisc/include/asm/checksum.h ++++ b/arch/parisc/include/asm/checksum.h +@@ -40,7 +40,7 @@ static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) + " addc %0, %5, %0\n" + " addc %0, %3, %0\n" + "1: ldws,ma 4(%1), %3\n" +-" addib,< 0, %2, 1b\n" ++" addib,> -1, %2, 1b\n" + " addc %0, %3, %0\n" + "\n" + " extru %0, 31, 16, %4\n" +@@ -126,6 +126,7 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, + ** Try to keep 4 registers with "live" values ahead of the ALU. + */ + ++" depdi 0, 31, 32, %0\n"/* clear upper half of incoming checksum */ + " ldd,ma 8(%1), %4\n" /* get 1st saddr word */ + " ldd,ma 8(%2), %5\n" /* get 1st daddr word */ + " add %4, %0, %0\n" +@@ -137,8 +138,8 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, + " add,dc %3, %0, %0\n" /* fold in proto+len | carry bit */ + " extrd,u %0, 31, 32, %4\n"/* copy upper half down */ + " depdi 0, 31, 32, %0\n"/* clear upper half */ +-" add %4, %0, %0\n" /* fold into 32-bits */ +-" addc 0, %0, %0\n" /* add carry */ ++" add,dc %4, %0, %0\n" /* fold into 32-bits, plus carry */ ++" addc 0, %0, %0\n" /* add final carry */ + + #else + +@@ -163,7 +164,8 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, + " ldw,ma 4(%2), %7\n" /* 4th daddr */ + " addc %6, %0, %0\n" + " addc %7, %0, %0\n" +-" addc %3, %0, %0\n" /* fold in proto+len, catch carry */ ++" addc %3, %0, %0\n" /* fold in proto+len */ ++" addc 0, %0, %0\n" /* add carry */ + + #endif + : "=r" (sum), "=r" (saddr), "=r" (daddr), "=r" (len), +diff --git a/arch/parisc/include/asm/elf.h b/arch/parisc/include/asm/elf.h +index 140eaa97bf215d..2d73d3c3cd37f8 100644 +--- a/arch/parisc/include/asm/elf.h ++++ b/arch/parisc/include/asm/elf.h +@@ -349,15 +349,7 @@ struct pt_regs; /* forward declaration... */ + + #define ELF_HWCAP 0 + +-/* Masks for stack and mmap randomization */ +-#define BRK_RND_MASK (is_32bit_task() ? 0x07ffUL : 0x3ffffUL) +-#define MMAP_RND_MASK (is_32bit_task() ? 0x1fffUL : 0x3ffffUL) +-#define STACK_RND_MASK MMAP_RND_MASK +- +-struct mm_struct; +-extern unsigned long arch_randomize_brk(struct mm_struct *); +-#define arch_randomize_brk arch_randomize_brk +- ++#define STACK_RND_MASK 0x7ff /* 8MB of VA */ + + #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 + struct linux_binprm; +diff --git a/arch/parisc/include/asm/extable.h b/arch/parisc/include/asm/extable.h +new file mode 100644 +index 00000000000000..4ea23e3d79dc90 +--- /dev/null ++++ b/arch/parisc/include/asm/extable.h +@@ -0,0 +1,64 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __PARISC_EXTABLE_H ++#define __PARISC_EXTABLE_H ++ ++#include ++#include ++ ++/* ++ * The exception table consists of three addresses: ++ * ++ * - A relative address to the instruction that is allowed to fault. ++ * - A relative address at which the program should continue (fixup routine) ++ * - An asm statement which specifies which CPU register will ++ * receive -EFAULT when an exception happens if the lowest bit in ++ * the fixup address is set. ++ * ++ * Note: The register specified in the err_opcode instruction will be ++ * modified at runtime if a fault happens. Register %r0 will be ignored. ++ * ++ * Since relative addresses are used, 32bit values are sufficient even on ++ * 64bit kernel. ++ */ ++ ++struct pt_regs; ++int fixup_exception(struct pt_regs *regs); ++ ++#define ARCH_HAS_RELATIVE_EXTABLE ++struct exception_table_entry { ++ int insn; /* relative address of insn that is allowed to fault. */ ++ int fixup; /* relative address of fixup routine */ ++ int err_opcode; /* sample opcode with register which holds error code */ ++}; ++ ++#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr, opcode )\ ++ ".section __ex_table,\"aw\"\n" \ ++ ".align 4\n" \ ++ ".word (" #fault_addr " - .), (" #except_addr " - .)\n" \ ++ opcode "\n" \ ++ ".previous\n" ++ ++/* ++ * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry ++ * (with lowest bit set) for which the fault handler in fixup_exception() will ++ * load -EFAULT on fault into the register specified by the err_opcode instruction, ++ * and zeroes the target register in case of a read fault in get_user(). ++ */ ++#define ASM_EXCEPTIONTABLE_VAR(__err_var) \ ++ int __err_var = 0 ++#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr, register )\ ++ ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1, "or %%r0,%%r0," register) ++ ++static inline void swap_ex_entry_fixup(struct exception_table_entry *a, ++ struct exception_table_entry *b, ++ struct exception_table_entry tmp, ++ int delta) ++{ ++ a->fixup = b->fixup + delta; ++ b->fixup = tmp.fixup - delta; ++ a->err_opcode = b->err_opcode; ++ b->err_opcode = tmp.err_opcode; ++} ++#define swap_ex_entry_fixup swap_ex_entry_fixup ++ ++#endif +diff --git a/arch/parisc/include/asm/jump_label.h b/arch/parisc/include/asm/jump_label.h +index af2a598bc0f819..317ebc5edc9fe9 100644 +--- a/arch/parisc/include/asm/jump_label.h ++++ b/arch/parisc/include/asm/jump_label.h +@@ -12,13 +12,15 @@ + + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + "nop\n\t" + ".pushsection __jump_table, \"aw\"\n\t" ++ ".align %1\n\t" + ".word 1b - ., %l[l_yes] - .\n\t" + __stringify(ASM_ULONG_INSN) " %c0 - .\n\t" + ".popsection\n\t" +- : : "i" (&((char *)key)[branch]) : : l_yes); ++ : : "i" (&((char *)key)[branch]), "i" (sizeof(long)) ++ : : l_yes); + + return false; + l_yes: +@@ -27,13 +29,15 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran + + static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + "b,n %l[l_yes]\n\t" + ".pushsection __jump_table, \"aw\"\n\t" ++ ".align %1\n\t" + ".word 1b - ., %l[l_yes] - .\n\t" + __stringify(ASM_ULONG_INSN) " %c0 - .\n\t" + ".popsection\n\t" +- : : "i" (&((char *)key)[branch]) : : l_yes); ++ : : "i" (&((char *)key)[branch]), "i" (sizeof(long)) ++ : : l_yes); + + return false; + l_yes: +diff --git a/arch/parisc/include/asm/ldcw.h b/arch/parisc/include/asm/ldcw.h +index ee9e071859b2f4..47ebc4c91eaff3 100644 +--- a/arch/parisc/include/asm/ldcw.h ++++ b/arch/parisc/include/asm/ldcw.h +@@ -55,7 +55,7 @@ + }) + + #ifdef CONFIG_SMP +-# define __lock_aligned __section(".data..lock_aligned") ++# define __lock_aligned __section(".data..lock_aligned") __aligned(16) + #endif + + #endif /* __PARISC_LDCW_H */ +diff --git a/arch/parisc/include/asm/mman.h b/arch/parisc/include/asm/mman.h +new file mode 100644 +index 00000000000000..89b6beeda0b869 +--- /dev/null ++++ b/arch/parisc/include/asm/mman.h +@@ -0,0 +1,28 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __ASM_MMAN_H__ ++#define __ASM_MMAN_H__ ++ ++#include ++ ++/* PARISC cannot allow mdwe as it needs writable stacks */ ++static inline bool arch_memory_deny_write_exec_supported(void) ++{ ++ return false; ++} ++#define arch_memory_deny_write_exec_supported arch_memory_deny_write_exec_supported ++ ++static inline unsigned long arch_calc_vm_flag_bits(unsigned long flags) ++{ ++ /* ++ * The stack on parisc grows upwards, so if userspace requests memory ++ * for a stack, mark it with VM_GROWSUP so that the stack expansion in ++ * the fault handler will work. ++ */ ++ if (flags & MAP_STACK) ++ return VM_GROWSUP; ++ ++ return 0; ++} ++#define arch_calc_vm_flag_bits(flags) arch_calc_vm_flag_bits(flags) ++ ++#endif /* __ASM_MMAN_H__ */ +diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h +index 667e703c0e8f69..d6ad1812866a08 100644 +--- a/arch/parisc/include/asm/page.h ++++ b/arch/parisc/include/asm/page.h +@@ -16,6 +16,7 @@ + #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) + #define PAGE_MASK (~(PAGE_SIZE-1)) + ++#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA + + #ifndef __ASSEMBLY__ + +diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h +index 974accac05cd34..babf65751e8180 100644 +--- a/arch/parisc/include/asm/pgtable.h ++++ b/arch/parisc/include/asm/pgtable.h +@@ -448,14 +448,17 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte) + return pte; + } + ++static inline pte_t ptep_get(pte_t *ptep) ++{ ++ return READ_ONCE(*ptep); ++} ++#define ptep_get ptep_get ++ + static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) + { + pte_t pte; + +- if (!pte_young(*ptep)) +- return 0; +- +- pte = *ptep; ++ pte = ptep_get(ptep); + if (!pte_young(pte)) { + return 0; + } +@@ -463,17 +466,10 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned + return 1; + } + +-struct mm_struct; +-static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) +-{ +- pte_t old_pte; +- +- old_pte = *ptep; +- set_pte(ptep, __pte(0)); +- +- return old_pte; +-} ++int ptep_clear_flush_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep); ++pte_t ptep_clear_flush(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep); + ++struct mm_struct; + static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) + { + set_pte(ptep, pte_wrprotect(*ptep)); +@@ -511,7 +507,8 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, + #define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN + + #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG +-#define __HAVE_ARCH_PTEP_GET_AND_CLEAR ++#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH ++#define __HAVE_ARCH_PTEP_CLEAR_FLUSH + #define __HAVE_ARCH_PTEP_SET_WRPROTECT + #define __HAVE_ARCH_PTE_SAME + +diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h +index ff6cbdb6903bca..ece4b3046515c6 100644 +--- a/arch/parisc/include/asm/processor.h ++++ b/arch/parisc/include/asm/processor.h +@@ -47,6 +47,8 @@ + + #ifndef __ASSEMBLY__ + ++struct rlimit; ++unsigned long mmap_upper_limit(struct rlimit *rlim_stack); + unsigned long calc_max_stack_size(unsigned long stack_max); + + /* +diff --git a/arch/parisc/include/asm/signal.h b/arch/parisc/include/asm/signal.h +index 715c96ba2ec81c..e84883c6b4c7a0 100644 +--- a/arch/parisc/include/asm/signal.h ++++ b/arch/parisc/include/asm/signal.h +@@ -4,23 +4,11 @@ + + #include + +-#define _NSIG 64 +-/* bits-per-word, where word apparently means 'long' not 'int' */ +-#define _NSIG_BPW BITS_PER_LONG +-#define _NSIG_WORDS (_NSIG / _NSIG_BPW) +- + # ifndef __ASSEMBLY__ + + /* Most things should be clean enough to redefine this at will, if care + is taken to make libc match. */ + +-typedef unsigned long old_sigset_t; /* at least 32 bits */ +- +-typedef struct { +- /* next_signal() assumes this is a long - no choice */ +- unsigned long sig[_NSIG_WORDS]; +-} sigset_t; +- + #include + + #endif /* !__ASSEMBLY */ +diff --git a/arch/parisc/include/asm/special_insns.h b/arch/parisc/include/asm/special_insns.h +index c822bd0c0e3c6c..51f40eaf778065 100644 +--- a/arch/parisc/include/asm/special_insns.h ++++ b/arch/parisc/include/asm/special_insns.h +@@ -8,7 +8,8 @@ + "copy %%r0,%0\n" \ + "8:\tlpa %%r0(%1),%0\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY(8b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY(8b, 9b, \ ++ "or %%r0,%%r0,%%r0") \ + : "=&r" (pa) \ + : "r" (va) \ + : "memory" \ +@@ -22,7 +23,8 @@ + "copy %%r0,%0\n" \ + "8:\tlpa %%r0(%%sr3,%1),%0\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY(8b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY(8b, 9b, \ ++ "or %%r0,%%r0,%%r0") \ + : "=&r" (pa) \ + : "r" (va) \ + : "memory" \ +diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h +index 2bf660eabe421e..88d0ae5769dde5 100644 +--- a/arch/parisc/include/asm/uaccess.h ++++ b/arch/parisc/include/asm/uaccess.h +@@ -7,6 +7,7 @@ + */ + #include + #include ++#include + + #include + #include +@@ -26,36 +27,6 @@ + #define STD_USER(sr, x, ptr) __put_user_asm(sr, "std", x, ptr) + #endif + +-/* +- * The exception table contains two values: the first is the relative offset to +- * the address of the instruction that is allowed to fault, and the second is +- * the relative offset to the address of the fixup routine. Since relative +- * addresses are used, 32bit values are sufficient even on 64bit kernel. +- */ +- +-#define ARCH_HAS_RELATIVE_EXTABLE +-struct exception_table_entry { +- int insn; /* relative address of insn that is allowed to fault. */ +- int fixup; /* relative address of fixup routine */ +-}; +- +-#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\ +- ".section __ex_table,\"aw\"\n" \ +- ".word (" #fault_addr " - .), (" #except_addr " - .)\n\t" \ +- ".previous\n" +- +-/* +- * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry +- * (with lowest bit set) for which the fault handler in fixup_exception() will +- * load -EFAULT into %r29 for a read or write fault, and zeroes the target +- * register in case of a read fault in get_user(). +- */ +-#define ASM_EXCEPTIONTABLE_REG 29 +-#define ASM_EXCEPTIONTABLE_VAR(__variable) \ +- register long __variable __asm__ ("r29") = 0 +-#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr )\ +- ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1) +- + #define __get_user_internal(sr, val, ptr) \ + ({ \ + ASM_EXCEPTIONTABLE_VAR(__gu_err); \ +@@ -82,7 +53,7 @@ struct exception_table_entry { + \ + __asm__("1: " ldx " 0(%%sr%2,%3),%0\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%1") \ + : "=r"(__gu_val), "+r"(__gu_err) \ + : "i"(sr), "r"(ptr)); \ + \ +@@ -114,8 +85,8 @@ struct exception_table_entry { + "1: ldw 0(%%sr%2,%3),%0\n" \ + "2: ldw 4(%%sr%2,%3),%R0\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%1") \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b, "%1") \ + : "=&r"(__gu_tmp.l), "+r"(__gu_err) \ + : "i"(sr), "r"(ptr)); \ + \ +@@ -173,7 +144,7 @@ struct exception_table_entry { + __asm__ __volatile__ ( \ + "1: " stx " %1,0(%%sr%2,%3)\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%0") \ + : "+r"(__pu_err) \ + : "r"(x), "i"(sr), "r"(ptr)) + +@@ -185,15 +156,14 @@ struct exception_table_entry { + "1: stw %1,0(%%sr%2,%3)\n" \ + "2: stw %R1,4(%%sr%2,%3)\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%0") \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b, "%0") \ + : "+r"(__pu_err) \ + : "r"(__val), "i"(sr), "r"(ptr)); \ + } while (0) + + #endif /* !defined(CONFIG_64BIT) */ + +- + /* + * Complex access routines -- external declarations + */ +@@ -215,7 +185,4 @@ unsigned long __must_check raw_copy_from_user(void *dst, const void __user *src, + #define INLINE_COPY_TO_USER + #define INLINE_COPY_FROM_USER + +-struct pt_regs; +-int fixup_exception(struct pt_regs *regs); +- + #endif /* __PARISC_UACCESS_H */ +diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h +index 87245c584784ec..8d94739d75c67c 100644 +--- a/arch/parisc/include/uapi/asm/errno.h ++++ b/arch/parisc/include/uapi/asm/errno.h +@@ -75,7 +75,6 @@ + + /* We now return you to your regularly scheduled HPUX. */ + +-#define ENOSYM 215 /* symbol does not exist in executable */ + #define ENOTSOCK 216 /* Socket operation on non-socket */ + #define EDESTADDRREQ 217 /* Destination address required */ + #define EMSGSIZE 218 /* Message too long */ +@@ -101,7 +100,6 @@ + #define ETIMEDOUT 238 /* Connection timed out */ + #define ECONNREFUSED 239 /* Connection refused */ + #define EREFUSED ECONNREFUSED /* for HP's NFS apparently */ +-#define EREMOTERELEASE 240 /* Remote peer released connection */ + #define EHOSTDOWN 241 /* Host is down */ + #define EHOSTUNREACH 242 /* No route to host */ + +diff --git a/arch/parisc/include/uapi/asm/pdc.h b/arch/parisc/include/uapi/asm/pdc.h +index 7a90070136e823..8e38a86996fc60 100644 +--- a/arch/parisc/include/uapi/asm/pdc.h ++++ b/arch/parisc/include/uapi/asm/pdc.h +@@ -472,6 +472,7 @@ struct pdc_model { /* for PDC_MODEL */ + unsigned long arch_rev; + unsigned long pot_key; + unsigned long curr_key; ++ unsigned long width; /* default of PSW_W bit (1=enabled) */ + }; + + struct pdc_cache_cf { /* for PDC_CACHE (I/D-caches) */ +diff --git a/arch/parisc/include/uapi/asm/signal.h b/arch/parisc/include/uapi/asm/signal.h +index 8e4895c5ea5d37..40d7a574c5dd19 100644 +--- a/arch/parisc/include/uapi/asm/signal.h ++++ b/arch/parisc/include/uapi/asm/signal.h +@@ -57,10 +57,20 @@ + + #include + ++#define _NSIG 64 ++#define _NSIG_BPW (sizeof(unsigned long) * 8) ++#define _NSIG_WORDS (_NSIG / _NSIG_BPW) ++ + # ifndef __ASSEMBLY__ + + # include + ++typedef unsigned long old_sigset_t; /* at least 32 bits */ ++ ++typedef struct { ++ unsigned long sig[_NSIG_WORDS]; ++} sigset_t; ++ + /* Avoid too many header ordering problems. */ + struct siginfo; + +diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c +index 268d90a9325b46..f7953b0391cf60 100644 +--- a/arch/parisc/kernel/cache.c ++++ b/arch/parisc/kernel/cache.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -31,20 +32,31 @@ + #include + #include + ++#define PTR_PAGE_ALIGN_DOWN(addr) PTR_ALIGN_DOWN(addr, PAGE_SIZE) ++ ++/* ++ * When nonzero, use _PAGE_ACCESSED bit to try to reduce the number ++ * of page flushes done flush_cache_page_if_present. There are some ++ * pros and cons in using this option. It may increase the risk of ++ * random segmentation faults. ++ */ ++#define CONFIG_FLUSH_PAGE_ACCESSED 0 ++ + int split_tlb __ro_after_init; + int dcache_stride __ro_after_init; + int icache_stride __ro_after_init; + EXPORT_SYMBOL(dcache_stride); + ++/* Internal implementation in arch/parisc/kernel/pacache.S */ + void flush_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr); + EXPORT_SYMBOL(flush_dcache_page_asm); + void purge_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr); + void flush_icache_page_asm(unsigned long phys_addr, unsigned long vaddr); +- +-/* Internal implementation in arch/parisc/kernel/pacache.S */ + void flush_data_cache_local(void *); /* flushes local data-cache only */ + void flush_instruction_cache_local(void); /* flushes local code-cache only */ + ++static void flush_kernel_dcache_page_addr(const void *addr); ++ + /* On some machines (i.e., ones with the Merced bus), there can be + * only a single PxTLB broadcast at a time; this must be guaranteed + * by software. We need a spinlock around all TLB flushes to ensure +@@ -58,7 +70,7 @@ int pa_serialize_tlb_flushes __ro_after_init; + + struct pdc_cache_info cache_info __ro_after_init; + #ifndef CONFIG_PA20 +-struct pdc_btlb_info btlb_info __ro_after_init; ++struct pdc_btlb_info btlb_info; + #endif + + DEFINE_STATIC_KEY_TRUE(parisc_has_cache); +@@ -317,6 +329,18 @@ __flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, + { + if (!static_branch_likely(&parisc_has_cache)) + return; ++ ++ /* ++ * The TLB is the engine of coherence on parisc. The CPU is ++ * entitled to speculate any page with a TLB mapping, so here ++ * we kill the mapping then flush the page along a special flush ++ * only alias mapping. This guarantees that the page is no-longer ++ * in the cache for any process and nor may it be speculatively ++ * read in (until the user or kernel specifically accesses it, ++ * of course). ++ */ ++ flush_tlb_page(vma, vmaddr); ++ + preempt_disable(); + flush_dcache_page_asm(physaddr, vmaddr); + if (vma->vm_flags & VM_EXEC) +@@ -324,46 +348,44 @@ __flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, + preempt_enable(); + } + +-static void flush_user_cache_page(struct vm_area_struct *vma, unsigned long vmaddr) ++static void flush_kernel_dcache_page_addr(const void *addr) + { +- unsigned long flags, space, pgd, prot; +-#ifdef CONFIG_TLB_PTLOCK +- unsigned long pgd_lock; +-#endif ++ unsigned long vaddr = (unsigned long)addr; ++ unsigned long flags; + +- vmaddr &= PAGE_MASK; ++ /* Purge TLB entry to remove translation on all CPUs */ ++ purge_tlb_start(flags); ++ pdtlb(SR_KERNEL, addr); ++ purge_tlb_end(flags); + ++ /* Use tmpalias flush to prevent data cache move-in */ + preempt_disable(); ++ flush_dcache_page_asm(__pa(vaddr), vaddr); ++ preempt_enable(); ++} + +- /* Set context for flush */ +- local_irq_save(flags); +- prot = mfctl(8); +- space = mfsp(SR_USER); +- pgd = mfctl(25); +-#ifdef CONFIG_TLB_PTLOCK +- pgd_lock = mfctl(28); +-#endif +- switch_mm_irqs_off(NULL, vma->vm_mm, NULL); +- local_irq_restore(flags); +- +- flush_user_dcache_range_asm(vmaddr, vmaddr + PAGE_SIZE); +- if (vma->vm_flags & VM_EXEC) +- flush_user_icache_range_asm(vmaddr, vmaddr + PAGE_SIZE); +- flush_tlb_page(vma, vmaddr); ++static void flush_kernel_icache_page_addr(const void *addr) ++{ ++ unsigned long vaddr = (unsigned long)addr; ++ unsigned long flags; + +- /* Restore previous context */ +- local_irq_save(flags); +-#ifdef CONFIG_TLB_PTLOCK +- mtctl(pgd_lock, 28); +-#endif +- mtctl(pgd, 25); +- mtsp(space, SR_USER); +- mtctl(prot, 8); +- local_irq_restore(flags); ++ /* Purge TLB entry to remove translation on all CPUs */ ++ purge_tlb_start(flags); ++ pdtlb(SR_KERNEL, addr); ++ purge_tlb_end(flags); + ++ /* Use tmpalias flush to prevent instruction cache move-in */ ++ preempt_disable(); ++ flush_icache_page_asm(__pa(vaddr), vaddr); + preempt_enable(); + } + ++void kunmap_flush_on_unmap(const void *addr) ++{ ++ flush_kernel_dcache_page_addr(addr); ++} ++EXPORT_SYMBOL(kunmap_flush_on_unmap); ++ + void flush_icache_pages(struct vm_area_struct *vma, struct page *page, + unsigned int nr) + { +@@ -371,13 +393,16 @@ void flush_icache_pages(struct vm_area_struct *vma, struct page *page, + + for (;;) { + flush_kernel_dcache_page_addr(kaddr); +- flush_kernel_icache_page(kaddr); ++ flush_kernel_icache_page_addr(kaddr); + if (--nr == 0) + break; + kaddr += PAGE_SIZE; + } + } + ++/* ++ * Walk page directory for MM to find PTEP pointer for address ADDR. ++ */ + static inline pte_t *get_ptep(struct mm_struct *mm, unsigned long addr) + { + pte_t *ptep = NULL; +@@ -406,6 +431,41 @@ static inline bool pte_needs_flush(pte_t pte) + == (_PAGE_PRESENT | _PAGE_ACCESSED); + } + ++/* ++ * Return user physical address. Returns 0 if page is not present. ++ */ ++static inline unsigned long get_upa(struct mm_struct *mm, unsigned long addr) ++{ ++ unsigned long flags, space, pgd, prot, pa; ++#ifdef CONFIG_TLB_PTLOCK ++ unsigned long pgd_lock; ++#endif ++ ++ /* Save context */ ++ local_irq_save(flags); ++ prot = mfctl(8); ++ space = mfsp(SR_USER); ++ pgd = mfctl(25); ++#ifdef CONFIG_TLB_PTLOCK ++ pgd_lock = mfctl(28); ++#endif ++ ++ /* Set context for lpa_user */ ++ switch_mm_irqs_off(NULL, mm, NULL); ++ pa = lpa_user(addr); ++ ++ /* Restore previous context */ ++#ifdef CONFIG_TLB_PTLOCK ++ mtctl(pgd_lock, 28); ++#endif ++ mtctl(pgd, 25); ++ mtsp(space, SR_USER); ++ mtctl(prot, 8); ++ local_irq_restore(flags); ++ ++ return pa; ++} ++ + void flush_dcache_folio(struct folio *folio) + { + struct address_space *mapping = folio_flush_mapping(folio); +@@ -454,50 +514,23 @@ void flush_dcache_folio(struct folio *folio) + if (addr + nr * PAGE_SIZE > vma->vm_end) + nr = (vma->vm_end - addr) / PAGE_SIZE; + +- if (parisc_requires_coherency()) { +- for (i = 0; i < nr; i++) { +- pte_t *ptep = get_ptep(vma->vm_mm, +- addr + i * PAGE_SIZE); +- if (!ptep) +- continue; +- if (pte_needs_flush(*ptep)) +- flush_user_cache_page(vma, +- addr + i * PAGE_SIZE); +- /* Optimise accesses to the same table? */ +- pte_unmap(ptep); +- } +- } else { ++ if (old_addr == 0 || (old_addr & (SHM_COLOUR - 1)) ++ != (addr & (SHM_COLOUR - 1))) { ++ for (i = 0; i < nr; i++) ++ __flush_cache_page(vma, ++ addr + i * PAGE_SIZE, ++ (pfn + i) * PAGE_SIZE); + /* +- * The TLB is the engine of coherence on parisc: +- * The CPU is entitled to speculate any page +- * with a TLB mapping, so here we kill the +- * mapping then flush the page along a special +- * flush only alias mapping. This guarantees that +- * the page is no-longer in the cache for any +- * process and nor may it be speculatively read +- * in (until the user or kernel specifically +- * accesses it, of course) ++ * Software is allowed to have any number ++ * of private mappings to a page. + */ +- for (i = 0; i < nr; i++) +- flush_tlb_page(vma, addr + i * PAGE_SIZE); +- if (old_addr == 0 || (old_addr & (SHM_COLOUR - 1)) +- != (addr & (SHM_COLOUR - 1))) { +- for (i = 0; i < nr; i++) +- __flush_cache_page(vma, +- addr + i * PAGE_SIZE, +- (pfn + i) * PAGE_SIZE); +- /* +- * Software is allowed to have any number +- * of private mappings to a page. +- */ +- if (!(vma->vm_flags & VM_SHARED)) +- continue; +- if (old_addr) +- pr_err("INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %pD\n", +- old_addr, addr, vma->vm_file); +- if (nr == folio_nr_pages(folio)) +- old_addr = addr; +- } ++ if (!(vma->vm_flags & VM_SHARED)) ++ continue; ++ if (old_addr) ++ pr_err("INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %pD\n", ++ old_addr, addr, vma->vm_file); ++ if (nr == folio_nr_pages(folio)) ++ old_addr = addr; + } + WARN_ON(++count == 4096); + } +@@ -587,35 +620,28 @@ extern void purge_kernel_dcache_page_asm(unsigned long); + extern void clear_user_page_asm(void *, unsigned long); + extern void copy_user_page_asm(void *, void *, unsigned long); + +-void flush_kernel_dcache_page_addr(const void *addr) +-{ +- unsigned long flags; +- +- flush_kernel_dcache_page_asm(addr); +- purge_tlb_start(flags); +- pdtlb(SR_KERNEL, addr); +- purge_tlb_end(flags); +-} +-EXPORT_SYMBOL(flush_kernel_dcache_page_addr); +- + static void flush_cache_page_if_present(struct vm_area_struct *vma, +- unsigned long vmaddr, unsigned long pfn) ++ unsigned long vmaddr) + { ++#if CONFIG_FLUSH_PAGE_ACCESSED + bool needs_flush = false; +- pte_t *ptep; ++ pte_t *ptep, pte; + +- /* +- * The pte check is racy and sometimes the flush will trigger +- * a non-access TLB miss. Hopefully, the page has already been +- * flushed. +- */ + ptep = get_ptep(vma->vm_mm, vmaddr); + if (ptep) { +- needs_flush = pte_needs_flush(*ptep); ++ pte = ptep_get(ptep); ++ needs_flush = pte_needs_flush(pte); + pte_unmap(ptep); + } + if (needs_flush) +- flush_cache_page(vma, vmaddr, pfn); ++ __flush_cache_page(vma, vmaddr, PFN_PHYS(pte_pfn(pte))); ++#else ++ struct mm_struct *mm = vma->vm_mm; ++ unsigned long physaddr = get_upa(mm, vmaddr); ++ ++ if (physaddr) ++ __flush_cache_page(vma, vmaddr, PAGE_ALIGN_DOWN(physaddr)); ++#endif + } + + void copy_user_highpage(struct page *to, struct page *from, +@@ -625,7 +651,7 @@ void copy_user_highpage(struct page *to, struct page *from, + + kfrom = kmap_local_page(from); + kto = kmap_local_page(to); +- flush_cache_page_if_present(vma, vaddr, page_to_pfn(from)); ++ __flush_cache_page(vma, vaddr, PFN_PHYS(page_to_pfn(from))); + copy_page_asm(kto, kfrom); + kunmap_local(kto); + kunmap_local(kfrom); +@@ -634,16 +660,17 @@ void copy_user_highpage(struct page *to, struct page *from, + void copy_to_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long user_vaddr, void *dst, void *src, int len) + { +- flush_cache_page_if_present(vma, user_vaddr, page_to_pfn(page)); ++ __flush_cache_page(vma, user_vaddr, PFN_PHYS(page_to_pfn(page))); + memcpy(dst, src, len); +- flush_kernel_dcache_range_asm((unsigned long)dst, (unsigned long)dst + len); ++ flush_kernel_dcache_page_addr(PTR_PAGE_ALIGN_DOWN(dst)); + } + + void copy_from_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long user_vaddr, void *dst, void *src, int len) + { +- flush_cache_page_if_present(vma, user_vaddr, page_to_pfn(page)); ++ __flush_cache_page(vma, user_vaddr, PFN_PHYS(page_to_pfn(page))); + memcpy(dst, src, len); ++ flush_kernel_dcache_page_addr(PTR_PAGE_ALIGN_DOWN(src)); + } + + /* __flush_tlb_range() +@@ -677,32 +704,10 @@ int __flush_tlb_range(unsigned long sid, unsigned long start, + + static void flush_cache_pages(struct vm_area_struct *vma, unsigned long start, unsigned long end) + { +- unsigned long addr, pfn; +- pte_t *ptep; +- +- for (addr = start; addr < end; addr += PAGE_SIZE) { +- bool needs_flush = false; +- /* +- * The vma can contain pages that aren't present. Although +- * the pte search is expensive, we need the pte to find the +- * page pfn and to check whether the page should be flushed. +- */ +- ptep = get_ptep(vma->vm_mm, addr); +- if (ptep) { +- needs_flush = pte_needs_flush(*ptep); +- pfn = pte_pfn(*ptep); +- pte_unmap(ptep); +- } +- if (needs_flush) { +- if (parisc_requires_coherency()) { +- flush_user_cache_page(vma, addr); +- } else { +- if (WARN_ON(!pfn_valid(pfn))) +- return; +- __flush_cache_page(vma, addr, PFN_PHYS(pfn)); +- } +- } +- } ++ unsigned long addr; ++ ++ for (addr = start; addr < end; addr += PAGE_SIZE) ++ flush_cache_page_if_present(vma, addr); + } + + static inline unsigned long mm_total_size(struct mm_struct *mm) +@@ -753,21 +758,19 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned + if (WARN_ON(IS_ENABLED(CONFIG_SMP) && arch_irqs_disabled())) + return; + flush_tlb_range(vma, start, end); +- flush_cache_all(); ++ if (vma->vm_flags & VM_EXEC) ++ flush_cache_all(); ++ else ++ flush_data_cache(); + return; + } + +- flush_cache_pages(vma, start, end); ++ flush_cache_pages(vma, start & PAGE_MASK, end); + } + + void flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn) + { +- if (WARN_ON(!pfn_valid(pfn))) +- return; +- if (parisc_requires_coherency()) +- flush_user_cache_page(vma, vmaddr); +- else +- __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn)); ++ __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn)); + } + + void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr) +@@ -775,34 +778,133 @@ void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned lon + if (!PageAnon(page)) + return; + +- if (parisc_requires_coherency()) { +- if (vma->vm_flags & VM_SHARED) +- flush_data_cache(); +- else +- flush_user_cache_page(vma, vmaddr); ++ __flush_cache_page(vma, vmaddr, PFN_PHYS(page_to_pfn(page))); ++} ++ ++int ptep_clear_flush_young(struct vm_area_struct *vma, unsigned long addr, ++ pte_t *ptep) ++{ ++ pte_t pte = ptep_get(ptep); ++ ++ if (!pte_young(pte)) ++ return 0; ++ set_pte(ptep, pte_mkold(pte)); ++#if CONFIG_FLUSH_PAGE_ACCESSED ++ __flush_cache_page(vma, addr, PFN_PHYS(pte_pfn(pte))); ++#endif ++ return 1; ++} ++ ++/* ++ * After a PTE is cleared, we have no way to flush the cache for ++ * the physical page. On PA8800 and PA8900 processors, these lines ++ * can cause random cache corruption. Thus, we must flush the cache ++ * as well as the TLB when clearing a PTE that's valid. ++ */ ++pte_t ptep_clear_flush(struct vm_area_struct *vma, unsigned long addr, ++ pte_t *ptep) ++{ ++ struct mm_struct *mm = (vma)->vm_mm; ++ pte_t pte = ptep_get_and_clear(mm, addr, ptep); ++ unsigned long pfn = pte_pfn(pte); ++ ++ if (pfn_valid(pfn)) ++ __flush_cache_page(vma, addr, PFN_PHYS(pfn)); ++ else if (pte_accessible(mm, pte)) ++ flush_tlb_page(vma, addr); ++ ++ return pte; ++} ++ ++/* ++ * The physical address for pages in the ioremap case can be obtained ++ * from the vm_struct struct. I wasn't able to successfully handle the ++ * vmalloc and vmap cases. We have an array of struct page pointers in ++ * the uninitialized vmalloc case but the flush failed using page_to_pfn. ++ */ ++void flush_cache_vmap(unsigned long start, unsigned long end) ++{ ++ unsigned long addr, physaddr; ++ struct vm_struct *vm; ++ ++ /* Prevent cache move-in */ ++ flush_tlb_kernel_range(start, end); ++ ++ if (end - start >= parisc_cache_flush_threshold) { ++ flush_cache_all(); + return; + } + +- flush_tlb_page(vma, vmaddr); +- preempt_disable(); +- flush_dcache_page_asm(page_to_phys(page), vmaddr); +- preempt_enable(); ++ if (WARN_ON_ONCE(!is_vmalloc_addr((void *)start))) { ++ flush_cache_all(); ++ return; ++ } ++ ++ vm = find_vm_area((void *)start); ++ if (WARN_ON_ONCE(!vm)) { ++ flush_cache_all(); ++ return; ++ } ++ ++ /* The physical addresses of IOREMAP regions are contiguous */ ++ if (vm->flags & VM_IOREMAP) { ++ physaddr = vm->phys_addr; ++ for (addr = start; addr < end; addr += PAGE_SIZE) { ++ preempt_disable(); ++ flush_dcache_page_asm(physaddr, start); ++ flush_icache_page_asm(physaddr, start); ++ preempt_enable(); ++ physaddr += PAGE_SIZE; ++ } ++ return; ++ } ++ ++ flush_cache_all(); + } ++EXPORT_SYMBOL(flush_cache_vmap); + ++/* ++ * The vm_struct has been retired and the page table is set up. The ++ * last page in the range is a guard page. Its physical address can't ++ * be determined using lpa, so there is no way to flush the range ++ * using flush_dcache_page_asm. ++ */ ++void flush_cache_vunmap(unsigned long start, unsigned long end) ++{ ++ /* Prevent cache move-in */ ++ flush_tlb_kernel_range(start, end); ++ flush_data_cache(); ++} ++EXPORT_SYMBOL(flush_cache_vunmap); ++ ++/* ++ * On systems with PA8800/PA8900 processors, there is no way to flush ++ * a vmap range other than using the architected loop to flush the ++ * entire cache. The page directory is not set up, so we can't use ++ * fdc, etc. FDCE/FICE don't work to flush a portion of the cache. ++ * L2 is physically indexed but FDCE/FICE instructions in virtual ++ * mode output their virtual address on the core bus, not their ++ * real address. As a result, the L2 cache index formed from the ++ * virtual address will most likely not be the same as the L2 index ++ * formed from the real address. ++ */ + void flush_kernel_vmap_range(void *vaddr, int size) + { + unsigned long start = (unsigned long)vaddr; + unsigned long end = start + size; + +- if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && +- (unsigned long)size >= parisc_cache_flush_threshold) { +- flush_tlb_kernel_range(start, end); +- flush_data_cache(); ++ flush_tlb_kernel_range(start, end); ++ ++ if (!static_branch_likely(&parisc_has_dcache)) ++ return; ++ ++ /* If interrupts are disabled, we can only do local flush */ ++ if (WARN_ON(IS_ENABLED(CONFIG_SMP) && arch_irqs_disabled())) { ++ flush_data_cache_local(NULL); + return; + } + +- flush_kernel_dcache_range_asm(start, end); +- flush_tlb_kernel_range(start, end); ++ flush_data_cache(); + } + EXPORT_SYMBOL(flush_kernel_vmap_range); + +@@ -814,15 +916,18 @@ void invalidate_kernel_vmap_range(void *vaddr, int size) + /* Ensure DMA is complete */ + asm_syncdma(); + +- if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && +- (unsigned long)size >= parisc_cache_flush_threshold) { +- flush_tlb_kernel_range(start, end); +- flush_data_cache(); ++ flush_tlb_kernel_range(start, end); ++ ++ if (!static_branch_likely(&parisc_has_dcache)) ++ return; ++ ++ /* If interrupts are disabled, we can only do local flush */ ++ if (WARN_ON(IS_ENABLED(CONFIG_SMP) && arch_irqs_disabled())) { ++ flush_data_cache_local(NULL); + return; + } + +- purge_kernel_dcache_range_asm(start, end); +- flush_tlb_kernel_range(start, end); ++ flush_data_cache(); + } + EXPORT_SYMBOL(invalidate_kernel_vmap_range); + +@@ -850,7 +955,7 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes, + #endif + " fic,m %3(%4,%0)\n" + "2: sync\n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b, "%1") + : "+r" (start), "+r" (error) + : "r" (end), "r" (dcache_stride), "i" (SR_USER)); + } +@@ -865,7 +970,7 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes, + #endif + " fdc,m %3(%4,%0)\n" + "2: sync\n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b, "%1") + : "+r" (start), "+r" (error) + : "r" (end), "r" (icache_stride), "i" (SR_USER)); + } +diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c +index ed8b759480614b..8be4558ef33c0e 100644 +--- a/arch/parisc/kernel/drivers.c ++++ b/arch/parisc/kernel/drivers.c +@@ -1004,6 +1004,9 @@ static __init int qemu_print_iodc_data(struct device *lin_dev, void *data) + + pr_info("\n"); + ++ /* Prevent hung task messages when printing on serial console */ ++ cond_resched(); ++ + pr_info("#define HPA_%08lx_DESCRIPTION \"%s\"\n", + hpa, parisc_hardware_description(&dev->id)); + +diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S +index ae03b8679696e7..ea57bcc21dc5fe 100644 +--- a/arch/parisc/kernel/entry.S ++++ b/arch/parisc/kernel/entry.S +@@ -36,6 +36,24 @@ + .level 2.0 + #endif + ++/* ++ * We need seven instructions after a TLB insert for it to take effect. ++ * The PA8800/PA8900 processors are an exception and need 12 instructions. ++ * The RFI changes both IAOQ_Back and IAOQ_Front, so it counts as one. ++ */ ++#ifdef CONFIG_64BIT ++#define NUM_PIPELINE_INSNS 12 ++#else ++#define NUM_PIPELINE_INSNS 7 ++#endif ++ ++ /* Insert num nops */ ++ .macro insert_nops num ++ .rept \num ++ nop ++ .endr ++ .endm ++ + /* Get aligned page_table_lock address for this mm from cr28/tr4 */ + .macro get_ptl reg + mfctl %cr28,\reg +@@ -415,24 +433,20 @@ + 3: + .endm + +- /* Release page_table_lock without reloading lock address. +- We use an ordered store to ensure all prior accesses are +- performed prior to releasing the lock. */ +- .macro ptl_unlock0 spc,tmp,tmp2 ++ /* Release page_table_lock if for user space. We use an ordered ++ store to ensure all prior accesses are performed prior to ++ releasing the lock. Note stw may not be executed, so we ++ provide one extra nop when CONFIG_TLB_PTLOCK is defined. */ ++ .macro ptl_unlock spc,tmp,tmp2 + #ifdef CONFIG_TLB_PTLOCK +-98: ldi __ARCH_SPIN_LOCK_UNLOCKED_VAL, \tmp2 ++98: get_ptl \tmp ++ ldi __ARCH_SPIN_LOCK_UNLOCKED_VAL, \tmp2 + or,COND(=) %r0,\spc,%r0 + stw,ma \tmp2,0(\tmp) + 99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP) +-#endif +- .endm +- +- /* Release page_table_lock. */ +- .macro ptl_unlock1 spc,tmp,tmp2 +-#ifdef CONFIG_TLB_PTLOCK +-98: get_ptl \tmp +- ptl_unlock0 \spc,\tmp,\tmp2 +-99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP) ++ insert_nops NUM_PIPELINE_INSNS - 4 ++#else ++ insert_nops NUM_PIPELINE_INSNS - 1 + #endif + .endm + +@@ -461,13 +475,13 @@ + * to a CPU TLB 4k PFN (4k => 12 bits to shift) */ + #define PAGE_ADD_SHIFT (PAGE_SHIFT-12) + #define PAGE_ADD_HUGE_SHIFT (REAL_HPAGE_SHIFT-12) ++ #define PFN_START_BIT (63-ASM_PFN_PTE_SHIFT+(63-58)-PAGE_ADD_SHIFT) + + /* Drop prot bits and convert to page addr for iitlbt and idtlbt */ + .macro convert_for_tlb_insert20 pte,tmp + #ifdef CONFIG_HUGETLB_PAGE + copy \pte,\tmp +- extrd,u \tmp,(63-ASM_PFN_PTE_SHIFT)+(63-58)+PAGE_ADD_SHIFT,\ +- 64-PAGE_SHIFT-PAGE_ADD_SHIFT,\pte ++ extrd,u \tmp,PFN_START_BIT,PFN_START_BIT+1,\pte + + depdi _PAGE_SIZE_ENCODING_DEFAULT,63,\ + (63-58)+PAGE_ADD_SHIFT,\pte +@@ -475,8 +489,7 @@ + depdi _HUGE_PAGE_SIZE_ENCODING_DEFAULT,63,\ + (63-58)+PAGE_ADD_HUGE_SHIFT,\pte + #else /* Huge pages disabled */ +- extrd,u \pte,(63-ASM_PFN_PTE_SHIFT)+(63-58)+PAGE_ADD_SHIFT,\ +- 64-PAGE_SHIFT-PAGE_ADD_SHIFT,\pte ++ extrd,u \pte,PFN_START_BIT,PFN_START_BIT+1,\pte + depdi _PAGE_SIZE_ENCODING_DEFAULT,63,\ + (63-58)+PAGE_ADD_SHIFT,\pte + #endif +@@ -1038,8 +1051,7 @@ ENTRY_CFI(intr_save) /* for os_hpmc */ + STREG %r16, PT_ISR(%r29) + STREG %r17, PT_IOR(%r29) + +-#if 0 && defined(CONFIG_64BIT) +- /* Revisit when we have 64-bit code above 4Gb */ ++#if defined(CONFIG_64BIT) + b,n intr_save2 + + skip_save_ior: +@@ -1047,8 +1059,7 @@ skip_save_ior: + * need to adjust iasq/iaoq here in the same way we adjusted isr/ior + * above. + */ +- extrd,u,* %r8,PSW_W_BIT,1,%r1 +- cmpib,COND(=),n 1,%r1,intr_save2 ++ bb,COND(>=),n %r8,PSW_W_BIT,intr_save2 + LDREG PT_IASQ0(%r29), %r16 + LDREG PT_IAOQ0(%r29), %r17 + /* adjust iasq/iaoq */ +@@ -1124,7 +1135,7 @@ dtlb_miss_20w: + + idtlbt pte,prot + +- ptl_unlock1 spc,t0,t1 ++ ptl_unlock spc,t0,t1 + rfir + nop + +@@ -1133,6 +1144,7 @@ dtlb_check_alias_20w: + + idtlbt pte,prot + ++ insert_nops NUM_PIPELINE_INSNS - 1 + rfir + nop + +@@ -1150,7 +1162,7 @@ nadtlb_miss_20w: + + idtlbt pte,prot + +- ptl_unlock1 spc,t0,t1 ++ ptl_unlock spc,t0,t1 + rfir + nop + +@@ -1159,6 +1171,7 @@ nadtlb_check_alias_20w: + + idtlbt pte,prot + ++ insert_nops NUM_PIPELINE_INSNS - 1 + rfir + nop + +@@ -1184,7 +1197,7 @@ dtlb_miss_11: + + mtsp t1, %sr1 /* Restore sr1 */ + +- ptl_unlock1 spc,t0,t1 ++ ptl_unlock spc,t0,t1 + rfir + nop + +@@ -1194,6 +1207,7 @@ dtlb_check_alias_11: + idtlba pte,(va) + idtlbp prot,(va) + ++ insert_nops NUM_PIPELINE_INSNS - 1 + rfir + nop + +@@ -1217,7 +1231,7 @@ nadtlb_miss_11: + + mtsp t1, %sr1 /* Restore sr1 */ + +- ptl_unlock1 spc,t0,t1 ++ ptl_unlock spc,t0,t1 + rfir + nop + +@@ -1227,6 +1241,7 @@ nadtlb_check_alias_11: + idtlba pte,(va) + idtlbp prot,(va) + ++ insert_nops NUM_PIPELINE_INSNS - 1 + rfir + nop + +@@ -1246,7 +1261,7 @@ dtlb_miss_20: + + idtlbt pte,prot + +- ptl_unlock1 spc,t0,t1 ++ ptl_unlock spc,t0,t1 + rfir + nop + +@@ -1255,6 +1270,7 @@ dtlb_check_alias_20: + + idtlbt pte,prot + ++ insert_nops NUM_PIPELINE_INSNS - 1 + rfir + nop + +@@ -1274,7 +1290,7 @@ nadtlb_miss_20: + + idtlbt pte,prot + +- ptl_unlock1 spc,t0,t1 ++ ptl_unlock spc,t0,t1 + rfir + nop + +@@ -1283,6 +1299,7 @@ nadtlb_check_alias_20: + + idtlbt pte,prot + ++ insert_nops NUM_PIPELINE_INSNS - 1 + rfir + nop + +@@ -1319,7 +1336,7 @@ itlb_miss_20w: + + iitlbt pte,prot + +- ptl_unlock1 spc,t0,t1 ++ ptl_unlock spc,t0,t1 + rfir + nop + +@@ -1343,7 +1360,7 @@ naitlb_miss_20w: + + iitlbt pte,prot + +- ptl_unlock1 spc,t0,t1 ++ ptl_unlock spc,t0,t1 + rfir + nop + +@@ -1352,6 +1369,7 @@ naitlb_check_alias_20w: + + iitlbt pte,prot + ++ insert_nops NUM_PIPELINE_INSNS - 1 + rfir + nop + +@@ -1377,7 +1395,7 @@ itlb_miss_11: + + mtsp t1, %sr1 /* Restore sr1 */ + +- ptl_unlock1 spc,t0,t1 ++ ptl_unlock spc,t0,t1 + rfir + nop + +@@ -1401,7 +1419,7 @@ naitlb_miss_11: + + mtsp t1, %sr1 /* Restore sr1 */ + +- ptl_unlock1 spc,t0,t1 ++ ptl_unlock spc,t0,t1 + rfir + nop + +@@ -1411,6 +1429,7 @@ naitlb_check_alias_11: + iitlba pte,(%sr0, va) + iitlbp prot,(%sr0, va) + ++ insert_nops NUM_PIPELINE_INSNS - 1 + rfir + nop + +@@ -1431,7 +1450,7 @@ itlb_miss_20: + + iitlbt pte,prot + +- ptl_unlock1 spc,t0,t1 ++ ptl_unlock spc,t0,t1 + rfir + nop + +@@ -1451,7 +1470,7 @@ naitlb_miss_20: + + iitlbt pte,prot + +- ptl_unlock1 spc,t0,t1 ++ ptl_unlock spc,t0,t1 + rfir + nop + +@@ -1460,6 +1479,7 @@ naitlb_check_alias_20: + + iitlbt pte,prot + ++ insert_nops NUM_PIPELINE_INSNS - 1 + rfir + nop + +@@ -1481,7 +1501,7 @@ dbit_trap_20w: + + idtlbt pte,prot + +- ptl_unlock0 spc,t0,t1 ++ ptl_unlock spc,t0,t1 + rfir + nop + #else +@@ -1507,7 +1527,7 @@ dbit_trap_11: + + mtsp t1, %sr1 /* Restore sr1 */ + +- ptl_unlock0 spc,t0,t1 ++ ptl_unlock spc,t0,t1 + rfir + nop + +@@ -1527,7 +1547,7 @@ dbit_trap_20: + + idtlbt pte,prot + +- ptl_unlock0 spc,t0,t1 ++ ptl_unlock spc,t0,t1 + rfir + nop + #endif +diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c +index 81078abec521a7..56e694f6acc2d7 100644 +--- a/arch/parisc/kernel/firmware.c ++++ b/arch/parisc/kernel/firmware.c +@@ -123,10 +123,10 @@ static unsigned long f_extend(unsigned long address) + #ifdef CONFIG_64BIT + if(unlikely(parisc_narrow_firmware)) { + if((address & 0xff000000) == 0xf0000000) +- return 0xf0f0f0f000000000UL | (u32)address; ++ return (0xfffffff0UL << 32) | (u32)address; + + if((address & 0xf0000000) == 0xf0000000) +- return 0xffffffff00000000UL | (u32)address; ++ return (0xffffffffUL << 32) | (u32)address; + } + #endif + return address; +diff --git a/arch/parisc/kernel/ftrace.c b/arch/parisc/kernel/ftrace.c +index d1defb9ede70c0..c91f9c2e61ed25 100644 +--- a/arch/parisc/kernel/ftrace.c ++++ b/arch/parisc/kernel/ftrace.c +@@ -78,7 +78,7 @@ asmlinkage void notrace __hot ftrace_function_trampoline(unsigned long parent, + #endif + } + +-#ifdef CONFIG_FUNCTION_GRAPH_TRACER ++#if defined(CONFIG_DYNAMIC_FTRACE) && defined(CONFIG_FUNCTION_GRAPH_TRACER) + int ftrace_enable_ftrace_graph_caller(void) + { + static_key_enable(&ftrace_graph_enable.key); +@@ -206,6 +206,9 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, + struct kprobe *p; + int bit; + ++ if (unlikely(kprobe_ftrace_disabled)) ++ return; ++ + bit = ftrace_test_recursion_trylock(ip, parent_ip); + if (bit < 0) + return; +diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S +index a171bf3c6b318d..96e0264ac96163 100644 +--- a/arch/parisc/kernel/head.S ++++ b/arch/parisc/kernel/head.S +@@ -70,9 +70,8 @@ $bss_loop: + stw,ma %arg2,4(%r1) + stw,ma %arg3,4(%r1) + +-#if !defined(CONFIG_64BIT) && defined(CONFIG_PA20) +- /* This 32-bit kernel was compiled for PA2.0 CPUs. Check current CPU +- * and halt kernel if we detect a PA1.x CPU. */ ++#if defined(CONFIG_PA20) ++ /* check for 64-bit capable CPU as required by current kernel */ + ldi 32,%r10 + mtctl %r10,%cr11 + .level 2.0 +diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c +index 2f81bfd4f15e17..dff66be65d2900 100644 +--- a/arch/parisc/kernel/irq.c ++++ b/arch/parisc/kernel/irq.c +@@ -498,7 +498,7 @@ asmlinkage void do_cpu_irq_mask(struct pt_regs *regs) + + old_regs = set_irq_regs(regs); + local_irq_disable(); +- irq_enter(); ++ irq_enter_rcu(); + + eirr_val = mfctl(23) & cpu_eiem & per_cpu(local_ack_eiem, cpu); + if (!eirr_val) +@@ -533,7 +533,7 @@ asmlinkage void do_cpu_irq_mask(struct pt_regs *regs) + #endif /* CONFIG_IRQSTACKS */ + + out: +- irq_exit(); ++ irq_exit_rcu(); + set_irq_regs(old_regs); + return; + +diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c +index 6f0c92e8149d82..dcf61cbd314708 100644 +--- a/arch/parisc/kernel/parisc_ksyms.c ++++ b/arch/parisc/kernel/parisc_ksyms.c +@@ -22,6 +22,7 @@ EXPORT_SYMBOL(memset); + #include + EXPORT_SYMBOL(__xchg8); + EXPORT_SYMBOL(__xchg32); ++EXPORT_SYMBOL(__cmpxchg_u8); + EXPORT_SYMBOL(__cmpxchg_u32); + EXPORT_SYMBOL(__cmpxchg_u64); + #ifdef CONFIG_SMP +diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c +index 1fc89fa2c2d214..e37c48770b5854 100644 +--- a/arch/parisc/kernel/processor.c ++++ b/arch/parisc/kernel/processor.c +@@ -172,7 +172,6 @@ static int __init processor_probe(struct parisc_device *dev) + p->cpu_num = cpu_info.cpu_num; + p->cpu_loc = cpu_info.cpu_loc; + +- set_cpu_possible(cpuid, true); + store_cpu_topology(cpuid); + + #ifdef CONFIG_SMP +@@ -474,13 +473,6 @@ static struct parisc_driver cpu_driver __refdata = { + */ + void __init processor_init(void) + { +- unsigned int cpu; +- + reset_cpu_topology(); +- +- /* reset possible mask. We will mark those which are possible. */ +- for_each_possible_cpu(cpu) +- set_cpu_possible(cpu, false); +- + register_parisc_driver(&cpu_driver); + } +diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c +index ab896eff7a1de9..98af719d5f85b2 100644 +--- a/arch/parisc/kernel/sys_parisc.c ++++ b/arch/parisc/kernel/sys_parisc.c +@@ -77,7 +77,7 @@ unsigned long calc_max_stack_size(unsigned long stack_max) + * indicating that "current" should be used instead of a passed-in + * value from the exec bprm as done with arch_pick_mmap_layout(). + */ +-static unsigned long mmap_upper_limit(struct rlimit *rlim_stack) ++unsigned long mmap_upper_limit(struct rlimit *rlim_stack) + { + unsigned long stack_base; + +diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c +index 2a12a547b447bd..826c8e51b5853b 100644 +--- a/arch/parisc/kernel/sys_parisc32.c ++++ b/arch/parisc/kernel/sys_parisc32.c +@@ -23,12 +23,3 @@ asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23, + current->comm, current->pid, r20); + return -ENOSYS; + } +- +-asmlinkage long sys32_fanotify_mark(compat_int_t fanotify_fd, compat_uint_t flags, +- compat_uint_t mask0, compat_uint_t mask1, compat_int_t dfd, +- const char __user * pathname) +-{ +- return sys_fanotify_mark(fanotify_fd, flags, +- ((__u64)mask1 << 32) | mask0, +- dfd, pathname); +-} +diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S +index 1f51aa9c8230cc..0fa81bf1466b15 100644 +--- a/arch/parisc/kernel/syscall.S ++++ b/arch/parisc/kernel/syscall.S +@@ -243,10 +243,10 @@ linux_gateway_entry: + + #ifdef CONFIG_64BIT + ldil L%sys_call_table, %r1 +- or,= %r2,%r2,%r2 +- addil L%(sys_call_table64-sys_call_table), %r1 ++ or,ev %r2,%r2,%r2 ++ ldil L%sys_call_table64, %r1 + ldo R%sys_call_table(%r1), %r19 +- or,= %r2,%r2,%r2 ++ or,ev %r2,%r2,%r2 + ldo R%sys_call_table64(%r1), %r19 + #else + load32 sys_call_table, %r19 +@@ -379,10 +379,10 @@ tracesys_next: + extrd,u %r19,63,1,%r2 /* W hidden in bottom bit */ + + ldil L%sys_call_table, %r1 +- or,= %r2,%r2,%r2 +- addil L%(sys_call_table64-sys_call_table), %r1 ++ or,ev %r2,%r2,%r2 ++ ldil L%sys_call_table64, %r1 + ldo R%sys_call_table(%r1), %r19 +- or,= %r2,%r2,%r2 ++ or,ev %r2,%r2,%r2 + ldo R%sys_call_table64(%r1), %r19 + #else + load32 sys_call_table, %r19 +@@ -1327,6 +1327,8 @@ ENTRY(sys_call_table) + END(sys_call_table) + + #ifdef CONFIG_64BIT ++#undef __SYSCALL_WITH_COMPAT ++#define __SYSCALL_WITH_COMPAT(nr, native, compat) __SYSCALL(nr, native) + .align 8 + ENTRY(sys_call_table64) + #include /* 64-bit syscalls */ +diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl +index e97c175b56f965..73f560e309573a 100644 +--- a/arch/parisc/kernel/syscalls/syscall.tbl ++++ b/arch/parisc/kernel/syscalls/syscall.tbl +@@ -108,7 +108,7 @@ + 95 common fchown sys_fchown + 96 common getpriority sys_getpriority + 97 common setpriority sys_setpriority +-98 common recv sys_recv ++98 common recv sys_recv compat_sys_recv + 99 common statfs sys_statfs compat_sys_statfs + 100 common fstatfs sys_fstatfs compat_sys_fstatfs + 101 common stat64 sys_stat64 +@@ -135,7 +135,7 @@ + 120 common clone sys_clone_wrapper + 121 common setdomainname sys_setdomainname + 122 common sendfile sys_sendfile compat_sys_sendfile +-123 common recvfrom sys_recvfrom ++123 common recvfrom sys_recvfrom compat_sys_recvfrom + 124 32 adjtimex sys_adjtimex_time32 + 124 64 adjtimex sys_adjtimex + 125 common mprotect sys_mprotect +@@ -364,7 +364,7 @@ + 320 common accept4 sys_accept4 + 321 common prlimit64 sys_prlimit64 + 322 common fanotify_init sys_fanotify_init +-323 common fanotify_mark sys_fanotify_mark sys32_fanotify_mark ++323 common fanotify_mark sys_fanotify_mark compat_sys_fanotify_mark + 324 32 clock_adjtime sys_clock_adjtime32 + 324 64 clock_adjtime sys_clock_adjtime + 325 common name_to_handle_at sys_name_to_handle_at +diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c +index ce25acfe4889d0..a8e75e5b884a70 100644 +--- a/arch/parisc/kernel/unaligned.c ++++ b/arch/parisc/kernel/unaligned.c +@@ -120,8 +120,8 @@ static int emulate_ldh(struct pt_regs *regs, int toreg) + "2: ldbs 1(%%sr1,%3), %0\n" + " depw %2, 23, 24, %0\n" + "3: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") + : "+r" (val), "+r" (ret), "=&r" (temp1) + : "r" (saddr), "r" (regs->isr) ); + +@@ -152,8 +152,8 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop) + " mtctl %2,11\n" + " vshd %0,%3,%0\n" + "3: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") + : "+r" (val), "+r" (ret), "=&r" (temp1), "=&r" (temp2) + : "r" (saddr), "r" (regs->isr) ); + +@@ -169,6 +169,7 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop) + static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) + { + unsigned long saddr = regs->ior; ++ unsigned long shift, temp1; + __u64 val = 0; + ASM_EXCEPTIONTABLE_VAR(ret); + +@@ -180,25 +181,22 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) + + #ifdef CONFIG_64BIT + __asm__ __volatile__ ( +-" depd,z %3,60,3,%%r19\n" /* r19=(ofs&7)*8 */ +-" mtsp %4, %%sr1\n" +-" depd %%r0,63,3,%3\n" +-"1: ldd 0(%%sr1,%3),%0\n" +-"2: ldd 8(%%sr1,%3),%%r20\n" +-" subi 64,%%r19,%%r19\n" +-" mtsar %%r19\n" +-" shrpd %0,%%r20,%%sar,%0\n" ++" depd,z %2,60,3,%3\n" /* shift=(ofs&7)*8 */ ++" mtsp %5, %%sr1\n" ++" depd %%r0,63,3,%2\n" ++"1: ldd 0(%%sr1,%2),%0\n" ++"2: ldd 8(%%sr1,%2),%4\n" ++" subi 64,%3,%3\n" ++" mtsar %3\n" ++" shrpd %0,%4,%%sar,%0\n" + "3: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) +- : "=r" (val), "+r" (ret) +- : "0" (val), "r" (saddr), "r" (regs->isr) +- : "r19", "r20" ); ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") ++ : "+r" (val), "+r" (ret), "+r" (saddr), "=&r" (shift), "=&r" (temp1) ++ : "r" (regs->isr) ); + #else +- { +- unsigned long shift, temp1; + __asm__ __volatile__ ( +-" zdep %2,29,2,%3\n" /* r19=(ofs&3)*8 */ ++" zdep %2,29,2,%3\n" /* shift=(ofs&3)*8 */ + " mtsp %5, %%sr1\n" + " dep %%r0,31,2,%2\n" + "1: ldw 0(%%sr1,%2),%0\n" +@@ -209,12 +207,11 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) + " vshd %0,%R0,%0\n" + " vshd %R0,%4,%R0\n" + "4: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 4b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 4b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 4b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 4b, "%1") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 4b, "%1") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 4b, "%1") + : "+r" (val), "+r" (ret), "+r" (saddr), "=&r" (shift), "=&r" (temp1) + : "r" (regs->isr) ); +- } + #endif + + DPRINTF("val = 0x%llx\n", val); +@@ -244,8 +241,8 @@ static int emulate_sth(struct pt_regs *regs, int frreg) + "1: stb %1, 0(%%sr1, %3)\n" + "2: stb %2, 1(%%sr1, %3)\n" + "3: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%0") + : "+r" (ret), "=&r" (temp1) + : "r" (val), "r" (regs->ior), "r" (regs->isr) ); + +@@ -285,8 +282,8 @@ static int emulate_stw(struct pt_regs *regs, int frreg, int flop) + " stw %%r20,0(%%sr1,%2)\n" + " stw %%r21,4(%%sr1,%2)\n" + "3: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%0") + : "+r" (ret) + : "r" (val), "r" (regs->ior), "r" (regs->isr) + : "r19", "r20", "r21", "r22", "r1" ); +@@ -329,10 +326,10 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop) + "3: std %%r20,0(%%sr1,%2)\n" + "4: std %%r21,8(%%sr1,%2)\n" + "5: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 5b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 5b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 5b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 5b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 5b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 5b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 5b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 5b, "%0") + : "+r" (ret) + : "r" (val), "r" (regs->ior), "r" (regs->isr) + : "r19", "r20", "r21", "r22", "r1" ); +@@ -357,11 +354,11 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop) + "4: stw %%r1,4(%%sr1,%2)\n" + "5: stw %R1,8(%%sr1,%2)\n" + "6: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 6b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 6b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 6b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 6b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(5b, 6b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 6b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 6b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 6b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 6b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(5b, 6b, "%0") + : "+r" (ret) + : "r" (val), "r" (regs->ior), "r" (regs->isr) + : "r19", "r20", "r21", "r1" ); +diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c +index 27ae40a443b80c..f7e0fee5ee55a3 100644 +--- a/arch/parisc/kernel/unwind.c ++++ b/arch/parisc/kernel/unwind.c +@@ -228,10 +228,8 @@ static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int + #ifdef CONFIG_IRQSTACKS + extern void * const _call_on_stack; + #endif /* CONFIG_IRQSTACKS */ +- void *ptr; + +- ptr = dereference_kernel_function_descriptor(&handle_interruption); +- if (pc_is_kernel_fn(pc, ptr)) { ++ if (pc_is_kernel_fn(pc, handle_interruption)) { + struct pt_regs *regs = (struct pt_regs *)(info->sp - frame_size - PT_SZ_ALGN); + dbg("Unwinding through handle_interruption()\n"); + info->prev_sp = regs->gr[30]; +@@ -239,13 +237,13 @@ static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int + return 1; + } + +- if (pc_is_kernel_fn(pc, ret_from_kernel_thread) || +- pc_is_kernel_fn(pc, syscall_exit)) { ++ if (pc == (unsigned long)&ret_from_kernel_thread || ++ pc == (unsigned long)&syscall_exit) { + info->prev_sp = info->prev_ip = 0; + return 1; + } + +- if (pc_is_kernel_fn(pc, intr_return)) { ++ if (pc == (unsigned long)&intr_return) { + struct pt_regs *regs; + + dbg("Found intr_return()\n"); +@@ -257,14 +255,14 @@ static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int + } + + if (pc_is_kernel_fn(pc, _switch_to) || +- pc_is_kernel_fn(pc, _switch_to_ret)) { ++ pc == (unsigned long)&_switch_to_ret) { + info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE; + info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET); + return 1; + } + + #ifdef CONFIG_IRQSTACKS +- if (pc_is_kernel_fn(pc, _call_on_stack)) { ++ if (pc == (unsigned long)&_call_on_stack) { + info->prev_sp = *(unsigned long *)(info->sp - FRAME_SIZE - REG_SZ); + info->prev_ip = *(unsigned long *)(info->sp - FRAME_SIZE - RP_OFFSET); + return 1; +diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S +index 58694d1989c233..548051b0b4aff6 100644 +--- a/arch/parisc/kernel/vmlinux.lds.S ++++ b/arch/parisc/kernel/vmlinux.lds.S +@@ -130,6 +130,7 @@ SECTIONS + RO_DATA(8) + + /* unwind info */ ++ . = ALIGN(4); + .PARISC.unwind : { + __start___unwind = .; + *(.PARISC.unwind) +diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c +index 2fe5b44986e092..c39de84e98b051 100644 +--- a/arch/parisc/mm/fault.c ++++ b/arch/parisc/mm/fault.c +@@ -150,11 +150,16 @@ int fixup_exception(struct pt_regs *regs) + * Fix up get_user() and put_user(). + * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() sets the least-significant + * bit in the relative address of the fixup routine to indicate +- * that gr[ASM_EXCEPTIONTABLE_REG] should be loaded with +- * -EFAULT to report a userspace access error. ++ * that the register encoded in the "or %r0,%r0,register" ++ * opcode should be loaded with -EFAULT to report a userspace ++ * access error. + */ + if (fix->fixup & 1) { +- regs->gr[ASM_EXCEPTIONTABLE_REG] = -EFAULT; ++ int fault_error_reg = fix->err_opcode & 0x1f; ++ if (!WARN_ON(!fault_error_reg)) ++ regs->gr[fault_error_reg] = -EFAULT; ++ pr_debug("Unalignment fixup of register %d at %pS\n", ++ fault_error_reg, (void*)regs->iaoq[0]); + + /* zero target register for get_user() */ + if (parisc_acctyp(0, regs->iir) == VM_READ) { +diff --git a/arch/parisc/net/bpf_jit_core.c b/arch/parisc/net/bpf_jit_core.c +index d6ee2fd4555037..7b9cb3cda27eeb 100644 +--- a/arch/parisc/net/bpf_jit_core.c ++++ b/arch/parisc/net/bpf_jit_core.c +@@ -114,7 +114,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) + jit_data->header = + bpf_jit_binary_alloc(prog_size + extable_size, + &jit_data->image, +- sizeof(u32), ++ sizeof(long), + bpf_fill_ill_insns); + if (!jit_data->header) { + prog = orig_prog; +diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig +index d5d5388973ac76..2fe51e0ad63713 100644 +--- a/arch/powerpc/Kconfig ++++ b/arch/powerpc/Kconfig +@@ -607,10 +607,10 @@ config ARCH_SUPPORTS_KEXEC + def_bool PPC_BOOK3S || PPC_E500 || (44x && !SMP) + + config ARCH_SUPPORTS_KEXEC_FILE +- def_bool PPC64 && CRYPTO=y && CRYPTO_SHA256=y ++ def_bool PPC64 + + config ARCH_SUPPORTS_KEXEC_PURGATORY +- def_bool KEXEC_FILE ++ def_bool y + + config ARCH_SELECTS_KEXEC_FILE + def_bool y +@@ -857,6 +857,7 @@ config THREAD_SHIFT + int "Thread shift" if EXPERT + range 13 15 + default "15" if PPC_256K_PAGES ++ default "15" if PPC_PSERIES || PPC_POWERNV + default "14" if PPC64 + default "13" + help +diff --git a/arch/powerpc/boot/simple_alloc.c b/arch/powerpc/boot/simple_alloc.c +index 267d6524caac47..d07796fdf91aa7 100644 +--- a/arch/powerpc/boot/simple_alloc.c ++++ b/arch/powerpc/boot/simple_alloc.c +@@ -112,8 +112,11 @@ static void *simple_realloc(void *ptr, unsigned long size) + return ptr; + + new = simple_malloc(size); +- memcpy(new, ptr, p->size); +- simple_free(ptr); ++ if (new) { ++ memcpy(new, ptr, p->size); ++ simple_free(ptr); ++ } ++ + return new; + } + +diff --git a/arch/powerpc/configs/85xx-hw.config b/arch/powerpc/configs/85xx-hw.config +index 524db76f47b737..8aff8321739778 100644 +--- a/arch/powerpc/configs/85xx-hw.config ++++ b/arch/powerpc/configs/85xx-hw.config +@@ -24,6 +24,7 @@ CONFIG_FS_ENET=y + CONFIG_FSL_CORENET_CF=y + CONFIG_FSL_DMA=y + CONFIG_FSL_HV_MANAGER=y ++CONFIG_FSL_IFC=y + CONFIG_FSL_PQ_MDIO=y + CONFIG_FSL_RIO=y + CONFIG_FSL_XGMAC_MDIO=y +@@ -58,6 +59,7 @@ CONFIG_INPUT_FF_MEMLESS=m + CONFIG_MARVELL_PHY=y + CONFIG_MDIO_BUS_MUX_GPIO=y + CONFIG_MDIO_BUS_MUX_MMIOREG=y ++CONFIG_MEMORY=y + CONFIG_MMC_SDHCI_OF_ESDHC=y + CONFIG_MMC_SDHCI_PLTFM=y + CONFIG_MMC_SDHCI=y +diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig +index 6e7b9e8fd2251a..65e518dde2c2fe 100644 +--- a/arch/powerpc/configs/ppc64_defconfig ++++ b/arch/powerpc/configs/ppc64_defconfig +@@ -81,7 +81,6 @@ CONFIG_MODULE_SIG_SHA512=y + CONFIG_PARTITION_ADVANCED=y + CONFIG_BINFMT_MISC=m + CONFIG_ZSWAP=y +-CONFIG_Z3FOLD=y + CONFIG_ZSMALLOC=y + # CONFIG_SLAB_MERGE_DEFAULT is not set + CONFIG_SLAB_FREELIST_RANDOM=y +diff --git a/arch/powerpc/configs/skiroot_defconfig b/arch/powerpc/configs/skiroot_defconfig +index 8d3eacb50d5601..9d44e6630908d2 100644 +--- a/arch/powerpc/configs/skiroot_defconfig ++++ b/arch/powerpc/configs/skiroot_defconfig +@@ -301,7 +301,6 @@ CONFIG_WQ_WATCHDOG=y + CONFIG_DEBUG_SG=y + CONFIG_DEBUG_NOTIFIERS=y + CONFIG_BUG_ON_DATA_CORRUPTION=y +-CONFIG_DEBUG_CREDENTIALS=y + # CONFIG_FTRACE is not set + CONFIG_XMON=y + # CONFIG_RUNTIME_TESTING_MENU is not set +diff --git a/arch/powerpc/crypto/Kconfig b/arch/powerpc/crypto/Kconfig +index 6fc2248ca56166..fccf742c55c2c3 100644 +--- a/arch/powerpc/crypto/Kconfig ++++ b/arch/powerpc/crypto/Kconfig +@@ -96,6 +96,7 @@ config CRYPTO_AES_PPC_SPE + + config CRYPTO_AES_GCM_P10 + tristate "Stitched AES/GCM acceleration support on P10 or later CPU (PPC)" ++ depends on BROKEN + depends on PPC64 && CPU_LITTLE_ENDIAN && VSX + select CRYPTO_LIB_AES + select CRYPTO_ALGAPI +diff --git a/arch/powerpc/crypto/aes-gcm-p10-glue.c b/arch/powerpc/crypto/aes-gcm-p10-glue.c +index 4b6e899895e7be..f62ee54076c06d 100644 +--- a/arch/powerpc/crypto/aes-gcm-p10-glue.c ++++ b/arch/powerpc/crypto/aes-gcm-p10-glue.c +@@ -37,7 +37,7 @@ asmlinkage void aes_p10_gcm_encrypt(u8 *in, u8 *out, size_t len, + void *rkey, u8 *iv, void *Xi); + asmlinkage void aes_p10_gcm_decrypt(u8 *in, u8 *out, size_t len, + void *rkey, u8 *iv, void *Xi); +-asmlinkage void gcm_init_htable(unsigned char htable[256], unsigned char Xi[16]); ++asmlinkage void gcm_init_htable(unsigned char htable[], unsigned char Xi[]); + asmlinkage void gcm_ghash_p10(unsigned char *Xi, unsigned char *Htable, + unsigned char *aad, unsigned int alen); + +diff --git a/arch/powerpc/crypto/chacha-p10-glue.c b/arch/powerpc/crypto/chacha-p10-glue.c +index 74fb86b0d2097c..7c728755852e1a 100644 +--- a/arch/powerpc/crypto/chacha-p10-glue.c ++++ b/arch/powerpc/crypto/chacha-p10-glue.c +@@ -197,6 +197,9 @@ static struct skcipher_alg algs[] = { + + static int __init chacha_p10_init(void) + { ++ if (!cpu_has_feature(CPU_FTR_ARCH_31)) ++ return 0; ++ + static_branch_enable(&have_p10); + + return crypto_register_skciphers(algs, ARRAY_SIZE(algs)); +@@ -204,10 +207,13 @@ static int __init chacha_p10_init(void) + + static void __exit chacha_p10_exit(void) + { ++ if (!static_branch_likely(&have_p10)) ++ return; ++ + crypto_unregister_skciphers(algs, ARRAY_SIZE(algs)); + } + +-module_cpu_feature_match(PPC_MODULE_FEATURE_P10, chacha_p10_init); ++module_init(chacha_p10_init); + module_exit(chacha_p10_exit); + + MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (P10 accelerated)"); +diff --git a/arch/powerpc/include/asm/asm-compat.h b/arch/powerpc/include/asm/asm-compat.h +index 2bc53c646ccd7d..83848b534cb171 100644 +--- a/arch/powerpc/include/asm/asm-compat.h ++++ b/arch/powerpc/include/asm/asm-compat.h +@@ -39,6 +39,12 @@ + #define STDX_BE stringify_in_c(stdbrx) + #endif + ++#ifdef CONFIG_CC_IS_CLANG ++#define DS_FORM_CONSTRAINT "Z<>" ++#else ++#define DS_FORM_CONSTRAINT "YZ<>" ++#endif ++ + #else /* 32-bit */ + + /* operations for longs and pointers */ +diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h +index 5bf6a4d49268c7..d1ea554c33ed7e 100644 +--- a/arch/powerpc/include/asm/atomic.h ++++ b/arch/powerpc/include/asm/atomic.h +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + /* + * Since *_return_relaxed and {cmp}xchg_relaxed are implemented with +@@ -197,7 +198,7 @@ static __inline__ s64 arch_atomic64_read(const atomic64_t *v) + if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED)) + __asm__ __volatile__("ld %0,0(%1)" : "=r"(t) : "b"(&v->counter)); + else +- __asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m<>"(v->counter)); ++ __asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : DS_FORM_CONSTRAINT (v->counter)); + + return t; + } +@@ -208,7 +209,7 @@ static __inline__ void arch_atomic64_set(atomic64_t *v, s64 i) + if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED)) + __asm__ __volatile__("std %1,0(%2)" : "=m"(v->counter) : "r"(i), "b"(&v->counter)); + else +- __asm__ __volatile__("std%U0%X0 %1,%0" : "=m<>"(v->counter) : "r"(i)); ++ __asm__ __volatile__("std%U0%X0 %1,%0" : "=" DS_FORM_CONSTRAINT (v->counter) : "r"(i)); + } + + #define ATOMIC64_OP(op, asm_op) \ +diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h +index 9e5a39b6a3114b..107fc5a4845696 100644 +--- a/arch/powerpc/include/asm/ftrace.h ++++ b/arch/powerpc/include/asm/ftrace.h +@@ -20,14 +20,6 @@ + #ifndef __ASSEMBLY__ + extern void _mcount(void); + +-static inline unsigned long ftrace_call_adjust(unsigned long addr) +-{ +- if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY)) +- addr += MCOUNT_INSN_SIZE; +- +- return addr; +-} +- + unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip, + unsigned long sp); + +@@ -142,8 +134,10 @@ static inline u8 this_cpu_get_ftrace_enabled(void) { return 1; } + #ifdef CONFIG_FUNCTION_TRACER + extern unsigned int ftrace_tramp_text[], ftrace_tramp_init[]; + void ftrace_free_init_tramp(void); ++unsigned long ftrace_call_adjust(unsigned long addr); + #else + static inline void ftrace_free_init_tramp(void) { } ++static inline unsigned long ftrace_call_adjust(unsigned long addr) { return addr; } + #endif + #endif /* !__ASSEMBLY__ */ + +diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h +index c099780385dd3d..218488407ac00e 100644 +--- a/arch/powerpc/include/asm/hvcall.h ++++ b/arch/powerpc/include/asm/hvcall.h +@@ -494,7 +494,7 @@ long plpar_hcall_norets_notrace(unsigned long opcode, ...); + * Used for all but the craziest of phyp interfaces (see plpar_hcall9) + */ + #define PLPAR_HCALL_BUFSIZE 4 +-long plpar_hcall(unsigned long opcode, unsigned long *retbuf, ...); ++long plpar_hcall(unsigned long opcode, unsigned long retbuf[static PLPAR_HCALL_BUFSIZE], ...); + + /** + * plpar_hcall_raw: - Make a hypervisor call without calculating hcall stats +@@ -508,7 +508,7 @@ long plpar_hcall(unsigned long opcode, unsigned long *retbuf, ...); + * plpar_hcall, but plpar_hcall_raw works in real mode and does not + * calculate hypervisor call statistics. + */ +-long plpar_hcall_raw(unsigned long opcode, unsigned long *retbuf, ...); ++long plpar_hcall_raw(unsigned long opcode, unsigned long retbuf[static PLPAR_HCALL_BUFSIZE], ...); + + /** + * plpar_hcall9: - Make a pseries hypervisor call with up to 9 return arguments +@@ -519,8 +519,8 @@ long plpar_hcall_raw(unsigned long opcode, unsigned long *retbuf, ...); + * PLPAR_HCALL9_BUFSIZE to size the return argument buffer. + */ + #define PLPAR_HCALL9_BUFSIZE 9 +-long plpar_hcall9(unsigned long opcode, unsigned long *retbuf, ...); +-long plpar_hcall9_raw(unsigned long opcode, unsigned long *retbuf, ...); ++long plpar_hcall9(unsigned long opcode, unsigned long retbuf[static PLPAR_HCALL9_BUFSIZE], ...); ++long plpar_hcall9_raw(unsigned long opcode, unsigned long retbuf[static PLPAR_HCALL9_BUFSIZE], ...); + + /* pseries hcall tracing */ + extern struct static_key hcall_tracepoint_key; +@@ -540,7 +540,7 @@ struct hvcall_mpp_data { + unsigned long backing_mem; + }; + +-int h_get_mpp(struct hvcall_mpp_data *); ++long h_get_mpp(struct hvcall_mpp_data *mpp_data); + + struct hvcall_mpp_x_data { + unsigned long coalesced_bytes; +diff --git a/arch/powerpc/include/asm/interrupt.h b/arch/powerpc/include/asm/interrupt.h +index a4196ab1d0167c..5f9d61b2159cc5 100644 +--- a/arch/powerpc/include/asm/interrupt.h ++++ b/arch/powerpc/include/asm/interrupt.h +@@ -336,6 +336,14 @@ static inline void interrupt_nmi_enter_prepare(struct pt_regs *regs, struct inte + if (IS_ENABLED(CONFIG_KASAN)) + return; + ++ /* ++ * Likewise, do not use it in real mode if percpu first chunk is not ++ * embedded. With CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK enabled there ++ * are chances where percpu allocation can come from vmalloc area. ++ */ ++ if (percpu_first_chunk_is_paged) ++ return; ++ + /* Otherwise, it should be safe to call it */ + nmi_enter(); + } +@@ -351,6 +359,8 @@ static inline void interrupt_nmi_exit_prepare(struct pt_regs *regs, struct inter + // no nmi_exit for a pseries hash guest taking a real mode exception + } else if (IS_ENABLED(CONFIG_KASAN)) { + // no nmi_exit for KASAN in real mode ++ } else if (percpu_first_chunk_is_paged) { ++ // no nmi_exit if percpu first chunk is not embedded + } else { + nmi_exit(); + } +diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h +index 0732b743e09962..99419e87f5556e 100644 +--- a/arch/powerpc/include/asm/io.h ++++ b/arch/powerpc/include/asm/io.h +@@ -37,7 +37,7 @@ extern struct pci_dev *isa_bridge_pcidev; + * define properly based on the platform + */ + #ifndef CONFIG_PCI +-#define _IO_BASE 0 ++#define _IO_BASE POISON_POINTER_DELTA + #define _ISA_MEM_BASE 0 + #define PCI_DRAM_OFFSET 0 + #elif defined(CONFIG_PPC32) +@@ -585,12 +585,12 @@ __do_out_asm(_rec_outl, "stwbrx") + #define __do_inw(port) _rec_inw(port) + #define __do_inl(port) _rec_inl(port) + #else /* CONFIG_PPC32 */ +-#define __do_outb(val, port) writeb(val,(PCI_IO_ADDR)_IO_BASE+port); +-#define __do_outw(val, port) writew(val,(PCI_IO_ADDR)_IO_BASE+port); +-#define __do_outl(val, port) writel(val,(PCI_IO_ADDR)_IO_BASE+port); +-#define __do_inb(port) readb((PCI_IO_ADDR)_IO_BASE + port); +-#define __do_inw(port) readw((PCI_IO_ADDR)_IO_BASE + port); +-#define __do_inl(port) readl((PCI_IO_ADDR)_IO_BASE + port); ++#define __do_outb(val, port) writeb(val,(PCI_IO_ADDR)(_IO_BASE+port)); ++#define __do_outw(val, port) writew(val,(PCI_IO_ADDR)(_IO_BASE+port)); ++#define __do_outl(val, port) writel(val,(PCI_IO_ADDR)(_IO_BASE+port)); ++#define __do_inb(port) readb((PCI_IO_ADDR)(_IO_BASE + port)); ++#define __do_inw(port) readw((PCI_IO_ADDR)(_IO_BASE + port)); ++#define __do_inl(port) readl((PCI_IO_ADDR)(_IO_BASE + port)); + #endif /* !CONFIG_PPC32 */ + + #ifdef CONFIG_EEH +@@ -606,12 +606,12 @@ __do_out_asm(_rec_outl, "stwbrx") + #define __do_writesw(a, b, n) _outsw(PCI_FIX_ADDR(a),(b),(n)) + #define __do_writesl(a, b, n) _outsl(PCI_FIX_ADDR(a),(b),(n)) + +-#define __do_insb(p, b, n) readsb((PCI_IO_ADDR)_IO_BASE+(p), (b), (n)) +-#define __do_insw(p, b, n) readsw((PCI_IO_ADDR)_IO_BASE+(p), (b), (n)) +-#define __do_insl(p, b, n) readsl((PCI_IO_ADDR)_IO_BASE+(p), (b), (n)) +-#define __do_outsb(p, b, n) writesb((PCI_IO_ADDR)_IO_BASE+(p),(b),(n)) +-#define __do_outsw(p, b, n) writesw((PCI_IO_ADDR)_IO_BASE+(p),(b),(n)) +-#define __do_outsl(p, b, n) writesl((PCI_IO_ADDR)_IO_BASE+(p),(b),(n)) ++#define __do_insb(p, b, n) readsb((PCI_IO_ADDR)(_IO_BASE+(p)), (b), (n)) ++#define __do_insw(p, b, n) readsw((PCI_IO_ADDR)(_IO_BASE+(p)), (b), (n)) ++#define __do_insl(p, b, n) readsl((PCI_IO_ADDR)(_IO_BASE+(p)), (b), (n)) ++#define __do_outsb(p, b, n) writesb((PCI_IO_ADDR)(_IO_BASE+(p)),(b),(n)) ++#define __do_outsw(p, b, n) writesw((PCI_IO_ADDR)(_IO_BASE+(p)),(b),(n)) ++#define __do_outsl(p, b, n) writesl((PCI_IO_ADDR)(_IO_BASE+(p)),(b),(n)) + + #define __do_memset_io(addr, c, n) \ + _memset_io(PCI_FIX_ADDR(addr), c, n) +diff --git a/arch/powerpc/include/asm/irq_work.h b/arch/powerpc/include/asm/irq_work.h +index b8b0be8f1a07ee..c6d3078bd8c3b4 100644 +--- a/arch/powerpc/include/asm/irq_work.h ++++ b/arch/powerpc/include/asm/irq_work.h +@@ -6,6 +6,5 @@ static inline bool arch_irq_work_has_interrupt(void) + { + return true; + } +-extern void arch_irq_work_raise(void); + + #endif /* _ASM_POWERPC_IRQ_WORK_H */ +diff --git a/arch/powerpc/include/asm/jump_label.h b/arch/powerpc/include/asm/jump_label.h +index 93ce3ec253877d..2f2a86ed2280aa 100644 +--- a/arch/powerpc/include/asm/jump_label.h ++++ b/arch/powerpc/include/asm/jump_label.h +@@ -17,7 +17,7 @@ + + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + "nop # arch_static_branch\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".long 1b - ., %l[l_yes] - .\n\t" +@@ -32,7 +32,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran + + static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + "b %l[l_yes] # arch_static_branch_jump\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".long 1b - ., %l[l_yes] - .\n\t" +diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h +index 52cc25864a1be2..d8b7e246a32f59 100644 +--- a/arch/powerpc/include/asm/mmu.h ++++ b/arch/powerpc/include/asm/mmu.h +@@ -412,5 +412,9 @@ extern void *abatron_pteptrs[2]; + #include + #endif + ++#if defined(CONFIG_FA_DUMP) || defined(CONFIG_PRESERVE_FA_DUMP) ++#define __HAVE_ARCH_RESERVED_KERNEL_PAGES ++#endif ++ + #endif /* __KERNEL__ */ + #endif /* _ASM_POWERPC_MMU_H_ */ +diff --git a/arch/powerpc/include/asm/mmzone.h b/arch/powerpc/include/asm/mmzone.h +index 4c6c6dbd182f45..da827d2d08666e 100644 +--- a/arch/powerpc/include/asm/mmzone.h ++++ b/arch/powerpc/include/asm/mmzone.h +@@ -42,14 +42,6 @@ u64 memory_hotplug_max(void); + #else + #define memory_hotplug_max() memblock_end_of_DRAM() + #endif /* CONFIG_NUMA */ +-#ifdef CONFIG_FA_DUMP +-#define __HAVE_ARCH_RESERVED_KERNEL_PAGES +-#endif +- +-#ifdef CONFIG_MEMORY_HOTPLUG +-extern int create_section_mapping(unsigned long start, unsigned long end, +- int nid, pgprot_t prot); +-#endif + + #endif /* __KERNEL__ */ + #endif /* _ASM_MMZONE_H_ */ +diff --git a/arch/powerpc/include/asm/nohash/32/pte-40x.h b/arch/powerpc/include/asm/nohash/32/pte-40x.h +index 6fe46e7545566c..0b4e5f8ce3e8a9 100644 +--- a/arch/powerpc/include/asm/nohash/32/pte-40x.h ++++ b/arch/powerpc/include/asm/nohash/32/pte-40x.h +@@ -69,9 +69,6 @@ + + #define _PTE_NONE_MASK 0 + +-/* Until my rework is finished, 40x still needs atomic PTE updates */ +-#define PTE_ATOMIC_UPDATES 1 +- + #define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED) + #define _PAGE_BASE (_PAGE_BASE_NC) + +diff --git a/arch/powerpc/include/asm/nohash/mmu-e500.h b/arch/powerpc/include/asm/nohash/mmu-e500.h +index 6ddced0415cb5c..7dc24b8632d7c2 100644 +--- a/arch/powerpc/include/asm/nohash/mmu-e500.h ++++ b/arch/powerpc/include/asm/nohash/mmu-e500.h +@@ -303,8 +303,7 @@ extern unsigned long linear_map_top; + extern int book3e_htw_mode; + + #define PPC_HTW_NONE 0 +-#define PPC_HTW_IBM 1 +-#define PPC_HTW_E6500 2 ++#define PPC_HTW_E6500 1 + + /* + * 64-bit booke platforms don't load the tlb in the tlb miss handler code. +diff --git a/arch/powerpc/include/asm/percpu.h b/arch/powerpc/include/asm/percpu.h +index 8e5b7d0b851c61..634970ce13c6b9 100644 +--- a/arch/powerpc/include/asm/percpu.h ++++ b/arch/powerpc/include/asm/percpu.h +@@ -15,6 +15,16 @@ + #endif /* CONFIG_SMP */ + #endif /* __powerpc64__ */ + ++#if defined(CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK) && defined(CONFIG_SMP) ++#include ++DECLARE_STATIC_KEY_FALSE(__percpu_first_chunk_is_paged); ++ ++#define percpu_first_chunk_is_paged \ ++ (static_key_enabled(&__percpu_first_chunk_is_paged.key)) ++#else ++#define percpu_first_chunk_is_paged false ++#endif /* CONFIG_PPC64 && CONFIG_SMP */ ++ + #include + + #include +diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h +index 23b77027c91637..7a84069759b032 100644 +--- a/arch/powerpc/include/asm/plpks.h ++++ b/arch/powerpc/include/asm/plpks.h +@@ -44,9 +44,8 @@ + #define PLPKS_MAX_DATA_SIZE 4000 + + // Timeouts for PLPKS operations +-#define PLPKS_MAX_TIMEOUT 5000 // msec +-#define PLPKS_FLUSH_SLEEP 10 // msec +-#define PLPKS_FLUSH_SLEEP_RANGE 400 ++#define PLPKS_MAX_TIMEOUT (5 * USEC_PER_SEC) ++#define PLPKS_FLUSH_SLEEP 10000 // usec + + struct plpks_var { + char *component; +diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h +index d9fcff5750271d..2689e7139b9ea7 100644 +--- a/arch/powerpc/include/asm/ppc-pci.h ++++ b/arch/powerpc/include/asm/ppc-pci.h +@@ -30,6 +30,16 @@ void *pci_traverse_device_nodes(struct device_node *start, + void *data); + extern void pci_devs_phb_init_dynamic(struct pci_controller *phb); + ++#if defined(CONFIG_IOMMU_API) && (defined(CONFIG_PPC_PSERIES) || \ ++ defined(CONFIG_PPC_POWERNV)) ++extern void ppc_iommu_register_device(struct pci_controller *phb); ++extern void ppc_iommu_unregister_device(struct pci_controller *phb); ++#else ++static inline void ppc_iommu_register_device(struct pci_controller *phb) { } ++static inline void ppc_iommu_unregister_device(struct pci_controller *phb) { } ++#endif ++ ++ + /* From rtas_pci.h */ + extern void init_pci_config_tokens (void); + extern unsigned long get_phb_buid (struct device_node *); +diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h +index 4ae4ab9090a2d4..ade5f094dbd222 100644 +--- a/arch/powerpc/include/asm/reg.h ++++ b/arch/powerpc/include/asm/reg.h +@@ -617,6 +617,8 @@ + #endif + #define SPRN_HID2 0x3F8 /* Hardware Implementation Register 2 */ + #define SPRN_HID2_GEKKO 0x398 /* Gekko HID2 Register */ ++#define SPRN_HID2_G2_LE 0x3F3 /* G2_LE HID2 Register */ ++#define HID2_G2_LE_HBE (1<<18) /* High BAT Enable (G2_LE) */ + #define SPRN_IABR 0x3F2 /* Instruction Address Breakpoint Register */ + #define SPRN_IABR2 0x3FA /* 83xx */ + #define SPRN_IBCR 0x135 /* 83xx Insn Breakpoint Control Reg */ +diff --git a/arch/powerpc/include/asm/reg_fsl_emb.h b/arch/powerpc/include/asm/reg_fsl_emb.h +index a21f529c43d96b..8359c06d92d9f8 100644 +--- a/arch/powerpc/include/asm/reg_fsl_emb.h ++++ b/arch/powerpc/include/asm/reg_fsl_emb.h +@@ -12,9 +12,16 @@ + #ifndef __ASSEMBLY__ + /* Performance Monitor Registers */ + #define mfpmr(rn) ({unsigned int rval; \ +- asm volatile("mfpmr %0," __stringify(rn) \ ++ asm volatile(".machine push; " \ ++ ".machine e300; " \ ++ "mfpmr %0," __stringify(rn) ";" \ ++ ".machine pop; " \ + : "=r" (rval)); rval;}) +-#define mtpmr(rn, v) asm volatile("mtpmr " __stringify(rn) ",%0" : : "r" (v)) ++#define mtpmr(rn, v) asm volatile(".machine push; " \ ++ ".machine e300; " \ ++ "mtpmr " __stringify(rn) ",%0; " \ ++ ".machine pop; " \ ++ : : "r" (v)) + #endif /* __ASSEMBLY__ */ + + /* Freescale Book E Performance Monitor APU Registers */ +diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h +index c697c3c746946d..33024a2874a691 100644 +--- a/arch/powerpc/include/asm/rtas.h ++++ b/arch/powerpc/include/asm/rtas.h +@@ -68,7 +68,7 @@ enum rtas_function_index { + RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE, + RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE2, + RTAS_FNIDX__IBM_REMOVE_PE_DMA_WINDOW, +- RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOWS, ++ RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOW, + RTAS_FNIDX__IBM_SCAN_LOG_DUMP, + RTAS_FNIDX__IBM_SET_DYNAMIC_INDICATOR, + RTAS_FNIDX__IBM_SET_EEH_OPTION, +@@ -163,7 +163,7 @@ typedef struct { + #define RTAS_FN_IBM_READ_SLOT_RESET_STATE rtas_fn_handle(RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE) + #define RTAS_FN_IBM_READ_SLOT_RESET_STATE2 rtas_fn_handle(RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE2) + #define RTAS_FN_IBM_REMOVE_PE_DMA_WINDOW rtas_fn_handle(RTAS_FNIDX__IBM_REMOVE_PE_DMA_WINDOW) +-#define RTAS_FN_IBM_RESET_PE_DMA_WINDOWS rtas_fn_handle(RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOWS) ++#define RTAS_FN_IBM_RESET_PE_DMA_WINDOW rtas_fn_handle(RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOW) + #define RTAS_FN_IBM_SCAN_LOG_DUMP rtas_fn_handle(RTAS_FNIDX__IBM_SCAN_LOG_DUMP) + #define RTAS_FN_IBM_SET_DYNAMIC_INDICATOR rtas_fn_handle(RTAS_FNIDX__IBM_SET_DYNAMIC_INDICATOR) + #define RTAS_FN_IBM_SET_EEH_OPTION rtas_fn_handle(RTAS_FNIDX__IBM_SET_EEH_OPTION) +diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h +index ea26665f82cfc8..f43f3a6b0051cf 100644 +--- a/arch/powerpc/include/asm/sections.h ++++ b/arch/powerpc/include/asm/sections.h +@@ -14,6 +14,7 @@ typedef struct func_desc func_desc_t; + + extern char __head_end[]; + extern char __srwx_boundary[]; ++extern char __exittext_begin[], __exittext_end[]; + + /* Patch sites */ + extern s32 patch__call_flush_branch_caches1; +diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h +index bf5dde1a411471..15c5691dd21844 100644 +--- a/arch/powerpc/include/asm/thread_info.h ++++ b/arch/powerpc/include/asm/thread_info.h +@@ -14,7 +14,7 @@ + + #ifdef __KERNEL__ + +-#ifdef CONFIG_KASAN ++#if defined(CONFIG_KASAN) && CONFIG_THREAD_SHIFT < 15 + #define MIN_THREAD_SHIFT (CONFIG_THREAD_SHIFT + 1) + #else + #define MIN_THREAD_SHIFT CONFIG_THREAD_SHIFT +diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h +index f4e6f2dd04b731..16bacfe8c7a2ca 100644 +--- a/arch/powerpc/include/asm/topology.h ++++ b/arch/powerpc/include/asm/topology.h +@@ -145,6 +145,7 @@ static inline int cpu_to_coregroup_id(int cpu) + + #ifdef CONFIG_HOTPLUG_SMT + #include ++#include + #include + + static inline bool topology_is_primary_thread(unsigned int cpu) +@@ -156,6 +157,18 @@ static inline bool topology_smt_thread_allowed(unsigned int cpu) + { + return cpu_thread_in_core(cpu) < cpu_smt_num_threads; + } ++ ++#define topology_is_core_online topology_is_core_online ++static inline bool topology_is_core_online(unsigned int cpu) ++{ ++ int i, first_cpu = cpu_first_thread_sibling(cpu); ++ ++ for (i = first_cpu; i < first_cpu + threads_per_core; ++i) { ++ if (cpu_online(i)) ++ return true; ++ } ++ return false; ++} + #endif + + #endif /* __KERNEL__ */ +diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h +index fb725ec77926e1..a81bd825087cda 100644 +--- a/arch/powerpc/include/asm/uaccess.h ++++ b/arch/powerpc/include/asm/uaccess.h +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + #ifdef __powerpc64__ + /* We use TASK_SIZE_USER64 as TASK_SIZE is not constant */ +@@ -74,7 +75,7 @@ __pu_failed: \ + /* -mprefixed can generate offsets beyond range, fall back hack */ + #ifdef CONFIG_PPC_KERNEL_PREFIXED + #define __put_user_asm_goto(x, addr, label, op) \ +- asm_volatile_goto( \ ++ asm goto( \ + "1: " op " %0,0(%1) # put_user\n" \ + EX_TABLE(1b, %l2) \ + : \ +@@ -83,7 +84,7 @@ __pu_failed: \ + : label) + #else + #define __put_user_asm_goto(x, addr, label, op) \ +- asm_volatile_goto( \ ++ asm goto( \ + "1: " op "%U1%X1 %0,%1 # put_user\n" \ + EX_TABLE(1b, %l2) \ + : \ +@@ -93,11 +94,21 @@ __pu_failed: \ + #endif + + #ifdef __powerpc64__ ++#ifdef CONFIG_PPC_KERNEL_PREFIXED + #define __put_user_asm2_goto(x, ptr, label) \ + __put_user_asm_goto(x, ptr, label, "std") ++#else ++#define __put_user_asm2_goto(x, addr, label) \ ++ asm goto ("1: std%U1%X1 %0,%1 # put_user\n" \ ++ EX_TABLE(1b, %l2) \ ++ : \ ++ : "r" (x), DS_FORM_CONSTRAINT (*addr) \ ++ : \ ++ : label) ++#endif // CONFIG_PPC_KERNEL_PREFIXED + #else /* __powerpc64__ */ + #define __put_user_asm2_goto(x, addr, label) \ +- asm_volatile_goto( \ ++ asm goto( \ + "1: stw%X1 %0, %1\n" \ + "2: stw%X1 %L0, %L1\n" \ + EX_TABLE(1b, %l2) \ +@@ -146,7 +157,7 @@ do { \ + /* -mprefixed can generate offsets beyond range, fall back hack */ + #ifdef CONFIG_PPC_KERNEL_PREFIXED + #define __get_user_asm_goto(x, addr, label, op) \ +- asm_volatile_goto( \ ++ asm_goto_output( \ + "1: "op" %0,0(%1) # get_user\n" \ + EX_TABLE(1b, %l2) \ + : "=r" (x) \ +@@ -155,7 +166,7 @@ do { \ + : label) + #else + #define __get_user_asm_goto(x, addr, label, op) \ +- asm_volatile_goto( \ ++ asm_goto_output( \ + "1: "op"%U1%X1 %0, %1 # get_user\n" \ + EX_TABLE(1b, %l2) \ + : "=r" (x) \ +@@ -169,7 +180,7 @@ do { \ + __get_user_asm_goto(x, addr, label, "ld") + #else /* __powerpc64__ */ + #define __get_user_asm2_goto(x, addr, label) \ +- asm_volatile_goto( \ ++ asm_goto_output( \ + "1: lwz%X1 %0, %1\n" \ + "2: lwz%X1 %L0, %L1\n" \ + EX_TABLE(1b, %l2) \ +diff --git a/arch/powerpc/include/asm/vdso_datapage.h b/arch/powerpc/include/asm/vdso_datapage.h +index a585c8e538ff0f..939daf6b695ef1 100644 +--- a/arch/powerpc/include/asm/vdso_datapage.h ++++ b/arch/powerpc/include/asm/vdso_datapage.h +@@ -111,6 +111,21 @@ extern struct vdso_arch_data *vdso_data; + addi \ptr, \ptr, (_vdso_datapage - 999b)@l + .endm + ++#include ++#include ++ ++.macro get_realdatapage ptr scratch ++ get_datapage \ptr ++#ifdef CONFIG_TIME_NS ++ lwz \scratch, VDSO_CLOCKMODE_OFFSET(\ptr) ++ xoris \scratch, \scratch, VDSO_CLOCKMODE_TIMENS@h ++ xori \scratch, \scratch, VDSO_CLOCKMODE_TIMENS@l ++ cntlzw \scratch, \scratch ++ rlwinm \scratch, \scratch, PAGE_SHIFT - 5, 1 << PAGE_SHIFT ++ add \ptr, \ptr, \scratch ++#endif ++.endm ++ + #endif /* __ASSEMBLY__ */ + + #endif /* __KERNEL__ */ +diff --git a/arch/powerpc/include/asm/vmalloc.h b/arch/powerpc/include/asm/vmalloc.h +index 4c69ece52a31e5..59ed89890c902b 100644 +--- a/arch/powerpc/include/asm/vmalloc.h ++++ b/arch/powerpc/include/asm/vmalloc.h +@@ -7,14 +7,14 @@ + #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP + + #define arch_vmap_pud_supported arch_vmap_pud_supported +-static inline bool arch_vmap_pud_supported(pgprot_t prot) ++static __always_inline bool arch_vmap_pud_supported(pgprot_t prot) + { + /* HPT does not cope with large pages in the vmalloc area */ + return radix_enabled(); + } + + #define arch_vmap_pmd_supported arch_vmap_pmd_supported +-static inline bool arch_vmap_pmd_supported(pgprot_t prot) ++static __always_inline bool arch_vmap_pmd_supported(pgprot_t prot) + { + return radix_enabled(); + } +diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c +index 9f14d95b8b32fd..2affd30468bc4c 100644 +--- a/arch/powerpc/kernel/asm-offsets.c ++++ b/arch/powerpc/kernel/asm-offsets.c +@@ -348,6 +348,8 @@ int main(void) + #else + OFFSET(CFG_SYSCALL_MAP32, vdso_arch_data, syscall_map); + #endif ++ OFFSET(VDSO_CLOCKMODE_OFFSET, vdso_arch_data, data[0].clock_mode); ++ DEFINE(VDSO_CLOCKMODE_TIMENS, VDSO_CLOCKMODE_TIMENS); + + #ifdef CONFIG_BUG + DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry)); +diff --git a/arch/powerpc/kernel/cpu_setup_6xx.S b/arch/powerpc/kernel/cpu_setup_6xx.S +index f29ce3dd6140f4..bfd3f442e5eb9d 100644 +--- a/arch/powerpc/kernel/cpu_setup_6xx.S ++++ b/arch/powerpc/kernel/cpu_setup_6xx.S +@@ -26,6 +26,15 @@ BEGIN_FTR_SECTION + bl __init_fpu_registers + END_FTR_SECTION_IFCLR(CPU_FTR_FPU_UNAVAILABLE) + bl setup_common_caches ++ ++ /* ++ * This assumes that all cores using __setup_cpu_603 with ++ * MMU_FTR_USE_HIGH_BATS are G2_LE compatible ++ */ ++BEGIN_MMU_FTR_SECTION ++ bl setup_g2_le_hid2 ++END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS) ++ + mtlr r5 + blr + _GLOBAL(__setup_cpu_604) +@@ -115,6 +124,16 @@ SYM_FUNC_START_LOCAL(setup_604_hid0) + blr + SYM_FUNC_END(setup_604_hid0) + ++/* Enable high BATs for G2_LE and derivatives like e300cX */ ++SYM_FUNC_START_LOCAL(setup_g2_le_hid2) ++ mfspr r11,SPRN_HID2_G2_LE ++ oris r11,r11,HID2_G2_LE_HBE@h ++ mtspr SPRN_HID2_G2_LE,r11 ++ sync ++ isync ++ blr ++SYM_FUNC_END(setup_g2_le_hid2) ++ + /* 7400 <= rev 2.7 and 7410 rev = 1.0 suffer from some + * erratas we work around here. + * Moto MPC710CE.pdf describes them, those are errata +@@ -495,4 +514,3 @@ _GLOBAL(__restore_cpu_setup) + mtcr r7 + blr + _ASM_NOKPROBE_SYMBOL(__restore_cpu_setup) +- +diff --git a/arch/powerpc/kernel/cpu_specs_e500mc.h b/arch/powerpc/kernel/cpu_specs_e500mc.h +index ceb06b109f8313..2ae8e9a7b461c8 100644 +--- a/arch/powerpc/kernel/cpu_specs_e500mc.h ++++ b/arch/powerpc/kernel/cpu_specs_e500mc.h +@@ -8,7 +8,8 @@ + + #ifdef CONFIG_PPC64 + #define COMMON_USER_BOOKE (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \ +- PPC_FEATURE_HAS_FPU | PPC_FEATURE_64) ++ PPC_FEATURE_HAS_FPU | PPC_FEATURE_64 | \ ++ PPC_FEATURE_BOOKE) + #else + #define COMMON_USER_BOOKE (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \ + PPC_FEATURE_BOOKE) +diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c +index e0ce812796241a..7d1b50599dd6c2 100644 +--- a/arch/powerpc/kernel/eeh_pe.c ++++ b/arch/powerpc/kernel/eeh_pe.c +@@ -849,6 +849,7 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) + { + struct eeh_dev *edev; + struct pci_dev *pdev; ++ struct pci_bus *bus = NULL; + + if (pe->type & EEH_PE_PHB) + return pe->phb->bus; +@@ -859,9 +860,11 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) + + /* Retrieve the parent PCI bus of first (top) PCI device */ + edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, entry); ++ pci_lock_rescan_remove(); + pdev = eeh_dev_to_pci_dev(edev); + if (pdev) +- return pdev->bus; ++ bus = pdev->bus; ++ pci_unlock_rescan_remove(); + +- return NULL; ++ return bus; + } +diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S +index 6a9acfb690c9f5..2f8f3f93cbb67e 100644 +--- a/arch/powerpc/kernel/fpu.S ++++ b/arch/powerpc/kernel/fpu.S +@@ -23,6 +23,15 @@ + #include + + #ifdef CONFIG_VSX ++#define __REST_1FPVSR(n,c,base) \ ++BEGIN_FTR_SECTION \ ++ b 2f; \ ++END_FTR_SECTION_IFSET(CPU_FTR_VSX); \ ++ REST_FPR(n,base); \ ++ b 3f; \ ++2: REST_VSR(n,c,base); \ ++3: ++ + #define __REST_32FPVSRS(n,c,base) \ + BEGIN_FTR_SECTION \ + b 2f; \ +@@ -41,9 +50,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX); \ + 2: SAVE_32VSRS(n,c,base); \ + 3: + #else ++#define __REST_1FPVSR(n,b,base) REST_FPR(n, base) + #define __REST_32FPVSRS(n,b,base) REST_32FPRS(n, base) + #define __SAVE_32FPVSRS(n,b,base) SAVE_32FPRS(n, base) + #endif ++#define REST_1FPVSR(n,c,base) __REST_1FPVSR(n,__REG_##c,__REG_##base) + #define REST_32FPVSRS(n,c,base) __REST_32FPVSRS(n,__REG_##c,__REG_##base) + #define SAVE_32FPVSRS(n,c,base) __SAVE_32FPVSRS(n,__REG_##c,__REG_##base) + +@@ -67,6 +78,7 @@ _GLOBAL(store_fp_state) + SAVE_32FPVSRS(0, R4, R3) + mffs fr0 + stfd fr0,FPSTATE_FPSCR(r3) ++ REST_1FPVSR(0, R4, R3) + blr + EXPORT_SYMBOL(store_fp_state) + +@@ -138,4 +150,5 @@ _GLOBAL(save_fpu) + 2: SAVE_32FPVSRS(0, R4, R6) + mffs fr0 + stfd fr0,FPSTATE_FPSCR(r6) ++ REST_1FPVSR(0, R4, R6) + blr +diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S +index 4690c219bfa4df..63432a33ec49ac 100644 +--- a/arch/powerpc/kernel/head_64.S ++++ b/arch/powerpc/kernel/head_64.S +@@ -647,8 +647,9 @@ __after_prom_start: + * Note: This process overwrites the OF exception vectors. + */ + LOAD_REG_IMMEDIATE(r3, PAGE_OFFSET) +- mr. r4,r26 /* In some cases the loader may */ +- beq 9f /* have already put us at zero */ ++ mr r4,r26 /* Load the virtual source address into r4 */ ++ cmpld r3,r4 /* Check if source == dest */ ++ beq 9f /* If so skip the copy */ + li r6,0x100 /* Start offset, the first 0x100 */ + /* bytes were copied earlier. */ + +diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S +index 647b0b445e89db..0c94db8e2bdedb 100644 +--- a/arch/powerpc/kernel/head_8xx.S ++++ b/arch/powerpc/kernel/head_8xx.S +@@ -41,12 +41,12 @@ + #include "head_32.h" + + .macro compare_to_kernel_boundary scratch, addr +-#if CONFIG_TASK_SIZE <= 0x80000000 && CONFIG_PAGE_OFFSET >= 0x80000000 ++#if CONFIG_TASK_SIZE <= 0x80000000 && MODULES_VADDR >= 0x80000000 + /* By simply checking Address >= 0x80000000, we know if its a kernel address */ + not. \scratch, \addr + #else + rlwinm \scratch, \addr, 16, 0xfff8 +- cmpli cr0, \scratch, PAGE_OFFSET@h ++ cmpli cr0, \scratch, TASK_SIZE@h + #endif + .endm + +@@ -404,7 +404,7 @@ FixupDAR:/* Entry point for dcbx workaround. */ + mfspr r10, SPRN_SRR0 + mtspr SPRN_MD_EPN, r10 + rlwinm r11, r10, 16, 0xfff8 +- cmpli cr1, r11, PAGE_OFFSET@h ++ cmpli cr1, r11, TASK_SIZE@h + mfspr r11, SPRN_M_TWB /* Get level 1 table */ + blt+ cr1, 3f + +diff --git a/arch/powerpc/kernel/interrupt_64.S b/arch/powerpc/kernel/interrupt_64.S +index bd863702d81218..1ad059a9e2fef3 100644 +--- a/arch/powerpc/kernel/interrupt_64.S ++++ b/arch/powerpc/kernel/interrupt_64.S +@@ -52,7 +52,8 @@ _ASM_NOKPROBE_SYMBOL(system_call_vectored_\name) + mr r10,r1 + ld r1,PACAKSAVE(r13) + std r10,0(r1) +- std r11,_NIP(r1) ++ std r11,_LINK(r1) ++ std r11,_NIP(r1) /* Saved LR is also the next instruction */ + std r12,_MSR(r1) + std r0,GPR0(r1) + std r10,GPR1(r1) +@@ -70,7 +71,6 @@ _ASM_NOKPROBE_SYMBOL(system_call_vectored_\name) + std r9,GPR13(r1) + SAVE_NVGPRS(r1) + std r11,_XER(r1) +- std r11,_LINK(r1) + std r11,_CTR(r1) + + li r11,\trapnr +diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c +index 14251bc5219eba..efaca0c6eff9d0 100644 +--- a/arch/powerpc/kernel/iommu.c ++++ b/arch/powerpc/kernel/iommu.c +@@ -1344,7 +1344,7 @@ static struct iommu_device *spapr_tce_iommu_probe_device(struct device *dev) + struct pci_controller *hose; + + if (!dev_is_pci(dev)) +- return ERR_PTR(-EPERM); ++ return ERR_PTR(-ENODEV); + + pdev = to_pci_dev(dev); + hose = pdev->bus->sysdata; +@@ -1393,6 +1393,21 @@ static const struct attribute_group *spapr_tce_iommu_groups[] = { + NULL, + }; + ++void ppc_iommu_register_device(struct pci_controller *phb) ++{ ++ iommu_device_sysfs_add(&phb->iommu, phb->parent, ++ spapr_tce_iommu_groups, "iommu-phb%04x", ++ phb->global_number); ++ iommu_device_register(&phb->iommu, &spapr_tce_iommu_ops, ++ phb->parent); ++} ++ ++void ppc_iommu_unregister_device(struct pci_controller *phb) ++{ ++ iommu_device_unregister(&phb->iommu); ++ iommu_device_sysfs_remove(&phb->iommu); ++} ++ + /* + * This registers IOMMU devices of PHBs. This needs to happen + * after core_initcall(iommu_init) + postcore_initcall(pci_driver_init) and +@@ -1403,11 +1418,7 @@ static int __init spapr_tce_setup_phb_iommus_initcall(void) + struct pci_controller *hose; + + list_for_each_entry(hose, &hose_list, list_node) { +- iommu_device_sysfs_add(&hose->iommu, hose->parent, +- spapr_tce_iommu_groups, "iommu-phb%04x", +- hose->global_number); +- iommu_device_register(&hose->iommu, &spapr_tce_iommu_ops, +- hose->parent); ++ ppc_iommu_register_device(hose); + } + return 0; + } +diff --git a/arch/powerpc/kernel/irq_64.c b/arch/powerpc/kernel/irq_64.c +index 938e66829eae65..d5c48d1b0a31ea 100644 +--- a/arch/powerpc/kernel/irq_64.c ++++ b/arch/powerpc/kernel/irq_64.c +@@ -230,7 +230,7 @@ notrace __no_kcsan void arch_local_irq_restore(unsigned long mask) + * This allows interrupts to be unmasked without hard disabling, and + * also without new hard interrupts coming in ahead of pending ones. + */ +- asm_volatile_goto( ++ asm goto( + "1: \n" + " lbz 9,%0(13) \n" + " cmpwi 9,0 \n" +diff --git a/arch/powerpc/kernel/kprobes-ftrace.c b/arch/powerpc/kernel/kprobes-ftrace.c +index 072ebe7f290ba7..f8208c027148fd 100644 +--- a/arch/powerpc/kernel/kprobes-ftrace.c ++++ b/arch/powerpc/kernel/kprobes-ftrace.c +@@ -21,6 +21,9 @@ void kprobe_ftrace_handler(unsigned long nip, unsigned long parent_nip, + struct pt_regs *regs; + int bit; + ++ if (unlikely(kprobe_ftrace_disabled)) ++ return; ++ + bit = ftrace_test_recursion_trylock(nip, parent_nip); + if (bit < 0) + return; +diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c +index b68898ac07e199..9452a54d356c97 100644 +--- a/arch/powerpc/kernel/process.c ++++ b/arch/powerpc/kernel/process.c +@@ -1198,11 +1198,11 @@ void kvmppc_save_user_regs(void) + + usermsr = current->thread.regs->msr; + ++ /* Caller has enabled FP/VEC/VSX/TM in MSR */ + if (usermsr & MSR_FP) +- save_fpu(current); +- ++ __giveup_fpu(current); + if (usermsr & MSR_VEC) +- save_altivec(current); ++ __giveup_altivec(current); + + #ifdef CONFIG_PPC_TRANSACTIONAL_MEM + if (usermsr & MSR_TM) { +@@ -2258,6 +2258,22 @@ unsigned long __get_wchan(struct task_struct *p) + return ret; + } + ++static bool empty_user_regs(struct pt_regs *regs, struct task_struct *tsk) ++{ ++ unsigned long stack_page; ++ ++ // A non-empty pt_regs should never have a zero MSR or TRAP value. ++ if (regs->msr || regs->trap) ++ return false; ++ ++ // Check it sits at the very base of the stack ++ stack_page = (unsigned long)task_stack_page(tsk); ++ if ((unsigned long)(regs + 1) != stack_page + THREAD_SIZE) ++ return false; ++ ++ return true; ++} ++ + static int kstack_depth_to_print = CONFIG_PRINT_STACK_DEPTH; + + void __no_sanitize_address show_stack(struct task_struct *tsk, +@@ -2322,9 +2338,13 @@ void __no_sanitize_address show_stack(struct task_struct *tsk, + lr = regs->link; + printk("%s--- interrupt: %lx at %pS\n", + loglvl, regs->trap, (void *)regs->nip); +- __show_regs(regs); +- printk("%s--- interrupt: %lx\n", +- loglvl, regs->trap); ++ ++ // Detect the case of an empty pt_regs at the very base ++ // of the stack and suppress showing it in full. ++ if (!empty_user_regs(regs, tsk)) { ++ __show_regs(regs); ++ printk("%s--- interrupt: %lx\n", loglvl, regs->trap); ++ } + + firstframe = 1; + } +diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c +index 0b5878c3125b1c..bf6d8ad3819e99 100644 +--- a/arch/powerpc/kernel/prom.c ++++ b/arch/powerpc/kernel/prom.c +@@ -327,6 +327,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, + void *data) + { + const char *type = of_get_flat_dt_prop(node, "device_type", NULL); ++ const __be32 *cpu_version = NULL; + const __be32 *prop; + const __be32 *intserv; + int i, nthreads; +@@ -375,6 +376,18 @@ static int __init early_init_dt_scan_cpus(unsigned long node, + if (IS_ENABLED(CONFIG_PPC64)) + boot_cpu_hwid = be32_to_cpu(intserv[found_thread]); + ++ if (nr_cpu_ids % nthreads != 0) { ++ set_nr_cpu_ids(ALIGN(nr_cpu_ids, nthreads)); ++ pr_warn("nr_cpu_ids was not a multiple of threads_per_core, adjusted to %d\n", ++ nr_cpu_ids); ++ } ++ ++ if (boot_cpuid >= nr_cpu_ids) { ++ set_nr_cpu_ids(min(CONFIG_NR_CPUS, ALIGN(boot_cpuid + 1, nthreads))); ++ pr_warn("Boot CPU %d >= nr_cpu_ids, adjusted nr_cpu_ids to %d\n", ++ boot_cpuid, nr_cpu_ids); ++ } ++ + /* + * PAPR defines "logical" PVR values for cpus that + * meet various levels of the architecture: +@@ -398,7 +411,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, + prop = of_get_flat_dt_prop(node, "cpu-version", NULL); + if (prop && (be32_to_cpup(prop) & 0xff000000) == 0x0f000000) { + identify_cpu(0, be32_to_cpup(prop)); +- seq_buf_printf(&ppc_hw_desc, "0x%04x ", be32_to_cpup(prop)); ++ cpu_version = prop; + } + + check_cpu_feature_properties(node); +@@ -409,6 +422,12 @@ static int __init early_init_dt_scan_cpus(unsigned long node, + } + + identical_pvr_fixup(node); ++ ++ // We can now add the CPU name & PVR to the hardware description ++ seq_buf_printf(&ppc_hw_desc, "%s 0x%04lx ", cur_cpu_spec->cpu_name, mfspr(SPRN_PVR)); ++ if (cpu_version) ++ seq_buf_printf(&ppc_hw_desc, "0x%04x ", be32_to_cpup(cpu_version)); ++ + init_mmu_slb_size(node); + + #ifdef CONFIG_PPC64 +@@ -846,9 +865,6 @@ void __init early_init_devtree(void *params) + + dt_cpu_ftrs_scan(); + +- // We can now add the CPU name & PVR to the hardware description +- seq_buf_printf(&ppc_hw_desc, "%s 0x%04lx ", cur_cpu_spec->cpu_name, mfspr(SPRN_PVR)); +- + /* Retrieve CPU related informations from the flat tree + * (altivec support, boot CPU ID, ...) + */ +diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c +index eddc031c4b95f4..46b9476d758249 100644 +--- a/arch/powerpc/kernel/rtas.c ++++ b/arch/powerpc/kernel/rtas.c +@@ -310,8 +310,13 @@ static struct rtas_function rtas_function_table[] __ro_after_init = { + [RTAS_FNIDX__IBM_REMOVE_PE_DMA_WINDOW] = { + .name = "ibm,remove-pe-dma-window", + }, +- [RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOWS] = { +- .name = "ibm,reset-pe-dma-windows", ++ [RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOW] = { ++ /* ++ * Note: PAPR+ v2.13 7.3.31.4.1 spells this as ++ * "ibm,reset-pe-dma-windows" (plural), but RTAS ++ * implementations use the singular form in practice. ++ */ ++ .name = "ibm,reset-pe-dma-window", + }, + [RTAS_FNIDX__IBM_SCAN_LOG_DUMP] = { + .name = "ibm,scan-log-dump", +@@ -544,6 +549,21 @@ static int __init rtas_token_to_function_xarray_init(void) + } + arch_initcall(rtas_token_to_function_xarray_init); + ++/* ++ * For use by sys_rtas(), where the token value is provided by user ++ * space and we don't want to warn on failed lookups. ++ */ ++static const struct rtas_function *rtas_token_to_function_untrusted(s32 token) ++{ ++ return xa_load(&rtas_token_to_function_xarray, token); ++} ++ ++/* ++ * Reverse lookup for deriving the function descriptor from a ++ * known-good token value in contexts where the former is not already ++ * available. @token must be valid, e.g. derived from the result of a ++ * prior lookup against the function table. ++ */ + static const struct rtas_function *rtas_token_to_function(s32 token) + { + const struct rtas_function *func; +@@ -551,7 +571,7 @@ static const struct rtas_function *rtas_token_to_function(s32 token) + if (WARN_ONCE(token < 0, "invalid token %d", token)) + return NULL; + +- func = xa_load(&rtas_token_to_function_xarray, token); ++ func = rtas_token_to_function_untrusted(token); + + if (WARN_ONCE(!func, "unexpected failed lookup for token %d", token)) + return NULL; +@@ -1726,7 +1746,7 @@ static bool block_rtas_call(int token, int nargs, + * If this token doesn't correspond to a function the kernel + * understands, you're not allowed to call it. + */ +- func = rtas_token_to_function(token); ++ func = rtas_token_to_function_untrusted(token); + if (!func) + goto err; + /* +diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c +index 20f72cd1d8138d..03eaad5949f141 100644 +--- a/arch/powerpc/kernel/setup-common.c ++++ b/arch/powerpc/kernel/setup-common.c +@@ -950,6 +950,7 @@ void __init setup_arch(char **cmdline_p) + mem_topology_setup(); + /* Set max_mapnr before paging_init() */ + set_max_mapnr(max_pfn); ++ high_memory = (void *)__va(max_low_pfn * PAGE_SIZE); + + /* + * Release secondary cpus out of their spinloops at 0x60 now that +diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c +index 246201d0d879ef..394f209536cee0 100644 +--- a/arch/powerpc/kernel/setup_64.c ++++ b/arch/powerpc/kernel/setup_64.c +@@ -834,6 +834,7 @@ static __init int pcpu_cpu_to_node(int cpu) + + unsigned long __per_cpu_offset[NR_CPUS] __read_mostly; + EXPORT_SYMBOL(__per_cpu_offset); ++DEFINE_STATIC_KEY_FALSE(__percpu_first_chunk_is_paged); + + void __init setup_per_cpu_areas(void) + { +@@ -876,6 +877,7 @@ void __init setup_per_cpu_areas(void) + if (rc < 0) + panic("cannot initialize percpu area (err=%d)", rc); + ++ static_key_enable(&__percpu_first_chunk_is_paged.key); + delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; + for_each_possible_cpu(cpu) { + __per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu]; +diff --git a/arch/powerpc/kernel/syscalls/syscall.tbl b/arch/powerpc/kernel/syscalls/syscall.tbl +index 20e50586e8a26c..40f6751271d3d8 100644 +--- a/arch/powerpc/kernel/syscalls/syscall.tbl ++++ b/arch/powerpc/kernel/syscalls/syscall.tbl +@@ -230,8 +230,10 @@ + 178 nospu rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend + 179 32 pread64 sys_ppc_pread64 compat_sys_ppc_pread64 + 179 64 pread64 sys_pread64 ++179 spu pread64 sys_pread64 + 180 32 pwrite64 sys_ppc_pwrite64 compat_sys_ppc_pwrite64 + 180 64 pwrite64 sys_pwrite64 ++180 spu pwrite64 sys_pwrite64 + 181 common chown sys_chown + 182 common getcwd sys_getcwd + 183 common capget sys_capget +@@ -246,6 +248,7 @@ + 190 common ugetrlimit sys_getrlimit compat_sys_getrlimit + 191 32 readahead sys_ppc_readahead compat_sys_ppc_readahead + 191 64 readahead sys_readahead ++191 spu readahead sys_readahead + 192 32 mmap2 sys_mmap2 compat_sys_mmap2 + 193 32 truncate64 sys_ppc_truncate64 compat_sys_ppc_truncate64 + 194 32 ftruncate64 sys_ppc_ftruncate64 compat_sys_ppc_ftruncate64 +@@ -293,6 +296,7 @@ + 232 nospu set_tid_address sys_set_tid_address + 233 32 fadvise64 sys_ppc32_fadvise64 compat_sys_ppc32_fadvise64 + 233 64 fadvise64 sys_fadvise64 ++233 spu fadvise64 sys_fadvise64 + 234 nospu exit_group sys_exit_group + 235 nospu lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie + 236 common epoll_create sys_epoll_create +@@ -502,7 +506,7 @@ + 412 32 utimensat_time64 sys_utimensat sys_utimensat + 413 32 pselect6_time64 sys_pselect6 compat_sys_pselect6_time64 + 414 32 ppoll_time64 sys_ppoll compat_sys_ppoll_time64 +-416 32 io_pgetevents_time64 sys_io_pgetevents sys_io_pgetevents ++416 32 io_pgetevents_time64 sys_io_pgetevents compat_sys_io_pgetevents_time64 + 417 32 recvmmsg_time64 sys_recvmmsg compat_sys_recvmmsg_time64 + 418 32 mq_timedsend_time64 sys_mq_timedsend sys_mq_timedsend + 419 32 mq_timedreceive_time64 sys_mq_timedreceive sys_mq_timedreceive +diff --git a/arch/powerpc/kernel/trace/ftrace.c b/arch/powerpc/kernel/trace/ftrace.c +index 82010629cf887c..d8d6b4fd9a14cb 100644 +--- a/arch/powerpc/kernel/trace/ftrace.c ++++ b/arch/powerpc/kernel/trace/ftrace.c +@@ -27,10 +27,22 @@ + #include + #include + #include ++#include + + #define NUM_FTRACE_TRAMPS 2 + static unsigned long ftrace_tramps[NUM_FTRACE_TRAMPS]; + ++unsigned long ftrace_call_adjust(unsigned long addr) ++{ ++ if (addr >= (unsigned long)__exittext_begin && addr < (unsigned long)__exittext_end) ++ return 0; ++ ++ if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY)) ++ addr += MCOUNT_INSN_SIZE; ++ ++ return addr; ++} ++ + static ppc_inst_t ftrace_create_branch_inst(unsigned long ip, unsigned long addr, int link) + { + ppc_inst_t op; +diff --git a/arch/powerpc/kernel/trace/ftrace_64_pg.c b/arch/powerpc/kernel/trace/ftrace_64_pg.c +index 7b85c3b460a3c0..12fab1803bcf45 100644 +--- a/arch/powerpc/kernel/trace/ftrace_64_pg.c ++++ b/arch/powerpc/kernel/trace/ftrace_64_pg.c +@@ -37,6 +37,11 @@ + #define NUM_FTRACE_TRAMPS 8 + static unsigned long ftrace_tramps[NUM_FTRACE_TRAMPS]; + ++unsigned long ftrace_call_adjust(unsigned long addr) ++{ ++ return addr; ++} ++ + static ppc_inst_t + ftrace_call_replace(unsigned long ip, unsigned long addr, int link) + { +diff --git a/arch/powerpc/kernel/trace/ftrace_entry.S b/arch/powerpc/kernel/trace/ftrace_entry.S +index 90701885762cf1..40677416d7b262 100644 +--- a/arch/powerpc/kernel/trace/ftrace_entry.S ++++ b/arch/powerpc/kernel/trace/ftrace_entry.S +@@ -62,7 +62,7 @@ + .endif + + /* Save previous stack pointer (r1) */ +- addi r8, r1, SWITCH_FRAME_SIZE ++ addi r8, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE + PPC_STL r8, GPR1(r1) + + .if \allregs == 1 +@@ -182,7 +182,7 @@ ftrace_no_trace: + mflr r3 + mtctr r3 + REST_GPR(3, r1) +- addi r1, r1, SWITCH_FRAME_SIZE ++ addi r1, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE + mtlr r0 + bctr + #endif +diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c +index 64ff37721fd06f..2de7f6dcd32b06 100644 +--- a/arch/powerpc/kernel/traps.c ++++ b/arch/powerpc/kernel/traps.c +@@ -1164,6 +1164,7 @@ void emulate_single_step(struct pt_regs *regs) + __single_step_exception(regs); + } + ++#ifdef CONFIG_PPC_FPU_REGS + static inline int __parse_fpscr(unsigned long fpscr) + { + int ret = FPE_FLTUNK; +@@ -1190,6 +1191,7 @@ static inline int __parse_fpscr(unsigned long fpscr) + + return ret; + } ++#endif + + static void parse_fpe(struct pt_regs *regs) + { +@@ -1437,10 +1439,12 @@ static int emulate_instruction(struct pt_regs *regs) + return -EINVAL; + } + ++#ifdef CONFIG_GENERIC_BUG + int is_valid_bugaddr(unsigned long addr) + { + return is_kernel_addr(addr); + } ++#endif + + #ifdef CONFIG_MATH_EMULATION + static int emulate_math(struct pt_regs *regs) +diff --git a/arch/powerpc/kernel/vdso/cacheflush.S b/arch/powerpc/kernel/vdso/cacheflush.S +index 0085ae464dac9c..3b2479bd2f9a1d 100644 +--- a/arch/powerpc/kernel/vdso/cacheflush.S ++++ b/arch/powerpc/kernel/vdso/cacheflush.S +@@ -30,7 +30,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) + #ifdef CONFIG_PPC64 + mflr r12 + .cfi_register lr,r12 +- get_datapage r10 ++ get_realdatapage r10, r11 + mtlr r12 + .cfi_restore lr + #endif +diff --git a/arch/powerpc/kernel/vdso/datapage.S b/arch/powerpc/kernel/vdso/datapage.S +index db8e167f01667e..2b19b6201a33a8 100644 +--- a/arch/powerpc/kernel/vdso/datapage.S ++++ b/arch/powerpc/kernel/vdso/datapage.S +@@ -28,7 +28,7 @@ V_FUNCTION_BEGIN(__kernel_get_syscall_map) + mflr r12 + .cfi_register lr,r12 + mr. r4,r3 +- get_datapage r3 ++ get_realdatapage r3, r11 + mtlr r12 + #ifdef __powerpc64__ + addi r3,r3,CFG_SYSCALL_MAP64 +@@ -52,7 +52,7 @@ V_FUNCTION_BEGIN(__kernel_get_tbfreq) + .cfi_startproc + mflr r12 + .cfi_register lr,r12 +- get_datapage r3 ++ get_realdatapage r3, r11 + #ifndef __powerpc64__ + lwz r4,(CFG_TB_TICKS_PER_SEC + 4)(r3) + #endif +diff --git a/arch/powerpc/kernel/vdso/gettimeofday.S b/arch/powerpc/kernel/vdso/gettimeofday.S +index 48fc6658053aa4..894cb939cd2b31 100644 +--- a/arch/powerpc/kernel/vdso/gettimeofday.S ++++ b/arch/powerpc/kernel/vdso/gettimeofday.S +@@ -38,11 +38,7 @@ + .else + addi r4, r5, VDSO_DATA_OFFSET + .endif +-#ifdef __powerpc64__ + bl CFUNC(DOTSYM(\funct)) +-#else +- bl \funct +-#endif + PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) + #ifdef __powerpc64__ + PPC_LL r2, PPC_MIN_STKFRM + STK_GOT(r1) +diff --git a/arch/powerpc/kernel/vdso/vdso32.lds.S b/arch/powerpc/kernel/vdso/vdso32.lds.S +index 426e1ccc6971a3..8f57107000a247 100644 +--- a/arch/powerpc/kernel/vdso/vdso32.lds.S ++++ b/arch/powerpc/kernel/vdso/vdso32.lds.S +@@ -74,6 +74,8 @@ SECTIONS + .got : { *(.got) } :text + .plt : { *(.plt) } + ++ .rela.dyn : { *(.rela .rela*) } ++ + _end = .; + __end = .; + PROVIDE(end = .); +@@ -87,7 +89,7 @@ SECTIONS + *(.branch_lt) + *(.data .data.* .gnu.linkonce.d.* .sdata*) + *(.bss .sbss .dynbss .dynsbss) +- *(.got1 .glink .iplt .rela*) ++ *(.got1 .glink .iplt) + } + } + +diff --git a/arch/powerpc/kernel/vdso/vdso64.lds.S b/arch/powerpc/kernel/vdso/vdso64.lds.S +index bda6c8cdd459c0..400819258c06b7 100644 +--- a/arch/powerpc/kernel/vdso/vdso64.lds.S ++++ b/arch/powerpc/kernel/vdso/vdso64.lds.S +@@ -69,7 +69,7 @@ SECTIONS + .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr + .eh_frame : { KEEP (*(.eh_frame)) } :text + .gcc_except_table : { *(.gcc_except_table) } +- .rela.dyn ALIGN(8) : { *(.rela.dyn) } ++ .rela.dyn ALIGN(8) : { *(.rela .rela*) } + + .got ALIGN(8) : { *(.got .toc) } + +@@ -86,7 +86,7 @@ SECTIONS + *(.data .data.* .gnu.linkonce.d.* .sdata*) + *(.bss .sbss .dynbss .dynsbss) + *(.opd) +- *(.glink .iplt .plt .rela*) ++ *(.glink .iplt .plt) + } + } + +diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S +index 4094e4c4c77a77..80b3f6e476b66b 100644 +--- a/arch/powerpc/kernel/vector.S ++++ b/arch/powerpc/kernel/vector.S +@@ -33,6 +33,7 @@ _GLOBAL(store_vr_state) + mfvscr v0 + li r4, VRSTATE_VSCR + stvx v0, r4, r3 ++ lvx v0, 0, r3 + blr + EXPORT_SYMBOL(store_vr_state) + +@@ -109,6 +110,7 @@ _GLOBAL(save_altivec) + mfvscr v0 + li r4,VRSTATE_VSCR + stvx v0,r4,r7 ++ lvx v0,0,r7 + blr + + #ifdef CONFIG_VSX +diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S +index 1c5970df323366..f420df7888a75c 100644 +--- a/arch/powerpc/kernel/vmlinux.lds.S ++++ b/arch/powerpc/kernel/vmlinux.lds.S +@@ -281,7 +281,9 @@ SECTIONS + * to deal with references from __bug_table + */ + .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { ++ __exittext_begin = .; + EXIT_TEXT ++ __exittext_end = .; + } + + . = ALIGN(PAGE_SIZE); +diff --git a/arch/powerpc/kexec/core.c b/arch/powerpc/kexec/core.c +index de64c796299121..005269ac3244c4 100644 +--- a/arch/powerpc/kexec/core.c ++++ b/arch/powerpc/kexec/core.c +@@ -74,6 +74,9 @@ void arch_crash_save_vmcoreinfo(void) + VMCOREINFO_STRUCT_SIZE(mmu_psize_def); + VMCOREINFO_OFFSET(mmu_psize_def, shift); + #endif ++ VMCOREINFO_SYMBOL(cur_cpu_spec); ++ VMCOREINFO_OFFSET(cpu_spec, mmu_features); ++ vmcoreinfo_append_str("NUMBER(RADIX_MMU)=%d\n", early_radix_enabled()); + vmcoreinfo_append_str("KERNELOFFSET=%lx\n", kaslr_offset()); + } + +diff --git a/arch/powerpc/kexec/core_64.c b/arch/powerpc/kexec/core_64.c +index a79e28c91e2be3..e465e448773768 100644 +--- a/arch/powerpc/kexec/core_64.c ++++ b/arch/powerpc/kexec/core_64.c +@@ -26,6 +26,7 @@ + #include + #include + #include /* _end */ ++#include + #include + #include + #include +@@ -316,6 +317,16 @@ void default_machine_kexec(struct kimage *image) + if (!kdump_in_progress()) + kexec_prepare_cpus(); + ++#ifdef CONFIG_PPC_PSERIES ++ /* ++ * This must be done after other CPUs have shut down, otherwise they ++ * could execute the 'scv' instruction, which is not supported with ++ * reloc disabled (see configure_exceptions()). ++ */ ++ if (firmware_has_feature(FW_FEATURE_SET_MODE)) ++ pseries_disable_reloc_on_exc(); ++#endif ++ + printk("kexec: Starting switchover sequence.\n"); + + /* switch to a staticly allocated stack. Based on irq stack code. +diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c +index efd0ebf70a5e60..fdfc2a62dd67df 100644 +--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c ++++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c +@@ -28,6 +28,7 @@ + #include + + #include "book3s.h" ++#include "book3s_hv.h" + #include "trace_hv.h" + + //#define DEBUG_RESIZE_HPT 1 +@@ -347,7 +348,7 @@ static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, + unsigned long v, orig_v, gr; + __be64 *hptep; + long int index; +- int virtmode = vcpu->arch.shregs.msr & (data ? MSR_DR : MSR_IR); ++ int virtmode = __kvmppc_get_msr_hv(vcpu) & (data ? MSR_DR : MSR_IR); + + if (kvm_is_radix(vcpu->kvm)) + return kvmppc_mmu_radix_xlate(vcpu, eaddr, gpte, data, iswrite); +@@ -385,7 +386,7 @@ static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, + + /* Get PP bits and key for permission check */ + pp = gr & (HPTE_R_PP0 | HPTE_R_PP); +- key = (vcpu->arch.shregs.msr & MSR_PR) ? SLB_VSID_KP : SLB_VSID_KS; ++ key = (__kvmppc_get_msr_hv(vcpu) & MSR_PR) ? SLB_VSID_KP : SLB_VSID_KS; + key &= slb_v; + + /* Calculate permissions */ +diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c +index 572707858d65d4..10aacbf92466a5 100644 +--- a/arch/powerpc/kvm/book3s_64_mmu_radix.c ++++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c +@@ -15,6 +15,7 @@ + + #include + #include ++#include "book3s_hv.h" + #include + #include + #include +@@ -294,9 +295,9 @@ int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, + } else { + if (!(pte & _PAGE_PRIVILEGED)) { + /* Check AMR/IAMR to see if strict mode is in force */ +- if (vcpu->arch.amr & (1ul << 62)) ++ if (kvmppc_get_amr_hv(vcpu) & (1ul << 62)) + gpte->may_read = 0; +- if (vcpu->arch.amr & (1ul << 63)) ++ if (kvmppc_get_amr_hv(vcpu) & (1ul << 63)) + gpte->may_write = 0; + if (vcpu->arch.iamr & (1ul << 62)) + gpte->may_execute = 0; +diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c +index 93b695b289e99a..395659f2f4c8ef 100644 +--- a/arch/powerpc/kvm/book3s_64_vio.c ++++ b/arch/powerpc/kvm/book3s_64_vio.c +@@ -129,14 +129,16 @@ extern long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, + } + rcu_read_unlock(); + +- fdput(f); +- +- if (!found) ++ if (!found) { ++ fdput(f); + return -EINVAL; ++ } + + table_group = iommu_group_get_iommudata(grp); +- if (WARN_ON(!table_group)) ++ if (WARN_ON(!table_group)) { ++ fdput(f); + return -EFAULT; ++ } + + for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { + struct iommu_table *tbltmp = table_group->tables[i]; +@@ -157,8 +159,10 @@ extern long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, + break; + } + } +- if (!tbl) ++ if (!tbl) { ++ fdput(f); + return -EINVAL; ++ } + + rcu_read_lock(); + list_for_each_entry_rcu(stit, &stt->iommu_tables, next) { +@@ -169,6 +173,7 @@ extern long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, + /* stit is being destroyed */ + iommu_tce_table_put(tbl); + rcu_read_unlock(); ++ fdput(f); + return -ENOTTY; + } + /* +@@ -176,6 +181,7 @@ extern long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, + * its KVM reference counter and can return. + */ + rcu_read_unlock(); ++ fdput(f); + return 0; + } + rcu_read_unlock(); +@@ -183,6 +189,7 @@ extern long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, + stit = kzalloc(sizeof(*stit), GFP_KERNEL); + if (!stit) { + iommu_tce_table_put(tbl); ++ fdput(f); + return -ENOMEM; + } + +@@ -191,6 +198,7 @@ extern long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, + + list_add_rcu(&stit->next, &stt->iommu_tables); + ++ fdput(f); + return 0; + } + +diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c +index 130bafdb143088..1bb00c72154407 100644 +--- a/arch/powerpc/kvm/book3s_hv.c ++++ b/arch/powerpc/kvm/book3s_hv.c +@@ -868,7 +868,7 @@ static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags, + /* Guests can't breakpoint the hypervisor */ + if ((value1 & CIABR_PRIV) == CIABR_PRIV_HYPER) + return H_P3; +- vcpu->arch.ciabr = value1; ++ kvmppc_set_ciabr_hv(vcpu, value1); + return H_SUCCESS; + case H_SET_MODE_RESOURCE_SET_DAWR0: + if (!kvmppc_power8_compatible(vcpu)) +@@ -879,8 +879,8 @@ static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags, + return H_UNSUPPORTED_FLAG_START; + if (value2 & DABRX_HYP) + return H_P4; +- vcpu->arch.dawr0 = value1; +- vcpu->arch.dawrx0 = value2; ++ kvmppc_set_dawr0_hv(vcpu, value1); ++ kvmppc_set_dawrx0_hv(vcpu, value2); + return H_SUCCESS; + case H_SET_MODE_RESOURCE_SET_DAWR1: + if (!kvmppc_power8_compatible(vcpu)) +@@ -895,8 +895,8 @@ static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags, + return H_UNSUPPORTED_FLAG_START; + if (value2 & DABRX_HYP) + return H_P4; +- vcpu->arch.dawr1 = value1; +- vcpu->arch.dawrx1 = value2; ++ kvmppc_set_dawr1_hv(vcpu, value1); ++ kvmppc_set_dawrx1_hv(vcpu, value2); + return H_SUCCESS; + case H_SET_MODE_RESOURCE_ADDR_TRANS_MODE: + /* +@@ -1370,7 +1370,7 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) + */ + static void kvmppc_cede(struct kvm_vcpu *vcpu) + { +- vcpu->arch.shregs.msr |= MSR_EE; ++ __kvmppc_set_msr_hv(vcpu, __kvmppc_get_msr_hv(vcpu) | MSR_EE); + vcpu->arch.ceded = 1; + smp_mb(); + if (vcpu->arch.prodded) { +@@ -1544,7 +1544,7 @@ static int kvmppc_pmu_unavailable(struct kvm_vcpu *vcpu) + if (!(vcpu->arch.hfscr_permitted & HFSCR_PM)) + return EMULATE_FAIL; + +- vcpu->arch.hfscr |= HFSCR_PM; ++ kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) | HFSCR_PM); + + return RESUME_GUEST; + } +@@ -1554,7 +1554,7 @@ static int kvmppc_ebb_unavailable(struct kvm_vcpu *vcpu) + if (!(vcpu->arch.hfscr_permitted & HFSCR_EBB)) + return EMULATE_FAIL; + +- vcpu->arch.hfscr |= HFSCR_EBB; ++ kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) | HFSCR_EBB); + + return RESUME_GUEST; + } +@@ -1564,7 +1564,7 @@ static int kvmppc_tm_unavailable(struct kvm_vcpu *vcpu) + if (!(vcpu->arch.hfscr_permitted & HFSCR_TM)) + return EMULATE_FAIL; + +- vcpu->arch.hfscr |= HFSCR_TM; ++ kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) | HFSCR_TM); + + return RESUME_GUEST; + } +@@ -1585,7 +1585,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, + * That can happen due to a bug, or due to a machine check + * occurring at just the wrong time. + */ +- if (vcpu->arch.shregs.msr & MSR_HV) { ++ if (__kvmppc_get_msr_hv(vcpu) & MSR_HV) { + printk(KERN_EMERG "KVM trap in HV mode!\n"); + printk(KERN_EMERG "trap=0x%x | pc=0x%lx | msr=0x%llx\n", + vcpu->arch.trap, kvmppc_get_pc(vcpu), +@@ -1636,7 +1636,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, + * so that it knows that the machine check occurred. + */ + if (!vcpu->kvm->arch.fwnmi_enabled) { +- ulong flags = (vcpu->arch.shregs.msr & 0x083c0000) | ++ ulong flags = (__kvmppc_get_msr_hv(vcpu) & 0x083c0000) | + (kvmppc_get_msr(vcpu) & SRR1_PREFIXED); + kvmppc_core_queue_machine_check(vcpu, flags); + r = RESUME_GUEST; +@@ -1666,7 +1666,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, + * as a result of a hypervisor emulation interrupt + * (e40) getting turned into a 700 by BML RTAS. + */ +- flags = (vcpu->arch.shregs.msr & 0x1f0000ull) | ++ flags = (__kvmppc_get_msr_hv(vcpu) & 0x1f0000ull) | + (kvmppc_get_msr(vcpu) & SRR1_PREFIXED); + kvmppc_core_queue_program(vcpu, flags); + r = RESUME_GUEST; +@@ -1676,7 +1676,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, + { + int i; + +- if (unlikely(vcpu->arch.shregs.msr & MSR_PR)) { ++ if (unlikely(__kvmppc_get_msr_hv(vcpu) & MSR_PR)) { + /* + * Guest userspace executed sc 1. This can only be + * reached by the P9 path because the old path +@@ -1754,7 +1754,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, + break; + } + +- if (!(vcpu->arch.shregs.msr & MSR_DR)) ++ if (!(__kvmppc_get_msr_hv(vcpu) & MSR_DR)) + vsid = vcpu->kvm->arch.vrma_slb_v; + else + vsid = vcpu->arch.fault_gpa; +@@ -1778,7 +1778,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, + long err; + + vcpu->arch.fault_dar = kvmppc_get_pc(vcpu); +- vcpu->arch.fault_dsisr = vcpu->arch.shregs.msr & ++ vcpu->arch.fault_dsisr = __kvmppc_get_msr_hv(vcpu) & + DSISR_SRR1_MATCH_64S; + if (kvm_is_radix(vcpu->kvm) || !cpu_has_feature(CPU_FTR_ARCH_300)) { + /* +@@ -1787,7 +1787,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, + * hash fault handling below is v3 only (it uses ASDR + * via fault_gpa). + */ +- if (vcpu->arch.shregs.msr & HSRR1_HISI_WRITE) ++ if (__kvmppc_get_msr_hv(vcpu) & HSRR1_HISI_WRITE) + vcpu->arch.fault_dsisr |= DSISR_ISSTORE; + r = RESUME_PAGE_FAULT; + break; +@@ -1801,7 +1801,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, + break; + } + +- if (!(vcpu->arch.shregs.msr & MSR_IR)) ++ if (!(__kvmppc_get_msr_hv(vcpu) & MSR_IR)) + vsid = vcpu->kvm->arch.vrma_slb_v; + else + vsid = vcpu->arch.fault_gpa; +@@ -1863,7 +1863,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, + * Otherwise, we just generate a program interrupt to the guest. + */ + case BOOK3S_INTERRUPT_H_FAC_UNAVAIL: { +- u64 cause = vcpu->arch.hfscr >> 56; ++ u64 cause = kvmppc_get_hfscr_hv(vcpu) >> 56; + + r = EMULATE_FAIL; + if (cpu_has_feature(CPU_FTR_ARCH_300)) { +@@ -1891,7 +1891,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, + kvmppc_dump_regs(vcpu); + printk(KERN_EMERG "trap=0x%x | pc=0x%lx | msr=0x%llx\n", + vcpu->arch.trap, kvmppc_get_pc(vcpu), +- vcpu->arch.shregs.msr); ++ __kvmppc_get_msr_hv(vcpu)); + run->hw.hardware_exit_reason = vcpu->arch.trap; + r = RESUME_HOST; + break; +@@ -1915,11 +1915,11 @@ static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu) + * That can happen due to a bug, or due to a machine check + * occurring at just the wrong time. + */ +- if (vcpu->arch.shregs.msr & MSR_HV) { ++ if (__kvmppc_get_msr_hv(vcpu) & MSR_HV) { + pr_emerg("KVM trap in HV mode while nested!\n"); + pr_emerg("trap=0x%x | pc=0x%lx | msr=0x%llx\n", + vcpu->arch.trap, kvmppc_get_pc(vcpu), +- vcpu->arch.shregs.msr); ++ __kvmppc_get_msr_hv(vcpu)); + kvmppc_dump_regs(vcpu); + return RESUME_HOST; + } +@@ -1976,7 +1976,7 @@ static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu) + vcpu->arch.fault_dar = kvmppc_get_pc(vcpu); + vcpu->arch.fault_dsisr = kvmppc_get_msr(vcpu) & + DSISR_SRR1_MATCH_64S; +- if (vcpu->arch.shregs.msr & HSRR1_HISI_WRITE) ++ if (__kvmppc_get_msr_hv(vcpu) & HSRR1_HISI_WRITE) + vcpu->arch.fault_dsisr |= DSISR_ISSTORE; + srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); + r = kvmhv_nested_page_fault(vcpu); +@@ -2207,64 +2207,64 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, + *val = get_reg_val(id, vcpu->arch.dabrx); + break; + case KVM_REG_PPC_DSCR: +- *val = get_reg_val(id, vcpu->arch.dscr); ++ *val = get_reg_val(id, kvmppc_get_dscr_hv(vcpu)); + break; + case KVM_REG_PPC_PURR: +- *val = get_reg_val(id, vcpu->arch.purr); ++ *val = get_reg_val(id, kvmppc_get_purr_hv(vcpu)); + break; + case KVM_REG_PPC_SPURR: +- *val = get_reg_val(id, vcpu->arch.spurr); ++ *val = get_reg_val(id, kvmppc_get_spurr_hv(vcpu)); + break; + case KVM_REG_PPC_AMR: +- *val = get_reg_val(id, vcpu->arch.amr); ++ *val = get_reg_val(id, kvmppc_get_amr_hv(vcpu)); + break; + case KVM_REG_PPC_UAMOR: +- *val = get_reg_val(id, vcpu->arch.uamor); ++ *val = get_reg_val(id, kvmppc_get_uamor_hv(vcpu)); + break; + case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCR1: + i = id - KVM_REG_PPC_MMCR0; +- *val = get_reg_val(id, vcpu->arch.mmcr[i]); ++ *val = get_reg_val(id, kvmppc_get_mmcr_hv(vcpu, i)); + break; + case KVM_REG_PPC_MMCR2: +- *val = get_reg_val(id, vcpu->arch.mmcr[2]); ++ *val = get_reg_val(id, kvmppc_get_mmcr_hv(vcpu, 2)); + break; + case KVM_REG_PPC_MMCRA: +- *val = get_reg_val(id, vcpu->arch.mmcra); ++ *val = get_reg_val(id, kvmppc_get_mmcra_hv(vcpu)); + break; + case KVM_REG_PPC_MMCRS: + *val = get_reg_val(id, vcpu->arch.mmcrs); + break; + case KVM_REG_PPC_MMCR3: +- *val = get_reg_val(id, vcpu->arch.mmcr[3]); ++ *val = get_reg_val(id, kvmppc_get_mmcr_hv(vcpu, 3)); + break; + case KVM_REG_PPC_PMC1 ... KVM_REG_PPC_PMC8: + i = id - KVM_REG_PPC_PMC1; +- *val = get_reg_val(id, vcpu->arch.pmc[i]); ++ *val = get_reg_val(id, kvmppc_get_pmc_hv(vcpu, i)); + break; + case KVM_REG_PPC_SPMC1 ... KVM_REG_PPC_SPMC2: + i = id - KVM_REG_PPC_SPMC1; + *val = get_reg_val(id, vcpu->arch.spmc[i]); + break; + case KVM_REG_PPC_SIAR: +- *val = get_reg_val(id, vcpu->arch.siar); ++ *val = get_reg_val(id, kvmppc_get_siar_hv(vcpu)); + break; + case KVM_REG_PPC_SDAR: +- *val = get_reg_val(id, vcpu->arch.sdar); ++ *val = get_reg_val(id, kvmppc_get_sdar_hv(vcpu)); + break; + case KVM_REG_PPC_SIER: +- *val = get_reg_val(id, vcpu->arch.sier[0]); ++ *val = get_reg_val(id, kvmppc_get_sier_hv(vcpu, 0)); + break; + case KVM_REG_PPC_SIER2: +- *val = get_reg_val(id, vcpu->arch.sier[1]); ++ *val = get_reg_val(id, kvmppc_get_sier_hv(vcpu, 1)); + break; + case KVM_REG_PPC_SIER3: +- *val = get_reg_val(id, vcpu->arch.sier[2]); ++ *val = get_reg_val(id, kvmppc_get_sier_hv(vcpu, 2)); + break; + case KVM_REG_PPC_IAMR: +- *val = get_reg_val(id, vcpu->arch.iamr); ++ *val = get_reg_val(id, kvmppc_get_iamr_hv(vcpu)); + break; + case KVM_REG_PPC_PSPB: +- *val = get_reg_val(id, vcpu->arch.pspb); ++ *val = get_reg_val(id, kvmppc_get_pspb_hv(vcpu)); + break; + case KVM_REG_PPC_DPDES: + /* +@@ -2282,19 +2282,19 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, + *val = get_reg_val(id, vcpu->arch.vcore->vtb); + break; + case KVM_REG_PPC_DAWR: +- *val = get_reg_val(id, vcpu->arch.dawr0); ++ *val = get_reg_val(id, kvmppc_get_dawr0_hv(vcpu)); + break; + case KVM_REG_PPC_DAWRX: +- *val = get_reg_val(id, vcpu->arch.dawrx0); ++ *val = get_reg_val(id, kvmppc_get_dawrx0_hv(vcpu)); + break; + case KVM_REG_PPC_DAWR1: +- *val = get_reg_val(id, vcpu->arch.dawr1); ++ *val = get_reg_val(id, kvmppc_get_dawr1_hv(vcpu)); + break; + case KVM_REG_PPC_DAWRX1: +- *val = get_reg_val(id, vcpu->arch.dawrx1); ++ *val = get_reg_val(id, kvmppc_get_dawrx1_hv(vcpu)); + break; + case KVM_REG_PPC_CIABR: +- *val = get_reg_val(id, vcpu->arch.ciabr); ++ *val = get_reg_val(id, kvmppc_get_ciabr_hv(vcpu)); + break; + case KVM_REG_PPC_CSIGR: + *val = get_reg_val(id, vcpu->arch.csigr); +@@ -2312,7 +2312,7 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, + *val = get_reg_val(id, vcpu->arch.acop); + break; + case KVM_REG_PPC_WORT: +- *val = get_reg_val(id, vcpu->arch.wort); ++ *val = get_reg_val(id, kvmppc_get_wort_hv(vcpu)); + break; + case KVM_REG_PPC_TIDR: + *val = get_reg_val(id, vcpu->arch.tid); +@@ -2345,7 +2345,7 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, + *val = get_reg_val(id, vcpu->arch.vcore->lpcr); + break; + case KVM_REG_PPC_PPR: +- *val = get_reg_val(id, vcpu->arch.ppr); ++ *val = get_reg_val(id, kvmppc_get_ppr_hv(vcpu)); + break; + #ifdef CONFIG_PPC_TRANSACTIONAL_MEM + case KVM_REG_PPC_TFHAR: +@@ -2425,6 +2425,9 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, + case KVM_REG_PPC_PTCR: + *val = get_reg_val(id, vcpu->kvm->arch.l1_ptcr); + break; ++ case KVM_REG_PPC_FSCR: ++ *val = get_reg_val(id, kvmppc_get_fscr_hv(vcpu)); ++ break; + default: + r = -EINVAL; + break; +@@ -2453,64 +2456,64 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, + vcpu->arch.dabrx = set_reg_val(id, *val) & ~DABRX_HYP; + break; + case KVM_REG_PPC_DSCR: +- vcpu->arch.dscr = set_reg_val(id, *val); ++ kvmppc_set_dscr_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_PURR: +- vcpu->arch.purr = set_reg_val(id, *val); ++ kvmppc_set_purr_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_SPURR: +- vcpu->arch.spurr = set_reg_val(id, *val); ++ kvmppc_set_spurr_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_AMR: +- vcpu->arch.amr = set_reg_val(id, *val); ++ kvmppc_set_amr_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_UAMOR: +- vcpu->arch.uamor = set_reg_val(id, *val); ++ kvmppc_set_uamor_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCR1: + i = id - KVM_REG_PPC_MMCR0; +- vcpu->arch.mmcr[i] = set_reg_val(id, *val); ++ kvmppc_set_mmcr_hv(vcpu, i, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_MMCR2: +- vcpu->arch.mmcr[2] = set_reg_val(id, *val); ++ kvmppc_set_mmcr_hv(vcpu, 2, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_MMCRA: +- vcpu->arch.mmcra = set_reg_val(id, *val); ++ kvmppc_set_mmcra_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_MMCRS: + vcpu->arch.mmcrs = set_reg_val(id, *val); + break; + case KVM_REG_PPC_MMCR3: +- *val = get_reg_val(id, vcpu->arch.mmcr[3]); ++ kvmppc_set_mmcr_hv(vcpu, 3, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_PMC1 ... KVM_REG_PPC_PMC8: + i = id - KVM_REG_PPC_PMC1; +- vcpu->arch.pmc[i] = set_reg_val(id, *val); ++ kvmppc_set_pmc_hv(vcpu, i, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_SPMC1 ... KVM_REG_PPC_SPMC2: + i = id - KVM_REG_PPC_SPMC1; + vcpu->arch.spmc[i] = set_reg_val(id, *val); + break; + case KVM_REG_PPC_SIAR: +- vcpu->arch.siar = set_reg_val(id, *val); ++ kvmppc_set_siar_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_SDAR: +- vcpu->arch.sdar = set_reg_val(id, *val); ++ kvmppc_set_sdar_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_SIER: +- vcpu->arch.sier[0] = set_reg_val(id, *val); ++ kvmppc_set_sier_hv(vcpu, 0, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_SIER2: +- vcpu->arch.sier[1] = set_reg_val(id, *val); ++ kvmppc_set_sier_hv(vcpu, 1, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_SIER3: +- vcpu->arch.sier[2] = set_reg_val(id, *val); ++ kvmppc_set_sier_hv(vcpu, 2, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_IAMR: +- vcpu->arch.iamr = set_reg_val(id, *val); ++ kvmppc_set_iamr_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_PSPB: +- vcpu->arch.pspb = set_reg_val(id, *val); ++ kvmppc_set_pspb_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_DPDES: + if (cpu_has_feature(CPU_FTR_ARCH_300)) +@@ -2522,22 +2525,22 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, + vcpu->arch.vcore->vtb = set_reg_val(id, *val); + break; + case KVM_REG_PPC_DAWR: +- vcpu->arch.dawr0 = set_reg_val(id, *val); ++ kvmppc_set_dawr0_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_DAWRX: +- vcpu->arch.dawrx0 = set_reg_val(id, *val) & ~DAWRX_HYP; ++ kvmppc_set_dawrx0_hv(vcpu, set_reg_val(id, *val) & ~DAWRX_HYP); + break; + case KVM_REG_PPC_DAWR1: +- vcpu->arch.dawr1 = set_reg_val(id, *val); ++ kvmppc_set_dawr1_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_DAWRX1: +- vcpu->arch.dawrx1 = set_reg_val(id, *val) & ~DAWRX_HYP; ++ kvmppc_set_dawrx1_hv(vcpu, set_reg_val(id, *val) & ~DAWRX_HYP); + break; + case KVM_REG_PPC_CIABR: +- vcpu->arch.ciabr = set_reg_val(id, *val); ++ kvmppc_set_ciabr_hv(vcpu, set_reg_val(id, *val)); + /* Don't allow setting breakpoints in hypervisor code */ +- if ((vcpu->arch.ciabr & CIABR_PRIV) == CIABR_PRIV_HYPER) +- vcpu->arch.ciabr &= ~CIABR_PRIV; /* disable */ ++ if ((kvmppc_get_ciabr_hv(vcpu) & CIABR_PRIV) == CIABR_PRIV_HYPER) ++ kvmppc_set_ciabr_hv(vcpu, kvmppc_get_ciabr_hv(vcpu) & ~CIABR_PRIV); + break; + case KVM_REG_PPC_CSIGR: + vcpu->arch.csigr = set_reg_val(id, *val); +@@ -2555,7 +2558,7 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, + vcpu->arch.acop = set_reg_val(id, *val); + break; + case KVM_REG_PPC_WORT: +- vcpu->arch.wort = set_reg_val(id, *val); ++ kvmppc_set_wort_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_TIDR: + vcpu->arch.tid = set_reg_val(id, *val); +@@ -2615,7 +2618,7 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, + kvmppc_set_lpcr(vcpu, set_reg_val(id, *val), false); + break; + case KVM_REG_PPC_PPR: +- vcpu->arch.ppr = set_reg_val(id, *val); ++ kvmppc_set_ppr_hv(vcpu, set_reg_val(id, *val)); + break; + #ifdef CONFIG_PPC_TRANSACTIONAL_MEM + case KVM_REG_PPC_TFHAR: +@@ -2699,6 +2702,9 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, + case KVM_REG_PPC_PTCR: + vcpu->kvm->arch.l1_ptcr = set_reg_val(id, *val); + break; ++ case KVM_REG_PPC_FSCR: ++ kvmppc_set_fscr_hv(vcpu, set_reg_val(id, *val)); ++ break; + default: + r = -EINVAL; + break; +@@ -2916,19 +2922,20 @@ static int kvmppc_core_vcpu_create_hv(struct kvm_vcpu *vcpu) + vcpu->arch.shared_big_endian = false; + #endif + #endif +- vcpu->arch.mmcr[0] = MMCR0_FC; ++ kvmppc_set_mmcr_hv(vcpu, 0, MMCR0_FC); ++ + if (cpu_has_feature(CPU_FTR_ARCH_31)) { +- vcpu->arch.mmcr[0] |= MMCR0_PMCCEXT; +- vcpu->arch.mmcra = MMCRA_BHRB_DISABLE; ++ kvmppc_set_mmcr_hv(vcpu, 0, kvmppc_get_mmcr_hv(vcpu, 0) | MMCR0_PMCCEXT); ++ kvmppc_set_mmcra_hv(vcpu, MMCRA_BHRB_DISABLE); + } + +- vcpu->arch.ctrl = CTRL_RUNLATCH; ++ kvmppc_set_ctrl_hv(vcpu, CTRL_RUNLATCH); + /* default to host PVR, since we can't spoof it */ + kvmppc_set_pvr_hv(vcpu, mfspr(SPRN_PVR)); + spin_lock_init(&vcpu->arch.vpa_update_lock); + spin_lock_init(&vcpu->arch.tbacct_lock); + vcpu->arch.busy_preempt = TB_NIL; +- vcpu->arch.shregs.msr = MSR_ME; ++ __kvmppc_set_msr_hv(vcpu, MSR_ME); + vcpu->arch.intr_msr = MSR_SF | MSR_ME; + + /* +@@ -2938,29 +2945,30 @@ static int kvmppc_core_vcpu_create_hv(struct kvm_vcpu *vcpu) + * don't set the HFSCR_MSGP bit, and that causes those instructions + * to trap and then we emulate them. + */ +- vcpu->arch.hfscr = HFSCR_TAR | HFSCR_EBB | HFSCR_PM | HFSCR_BHRB | +- HFSCR_DSCR | HFSCR_VECVSX | HFSCR_FP; ++ kvmppc_set_hfscr_hv(vcpu, HFSCR_TAR | HFSCR_EBB | HFSCR_PM | HFSCR_BHRB | ++ HFSCR_DSCR | HFSCR_VECVSX | HFSCR_FP); + + /* On POWER10 and later, allow prefixed instructions */ + if (cpu_has_feature(CPU_FTR_ARCH_31)) +- vcpu->arch.hfscr |= HFSCR_PREFIX; ++ kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) | HFSCR_PREFIX); + + if (cpu_has_feature(CPU_FTR_HVMODE)) { +- vcpu->arch.hfscr &= mfspr(SPRN_HFSCR); ++ kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) & mfspr(SPRN_HFSCR)); ++ + #ifdef CONFIG_PPC_TRANSACTIONAL_MEM + if (cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST)) +- vcpu->arch.hfscr |= HFSCR_TM; ++ kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) | HFSCR_TM); + #endif + } + if (cpu_has_feature(CPU_FTR_TM_COMP)) + vcpu->arch.hfscr |= HFSCR_TM; + +- vcpu->arch.hfscr_permitted = vcpu->arch.hfscr; ++ vcpu->arch.hfscr_permitted = kvmppc_get_hfscr_hv(vcpu); + + /* + * PM, EBB, TM are demand-faulted so start with it clear. + */ +- vcpu->arch.hfscr &= ~(HFSCR_PM | HFSCR_EBB | HFSCR_TM); ++ kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) & ~(HFSCR_PM | HFSCR_EBB | HFSCR_TM)); + + kvmppc_mmu_book3s_hv_init(vcpu); + +@@ -4176,7 +4184,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, + __this_cpu_write(cpu_in_guest, NULL); + + if (trap == BOOK3S_INTERRUPT_SYSCALL && +- !(vcpu->arch.shregs.msr & MSR_PR)) { ++ !(__kvmppc_get_msr_hv(vcpu) & MSR_PR)) { + unsigned long req = kvmppc_get_gpr(vcpu, 3); + + /* +@@ -4655,13 +4663,19 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, + + if (!nested) { + kvmppc_core_prepare_to_enter(vcpu); +- if (vcpu->arch.shregs.msr & MSR_EE) { +- if (xive_interrupt_pending(vcpu)) ++ if (test_bit(BOOK3S_IRQPRIO_EXTERNAL, ++ &vcpu->arch.pending_exceptions) || ++ xive_interrupt_pending(vcpu)) { ++ /* ++ * For nested HV, don't synthesize but always pass MER, ++ * the L0 will be able to optimise that more ++ * effectively than manipulating registers directly. ++ */ ++ if (!kvmhv_on_pseries() && (__kvmppc_get_msr_hv(vcpu) & MSR_EE)) + kvmppc_inject_interrupt_hv(vcpu, +- BOOK3S_INTERRUPT_EXTERNAL, 0); +- } else if (test_bit(BOOK3S_IRQPRIO_EXTERNAL, +- &vcpu->arch.pending_exceptions)) { +- lpcr |= LPCR_MER; ++ BOOK3S_INTERRUPT_EXTERNAL, 0); ++ else ++ lpcr |= LPCR_MER; + } + } else if (vcpu->arch.pending_exceptions || + vcpu->arch.doorbell_request || +@@ -4844,7 +4858,7 @@ static int kvmppc_vcpu_run_hv(struct kvm_vcpu *vcpu) + msr |= MSR_VSX; + if ((cpu_has_feature(CPU_FTR_TM) || + cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST)) && +- (vcpu->arch.hfscr & HFSCR_TM)) ++ (kvmppc_get_hfscr_hv(vcpu) & HFSCR_TM)) + msr |= MSR_TM; + msr = msr_check_and_set(msr); + +@@ -4868,7 +4882,7 @@ static int kvmppc_vcpu_run_hv(struct kvm_vcpu *vcpu) + if (run->exit_reason == KVM_EXIT_PAPR_HCALL) { + accumulate_time(vcpu, &vcpu->arch.hcall); + +- if (WARN_ON_ONCE(vcpu->arch.shregs.msr & MSR_PR)) { ++ if (WARN_ON_ONCE(__kvmppc_get_msr_hv(vcpu) & MSR_PR)) { + /* + * These should have been caught reflected + * into the guest by now. Final sanity check: +diff --git a/arch/powerpc/kvm/book3s_hv.h b/arch/powerpc/kvm/book3s_hv.h +index 2f2e59d7d433a6..95241764dfb4eb 100644 +--- a/arch/powerpc/kvm/book3s_hv.h ++++ b/arch/powerpc/kvm/book3s_hv.h +@@ -50,3 +50,71 @@ void accumulate_time(struct kvm_vcpu *vcpu, struct kvmhv_tb_accumulator *next); + #define start_timing(vcpu, next) do {} while (0) + #define end_timing(vcpu) do {} while (0) + #endif ++ ++static inline void __kvmppc_set_msr_hv(struct kvm_vcpu *vcpu, u64 val) ++{ ++ vcpu->arch.shregs.msr = val; ++} ++ ++static inline u64 __kvmppc_get_msr_hv(struct kvm_vcpu *vcpu) ++{ ++ return vcpu->arch.shregs.msr; ++} ++ ++#define KVMPPC_BOOK3S_HV_VCPU_ACCESSOR_SET(reg, size) \ ++static inline void kvmppc_set_##reg ##_hv(struct kvm_vcpu *vcpu, u##size val) \ ++{ \ ++ vcpu->arch.reg = val; \ ++} ++ ++#define KVMPPC_BOOK3S_HV_VCPU_ACCESSOR_GET(reg, size) \ ++static inline u##size kvmppc_get_##reg ##_hv(struct kvm_vcpu *vcpu) \ ++{ \ ++ return vcpu->arch.reg; \ ++} ++ ++#define KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(reg, size) \ ++ KVMPPC_BOOK3S_HV_VCPU_ACCESSOR_SET(reg, size) \ ++ KVMPPC_BOOK3S_HV_VCPU_ACCESSOR_GET(reg, size) \ ++ ++#define KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR_SET(reg, size) \ ++static inline void kvmppc_set_##reg ##_hv(struct kvm_vcpu *vcpu, int i, u##size val) \ ++{ \ ++ vcpu->arch.reg[i] = val; \ ++} ++ ++#define KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR_GET(reg, size) \ ++static inline u##size kvmppc_get_##reg ##_hv(struct kvm_vcpu *vcpu, int i) \ ++{ \ ++ return vcpu->arch.reg[i]; \ ++} ++ ++#define KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR(reg, size) \ ++ KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR_SET(reg, size) \ ++ KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR_GET(reg, size) \ ++ ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(mmcra, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(hfscr, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(fscr, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dscr, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(purr, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(spurr, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(amr, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(uamor, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(siar, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(sdar, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(iamr, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawr0, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawr1, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawrx0, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawrx1, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(ciabr, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(wort, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(ppr, 64) ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(ctrl, 64) ++ ++KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR(mmcr, 64) ++KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR(sier, 64) ++KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR(pmc, 32) ++ ++KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(pspb, 32) +diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c +index 0f5b021fa5590b..663f5222f3d06d 100644 +--- a/arch/powerpc/kvm/book3s_hv_builtin.c ++++ b/arch/powerpc/kvm/book3s_hv_builtin.c +@@ -32,6 +32,7 @@ + + #include "book3s_xics.h" + #include "book3s_xive.h" ++#include "book3s_hv.h" + + /* + * Hash page table alignment on newer cpus(CPU_FTR_ARCH_206) +@@ -510,7 +511,7 @@ void kvmppc_set_msr_hv(struct kvm_vcpu *vcpu, u64 msr) + */ + if ((msr & MSR_TS_MASK) == MSR_TS_MASK) + msr &= ~MSR_TS_MASK; +- vcpu->arch.shregs.msr = msr; ++ __kvmppc_set_msr_hv(vcpu, msr); + kvmppc_end_cede(vcpu); + } + EXPORT_SYMBOL_GPL(kvmppc_set_msr_hv); +@@ -548,7 +549,7 @@ static void inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 srr1_flags) + kvmppc_set_srr0(vcpu, pc); + kvmppc_set_srr1(vcpu, (msr & SRR1_MSR_BITS) | srr1_flags); + kvmppc_set_pc(vcpu, new_pc); +- vcpu->arch.shregs.msr = new_msr; ++ __kvmppc_set_msr_hv(vcpu, new_msr); + } + + void kvmppc_inject_interrupt_hv(struct kvm_vcpu *vcpu, int vec, u64 srr1_flags) +diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c +index 7197c8256668b8..6cef200c2404df 100644 +--- a/arch/powerpc/kvm/powerpc.c ++++ b/arch/powerpc/kvm/powerpc.c +@@ -1990,8 +1990,10 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, + break; + + r = -ENXIO; +- if (!xive_enabled()) ++ if (!xive_enabled()) { ++ fdput(f); + break; ++ } + + r = -EPERM; + dev = kvm_device_from_filp(f.file); +diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile +index 51ad0397c17abf..0ab65eeb93ee3a 100644 +--- a/arch/powerpc/lib/Makefile ++++ b/arch/powerpc/lib/Makefile +@@ -45,7 +45,7 @@ obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o + # so it is only needed for modules, and only for older linkers which + # do not support --save-restore-funcs + ifndef CONFIG_LD_IS_BFD +-extra-$(CONFIG_PPC64) += crtsavres.o ++always-$(CONFIG_PPC64) += crtsavres.o + endif + + obj-$(CONFIG_PPC_BOOK3S_64) += copyuser_power7.o copypage_power7.o \ +@@ -76,7 +76,7 @@ obj-$(CONFIG_PPC_LIB_RHEAP) += rheap.o + obj-$(CONFIG_FTR_FIXUP_SELFTEST) += feature-fixups-test.o + + obj-$(CONFIG_ALTIVEC) += xor_vmx.o xor_vmx_glue.o +-CFLAGS_xor_vmx.o += -maltivec $(call cc-option,-mabi=altivec) ++CFLAGS_xor_vmx.o += -mhard-float -maltivec $(call cc-option,-mabi=altivec) + # Enable + CFLAGS_xor_vmx.o += -isystem $(shell $(CC) -print-file-name=include) + +diff --git a/arch/powerpc/lib/qspinlock.c b/arch/powerpc/lib/qspinlock.c +index 6dd2f46bd3ef64..8830267789c9c0 100644 +--- a/arch/powerpc/lib/qspinlock.c ++++ b/arch/powerpc/lib/qspinlock.c +@@ -715,7 +715,15 @@ static __always_inline void queued_spin_lock_mcs_queue(struct qspinlock *lock, b + } + + release: +- qnodesp->count--; /* release the node */ ++ /* ++ * Clear the lock before releasing the node, as another CPU might see stale ++ * values if an interrupt occurs after we increment qnodesp->count ++ * but before node->lock is initialized. The barrier ensures that ++ * there are no further stores to the node after it has been released. ++ */ ++ node->lock = NULL; ++ barrier(); ++ qnodesp->count--; + } + + void queued_spin_lock_slowpath(struct qspinlock *lock) +diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c +index a4ab8625061a66..6af97dc0f6d5a8 100644 +--- a/arch/powerpc/lib/sstep.c ++++ b/arch/powerpc/lib/sstep.c +@@ -586,6 +586,8 @@ static int do_fp_load(struct instruction_op *op, unsigned long ea, + } u; + + nb = GETSIZE(op->type); ++ if (nb > sizeof(u)) ++ return -EINVAL; + if (!address_ok(regs, ea, nb)) + return -EFAULT; + rn = op->reg; +@@ -636,6 +638,8 @@ static int do_fp_store(struct instruction_op *op, unsigned long ea, + } u; + + nb = GETSIZE(op->type); ++ if (nb > sizeof(u)) ++ return -EINVAL; + if (!address_ok(regs, ea, nb)) + return -EFAULT; + rn = op->reg; +@@ -680,6 +684,9 @@ static nokprobe_inline int do_vec_load(int rn, unsigned long ea, + u8 b[sizeof(__vector128)]; + } u = {}; + ++ if (size > sizeof(u)) ++ return -EINVAL; ++ + if (!address_ok(regs, ea & ~0xfUL, 16)) + return -EFAULT; + /* align to multiple of size */ +@@ -707,6 +714,9 @@ static nokprobe_inline int do_vec_store(int rn, unsigned long ea, + u8 b[sizeof(__vector128)]; + } u; + ++ if (size > sizeof(u)) ++ return -EINVAL; ++ + if (!address_ok(regs, ea & ~0xfUL, 16)) + return -EFAULT; + /* align to multiple of size */ +diff --git a/arch/powerpc/mm/book3s64/pgtable.c b/arch/powerpc/mm/book3s64/pgtable.c +index 8f8a62d3ff4de4..5b4cbb25d9cf77 100644 +--- a/arch/powerpc/mm/book3s64/pgtable.c ++++ b/arch/powerpc/mm/book3s64/pgtable.c +@@ -130,7 +130,7 @@ void set_pud_at(struct mm_struct *mm, unsigned long addr, + + WARN_ON(pte_hw_valid(pud_pte(*pudp))); + assert_spin_locked(pud_lockptr(mm, pudp)); +- WARN_ON(!(pud_large(pud))); ++ WARN_ON(!(pud_leaf(pud))); + #endif + trace_hugepage_set_pud(addr, pud_val(pud)); + return set_pte_at(mm, addr, pudp_ptep(pudp), pud_pte(pud)); +@@ -170,6 +170,7 @@ pmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, + { + unsigned long old_pmd; + ++ VM_WARN_ON_ONCE(!pmd_present(*pmdp)); + old_pmd = pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, _PAGE_INVALID); + flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE); + return __pmd(old_pmd); +@@ -542,6 +543,7 @@ void ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr, + set_pte_at(vma->vm_mm, addr, ptep, pte); + } + ++#ifdef CONFIG_TRANSPARENT_HUGEPAGE + /* + * For hash translation mode, we use the deposited table to store hash slot + * information and they are stored at PTRS_PER_PMD offset from related pmd +@@ -563,6 +565,7 @@ int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl, + + return true; + } ++#endif + + /* + * Does the CPU support tlbie? +diff --git a/arch/powerpc/mm/init-common.c b/arch/powerpc/mm/init-common.c +index 119ef491f79760..d3a7726ecf512c 100644 +--- a/arch/powerpc/mm/init-common.c ++++ b/arch/powerpc/mm/init-common.c +@@ -126,7 +126,7 @@ void pgtable_cache_add(unsigned int shift) + * as to leave enough 0 bits in the address to contain it. */ + unsigned long minalign = max(MAX_PGTABLE_INDEX_SIZE + 1, + HUGEPD_SHIFT_MASK + 1); +- struct kmem_cache *new; ++ struct kmem_cache *new = NULL; + + /* It would be nice if this was a BUILD_BUG_ON(), but at the + * moment, gcc doesn't seem to recognize is_power_of_2 as a +@@ -139,7 +139,8 @@ void pgtable_cache_add(unsigned int shift) + + align = max_t(unsigned long, align, minalign); + name = kasprintf(GFP_KERNEL, "pgtable-2^%d", shift); +- new = kmem_cache_create(name, table_size, align, 0, ctor(shift)); ++ if (name) ++ new = kmem_cache_create(name, table_size, align, 0, ctor(shift)); + if (!new) + panic("Could not allocate pgtable cache for order %d", shift); + +diff --git a/arch/powerpc/mm/kasan/init_32.c b/arch/powerpc/mm/kasan/init_32.c +index a70828a6d9357d..aa9aa11927b2f8 100644 +--- a/arch/powerpc/mm/kasan/init_32.c ++++ b/arch/powerpc/mm/kasan/init_32.c +@@ -64,6 +64,7 @@ int __init __weak kasan_init_region(void *start, size_t size) + if (ret) + return ret; + ++ k_start = k_start & PAGE_MASK; + block = memblock_alloc(k_end - k_start, PAGE_SIZE); + if (!block) + return -ENOMEM; +diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c +index 07e8f4f1e07f89..9dbef559af4cbf 100644 +--- a/arch/powerpc/mm/mem.c ++++ b/arch/powerpc/mm/mem.c +@@ -287,8 +287,6 @@ void __init mem_init(void) + swiotlb_init(ppc_swiotlb_enable, ppc_swiotlb_flags); + #endif + +- high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); +- + kasan_late_init(); + + memblock_free_all(); +diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h +index 7f9ff0640124af..72341b9fb5521f 100644 +--- a/arch/powerpc/mm/mmu_decl.h ++++ b/arch/powerpc/mm/mmu_decl.h +@@ -181,3 +181,8 @@ static inline bool debug_pagealloc_enabled_or_kfence(void) + { + return IS_ENABLED(CONFIG_KFENCE) || debug_pagealloc_enabled(); + } ++ ++#ifdef CONFIG_MEMORY_HOTPLUG ++int create_section_mapping(unsigned long start, unsigned long end, ++ int nid, pgprot_t prot); ++#endif +diff --git a/arch/powerpc/mm/nohash/8xx.c b/arch/powerpc/mm/nohash/8xx.c +index a642a79298929d..a947dff35d6517 100644 +--- a/arch/powerpc/mm/nohash/8xx.c ++++ b/arch/powerpc/mm/nohash/8xx.c +@@ -92,7 +92,8 @@ static int __ref __early_map_kernel_hugepage(unsigned long va, phys_addr_t pa, + return -EINVAL; + + set_huge_pte_at(&init_mm, va, ptep, +- pte_mkhuge(pfn_pte(pa >> PAGE_SHIFT, prot)), psize); ++ pte_mkhuge(pfn_pte(pa >> PAGE_SHIFT, prot)), ++ 1UL << mmu_psize_to_shift(psize)); + + return 0; + } +@@ -148,11 +149,11 @@ unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top) + + mmu_mapin_immr(); + +- mmu_mapin_ram_chunk(0, boundary, PAGE_KERNEL_TEXT, true); ++ mmu_mapin_ram_chunk(0, boundary, PAGE_KERNEL_X, true); + if (debug_pagealloc_enabled_or_kfence()) { + top = boundary; + } else { +- mmu_mapin_ram_chunk(boundary, einittext8, PAGE_KERNEL_TEXT, true); ++ mmu_mapin_ram_chunk(boundary, einittext8, PAGE_KERNEL_X, true); + mmu_mapin_ram_chunk(einittext8, top, PAGE_KERNEL, true); + } + +diff --git a/arch/powerpc/mm/nohash/Makefile b/arch/powerpc/mm/nohash/Makefile +index f3894e79d5f700..24b445a5fcaccd 100644 +--- a/arch/powerpc/mm/nohash/Makefile ++++ b/arch/powerpc/mm/nohash/Makefile +@@ -3,7 +3,7 @@ + ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC) + + obj-y += mmu_context.o tlb.o tlb_low.o kup.o +-obj-$(CONFIG_PPC_BOOK3E_64) += tlb_low_64e.o book3e_pgtable.o ++obj-$(CONFIG_PPC_BOOK3E_64) += tlb_64e.o tlb_low_64e.o book3e_pgtable.o + obj-$(CONFIG_40x) += 40x.o + obj-$(CONFIG_44x) += 44x.o + obj-$(CONFIG_PPC_8xx) += 8xx.o +diff --git a/arch/powerpc/mm/nohash/tlb.c b/arch/powerpc/mm/nohash/tlb.c +index 5ffa0af4328af8..f57dc721d0636a 100644 +--- a/arch/powerpc/mm/nohash/tlb.c ++++ b/arch/powerpc/mm/nohash/tlb.c +@@ -110,28 +110,6 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = { + }; + #endif + +-/* The variables below are currently only used on 64-bit Book3E +- * though this will probably be made common with other nohash +- * implementations at some point +- */ +-#ifdef CONFIG_PPC64 +- +-int mmu_pte_psize; /* Page size used for PTE pages */ +-int mmu_vmemmap_psize; /* Page size used for the virtual mem map */ +-int book3e_htw_mode; /* HW tablewalk? Value is PPC_HTW_* */ +-unsigned long linear_map_top; /* Top of linear mapping */ +- +- +-/* +- * Number of bytes to add to SPRN_SPRG_TLB_EXFRAME on crit/mcheck/debug +- * exceptions. This is used for bolted and e6500 TLB miss handlers which +- * do not modify this SPRG in the TLB miss code; for other TLB miss handlers, +- * this is set to zero. +- */ +-int extlb_level_exc; +- +-#endif /* CONFIG_PPC64 */ +- + #ifdef CONFIG_PPC_E500 + /* next_tlbcam_idx is used to round-robin tlbcam entry assignment */ + DEFINE_PER_CPU(int, next_tlbcam_idx); +@@ -358,381 +336,7 @@ void tlb_flush(struct mmu_gather *tlb) + flush_tlb_mm(tlb->mm); + } + +-/* +- * Below are functions specific to the 64-bit variant of Book3E though that +- * may change in the future +- */ +- +-#ifdef CONFIG_PPC64 +- +-/* +- * Handling of virtual linear page tables or indirect TLB entries +- * flushing when PTE pages are freed +- */ +-void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address) +-{ +- int tsize = mmu_psize_defs[mmu_pte_psize].enc; +- +- if (book3e_htw_mode != PPC_HTW_NONE) { +- unsigned long start = address & PMD_MASK; +- unsigned long end = address + PMD_SIZE; +- unsigned long size = 1UL << mmu_psize_defs[mmu_pte_psize].shift; +- +- /* This isn't the most optimal, ideally we would factor out the +- * while preempt & CPU mask mucking around, or even the IPI but +- * it will do for now +- */ +- while (start < end) { +- __flush_tlb_page(tlb->mm, start, tsize, 1); +- start += size; +- } +- } else { +- unsigned long rmask = 0xf000000000000000ul; +- unsigned long rid = (address & rmask) | 0x1000000000000000ul; +- unsigned long vpte = address & ~rmask; +- +- vpte = (vpte >> (PAGE_SHIFT - 3)) & ~0xffful; +- vpte |= rid; +- __flush_tlb_page(tlb->mm, vpte, tsize, 0); +- } +-} +- +-static void __init setup_page_sizes(void) +-{ +- unsigned int tlb0cfg; +- unsigned int tlb0ps; +- unsigned int eptcfg; +- int i, psize; +- +-#ifdef CONFIG_PPC_E500 +- unsigned int mmucfg = mfspr(SPRN_MMUCFG); +- int fsl_mmu = mmu_has_feature(MMU_FTR_TYPE_FSL_E); +- +- if (fsl_mmu && (mmucfg & MMUCFG_MAVN) == MMUCFG_MAVN_V1) { +- unsigned int tlb1cfg = mfspr(SPRN_TLB1CFG); +- unsigned int min_pg, max_pg; +- +- min_pg = (tlb1cfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT; +- max_pg = (tlb1cfg & TLBnCFG_MAXSIZE) >> TLBnCFG_MAXSIZE_SHIFT; +- +- for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { +- struct mmu_psize_def *def; +- unsigned int shift; +- +- def = &mmu_psize_defs[psize]; +- shift = def->shift; +- +- if (shift == 0 || shift & 1) +- continue; +- +- /* adjust to be in terms of 4^shift Kb */ +- shift = (shift - 10) >> 1; +- +- if ((shift >= min_pg) && (shift <= max_pg)) +- def->flags |= MMU_PAGE_SIZE_DIRECT; +- } +- +- goto out; +- } +- +- if (fsl_mmu && (mmucfg & MMUCFG_MAVN) == MMUCFG_MAVN_V2) { +- u32 tlb1cfg, tlb1ps; +- +- tlb0cfg = mfspr(SPRN_TLB0CFG); +- tlb1cfg = mfspr(SPRN_TLB1CFG); +- tlb1ps = mfspr(SPRN_TLB1PS); +- eptcfg = mfspr(SPRN_EPTCFG); +- +- if ((tlb1cfg & TLBnCFG_IND) && (tlb0cfg & TLBnCFG_PT)) +- book3e_htw_mode = PPC_HTW_E6500; +- +- /* +- * We expect 4K subpage size and unrestricted indirect size. +- * The lack of a restriction on indirect size is a Freescale +- * extension, indicated by PSn = 0 but SPSn != 0. +- */ +- if (eptcfg != 2) +- book3e_htw_mode = PPC_HTW_NONE; +- +- for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { +- struct mmu_psize_def *def = &mmu_psize_defs[psize]; +- +- if (!def->shift) +- continue; +- +- if (tlb1ps & (1U << (def->shift - 10))) { +- def->flags |= MMU_PAGE_SIZE_DIRECT; +- +- if (book3e_htw_mode && psize == MMU_PAGE_2M) +- def->flags |= MMU_PAGE_SIZE_INDIRECT; +- } +- } +- +- goto out; +- } +-#endif +- +- tlb0cfg = mfspr(SPRN_TLB0CFG); +- tlb0ps = mfspr(SPRN_TLB0PS); +- eptcfg = mfspr(SPRN_EPTCFG); +- +- /* Look for supported direct sizes */ +- for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { +- struct mmu_psize_def *def = &mmu_psize_defs[psize]; +- +- if (tlb0ps & (1U << (def->shift - 10))) +- def->flags |= MMU_PAGE_SIZE_DIRECT; +- } +- +- /* Indirect page sizes supported ? */ +- if ((tlb0cfg & TLBnCFG_IND) == 0 || +- (tlb0cfg & TLBnCFG_PT) == 0) +- goto out; +- +- book3e_htw_mode = PPC_HTW_IBM; +- +- /* Now, we only deal with one IND page size for each +- * direct size. Hopefully all implementations today are +- * unambiguous, but we might want to be careful in the +- * future. +- */ +- for (i = 0; i < 3; i++) { +- unsigned int ps, sps; +- +- sps = eptcfg & 0x1f; +- eptcfg >>= 5; +- ps = eptcfg & 0x1f; +- eptcfg >>= 5; +- if (!ps || !sps) +- continue; +- for (psize = 0; psize < MMU_PAGE_COUNT; psize++) { +- struct mmu_psize_def *def = &mmu_psize_defs[psize]; +- +- if (ps == (def->shift - 10)) +- def->flags |= MMU_PAGE_SIZE_INDIRECT; +- if (sps == (def->shift - 10)) +- def->ind = ps + 10; +- } +- } +- +-out: +- /* Cleanup array and print summary */ +- pr_info("MMU: Supported page sizes\n"); +- for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { +- struct mmu_psize_def *def = &mmu_psize_defs[psize]; +- const char *__page_type_names[] = { +- "unsupported", +- "direct", +- "indirect", +- "direct & indirect" +- }; +- if (def->flags == 0) { +- def->shift = 0; +- continue; +- } +- pr_info(" %8ld KB as %s\n", 1ul << (def->shift - 10), +- __page_type_names[def->flags & 0x3]); +- } +-} +- +-static void __init setup_mmu_htw(void) +-{ +- /* +- * If we want to use HW tablewalk, enable it by patching the TLB miss +- * handlers to branch to the one dedicated to it. +- */ +- +- switch (book3e_htw_mode) { +- case PPC_HTW_IBM: +- patch_exception(0x1c0, exc_data_tlb_miss_htw_book3e); +- patch_exception(0x1e0, exc_instruction_tlb_miss_htw_book3e); +- break; +-#ifdef CONFIG_PPC_E500 +- case PPC_HTW_E6500: +- extlb_level_exc = EX_TLB_SIZE; +- patch_exception(0x1c0, exc_data_tlb_miss_e6500_book3e); +- patch_exception(0x1e0, exc_instruction_tlb_miss_e6500_book3e); +- break; +-#endif +- } +- pr_info("MMU: Book3E HW tablewalk %s\n", +- book3e_htw_mode != PPC_HTW_NONE ? "enabled" : "not supported"); +-} +- +-/* +- * Early initialization of the MMU TLB code +- */ +-static void early_init_this_mmu(void) +-{ +- unsigned int mas4; +- +- /* Set MAS4 based on page table setting */ +- +- mas4 = 0x4 << MAS4_WIMGED_SHIFT; +- switch (book3e_htw_mode) { +- case PPC_HTW_E6500: +- mas4 |= MAS4_INDD; +- mas4 |= BOOK3E_PAGESZ_2M << MAS4_TSIZED_SHIFT; +- mas4 |= MAS4_TLBSELD(1); +- mmu_pte_psize = MMU_PAGE_2M; +- break; +- +- case PPC_HTW_IBM: +- mas4 |= MAS4_INDD; +- mas4 |= BOOK3E_PAGESZ_1M << MAS4_TSIZED_SHIFT; +- mmu_pte_psize = MMU_PAGE_1M; +- break; +- +- case PPC_HTW_NONE: +- mas4 |= BOOK3E_PAGESZ_4K << MAS4_TSIZED_SHIFT; +- mmu_pte_psize = mmu_virtual_psize; +- break; +- } +- mtspr(SPRN_MAS4, mas4); +- +-#ifdef CONFIG_PPC_E500 +- if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) { +- unsigned int num_cams; +- bool map = true; +- +- /* use a quarter of the TLBCAM for bolted linear map */ +- num_cams = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) / 4; +- +- /* +- * Only do the mapping once per core, or else the +- * transient mapping would cause problems. +- */ +-#ifdef CONFIG_SMP +- if (hweight32(get_tensr()) > 1) +- map = false; +-#endif +- +- if (map) +- linear_map_top = map_mem_in_cams(linear_map_top, +- num_cams, false, true); +- } +-#endif +- +- /* A sync won't hurt us after mucking around with +- * the MMU configuration +- */ +- mb(); +-} +- +-static void __init early_init_mmu_global(void) +-{ +- /* XXX This should be decided at runtime based on supported +- * page sizes in the TLB, but for now let's assume 16M is +- * always there and a good fit (which it probably is) +- * +- * Freescale booke only supports 4K pages in TLB0, so use that. +- */ +- if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) +- mmu_vmemmap_psize = MMU_PAGE_4K; +- else +- mmu_vmemmap_psize = MMU_PAGE_16M; +- +- /* XXX This code only checks for TLB 0 capabilities and doesn't +- * check what page size combos are supported by the HW. It +- * also doesn't handle the case where a separate array holds +- * the IND entries from the array loaded by the PT. +- */ +- /* Look for supported page sizes */ +- setup_page_sizes(); +- +- /* Look for HW tablewalk support */ +- setup_mmu_htw(); +- +-#ifdef CONFIG_PPC_E500 +- if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) { +- if (book3e_htw_mode == PPC_HTW_NONE) { +- extlb_level_exc = EX_TLB_SIZE; +- patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e); +- patch_exception(0x1e0, +- exc_instruction_tlb_miss_bolted_book3e); +- } +- } +-#endif +- +- /* Set the global containing the top of the linear mapping +- * for use by the TLB miss code +- */ +- linear_map_top = memblock_end_of_DRAM(); +- +- ioremap_bot = IOREMAP_BASE; +-} +- +-static void __init early_mmu_set_memory_limit(void) +-{ +-#ifdef CONFIG_PPC_E500 +- if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) { +- /* +- * Limit memory so we dont have linear faults. +- * Unlike memblock_set_current_limit, which limits +- * memory available during early boot, this permanently +- * reduces the memory available to Linux. We need to +- * do this because highmem is not supported on 64-bit. +- */ +- memblock_enforce_memory_limit(linear_map_top); +- } +-#endif +- +- memblock_set_current_limit(linear_map_top); +-} +- +-/* boot cpu only */ +-void __init early_init_mmu(void) +-{ +- early_init_mmu_global(); +- early_init_this_mmu(); +- early_mmu_set_memory_limit(); +-} +- +-void early_init_mmu_secondary(void) +-{ +- early_init_this_mmu(); +-} +- +-void setup_initial_memory_limit(phys_addr_t first_memblock_base, +- phys_addr_t first_memblock_size) +-{ +- /* On non-FSL Embedded 64-bit, we adjust the RMA size to match +- * the bolted TLB entry. We know for now that only 1G +- * entries are supported though that may eventually +- * change. +- * +- * on FSL Embedded 64-bit, usually all RAM is bolted, but with +- * unusual memory sizes it's possible for some RAM to not be mapped +- * (such RAM is not used at all by Linux, since we don't support +- * highmem on 64-bit). We limit ppc64_rma_size to what would be +- * mappable if this memblock is the only one. Additional memblocks +- * can only increase, not decrease, the amount that ends up getting +- * mapped. We still limit max to 1G even if we'll eventually map +- * more. This is due to what the early init code is set up to do. +- * +- * We crop it to the size of the first MEMBLOCK to +- * avoid going over total available memory just in case... +- */ +-#ifdef CONFIG_PPC_E500 +- if (early_mmu_has_feature(MMU_FTR_TYPE_FSL_E)) { +- unsigned long linear_sz; +- unsigned int num_cams; +- +- /* use a quarter of the TLBCAM for bolted linear map */ +- num_cams = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) / 4; +- +- linear_sz = map_mem_in_cams(first_memblock_size, num_cams, +- true, true); +- +- ppc64_rma_size = min_t(u64, linear_sz, 0x40000000); +- } else +-#endif +- ppc64_rma_size = min_t(u64, first_memblock_size, 0x40000000); +- +- /* Finally limit subsequent allocations */ +- memblock_set_current_limit(first_memblock_base + ppc64_rma_size); +-} +-#else /* ! CONFIG_PPC64 */ ++#ifndef CONFIG_PPC64 + void __init early_init_mmu(void) + { + unsigned long root = of_get_flat_dt_root(); +diff --git a/arch/powerpc/mm/nohash/tlb_64e.c b/arch/powerpc/mm/nohash/tlb_64e.c +new file mode 100644 +index 00000000000000..b6af3ec4d001dc +--- /dev/null ++++ b/arch/powerpc/mm/nohash/tlb_64e.c +@@ -0,0 +1,361 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright 2008,2009 Ben Herrenschmidt ++ * IBM Corp. ++ * ++ * Derived from arch/ppc/mm/init.c: ++ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) ++ * ++ * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) ++ * and Cort Dougan (PReP) (cort@cs.nmt.edu) ++ * Copyright (C) 1996 Paul Mackerras ++ * ++ * Derived from "arch/i386/mm/init.c" ++ * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* The variables below are currently only used on 64-bit Book3E ++ * though this will probably be made common with other nohash ++ * implementations at some point ++ */ ++static int mmu_pte_psize; /* Page size used for PTE pages */ ++int mmu_vmemmap_psize; /* Page size used for the virtual mem map */ ++int book3e_htw_mode; /* HW tablewalk? Value is PPC_HTW_* */ ++unsigned long linear_map_top; /* Top of linear mapping */ ++ ++ ++/* ++ * Number of bytes to add to SPRN_SPRG_TLB_EXFRAME on crit/mcheck/debug ++ * exceptions. This is used for bolted and e6500 TLB miss handlers which ++ * do not modify this SPRG in the TLB miss code; for other TLB miss handlers, ++ * this is set to zero. ++ */ ++int extlb_level_exc; ++ ++/* ++ * Handling of virtual linear page tables or indirect TLB entries ++ * flushing when PTE pages are freed ++ */ ++void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address) ++{ ++ int tsize = mmu_psize_defs[mmu_pte_psize].enc; ++ ++ if (book3e_htw_mode != PPC_HTW_NONE) { ++ unsigned long start = address & PMD_MASK; ++ unsigned long end = address + PMD_SIZE; ++ unsigned long size = 1UL << mmu_psize_defs[mmu_pte_psize].shift; ++ ++ /* This isn't the most optimal, ideally we would factor out the ++ * while preempt & CPU mask mucking around, or even the IPI but ++ * it will do for now ++ */ ++ while (start < end) { ++ __flush_tlb_page(tlb->mm, start, tsize, 1); ++ start += size; ++ } ++ } else { ++ unsigned long rmask = 0xf000000000000000ul; ++ unsigned long rid = (address & rmask) | 0x1000000000000000ul; ++ unsigned long vpte = address & ~rmask; ++ ++ vpte = (vpte >> (PAGE_SHIFT - 3)) & ~0xffful; ++ vpte |= rid; ++ __flush_tlb_page(tlb->mm, vpte, tsize, 0); ++ } ++} ++ ++static void __init setup_page_sizes(void) ++{ ++ unsigned int tlb0cfg; ++ unsigned int eptcfg; ++ int psize; ++ ++#ifdef CONFIG_PPC_E500 ++ unsigned int mmucfg = mfspr(SPRN_MMUCFG); ++ int fsl_mmu = mmu_has_feature(MMU_FTR_TYPE_FSL_E); ++ ++ if (fsl_mmu && (mmucfg & MMUCFG_MAVN) == MMUCFG_MAVN_V1) { ++ unsigned int tlb1cfg = mfspr(SPRN_TLB1CFG); ++ unsigned int min_pg, max_pg; ++ ++ min_pg = (tlb1cfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT; ++ max_pg = (tlb1cfg & TLBnCFG_MAXSIZE) >> TLBnCFG_MAXSIZE_SHIFT; ++ ++ for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { ++ struct mmu_psize_def *def; ++ unsigned int shift; ++ ++ def = &mmu_psize_defs[psize]; ++ shift = def->shift; ++ ++ if (shift == 0 || shift & 1) ++ continue; ++ ++ /* adjust to be in terms of 4^shift Kb */ ++ shift = (shift - 10) >> 1; ++ ++ if ((shift >= min_pg) && (shift <= max_pg)) ++ def->flags |= MMU_PAGE_SIZE_DIRECT; ++ } ++ ++ goto out; ++ } ++ ++ if (fsl_mmu && (mmucfg & MMUCFG_MAVN) == MMUCFG_MAVN_V2) { ++ u32 tlb1cfg, tlb1ps; ++ ++ tlb0cfg = mfspr(SPRN_TLB0CFG); ++ tlb1cfg = mfspr(SPRN_TLB1CFG); ++ tlb1ps = mfspr(SPRN_TLB1PS); ++ eptcfg = mfspr(SPRN_EPTCFG); ++ ++ if ((tlb1cfg & TLBnCFG_IND) && (tlb0cfg & TLBnCFG_PT)) ++ book3e_htw_mode = PPC_HTW_E6500; ++ ++ /* ++ * We expect 4K subpage size and unrestricted indirect size. ++ * The lack of a restriction on indirect size is a Freescale ++ * extension, indicated by PSn = 0 but SPSn != 0. ++ */ ++ if (eptcfg != 2) ++ book3e_htw_mode = PPC_HTW_NONE; ++ ++ for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { ++ struct mmu_psize_def *def = &mmu_psize_defs[psize]; ++ ++ if (!def->shift) ++ continue; ++ ++ if (tlb1ps & (1U << (def->shift - 10))) { ++ def->flags |= MMU_PAGE_SIZE_DIRECT; ++ ++ if (book3e_htw_mode && psize == MMU_PAGE_2M) ++ def->flags |= MMU_PAGE_SIZE_INDIRECT; ++ } ++ } ++ ++ goto out; ++ } ++#endif ++out: ++ /* Cleanup array and print summary */ ++ pr_info("MMU: Supported page sizes\n"); ++ for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { ++ struct mmu_psize_def *def = &mmu_psize_defs[psize]; ++ const char *__page_type_names[] = { ++ "unsupported", ++ "direct", ++ "indirect", ++ "direct & indirect" ++ }; ++ if (def->flags == 0) { ++ def->shift = 0; ++ continue; ++ } ++ pr_info(" %8ld KB as %s\n", 1ul << (def->shift - 10), ++ __page_type_names[def->flags & 0x3]); ++ } ++} ++ ++static void __init setup_mmu_htw(void) ++{ ++ /* ++ * If we want to use HW tablewalk, enable it by patching the TLB miss ++ * handlers to branch to the one dedicated to it. ++ */ ++ ++ switch (book3e_htw_mode) { ++#ifdef CONFIG_PPC_E500 ++ case PPC_HTW_E6500: ++ extlb_level_exc = EX_TLB_SIZE; ++ patch_exception(0x1c0, exc_data_tlb_miss_e6500_book3e); ++ patch_exception(0x1e0, exc_instruction_tlb_miss_e6500_book3e); ++ break; ++#endif ++ } ++ pr_info("MMU: Book3E HW tablewalk %s\n", ++ book3e_htw_mode != PPC_HTW_NONE ? "enabled" : "not supported"); ++} ++ ++/* ++ * Early initialization of the MMU TLB code ++ */ ++static void early_init_this_mmu(void) ++{ ++ unsigned int mas4; ++ ++ /* Set MAS4 based on page table setting */ ++ ++ mas4 = 0x4 << MAS4_WIMGED_SHIFT; ++ switch (book3e_htw_mode) { ++ case PPC_HTW_E6500: ++ mas4 |= MAS4_INDD; ++ mas4 |= BOOK3E_PAGESZ_2M << MAS4_TSIZED_SHIFT; ++ mas4 |= MAS4_TLBSELD(1); ++ mmu_pte_psize = MMU_PAGE_2M; ++ break; ++ ++ case PPC_HTW_NONE: ++ mas4 |= BOOK3E_PAGESZ_4K << MAS4_TSIZED_SHIFT; ++ mmu_pte_psize = mmu_virtual_psize; ++ break; ++ } ++ mtspr(SPRN_MAS4, mas4); ++ ++#ifdef CONFIG_PPC_E500 ++ if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) { ++ unsigned int num_cams; ++ bool map = true; ++ ++ /* use a quarter of the TLBCAM for bolted linear map */ ++ num_cams = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) / 4; ++ ++ /* ++ * Only do the mapping once per core, or else the ++ * transient mapping would cause problems. ++ */ ++#ifdef CONFIG_SMP ++ if (hweight32(get_tensr()) > 1) ++ map = false; ++#endif ++ ++ if (map) ++ linear_map_top = map_mem_in_cams(linear_map_top, ++ num_cams, false, true); ++ } ++#endif ++ ++ /* A sync won't hurt us after mucking around with ++ * the MMU configuration ++ */ ++ mb(); ++} ++ ++static void __init early_init_mmu_global(void) ++{ ++ /* XXX This should be decided at runtime based on supported ++ * page sizes in the TLB, but for now let's assume 16M is ++ * always there and a good fit (which it probably is) ++ * ++ * Freescale booke only supports 4K pages in TLB0, so use that. ++ */ ++ if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) ++ mmu_vmemmap_psize = MMU_PAGE_4K; ++ else ++ mmu_vmemmap_psize = MMU_PAGE_16M; ++ ++ /* XXX This code only checks for TLB 0 capabilities and doesn't ++ * check what page size combos are supported by the HW. It ++ * also doesn't handle the case where a separate array holds ++ * the IND entries from the array loaded by the PT. ++ */ ++ /* Look for supported page sizes */ ++ setup_page_sizes(); ++ ++ /* Look for HW tablewalk support */ ++ setup_mmu_htw(); ++ ++#ifdef CONFIG_PPC_E500 ++ if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) { ++ if (book3e_htw_mode == PPC_HTW_NONE) { ++ extlb_level_exc = EX_TLB_SIZE; ++ patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e); ++ patch_exception(0x1e0, ++ exc_instruction_tlb_miss_bolted_book3e); ++ } ++ } ++#endif ++ ++ /* Set the global containing the top of the linear mapping ++ * for use by the TLB miss code ++ */ ++ linear_map_top = memblock_end_of_DRAM(); ++ ++ ioremap_bot = IOREMAP_BASE; ++} ++ ++static void __init early_mmu_set_memory_limit(void) ++{ ++#ifdef CONFIG_PPC_E500 ++ if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) { ++ /* ++ * Limit memory so we dont have linear faults. ++ * Unlike memblock_set_current_limit, which limits ++ * memory available during early boot, this permanently ++ * reduces the memory available to Linux. We need to ++ * do this because highmem is not supported on 64-bit. ++ */ ++ memblock_enforce_memory_limit(linear_map_top); ++ } ++#endif ++ ++ memblock_set_current_limit(linear_map_top); ++} ++ ++/* boot cpu only */ ++void __init early_init_mmu(void) ++{ ++ early_init_mmu_global(); ++ early_init_this_mmu(); ++ early_mmu_set_memory_limit(); ++} ++ ++void early_init_mmu_secondary(void) ++{ ++ early_init_this_mmu(); ++} ++ ++void setup_initial_memory_limit(phys_addr_t first_memblock_base, ++ phys_addr_t first_memblock_size) ++{ ++ /* On non-FSL Embedded 64-bit, we adjust the RMA size to match ++ * the bolted TLB entry. We know for now that only 1G ++ * entries are supported though that may eventually ++ * change. ++ * ++ * on FSL Embedded 64-bit, usually all RAM is bolted, but with ++ * unusual memory sizes it's possible for some RAM to not be mapped ++ * (such RAM is not used at all by Linux, since we don't support ++ * highmem on 64-bit). We limit ppc64_rma_size to what would be ++ * mappable if this memblock is the only one. Additional memblocks ++ * can only increase, not decrease, the amount that ends up getting ++ * mapped. We still limit max to 1G even if we'll eventually map ++ * more. This is due to what the early init code is set up to do. ++ * ++ * We crop it to the size of the first MEMBLOCK to ++ * avoid going over total available memory just in case... ++ */ ++#ifdef CONFIG_PPC_E500 ++ if (early_mmu_has_feature(MMU_FTR_TYPE_FSL_E)) { ++ unsigned long linear_sz; ++ unsigned int num_cams; ++ ++ /* use a quarter of the TLBCAM for bolted linear map */ ++ num_cams = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) / 4; ++ ++ linear_sz = map_mem_in_cams(first_memblock_size, num_cams, ++ true, true); ++ ++ ppc64_rma_size = min_t(u64, linear_sz, 0x40000000); ++ } else ++#endif ++ ppc64_rma_size = min_t(u64, first_memblock_size, 0x40000000); ++ ++ /* Finally limit subsequent allocations */ ++ memblock_set_current_limit(first_memblock_base + ppc64_rma_size); ++} +diff --git a/arch/powerpc/mm/nohash/tlb_low_64e.S b/arch/powerpc/mm/nohash/tlb_low_64e.S +index 7e0b8fe1c27975..b0eb3f7eaed149 100644 +--- a/arch/powerpc/mm/nohash/tlb_low_64e.S ++++ b/arch/powerpc/mm/nohash/tlb_low_64e.S +@@ -893,201 +893,6 @@ virt_page_table_tlb_miss_whacko_fault: + TLB_MISS_EPILOG_ERROR + b exc_data_storage_book3e + +- +-/************************************************************** +- * * +- * TLB miss handling for Book3E with hw page table support * +- * * +- **************************************************************/ +- +- +-/* Data TLB miss */ +- START_EXCEPTION(data_tlb_miss_htw) +- TLB_MISS_PROLOG +- +- /* Now we handle the fault proper. We only save DEAR in normal +- * fault case since that's the only interesting values here. +- * We could probably also optimize by not saving SRR0/1 in the +- * linear mapping case but I'll leave that for later +- */ +- mfspr r14,SPRN_ESR +- mfspr r16,SPRN_DEAR /* get faulting address */ +- srdi r11,r16,44 /* get region */ +- xoris r11,r11,0xc +- cmpldi cr0,r11,0 /* linear mapping ? */ +- beq tlb_load_linear /* yes -> go to linear map load */ +- cmpldi cr1,r11,1 /* vmalloc mapping ? */ +- +- /* We do the user/kernel test for the PID here along with the RW test +- */ +- srdi. r11,r16,60 /* Check for user region */ +- ld r15,PACAPGD(r13) /* Load user pgdir */ +- beq htw_tlb_miss +- +- /* XXX replace the RMW cycles with immediate loads + writes */ +-1: mfspr r10,SPRN_MAS1 +- rlwinm r10,r10,0,16,1 /* Clear TID */ +- mtspr SPRN_MAS1,r10 +- ld r15,PACA_KERNELPGD(r13) /* Load kernel pgdir */ +- beq+ cr1,htw_tlb_miss +- +- /* We got a crappy address, just fault with whatever DEAR and ESR +- * are here +- */ +- TLB_MISS_EPILOG_ERROR +- b exc_data_storage_book3e +- +-/* Instruction TLB miss */ +- START_EXCEPTION(instruction_tlb_miss_htw) +- TLB_MISS_PROLOG +- +- /* If we take a recursive fault, the second level handler may need +- * to know whether we are handling a data or instruction fault in +- * order to get to the right store fault handler. We provide that +- * info by keeping a crazy value for ESR in r14 +- */ +- li r14,-1 /* store to exception frame is done later */ +- +- /* Now we handle the fault proper. We only save DEAR in the non +- * linear mapping case since we know the linear mapping case will +- * not re-enter. We could indeed optimize and also not save SRR0/1 +- * in the linear mapping case but I'll leave that for later +- * +- * Faulting address is SRR0 which is already in r16 +- */ +- srdi r11,r16,44 /* get region */ +- xoris r11,r11,0xc +- cmpldi cr0,r11,0 /* linear mapping ? */ +- beq tlb_load_linear /* yes -> go to linear map load */ +- cmpldi cr1,r11,1 /* vmalloc mapping ? */ +- +- /* We do the user/kernel test for the PID here along with the RW test +- */ +- srdi. r11,r16,60 /* Check for user region */ +- ld r15,PACAPGD(r13) /* Load user pgdir */ +- beq htw_tlb_miss +- +- /* XXX replace the RMW cycles with immediate loads + writes */ +-1: mfspr r10,SPRN_MAS1 +- rlwinm r10,r10,0,16,1 /* Clear TID */ +- mtspr SPRN_MAS1,r10 +- ld r15,PACA_KERNELPGD(r13) /* Load kernel pgdir */ +- beq+ htw_tlb_miss +- +- /* We got a crappy address, just fault */ +- TLB_MISS_EPILOG_ERROR +- b exc_instruction_storage_book3e +- +- +-/* +- * This is the guts of the second-level TLB miss handler for direct +- * misses. We are entered with: +- * +- * r16 = virtual page table faulting address +- * r15 = PGD pointer +- * r14 = ESR +- * r13 = PACA +- * r12 = TLB exception frame in PACA +- * r11 = crap (free to use) +- * r10 = crap (free to use) +- * +- * It can be re-entered by the linear mapping miss handler. However, to +- * avoid too much complication, it will save/restore things for us +- */ +-htw_tlb_miss: +-#ifdef CONFIG_PPC_KUAP +- mfspr r10,SPRN_MAS1 +- rlwinm. r10,r10,0,0x3fff0000 +- beq- htw_tlb_miss_fault /* KUAP fault */ +-#endif +- /* Search if we already have a TLB entry for that virtual address, and +- * if we do, bail out. +- * +- * MAS1:IND should be already set based on MAS4 +- */ +- PPC_TLBSRX_DOT(0,R16) +- beq htw_tlb_miss_done +- +- /* Now, we need to walk the page tables. First check if we are in +- * range. +- */ +- rldicl. r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4 +- bne- htw_tlb_miss_fault +- +- /* Get the PGD pointer */ +- cmpldi cr0,r15,0 +- beq- htw_tlb_miss_fault +- +- /* Get to PGD entry */ +- rldicl r11,r16,64-(PGDIR_SHIFT-3),64-PGD_INDEX_SIZE-3 +- clrrdi r10,r11,3 +- ldx r15,r10,r15 +- cmpdi cr0,r15,0 +- bge htw_tlb_miss_fault +- +- /* Get to PUD entry */ +- rldicl r11,r16,64-(PUD_SHIFT-3),64-PUD_INDEX_SIZE-3 +- clrrdi r10,r11,3 +- ldx r15,r10,r15 +- cmpdi cr0,r15,0 +- bge htw_tlb_miss_fault +- +- /* Get to PMD entry */ +- rldicl r11,r16,64-(PMD_SHIFT-3),64-PMD_INDEX_SIZE-3 +- clrrdi r10,r11,3 +- ldx r15,r10,r15 +- cmpdi cr0,r15,0 +- bge htw_tlb_miss_fault +- +- /* Ok, we're all right, we can now create an indirect entry for +- * a 1M or 256M page. +- * +- * The last trick is now that because we use "half" pages for +- * the HTW (1M IND is 2K and 256M IND is 32K) we need to account +- * for an added LSB bit to the RPN. For 64K pages, there is no +- * problem as we already use 32K arrays (half PTE pages), but for +- * 4K page we need to extract a bit from the virtual address and +- * insert it into the "PA52" bit of the RPN. +- */ +- rlwimi r15,r16,32-9,20,20 +- /* Now we build the MAS: +- * +- * MAS 0 : Fully setup with defaults in MAS4 and TLBnCFG +- * MAS 1 : Almost fully setup +- * - PID already updated by caller if necessary +- * - TSIZE for now is base ind page size always +- * MAS 2 : Use defaults +- * MAS 3+7 : Needs to be done +- */ +- ori r10,r15,(BOOK3E_PAGESZ_4K << MAS3_SPSIZE_SHIFT) +- +- srdi r16,r10,32 +- mtspr SPRN_MAS3,r10 +- mtspr SPRN_MAS7,r16 +- +- tlbwe +- +-htw_tlb_miss_done: +- /* We don't bother with restoring DEAR or ESR since we know we are +- * level 0 and just going back to userland. They are only needed +- * if you are going to take an access fault +- */ +- TLB_MISS_EPILOG_SUCCESS +- rfi +- +-htw_tlb_miss_fault: +- /* We need to check if it was an instruction miss. We know this +- * though because r14 would contain -1 +- */ +- cmpdi cr0,r14,-1 +- beq 1f +- mtspr SPRN_DEAR,r16 +- mtspr SPRN_ESR,r14 +- TLB_MISS_EPILOG_ERROR +- b exc_data_storage_book3e +-1: TLB_MISS_EPILOG_ERROR +- b exc_instruction_storage_book3e +- + /* + * This is the guts of "any" level TLB miss handler for kernel linear + * mapping misses. We are entered with: +diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c +index 7f91ea064c0874..06f886850a9327 100644 +--- a/arch/powerpc/net/bpf_jit_comp32.c ++++ b/arch/powerpc/net/bpf_jit_comp32.c +@@ -851,6 +851,15 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context * + + /* Get offset into TMP_REG */ + EMIT(PPC_RAW_LI(tmp_reg, off)); ++ /* ++ * Enforce full ordering for operations with BPF_FETCH by emitting a 'sync' ++ * before and after the operation. ++ * ++ * This is a requirement in the Linux Kernel Memory Model. ++ * See __cmpxchg_u32() in asm/cmpxchg.h as an example. ++ */ ++ if ((imm & BPF_FETCH) && IS_ENABLED(CONFIG_SMP)) ++ EMIT(PPC_RAW_SYNC()); + tmp_idx = ctx->idx * 4; + /* load value from memory into r0 */ + EMIT(PPC_RAW_LWARX(_R0, tmp_reg, dst_reg, 0)); +@@ -904,6 +913,9 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context * + + /* For the BPF_FETCH variant, get old data into src_reg */ + if (imm & BPF_FETCH) { ++ /* Emit 'sync' to enforce full ordering */ ++ if (IS_ENABLED(CONFIG_SMP)) ++ EMIT(PPC_RAW_SYNC()); + EMIT(PPC_RAW_MR(ret_reg, ax_reg)); + if (!fp->aux->verifier_zext) + EMIT(PPC_RAW_LI(ret_reg - 1, 0)); /* higher 32-bit */ +diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c +index 0f8048f6dad630..2239ce5e8501cd 100644 +--- a/arch/powerpc/net/bpf_jit_comp64.c ++++ b/arch/powerpc/net/bpf_jit_comp64.c +@@ -803,6 +803,15 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context * + + /* Get offset into TMP_REG_1 */ + EMIT(PPC_RAW_LI(tmp1_reg, off)); ++ /* ++ * Enforce full ordering for operations with BPF_FETCH by emitting a 'sync' ++ * before and after the operation. ++ * ++ * This is a requirement in the Linux Kernel Memory Model. ++ * See __cmpxchg_u64() in asm/cmpxchg.h as an example. ++ */ ++ if ((imm & BPF_FETCH) && IS_ENABLED(CONFIG_SMP)) ++ EMIT(PPC_RAW_SYNC()); + tmp_idx = ctx->idx * 4; + /* load value from memory into TMP_REG_2 */ + if (size == BPF_DW) +@@ -865,6 +874,9 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context * + PPC_BCC_SHORT(COND_NE, tmp_idx); + + if (imm & BPF_FETCH) { ++ /* Emit 'sync' to enforce full ordering */ ++ if (IS_ENABLED(CONFIG_SMP)) ++ EMIT(PPC_RAW_SYNC()); + EMIT(PPC_RAW_MR(ret_reg, _R0)); + /* + * Skip unnecessary zero-extension for 32-bit cmpxchg. +diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c +index 8c1f7def596e4a..10b946e9c6e756 100644 +--- a/arch/powerpc/perf/core-book3s.c ++++ b/arch/powerpc/perf/core-book3s.c +@@ -1371,8 +1371,7 @@ static void power_pmu_disable(struct pmu *pmu) + /* + * Disable instruction sampling if it was enabled + */ +- if (cpuhw->mmcr.mmcra & MMCRA_SAMPLE_ENABLE) +- val &= ~MMCRA_SAMPLE_ENABLE; ++ val &= ~MMCRA_SAMPLE_ENABLE; + + /* Disable BHRB via mmcra (BHRBRD) for p10 */ + if (ppmu->flags & PPMU_ARCH_31) +@@ -1383,7 +1382,7 @@ static void power_pmu_disable(struct pmu *pmu) + * instruction sampling or BHRB. + */ + if (val != mmcra) { +- mtspr(SPRN_MMCRA, mmcra); ++ mtspr(SPRN_MMCRA, val); + mb(); + isync(); + } +diff --git a/arch/powerpc/perf/hv-gpci.c b/arch/powerpc/perf/hv-gpci.c +index 39dbe6b348df28..241551d1282f80 100644 +--- a/arch/powerpc/perf/hv-gpci.c ++++ b/arch/powerpc/perf/hv-gpci.c +@@ -534,6 +534,9 @@ static ssize_t affinity_domain_via_partition_show(struct device *dev, struct dev + if (!ret) + goto parse_result; + ++ if (ret && (ret != H_PARAMETER)) ++ goto out; ++ + /* + * ret value as 'H_PARAMETER' implies that the current buffer size + * can't accommodate all the information, and a partial buffer +@@ -692,6 +695,20 @@ static unsigned long single_gpci_request(u32 req, u32 starting_index, + + ret = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO, + virt_to_phys(arg), HGPCI_REQ_BUFFER_SIZE); ++ ++ /* ++ * ret value as 'H_PARAMETER' with detail_rc as 'GEN_BUF_TOO_SMALL', ++ * specifies that the current buffer size cannot accommodate ++ * all the information and a partial buffer returned. ++ * Since in this function we are only accessing data for a given starting index, ++ * we don't need to accommodate whole data and can get required count by ++ * accessing first entry data. ++ * Hence hcall fails only incase the ret value is other than H_SUCCESS or ++ * H_PARAMETER with detail_rc value as GEN_BUF_TOO_SMALL(0x1B). ++ */ ++ if (ret == H_PARAMETER && be32_to_cpu(arg->params.detail_rc) == 0x1B) ++ ret = 0; ++ + if (ret) { + pr_devel("hcall failed: 0x%lx\n", ret); + goto out; +@@ -756,6 +773,7 @@ static int h_gpci_event_init(struct perf_event *event) + { + u64 count; + u8 length; ++ unsigned long ret; + + /* Not our event */ + if (event->attr.type != event->pmu->type) +@@ -786,13 +804,23 @@ static int h_gpci_event_init(struct perf_event *event) + } + + /* check if the request works... */ +- if (single_gpci_request(event_get_request(event), ++ ret = single_gpci_request(event_get_request(event), + event_get_starting_index(event), + event_get_secondary_index(event), + event_get_counter_info_version(event), + event_get_offset(event), + length, +- &count)) { ++ &count); ++ ++ /* ++ * ret value as H_AUTHORITY implies that partition is not permitted to retrieve ++ * performance information, and required to set ++ * "Enable Performance Information Collection" option. ++ */ ++ if (ret == H_AUTHORITY) ++ return -EPERM; ++ ++ if (ret) { + pr_devel("gpci hcall failed\n"); + return -EINVAL; + } +diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c +index 9d229ef7f86efa..56d82f7f9734e0 100644 +--- a/arch/powerpc/perf/imc-pmu.c ++++ b/arch/powerpc/perf/imc-pmu.c +@@ -51,7 +51,7 @@ static int trace_imc_mem_size; + * core and trace-imc + */ + static struct imc_pmu_ref imc_global_refc = { +- .lock = __SPIN_LOCK_INITIALIZER(imc_global_refc.lock), ++ .lock = __SPIN_LOCK_UNLOCKED(imc_global_refc.lock), + .id = 0, + .refc = 0, + }; +@@ -299,6 +299,8 @@ static int update_events_in_group(struct device_node *node, struct imc_pmu *pmu) + attr_group->attrs = attrs; + do { + ev_val_str = kasprintf(GFP_KERNEL, "event=0x%x", pmu->events[i].value); ++ if (!ev_val_str) ++ continue; + dev_str = device_str_attr_create(pmu->events[i].name, ev_val_str); + if (!dev_str) + continue; +@@ -306,6 +308,8 @@ static int update_events_in_group(struct device_node *node, struct imc_pmu *pmu) + attrs[j++] = dev_str; + if (pmu->events[i].scale) { + ev_scale_str = kasprintf(GFP_KERNEL, "%s.scale", pmu->events[i].name); ++ if (!ev_scale_str) ++ continue; + dev_str = device_str_attr_create(ev_scale_str, pmu->events[i].scale); + if (!dev_str) + continue; +@@ -315,6 +319,8 @@ static int update_events_in_group(struct device_node *node, struct imc_pmu *pmu) + + if (pmu->events[i].unit) { + ev_unit_str = kasprintf(GFP_KERNEL, "%s.unit", pmu->events[i].name); ++ if (!ev_unit_str) ++ continue; + dev_str = device_str_attr_create(ev_unit_str, pmu->events[i].unit); + if (!dev_str) + continue; +diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig +index 1624ebf95497ba..35a1f4b9f8272b 100644 +--- a/arch/powerpc/platforms/44x/Kconfig ++++ b/arch/powerpc/platforms/44x/Kconfig +@@ -173,6 +173,7 @@ config ISS4xx + config CURRITUCK + bool "IBM Currituck (476fpe) Support" + depends on PPC_47x ++ select I2C + select SWIOTLB + select 476FPE + select FORCE_PCI +diff --git a/arch/powerpc/platforms/book3s/vas-api.c b/arch/powerpc/platforms/book3s/vas-api.c +index 77ea9335fd049c..f381b177ea06ad 100644 +--- a/arch/powerpc/platforms/book3s/vas-api.c ++++ b/arch/powerpc/platforms/book3s/vas-api.c +@@ -4,6 +4,8 @@ + * Copyright (C) 2019 Haren Myneni, IBM Corp + */ + ++#define pr_fmt(fmt) "vas-api: " fmt ++ + #include + #include + #include +@@ -78,7 +80,7 @@ int get_vas_user_win_ref(struct vas_user_win_ref *task_ref) + task_ref->mm = get_task_mm(current); + if (!task_ref->mm) { + put_pid(task_ref->pid); +- pr_err("VAS: pid(%d): mm_struct is not found\n", ++ pr_err("pid(%d): mm_struct is not found\n", + current->pid); + return -EPERM; + } +@@ -235,8 +237,7 @@ void vas_update_csb(struct coprocessor_request_block *crb, + rc = kill_pid_info(SIGSEGV, &info, pid); + rcu_read_unlock(); + +- pr_devel("%s(): pid %d kill_proc_info() rc %d\n", __func__, +- pid_vnr(pid), rc); ++ pr_devel("pid %d kill_proc_info() rc %d\n", pid_vnr(pid), rc); + } + + void vas_dump_crb(struct coprocessor_request_block *crb) +@@ -294,7 +295,7 @@ static int coproc_ioc_tx_win_open(struct file *fp, unsigned long arg) + + rc = copy_from_user(&uattr, uptr, sizeof(uattr)); + if (rc) { +- pr_err("%s(): copy_from_user() returns %d\n", __func__, rc); ++ pr_err("copy_from_user() returns %d\n", rc); + return -EFAULT; + } + +@@ -311,7 +312,7 @@ static int coproc_ioc_tx_win_open(struct file *fp, unsigned long arg) + txwin = cp_inst->coproc->vops->open_win(uattr.vas_id, uattr.flags, + cp_inst->coproc->cop_type); + if (IS_ERR(txwin)) { +- pr_err("%s() VAS window open failed, %ld\n", __func__, ++ pr_err_ratelimited("VAS window open failed rc=%ld\n", + PTR_ERR(txwin)); + return PTR_ERR(txwin); + } +@@ -405,8 +406,7 @@ static vm_fault_t vas_mmap_fault(struct vm_fault *vmf) + * window is not opened. Shouldn't expect this error. + */ + if (!cp_inst || !cp_inst->txwin) { +- pr_err("%s(): Unexpected fault on paste address with TX window closed\n", +- __func__); ++ pr_err("Unexpected fault on paste address with TX window closed\n"); + return VM_FAULT_SIGBUS; + } + +@@ -421,8 +421,7 @@ static vm_fault_t vas_mmap_fault(struct vm_fault *vmf) + * issue NX request. + */ + if (txwin->task_ref.vma != vmf->vma) { +- pr_err("%s(): No previous mapping with paste address\n", +- __func__); ++ pr_err("No previous mapping with paste address\n"); + return VM_FAULT_SIGBUS; + } + +@@ -481,19 +480,19 @@ static int coproc_mmap(struct file *fp, struct vm_area_struct *vma) + txwin = cp_inst->txwin; + + if ((vma->vm_end - vma->vm_start) > PAGE_SIZE) { +- pr_debug("%s(): size 0x%zx, PAGE_SIZE 0x%zx\n", __func__, ++ pr_debug("size 0x%zx, PAGE_SIZE 0x%zx\n", + (vma->vm_end - vma->vm_start), PAGE_SIZE); + return -EINVAL; + } + + /* Ensure instance has an open send window */ + if (!txwin) { +- pr_err("%s(): No send window open?\n", __func__); ++ pr_err("No send window open?\n"); + return -EINVAL; + } + + if (!cp_inst->coproc->vops || !cp_inst->coproc->vops->paste_addr) { +- pr_err("%s(): VAS API is not registered\n", __func__); ++ pr_err("VAS API is not registered\n"); + return -EACCES; + } + +@@ -510,14 +509,14 @@ static int coproc_mmap(struct file *fp, struct vm_area_struct *vma) + */ + mutex_lock(&txwin->task_ref.mmap_mutex); + if (txwin->status != VAS_WIN_ACTIVE) { +- pr_err("%s(): Window is not active\n", __func__); ++ pr_err("Window is not active\n"); + rc = -EACCES; + goto out; + } + + paste_addr = cp_inst->coproc->vops->paste_addr(txwin); + if (!paste_addr) { +- pr_err("%s(): Window paste address failed\n", __func__); ++ pr_err("Window paste address failed\n"); + rc = -EINVAL; + goto out; + } +@@ -533,8 +532,8 @@ static int coproc_mmap(struct file *fp, struct vm_area_struct *vma) + rc = remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff, + vma->vm_end - vma->vm_start, prot); + +- pr_devel("%s(): paste addr %llx at %lx, rc %d\n", __func__, +- paste_addr, vma->vm_start, rc); ++ pr_devel("paste addr %llx at %lx, rc %d\n", paste_addr, ++ vma->vm_start, rc); + + txwin->task_ref.vma = vma; + vma->vm_ops = &vas_vm_ops; +@@ -609,8 +608,7 @@ int vas_register_coproc_api(struct module *mod, enum vas_cop_type cop_type, + goto err; + } + +- pr_devel("%s: Added dev [%d,%d]\n", __func__, MAJOR(devno), +- MINOR(devno)); ++ pr_devel("Added dev [%d,%d]\n", MAJOR(devno), MINOR(devno)); + + return 0; + +diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c +index 9c10aac40c7b11..e265f026eee2a9 100644 +--- a/arch/powerpc/platforms/embedded6xx/linkstation.c ++++ b/arch/powerpc/platforms/embedded6xx/linkstation.c +@@ -99,9 +99,6 @@ static void __init linkstation_init_IRQ(void) + mpic_init(mpic); + } + +-extern void avr_uart_configure(void); +-extern void avr_uart_send(const char); +- + static void __noreturn linkstation_restart(char *cmd) + { + local_irq_disable(); +diff --git a/arch/powerpc/platforms/embedded6xx/mpc10x.h b/arch/powerpc/platforms/embedded6xx/mpc10x.h +index 5ad12023e56280..ebc258fa4858d0 100644 +--- a/arch/powerpc/platforms/embedded6xx/mpc10x.h ++++ b/arch/powerpc/platforms/embedded6xx/mpc10x.h +@@ -156,4 +156,7 @@ int mpc10x_disable_store_gathering(struct pci_controller *hose); + /* For MPC107 boards that use the built-in openpic */ + void mpc10x_set_openpic(void); + ++void avr_uart_configure(void); ++void avr_uart_send(const char c); ++ + #endif /* __PPC_KERNEL_MPC10X_H */ +diff --git a/arch/powerpc/platforms/powernv/opal-irqchip.c b/arch/powerpc/platforms/powernv/opal-irqchip.c +index f9a7001dacb7a1..56a1f7ce78d2c7 100644 +--- a/arch/powerpc/platforms/powernv/opal-irqchip.c ++++ b/arch/powerpc/platforms/powernv/opal-irqchip.c +@@ -275,6 +275,8 @@ int __init opal_event_init(void) + else + name = kasprintf(GFP_KERNEL, "opal"); + ++ if (!name) ++ continue; + /* Install interrupt handler */ + rc = request_irq(r->start, opal_interrupt, r->flags & IRQD_TRIGGER_MASK, + name, NULL); +diff --git a/arch/powerpc/platforms/powernv/opal-powercap.c b/arch/powerpc/platforms/powernv/opal-powercap.c +index 7bfe4cbeb35a99..ea917266aa1725 100644 +--- a/arch/powerpc/platforms/powernv/opal-powercap.c ++++ b/arch/powerpc/platforms/powernv/opal-powercap.c +@@ -196,6 +196,12 @@ void __init opal_powercap_init(void) + + j = 0; + pcaps[i].pg.name = kasprintf(GFP_KERNEL, "%pOFn", node); ++ if (!pcaps[i].pg.name) { ++ kfree(pcaps[i].pattrs); ++ kfree(pcaps[i].pg.attrs); ++ goto out_pcaps_pattrs; ++ } ++ + if (has_min) { + powercap_add_attr(min, "powercap-min", + &pcaps[i].pattrs[j]); +diff --git a/arch/powerpc/platforms/powernv/opal-xscom.c b/arch/powerpc/platforms/powernv/opal-xscom.c +index 262cd6fac90714..748c2b97fa5370 100644 +--- a/arch/powerpc/platforms/powernv/opal-xscom.c ++++ b/arch/powerpc/platforms/powernv/opal-xscom.c +@@ -165,6 +165,11 @@ static int scom_debug_init_one(struct dentry *root, struct device_node *dn, + ent->chip = chip; + snprintf(ent->name, 16, "%08x", chip); + ent->path.data = (void *)kasprintf(GFP_KERNEL, "%pOF", dn); ++ if (!ent->path.data) { ++ kfree(ent); ++ return -ENOMEM; ++ } ++ + ent->path.size = strlen((char *)ent->path.data); + + dir = debugfs_create_dir(ent->name, root); +diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig +index a44869e5ea70f8..1bd1b0b49bc62a 100644 +--- a/arch/powerpc/platforms/ps3/Kconfig ++++ b/arch/powerpc/platforms/ps3/Kconfig +@@ -67,6 +67,7 @@ config PS3_VUART + config PS3_PS3AV + depends on PPC_PS3 + tristate "PS3 AV settings driver" if PS3_ADVANCED ++ select VIDEO + select PS3_VUART + default y + help +diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c +index 47f8eabd1bee31..9873b916b23704 100644 +--- a/arch/powerpc/platforms/pseries/dlpar.c ++++ b/arch/powerpc/platforms/pseries/dlpar.c +@@ -334,23 +334,6 @@ int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog) + { + int rc; + +- /* pseries error logs are in BE format, convert to cpu type */ +- switch (hp_elog->id_type) { +- case PSERIES_HP_ELOG_ID_DRC_COUNT: +- hp_elog->_drc_u.drc_count = +- be32_to_cpu(hp_elog->_drc_u.drc_count); +- break; +- case PSERIES_HP_ELOG_ID_DRC_INDEX: +- hp_elog->_drc_u.drc_index = +- be32_to_cpu(hp_elog->_drc_u.drc_index); +- break; +- case PSERIES_HP_ELOG_ID_DRC_IC: +- hp_elog->_drc_u.ic.count = +- be32_to_cpu(hp_elog->_drc_u.ic.count); +- hp_elog->_drc_u.ic.index = +- be32_to_cpu(hp_elog->_drc_u.ic.index); +- } +- + switch (hp_elog->resource) { + case PSERIES_HP_ELOG_RESOURCE_MEM: + rc = dlpar_memory(hp_elog); +diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c +index e62835a12d73fc..6838a0fcda296b 100644 +--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c ++++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c +@@ -757,7 +757,7 @@ int dlpar_cpu(struct pseries_hp_errorlog *hp_elog) + u32 drc_index; + int rc; + +- drc_index = hp_elog->_drc_u.drc_index; ++ drc_index = be32_to_cpu(hp_elog->_drc_u.drc_index); + + lock_device_hotplug(); + +diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c +index aa4042dcd6d40e..95ff84c55cb144 100644 +--- a/arch/powerpc/platforms/pseries/hotplug-memory.c ++++ b/arch/powerpc/platforms/pseries/hotplug-memory.c +@@ -435,14 +435,15 @@ static int dlpar_memory_remove_by_index(u32 drc_index) + } + } + +- if (!lmb_found) ++ if (!lmb_found) { ++ pr_debug("Failed to look up LMB for drc index %x\n", drc_index); + rc = -EINVAL; +- +- if (rc) ++ } else if (rc) { + pr_debug("Failed to hot-remove memory at %llx\n", + lmb->base_addr); +- else ++ } else { + pr_debug("Memory at %llx was hot-removed\n", lmb->base_addr); ++ } + + return rc; + } +@@ -810,16 +811,16 @@ int dlpar_memory(struct pseries_hp_errorlog *hp_elog) + case PSERIES_HP_ELOG_ACTION_ADD: + switch (hp_elog->id_type) { + case PSERIES_HP_ELOG_ID_DRC_COUNT: +- count = hp_elog->_drc_u.drc_count; ++ count = be32_to_cpu(hp_elog->_drc_u.drc_count); + rc = dlpar_memory_add_by_count(count); + break; + case PSERIES_HP_ELOG_ID_DRC_INDEX: +- drc_index = hp_elog->_drc_u.drc_index; ++ drc_index = be32_to_cpu(hp_elog->_drc_u.drc_index); + rc = dlpar_memory_add_by_index(drc_index); + break; + case PSERIES_HP_ELOG_ID_DRC_IC: +- count = hp_elog->_drc_u.ic.count; +- drc_index = hp_elog->_drc_u.ic.index; ++ count = be32_to_cpu(hp_elog->_drc_u.ic.count); ++ drc_index = be32_to_cpu(hp_elog->_drc_u.ic.index); + rc = dlpar_memory_add_by_ic(count, drc_index); + break; + default: +@@ -831,16 +832,16 @@ int dlpar_memory(struct pseries_hp_errorlog *hp_elog) + case PSERIES_HP_ELOG_ACTION_REMOVE: + switch (hp_elog->id_type) { + case PSERIES_HP_ELOG_ID_DRC_COUNT: +- count = hp_elog->_drc_u.drc_count; ++ count = be32_to_cpu(hp_elog->_drc_u.drc_count); + rc = dlpar_memory_remove_by_count(count); + break; + case PSERIES_HP_ELOG_ID_DRC_INDEX: +- drc_index = hp_elog->_drc_u.drc_index; ++ drc_index = be32_to_cpu(hp_elog->_drc_u.drc_index); + rc = dlpar_memory_remove_by_index(drc_index); + break; + case PSERIES_HP_ELOG_ID_DRC_IC: +- count = hp_elog->_drc_u.ic.count; +- drc_index = hp_elog->_drc_u.ic.index; ++ count = be32_to_cpu(hp_elog->_drc_u.ic.count); ++ drc_index = be32_to_cpu(hp_elog->_drc_u.ic.index); + rc = dlpar_memory_remove_by_ic(count, drc_index); + break; + default: +diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c +index 16d93b580f61f1..b1e6d275cda9eb 100644 +--- a/arch/powerpc/platforms/pseries/iommu.c ++++ b/arch/powerpc/platforms/pseries/iommu.c +@@ -574,29 +574,6 @@ static void iommu_table_setparms(struct pci_controller *phb, + + struct iommu_table_ops iommu_table_lpar_multi_ops; + +-/* +- * iommu_table_setparms_lpar +- * +- * Function: On pSeries LPAR systems, return TCE table info, given a pci bus. +- */ +-static void iommu_table_setparms_lpar(struct pci_controller *phb, +- struct device_node *dn, +- struct iommu_table *tbl, +- struct iommu_table_group *table_group, +- const __be32 *dma_window) +-{ +- unsigned long offset, size, liobn; +- +- of_parse_dma_window(dn, dma_window, &liobn, &offset, &size); +- +- iommu_table_setparms_common(tbl, phb->bus->number, liobn, offset, size, IOMMU_PAGE_SHIFT_4K, NULL, +- &iommu_table_lpar_multi_ops); +- +- +- table_group->tce32_start = offset; +- table_group->tce32_size = size; +-} +- + struct iommu_table_ops iommu_table_pseries_ops = { + .set = tce_build_pSeries, + .clear = tce_free_pSeries, +@@ -724,26 +701,71 @@ struct iommu_table_ops iommu_table_lpar_multi_ops = { + * dynamic 64bit DMA window, walking up the device tree. + */ + static struct device_node *pci_dma_find(struct device_node *dn, +- const __be32 **dma_window) ++ struct dynamic_dma_window_prop *prop) + { +- const __be32 *dw = NULL; ++ const __be32 *default_prop = NULL; ++ const __be32 *ddw_prop = NULL; ++ struct device_node *rdn = NULL; ++ bool default_win = false, ddw_win = false; + + for ( ; dn && PCI_DN(dn); dn = dn->parent) { +- dw = of_get_property(dn, "ibm,dma-window", NULL); +- if (dw) { +- if (dma_window) +- *dma_window = dw; +- return dn; ++ default_prop = of_get_property(dn, "ibm,dma-window", NULL); ++ if (default_prop) { ++ rdn = dn; ++ default_win = true; + } +- dw = of_get_property(dn, DIRECT64_PROPNAME, NULL); +- if (dw) +- return dn; +- dw = of_get_property(dn, DMA64_PROPNAME, NULL); +- if (dw) +- return dn; ++ ddw_prop = of_get_property(dn, DIRECT64_PROPNAME, NULL); ++ if (ddw_prop) { ++ rdn = dn; ++ ddw_win = true; ++ break; ++ } ++ ddw_prop = of_get_property(dn, DMA64_PROPNAME, NULL); ++ if (ddw_prop) { ++ rdn = dn; ++ ddw_win = true; ++ break; ++ } ++ ++ /* At least found default window, which is the case for normal boot */ ++ if (default_win) ++ break; + } + +- return NULL; ++ /* For PCI devices there will always be a DMA window, either on the device ++ * or parent bus ++ */ ++ WARN_ON(!(default_win | ddw_win)); ++ ++ /* caller doesn't want to get DMA window property */ ++ if (!prop) ++ return rdn; ++ ++ /* parse DMA window property. During normal system boot, only default ++ * DMA window is passed in OF. But, for kdump, a dedicated adapter might ++ * have both default and DDW in FDT. In this scenario, DDW takes precedence ++ * over default window. ++ */ ++ if (ddw_win) { ++ struct dynamic_dma_window_prop *p; ++ ++ p = (struct dynamic_dma_window_prop *)ddw_prop; ++ prop->liobn = p->liobn; ++ prop->dma_base = p->dma_base; ++ prop->tce_shift = p->tce_shift; ++ prop->window_shift = p->window_shift; ++ } else if (default_win) { ++ unsigned long offset, size, liobn; ++ ++ of_parse_dma_window(rdn, default_prop, &liobn, &offset, &size); ++ ++ prop->liobn = cpu_to_be32((u32)liobn); ++ prop->dma_base = cpu_to_be64(offset); ++ prop->tce_shift = cpu_to_be32(IOMMU_PAGE_SHIFT_4K); ++ prop->window_shift = cpu_to_be32(order_base_2(size)); ++ } ++ ++ return rdn; + } + + static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) +@@ -751,17 +773,28 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) + struct iommu_table *tbl; + struct device_node *dn, *pdn; + struct pci_dn *ppci; +- const __be32 *dma_window = NULL; ++ struct dynamic_dma_window_prop prop; + + dn = pci_bus_to_OF_node(bus); + + pr_debug("pci_dma_bus_setup_pSeriesLP: setting up bus %pOF\n", + dn); + +- pdn = pci_dma_find(dn, &dma_window); ++ pdn = pci_dma_find(dn, &prop); ++ ++ /* In PPC architecture, there will always be DMA window on bus or one of the ++ * parent bus. During reboot, there will be ibm,dma-window property to ++ * define DMA window. For kdump, there will at least be default window or DDW ++ * or both. ++ * There is an exception to the above. In case the PE goes into frozen ++ * state, firmware may not provide ibm,dma-window property at the time ++ * of LPAR boot up. ++ */ + +- if (dma_window == NULL) ++ if (!pdn) { + pr_debug(" no ibm,dma-window property !\n"); ++ return; ++ } + + ppci = PCI_DN(pdn); + +@@ -771,13 +804,24 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) + if (!ppci->table_group) { + ppci->table_group = iommu_pseries_alloc_group(ppci->phb->node); + tbl = ppci->table_group->tables[0]; +- if (dma_window) { +- iommu_table_setparms_lpar(ppci->phb, pdn, tbl, +- ppci->table_group, dma_window); + +- if (!iommu_init_table(tbl, ppci->phb->node, 0, 0)) +- panic("Failed to initialize iommu table"); +- } ++ iommu_table_setparms_common(tbl, ppci->phb->bus->number, ++ be32_to_cpu(prop.liobn), ++ be64_to_cpu(prop.dma_base), ++ 1ULL << be32_to_cpu(prop.window_shift), ++ be32_to_cpu(prop.tce_shift), NULL, ++ &iommu_table_lpar_multi_ops); ++ ++ /* Only for normal boot with default window. Doesn't matter even ++ * if we set these with DDW which is 64bit during kdump, since ++ * these will not be used during kdump. ++ */ ++ ppci->table_group->tce32_start = be64_to_cpu(prop.dma_base); ++ ppci->table_group->tce32_size = 1 << be32_to_cpu(prop.window_shift); ++ ++ if (!iommu_init_table(tbl, ppci->phb->node, 0, 0)) ++ panic("Failed to initialize iommu table"); ++ + iommu_register_group(ppci->table_group, + pci_domain_nr(bus), 0); + pr_debug(" created table: %p\n", ppci->table_group); +@@ -914,7 +958,8 @@ static int remove_ddw(struct device_node *np, bool remove_prop, const char *win_ + return 0; + } + +-static bool find_existing_ddw(struct device_node *pdn, u64 *dma_addr, int *window_shift) ++static bool find_existing_ddw(struct device_node *pdn, u64 *dma_addr, int *window_shift, ++ bool *direct_mapping) + { + struct dma_win *window; + const struct dynamic_dma_window_prop *dma64; +@@ -927,6 +972,7 @@ static bool find_existing_ddw(struct device_node *pdn, u64 *dma_addr, int *windo + dma64 = window->prop; + *dma_addr = be64_to_cpu(dma64->dma_base); + *window_shift = be32_to_cpu(dma64->window_shift); ++ *direct_mapping = window->direct; + found = true; + break; + } +@@ -966,6 +1012,12 @@ static void find_existing_ddw_windows_named(const char *name) + continue; + } + ++ /* If at the time of system initialization, there are DDWs in OF, ++ * it means this is during kexec. DDW could be direct or dynamic. ++ * We will just mark DDWs as "dynamic" since this is kdump path, ++ * no need to worry about perforance. ddw_list_new_entry() will ++ * set window->direct = false. ++ */ + window = ddw_list_new_entry(pdn, dma64); + if (!window) { + of_node_put(pdn); +@@ -1270,10 +1322,8 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn) + + mutex_lock(&dma_win_init_mutex); + +- if (find_existing_ddw(pdn, &dev->dev.archdata.dma_offset, &len)) { +- direct_mapping = (len >= max_ram_len); ++ if (find_existing_ddw(pdn, &dev->dev.archdata.dma_offset, &len, &direct_mapping)) + goto out_unlock; +- } + + /* + * If we already went through this for a previous function of +@@ -1524,8 +1574,8 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) + { + struct device_node *pdn, *dn; + struct iommu_table *tbl; +- const __be32 *dma_window = NULL; + struct pci_dn *pci; ++ struct dynamic_dma_window_prop prop; + + pr_debug("pci_dma_dev_setup_pSeriesLP: %s\n", pci_name(dev)); + +@@ -1538,7 +1588,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) + dn = pci_device_to_OF_node(dev); + pr_debug(" node is %pOF\n", dn); + +- pdn = pci_dma_find(dn, &dma_window); ++ pdn = pci_dma_find(dn, &prop); + if (!pdn || !PCI_DN(pdn)) { + printk(KERN_WARNING "pci_dma_dev_setup_pSeriesLP: " + "no DMA window found for pci dev=%s dn=%pOF\n", +@@ -1551,8 +1601,20 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) + if (!pci->table_group) { + pci->table_group = iommu_pseries_alloc_group(pci->phb->node); + tbl = pci->table_group->tables[0]; +- iommu_table_setparms_lpar(pci->phb, pdn, tbl, +- pci->table_group, dma_window); ++ ++ iommu_table_setparms_common(tbl, pci->phb->bus->number, ++ be32_to_cpu(prop.liobn), ++ be64_to_cpu(prop.dma_base), ++ 1ULL << be32_to_cpu(prop.window_shift), ++ be32_to_cpu(prop.tce_shift), NULL, ++ &iommu_table_lpar_multi_ops); ++ ++ /* Only for normal boot with default window. Doesn't matter even ++ * if we set these with DDW which is 64bit during kdump, since ++ * these will not be used during kdump. ++ */ ++ pci->table_group->tce32_start = be64_to_cpu(prop.dma_base); ++ pci->table_group->tce32_size = 1 << be32_to_cpu(prop.window_shift); + + iommu_init_table(tbl, pci->phb->node, 0, 0); + iommu_register_group(pci->table_group, +diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c +index 096d09ed89f673..431be156ca9bb3 100644 +--- a/arch/powerpc/platforms/pseries/kexec.c ++++ b/arch/powerpc/platforms/pseries/kexec.c +@@ -61,11 +61,3 @@ void pseries_kexec_cpu_down(int crash_shutdown, int secondary) + } else + xics_kexec_teardown_cpu(secondary); + } +- +-void pseries_machine_kexec(struct kimage *image) +-{ +- if (firmware_has_feature(FW_FEATURE_SET_MODE)) +- pseries_disable_reloc_on_exc(); +- +- default_machine_kexec(image); +-} +diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c +index f2cb62148f36f4..c3585e90c6db6b 100644 +--- a/arch/powerpc/platforms/pseries/lpar.c ++++ b/arch/powerpc/platforms/pseries/lpar.c +@@ -526,8 +526,10 @@ static ssize_t vcpudispatch_stats_write(struct file *file, const char __user *p, + + if (cmd) { + rc = init_cpu_associativity(); +- if (rc) ++ if (rc) { ++ destroy_cpu_associativity(); + goto out; ++ } + + for_each_possible_cpu(cpu) { + disp = per_cpu_ptr(&vcpu_disp_data, cpu); +@@ -660,8 +662,12 @@ u64 pseries_paravirt_steal_clock(int cpu) + { + struct lppaca *lppaca = &lppaca_of(cpu); + +- return be64_to_cpu(READ_ONCE(lppaca->enqueue_dispatch_tb)) + +- be64_to_cpu(READ_ONCE(lppaca->ready_enqueue_tb)); ++ /* ++ * VPA steal time counters are reported at TB frequency. Hence do a ++ * conversion to ns before returning ++ */ ++ return tb_to_ns(be64_to_cpu(READ_ONCE(lppaca->enqueue_dispatch_tb)) + ++ be64_to_cpu(READ_ONCE(lppaca->ready_enqueue_tb))); + } + #endif + +@@ -1880,10 +1886,10 @@ notrace void __trace_hcall_exit(long opcode, long retval, unsigned long *retbuf) + * h_get_mpp + * H_GET_MPP hcall returns info in 7 parms + */ +-int h_get_mpp(struct hvcall_mpp_data *mpp_data) ++long h_get_mpp(struct hvcall_mpp_data *mpp_data) + { +- int rc; +- unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; ++ unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = {0}; ++ long rc; + + rc = plpar_hcall9(H_GET_MPP, retbuf); + +diff --git a/arch/powerpc/platforms/pseries/lparcfg.c b/arch/powerpc/platforms/pseries/lparcfg.c +index 1c151d77e74b34..11d5208817b9d4 100644 +--- a/arch/powerpc/platforms/pseries/lparcfg.c ++++ b/arch/powerpc/platforms/pseries/lparcfg.c +@@ -113,8 +113,8 @@ struct hvcall_ppp_data { + */ + static unsigned int h_get_ppp(struct hvcall_ppp_data *ppp_data) + { +- unsigned long rc; +- unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; ++ unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = {0}; ++ long rc; + + rc = plpar_hcall9(H_GET_PPP, retbuf); + +@@ -193,7 +193,7 @@ static void parse_ppp_data(struct seq_file *m) + struct hvcall_ppp_data ppp_data; + struct device_node *root; + const __be32 *perf_level; +- int rc; ++ long rc; + + rc = h_get_ppp(&ppp_data); + if (rc) +@@ -357,8 +357,8 @@ static int read_dt_lpar_name(struct seq_file *m) + + static void read_lpar_name(struct seq_file *m) + { +- if (read_rtas_lpar_name(m) && read_dt_lpar_name(m)) +- pr_err_once("Error can't get the LPAR name"); ++ if (read_rtas_lpar_name(m)) ++ read_dt_lpar_name(m); + } + + #define SPLPAR_MAXLENGTH 1026*(sizeof(char)) +diff --git a/arch/powerpc/platforms/pseries/papr-sysparm.c b/arch/powerpc/platforms/pseries/papr-sysparm.c +index fedc61599e6cc7..a1e7aeac741616 100644 +--- a/arch/powerpc/platforms/pseries/papr-sysparm.c ++++ b/arch/powerpc/platforms/pseries/papr-sysparm.c +@@ -23,6 +23,46 @@ void papr_sysparm_buf_free(struct papr_sysparm_buf *buf) + kfree(buf); + } + ++static size_t papr_sysparm_buf_get_length(const struct papr_sysparm_buf *buf) ++{ ++ return be16_to_cpu(buf->len); ++} ++ ++static void papr_sysparm_buf_set_length(struct papr_sysparm_buf *buf, size_t length) ++{ ++ WARN_ONCE(length > sizeof(buf->val), ++ "bogus length %zu, clamping to safe value", length); ++ length = min(sizeof(buf->val), length); ++ buf->len = cpu_to_be16(length); ++} ++ ++/* ++ * For use on buffers returned from ibm,get-system-parameter before ++ * returning them to callers. Ensures the encoded length of valid data ++ * cannot overrun buf->val[]. ++ */ ++static void papr_sysparm_buf_clamp_length(struct papr_sysparm_buf *buf) ++{ ++ papr_sysparm_buf_set_length(buf, papr_sysparm_buf_get_length(buf)); ++} ++ ++/* ++ * Perform some basic diligence on the system parameter buffer before ++ * submitting it to RTAS. ++ */ ++static bool papr_sysparm_buf_can_submit(const struct papr_sysparm_buf *buf) ++{ ++ /* ++ * Firmware ought to reject buffer lengths that exceed the ++ * maximum specified in PAPR, but there's no reason for the ++ * kernel to allow them either. ++ */ ++ if (papr_sysparm_buf_get_length(buf) > sizeof(buf->val)) ++ return false; ++ ++ return true; ++} ++ + /** + * papr_sysparm_get() - Retrieve the value of a PAPR system parameter. + * @param: PAPR system parameter token as described in +@@ -63,6 +103,9 @@ int papr_sysparm_get(papr_sysparm_t param, struct papr_sysparm_buf *buf) + if (token == RTAS_UNKNOWN_SERVICE) + return -ENOENT; + ++ if (!papr_sysparm_buf_can_submit(buf)) ++ return -EINVAL; ++ + work_area = rtas_work_area_alloc(sizeof(*buf)); + + memcpy(rtas_work_area_raw_buf(work_area), buf, sizeof(*buf)); +@@ -77,6 +120,7 @@ int papr_sysparm_get(papr_sysparm_t param, struct papr_sysparm_buf *buf) + case 0: + ret = 0; + memcpy(buf, rtas_work_area_raw_buf(work_area), sizeof(*buf)); ++ papr_sysparm_buf_clamp_length(buf); + break; + case -3: /* parameter not implemented */ + ret = -EOPNOTSUPP; +@@ -115,6 +159,9 @@ int papr_sysparm_set(papr_sysparm_t param, const struct papr_sysparm_buf *buf) + if (token == RTAS_UNKNOWN_SERVICE) + return -ENOENT; + ++ if (!papr_sysparm_buf_can_submit(buf)) ++ return -EINVAL; ++ + work_area = rtas_work_area_alloc(sizeof(*buf)); + + memcpy(rtas_work_area_raw_buf(work_area), buf, sizeof(*buf)); +diff --git a/arch/powerpc/platforms/pseries/papr_platform_attributes.c b/arch/powerpc/platforms/pseries/papr_platform_attributes.c +index 526c621b098bec..eea2041b270b54 100644 +--- a/arch/powerpc/platforms/pseries/papr_platform_attributes.c ++++ b/arch/powerpc/platforms/pseries/papr_platform_attributes.c +@@ -101,10 +101,12 @@ static int papr_get_attr(u64 id, struct energy_scale_attribute *esi) + esi_buf_size = ESI_HDR_SIZE + (CURR_MAX_ESI_ATTRS * max_esi_attrs); + + temp_buf = krealloc(buf, esi_buf_size, GFP_KERNEL); +- if (temp_buf) ++ if (temp_buf) { + buf = temp_buf; +- else +- return -ENOMEM; ++ } else { ++ ret = -ENOMEM; ++ goto out_buf; ++ } + + goto retry; + } +diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c +index 4ba82456811921..4448386268d991 100644 +--- a/arch/powerpc/platforms/pseries/pci_dlpar.c ++++ b/arch/powerpc/platforms/pseries/pci_dlpar.c +@@ -35,6 +35,8 @@ struct pci_controller *init_phb_dynamic(struct device_node *dn) + + pseries_msi_allocate_domains(phb); + ++ ppc_iommu_register_device(phb); ++ + /* Create EEH devices for the PHB */ + eeh_phb_pe_create(phb); + +@@ -76,6 +78,8 @@ int remove_phb_dynamic(struct pci_controller *phb) + } + } + ++ ppc_iommu_unregister_device(phb); ++ + pseries_msi_free_domains(phb); + + /* Keep a reference so phb isn't freed yet */ +diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c +index 2d40304eb6c164..ed492d38f6ad6b 100644 +--- a/arch/powerpc/platforms/pseries/plpks.c ++++ b/arch/powerpc/platforms/pseries/plpks.c +@@ -415,8 +415,7 @@ static int plpks_confirm_object_flushed(struct label *label, + break; + } + +- usleep_range(PLPKS_FLUSH_SLEEP, +- PLPKS_FLUSH_SLEEP + PLPKS_FLUSH_SLEEP_RANGE); ++ fsleep(PLPKS_FLUSH_SLEEP); + timeout = timeout + PLPKS_FLUSH_SLEEP; + } while (timeout < PLPKS_MAX_TIMEOUT); + +@@ -464,9 +463,10 @@ int plpks_signed_update_var(struct plpks_var *var, u64 flags) + + continuetoken = retbuf[0]; + if (pseries_status_to_err(rc) == -EBUSY) { +- int delay_ms = get_longbusy_msecs(rc); +- mdelay(delay_ms); +- timeout += delay_ms; ++ int delay_us = get_longbusy_msecs(rc) * 1000; ++ ++ fsleep(delay_us); ++ timeout += delay_us; + } + rc = pseries_status_to_err(rc); + } while (rc == -EBUSY && timeout < PLPKS_MAX_TIMEOUT); +diff --git a/arch/powerpc/platforms/pseries/pmem.c b/arch/powerpc/platforms/pseries/pmem.c +index 3c290b9ed01b39..0f1d45f32e4a44 100644 +--- a/arch/powerpc/platforms/pseries/pmem.c ++++ b/arch/powerpc/platforms/pseries/pmem.c +@@ -121,7 +121,7 @@ int dlpar_hp_pmem(struct pseries_hp_errorlog *hp_elog) + return -EINVAL; + } + +- drc_index = hp_elog->_drc_u.drc_index; ++ drc_index = be32_to_cpu(hp_elog->_drc_u.drc_index); + + lock_device_hotplug(); + +diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h +index 8376f03f932a45..dd6c569f680687 100644 +--- a/arch/powerpc/platforms/pseries/pseries.h ++++ b/arch/powerpc/platforms/pseries/pseries.h +@@ -38,7 +38,6 @@ static inline void smp_init_pseries(void) { } + #endif + + extern void pseries_kexec_cpu_down(int crash_shutdown, int secondary); +-void pseries_machine_kexec(struct kimage *image); + + extern void pSeries_final_fixup(void); + +diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c +index ecea85c74c43fa..1feb6b919bd970 100644 +--- a/arch/powerpc/platforms/pseries/setup.c ++++ b/arch/powerpc/platforms/pseries/setup.c +@@ -343,8 +343,8 @@ static int alloc_dispatch_log_kmem_cache(void) + { + void (*ctor)(void *) = get_dtl_cache_ctor(); + +- dtl_cache = kmem_cache_create("dtl", DISPATCH_LOG_BYTES, +- DISPATCH_LOG_BYTES, 0, ctor); ++ dtl_cache = kmem_cache_create_usercopy("dtl", DISPATCH_LOG_BYTES, ++ DISPATCH_LOG_BYTES, 0, 0, DISPATCH_LOG_BYTES, ctor); + if (!dtl_cache) { + pr_warn("Failed to create dispatch trace log buffer cache\n"); + pr_warn("Stolen time statistics will be unreliable\n"); +@@ -1153,7 +1153,6 @@ define_machine(pseries) { + .machine_check_exception = pSeries_machine_check_exception, + .machine_check_log_err = pSeries_machine_check_log_err, + #ifdef CONFIG_KEXEC_CORE +- .machine_kexec = pseries_machine_kexec, + .kexec_cpu_down = pseries_kexec_cpu_down, + #endif + #ifdef CONFIG_MEMORY_HOTPLUG +diff --git a/arch/powerpc/platforms/pseries/vas.c b/arch/powerpc/platforms/pseries/vas.c +index e25ac52acf5073..71d52a670d951b 100644 +--- a/arch/powerpc/platforms/pseries/vas.c ++++ b/arch/powerpc/platforms/pseries/vas.c +@@ -341,7 +341,7 @@ static struct vas_window *vas_allocate_window(int vas_id, u64 flags, + + if (atomic_inc_return(&cop_feat_caps->nr_used_credits) > + atomic_read(&cop_feat_caps->nr_total_credits)) { +- pr_err("Credits are not available to allocate window\n"); ++ pr_err_ratelimited("Credits are not available to allocate window\n"); + rc = -EINVAL; + goto out; + } +@@ -385,11 +385,15 @@ static struct vas_window *vas_allocate_window(int vas_id, u64 flags, + * same fault IRQ is not freed by the OS before. + */ + mutex_lock(&vas_pseries_mutex); +- if (migration_in_progress) ++ if (migration_in_progress) { + rc = -EBUSY; +- else ++ } else { + rc = allocate_setup_window(txwin, (u64 *)&domain[0], + cop_feat_caps->win_type); ++ if (!rc) ++ caps->nr_open_wins_progress++; ++ } ++ + mutex_unlock(&vas_pseries_mutex); + if (rc) + goto out; +@@ -404,8 +408,17 @@ static struct vas_window *vas_allocate_window(int vas_id, u64 flags, + goto out_free; + + txwin->win_type = cop_feat_caps->win_type; +- mutex_lock(&vas_pseries_mutex); ++ + /* ++ * The migration SUSPEND thread sets migration_in_progress and ++ * closes all open windows from the list. But the window is ++ * added to the list after open and modify HCALLs. So possible ++ * that migration_in_progress is set before modify HCALL which ++ * may cause some windows are still open when the hypervisor ++ * initiates the migration. ++ * So checks the migration_in_progress flag again and close all ++ * open windows. ++ * + * Possible to lose the acquired credit with DLPAR core + * removal after the window is opened. So if there are any + * closed windows (means with lost credits), do not give new +@@ -413,9 +426,11 @@ static struct vas_window *vas_allocate_window(int vas_id, u64 flags, + * after the existing windows are reopened when credits are + * available. + */ +- if (!caps->nr_close_wins) { ++ mutex_lock(&vas_pseries_mutex); ++ if (!caps->nr_close_wins && !migration_in_progress) { + list_add(&txwin->win_list, &caps->list); + caps->nr_open_windows++; ++ caps->nr_open_wins_progress--; + mutex_unlock(&vas_pseries_mutex); + vas_user_win_add_mm_context(&txwin->vas_win.task_ref); + return &txwin->vas_win; +@@ -424,7 +439,7 @@ static struct vas_window *vas_allocate_window(int vas_id, u64 flags, + + put_vas_user_win_ref(&txwin->vas_win.task_ref); + rc = -EBUSY; +- pr_err("No credit is available to allocate window\n"); ++ pr_err_ratelimited("No credit is available to allocate window\n"); + + out_free: + /* +@@ -433,6 +448,12 @@ static struct vas_window *vas_allocate_window(int vas_id, u64 flags, + */ + free_irq_setup(txwin); + h_deallocate_vas_window(txwin->vas_win.winid); ++ /* ++ * Hold mutex and reduce nr_open_wins_progress counter. ++ */ ++ mutex_lock(&vas_pseries_mutex); ++ caps->nr_open_wins_progress--; ++ mutex_unlock(&vas_pseries_mutex); + out: + atomic_dec(&cop_feat_caps->nr_used_credits); + kfree(txwin); +@@ -937,14 +958,14 @@ int vas_migration_handler(int action) + struct vas_caps *vcaps; + int i, rc = 0; + ++ pr_info("VAS migration event %d\n", action); ++ + /* + * NX-GZIP is not enabled. Nothing to do for migration. + */ + if (!copypaste_feat) + return rc; + +- mutex_lock(&vas_pseries_mutex); +- + if (action == VAS_SUSPEND) + migration_in_progress = true; + else +@@ -990,12 +1011,27 @@ int vas_migration_handler(int action) + + switch (action) { + case VAS_SUSPEND: ++ mutex_lock(&vas_pseries_mutex); + rc = reconfig_close_windows(vcaps, vcaps->nr_open_windows, + true); ++ /* ++ * Windows are included in the list after successful ++ * open. So wait for closing these in-progress open ++ * windows in vas_allocate_window() which will be ++ * done if the migration_in_progress is set. ++ */ ++ while (vcaps->nr_open_wins_progress) { ++ mutex_unlock(&vas_pseries_mutex); ++ msleep(10); ++ mutex_lock(&vas_pseries_mutex); ++ } ++ mutex_unlock(&vas_pseries_mutex); + break; + case VAS_RESUME: ++ mutex_lock(&vas_pseries_mutex); + atomic_set(&caps->nr_total_credits, new_nr_creds); + rc = reconfig_open_windows(vcaps, new_nr_creds, true); ++ mutex_unlock(&vas_pseries_mutex); + break; + default: + /* should not happen */ +@@ -1011,8 +1047,9 @@ int vas_migration_handler(int action) + goto out; + } + ++ pr_info("VAS migration event (%d) successful\n", action); ++ + out: +- mutex_unlock(&vas_pseries_mutex); + return rc; + } + +diff --git a/arch/powerpc/platforms/pseries/vas.h b/arch/powerpc/platforms/pseries/vas.h +index 7115043ec48830..45567cd1317837 100644 +--- a/arch/powerpc/platforms/pseries/vas.h ++++ b/arch/powerpc/platforms/pseries/vas.h +@@ -91,6 +91,8 @@ struct vas_cop_feat_caps { + struct vas_caps { + struct vas_cop_feat_caps caps; + struct list_head list; /* List of open windows */ ++ int nr_open_wins_progress; /* Number of open windows in */ ++ /* progress. Used in migration */ + int nr_close_wins; /* closed windows in the hypervisor for DLPAR */ + int nr_open_windows; /* Number of successful open windows */ + u8 feat; /* Feature type */ +diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c +index 57978a44d55b69..ce9895633c4e0f 100644 +--- a/arch/powerpc/sysdev/fsl_msi.c ++++ b/arch/powerpc/sysdev/fsl_msi.c +@@ -568,10 +568,12 @@ static const struct fsl_msi_feature ipic_msi_feature = { + .msiir_offset = 0x38, + }; + ++#ifdef CONFIG_EPAPR_PARAVIRT + static const struct fsl_msi_feature vmpic_msi_feature = { + .fsl_pic_ip = FSL_PIC_IP_VMPIC, + .msiir_offset = 0, + }; ++#endif + + static const struct of_device_id fsl_of_msi_ids[] = { + { +diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c +index f6ec6dba92dcbc..700b67476a7d8d 100644 +--- a/arch/powerpc/sysdev/xics/icp-native.c ++++ b/arch/powerpc/sysdev/xics/icp-native.c +@@ -236,6 +236,8 @@ static int __init icp_native_map_one_cpu(int hw_id, unsigned long addr, + rname = kasprintf(GFP_KERNEL, "CPU %d [0x%x] Interrupt Presentation", + cpu, hw_id); + ++ if (!rname) ++ return -ENOMEM; + if (!request_mem_region(addr, size, rname)) { + pr_warn("icp_native: Could not reserve ICP MMIO for CPU %d, interrupt server #0x%x\n", + cpu, hw_id); +diff --git a/arch/powerpc/sysdev/xive/native.c b/arch/powerpc/sysdev/xive/native.c +index 9f0af4d795d886..f1c0fa6ece21d0 100644 +--- a/arch/powerpc/sysdev/xive/native.c ++++ b/arch/powerpc/sysdev/xive/native.c +@@ -802,7 +802,7 @@ int xive_native_get_queue_info(u32 vp_id, u32 prio, + if (out_qpage) + *out_qpage = be64_to_cpu(qpage); + if (out_qsize) +- *out_qsize = be32_to_cpu(qsize); ++ *out_qsize = be64_to_cpu(qsize); + if (out_qeoi_page) + *out_qeoi_page = be64_to_cpu(qeoi_page); + if (out_escalate_irq) +diff --git a/arch/powerpc/xmon/ppc-dis.c b/arch/powerpc/xmon/ppc-dis.c +index 75fa98221d485d..af105e1bc3fca4 100644 +--- a/arch/powerpc/xmon/ppc-dis.c ++++ b/arch/powerpc/xmon/ppc-dis.c +@@ -122,32 +122,21 @@ int print_insn_powerpc (unsigned long insn, unsigned long memaddr) + bool insn_is_short; + ppc_cpu_t dialect; + +- dialect = PPC_OPCODE_PPC | PPC_OPCODE_COMMON +- | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_ALTIVEC; ++ dialect = PPC_OPCODE_PPC | PPC_OPCODE_COMMON; + +- if (cpu_has_feature(CPU_FTRS_POWER5)) +- dialect |= PPC_OPCODE_POWER5; ++ if (IS_ENABLED(CONFIG_PPC64)) ++ dialect |= PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_CELL | ++ PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | ++ PPC_OPCODE_POWER9; + +- if (cpu_has_feature(CPU_FTRS_CELL)) +- dialect |= (PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC); ++ if (cpu_has_feature(CPU_FTR_TM)) ++ dialect |= PPC_OPCODE_HTM; + +- if (cpu_has_feature(CPU_FTRS_POWER6)) +- dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC); ++ if (cpu_has_feature(CPU_FTR_ALTIVEC)) ++ dialect |= PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2; + +- if (cpu_has_feature(CPU_FTRS_POWER7)) +- dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 +- | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX); +- +- if (cpu_has_feature(CPU_FTRS_POWER8)) +- dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 +- | PPC_OPCODE_POWER8 | PPC_OPCODE_HTM +- | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_VSX); +- +- if (cpu_has_feature(CPU_FTRS_POWER9)) +- dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 +- | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 | PPC_OPCODE_HTM +- | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 +- | PPC_OPCODE_VSX | PPC_OPCODE_VSX3); ++ if (cpu_has_feature(CPU_FTR_VSX)) ++ dialect |= PPC_OPCODE_VSX | PPC_OPCODE_VSX3; + + /* Get the major opcode of the insn. */ + opcode = NULL; +diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c +index b3b94cd3771373..1d815405a3b4f2 100644 +--- a/arch/powerpc/xmon/xmon.c ++++ b/arch/powerpc/xmon/xmon.c +@@ -1352,7 +1352,7 @@ static int cpu_cmd(void) + } + termch = cpu; + +- if (!scanhex(&cpu)) { ++ if (!scanhex(&cpu) || cpu >= num_possible_cpus()) { + /* print cpus waiting or in xmon */ + printf("cpus stopped:"); + last_cpu = first_cpu = NR_CPUS; +@@ -2774,7 +2774,7 @@ static void dump_pacas(void) + + termch = c; /* Put c back, it wasn't 'a' */ + +- if (scanhex(&num)) ++ if (scanhex(&num) && num < num_possible_cpus()) + dump_one_paca(num); + else + dump_one_paca(xmon_owner); +@@ -2847,7 +2847,7 @@ static void dump_xives(void) + + termch = c; /* Put c back, it wasn't 'a' */ + +- if (scanhex(&num)) ++ if (scanhex(&num) && num < num_possible_cpus()) + dump_one_xive(num); + else + dump_one_xive(xmon_owner); +diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig +index 9c48fecc671918..1304992232adbe 100644 +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -27,6 +27,7 @@ config RISCV + select ARCH_HAS_GCOV_PROFILE_ALL + select ARCH_HAS_GIGANTIC_PAGE + select ARCH_HAS_KCOV ++ select ARCH_HAS_MEMBARRIER_CALLBACKS + select ARCH_HAS_MMIOWB + select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE + select ARCH_HAS_PMEM_API +@@ -258,6 +259,11 @@ config GENERIC_HWEIGHT + config FIX_EARLYCON_MEM + def_bool MMU + ++config ILLEGAL_POINTER_VALUE ++ hex ++ default 0 if 32BIT ++ default 0xdead000000000000 if 64BIT ++ + config PGTABLE_LEVELS + int + default 5 if 64BIT +@@ -287,7 +293,6 @@ config AS_HAS_OPTION_ARCH + # https://reviews.llvm.org/D123515 + def_bool y + depends on $(as-instr, .option arch$(comma) +m) +- depends on !$(as-instr, .option arch$(comma) -i) + + source "arch/riscv/Kconfig.socs" + source "arch/riscv/Kconfig.errata" +@@ -490,8 +495,8 @@ config RISCV_ISA_SVPBMT + config TOOLCHAIN_HAS_V + bool + default y +- depends on !64BIT || $(cc-option,-mabi=lp64 -march=rv64iv) +- depends on !32BIT || $(cc-option,-mabi=ilp32 -march=rv32iv) ++ depends on !64BIT || $(cc-option,-mabi=lp64 -march=rv64imv) ++ depends on !32BIT || $(cc-option,-mabi=ilp32 -march=rv32imv) + depends on LLD_VERSION >= 140000 || LD_VERSION >= 23800 + depends on AS_HAS_OPTION_ARCH + +@@ -628,8 +633,7 @@ config IRQ_STACKS + config THREAD_SIZE_ORDER + int "Kernel stack size (in power-of-two numbers of page size)" if VMAP_STACK && EXPERT + range 0 4 +- default 1 if 32BIT && !KASAN +- default 3 if 64BIT && KASAN ++ default 1 if 32BIT + default 2 + help + Specify the Pages of thread stack size (from 4KB to 64KB), which also +@@ -669,7 +673,7 @@ config RISCV_BOOT_SPINWAIT + If unsure what to do here, say N. + + config ARCH_SUPPORTS_KEXEC +- def_bool MMU ++ def_bool y + + config ARCH_SELECTS_KEXEC + def_bool y +@@ -677,7 +681,7 @@ config ARCH_SELECTS_KEXEC + select HOTPLUG_CPU if SMP + + config ARCH_SUPPORTS_KEXEC_FILE +- def_bool 64BIT && MMU ++ def_bool 64BIT + + config ARCH_SELECTS_KEXEC_FILE + def_bool y +@@ -686,9 +690,7 @@ config ARCH_SELECTS_KEXEC_FILE + select KEXEC_ELF + + config ARCH_SUPPORTS_KEXEC_PURGATORY +- def_bool KEXEC_FILE +- depends on CRYPTO=y +- depends on CRYPTO_SHA256=y ++ def_bool ARCH_SUPPORTS_KEXEC_FILE + + config ARCH_SUPPORTS_CRASH_DUMP + def_bool y +diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs +index 6833d01e2e707b..30fd6a51282853 100644 +--- a/arch/riscv/Kconfig.socs ++++ b/arch/riscv/Kconfig.socs +@@ -29,6 +29,7 @@ config SOC_STARFIVE + bool "StarFive SoCs" + select PINCTRL + select RESET_CONTROLLER ++ select ARM_AMBA + help + This enables support for StarFive SoC platform hardware. + +diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile +index b43a6bb7e4dcb6..4d06f340267401 100644 +--- a/arch/riscv/Makefile ++++ b/arch/riscv/Makefile +@@ -130,12 +130,6 @@ endif + libs-y += arch/riscv/lib/ + libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a + +-PHONY += vdso_install +-vdso_install: +- $(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@ +- $(if $(CONFIG_COMPAT),$(Q)$(MAKE) \ +- $(build)=arch/riscv/kernel/compat_vdso compat_$@) +- + ifeq ($(KBUILD_EXTMOD),) + ifeq ($(CONFIG_MMU),y) + prepare: vdso_prepare +@@ -147,6 +141,9 @@ vdso_prepare: prepare0 + endif + endif + ++vdso-install-y += arch/riscv/kernel/vdso/vdso.so.dbg ++vdso-install-$(CONFIG_COMPAT) += arch/riscv/kernel/compat_vdso/compat_vdso.so.dbg:../compat_vdso/compat_vdso.so ++ + ifneq ($(CONFIG_XIP_KERNEL),y) + ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_ARCH_CANAAN),yy) + KBUILD_IMAGE := $(boot)/loader.bin +diff --git a/arch/riscv/boot/Makefile b/arch/riscv/boot/Makefile +index 22b13947bd131e..8e7fc0edf21d3e 100644 +--- a/arch/riscv/boot/Makefile ++++ b/arch/riscv/boot/Makefile +@@ -17,6 +17,7 @@ + KCOV_INSTRUMENT := n + + OBJCOPYFLAGS_Image :=-O binary -R .note -R .note.gnu.build-id -R .comment -S ++OBJCOPYFLAGS_loader.bin :=-O binary + OBJCOPYFLAGS_xipImage :=-O binary -R .note -R .note.gnu.build-id -R .comment -S + + targets := Image Image.* loader loader.o loader.lds loader.bin +diff --git a/arch/riscv/boot/dts/allwinner/sun20i-d1s.dtsi b/arch/riscv/boot/dts/allwinner/sun20i-d1s.dtsi +index 8275630af977d2..b8684312593e5b 100644 +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1s.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1s.dtsi +@@ -30,7 +30,6 @@ cpu0: cpu@0 { + cpu0_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; +- #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; +diff --git a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts +index 07387f9c135ca7..72b87b08ab444e 100644 +--- a/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts ++++ b/arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts +@@ -123,6 +123,7 @@ pmic@58 { + interrupt-parent = <&gpio>; + interrupts = <1 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; ++ #interrupt-cells = <2>; + + onkey { + compatible = "dlg,da9063-onkey"; +diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +index 2c02358abd711a..4874e3bb42ab10 100644 +--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +@@ -162,7 +162,6 @@ &i2c5 { + axp15060: pmic@36 { + compatible = "x-powers,axp15060"; + reg = <0x36>; +- interrupts = <0>; + interrupt-controller; + #interrupt-cells = <1>; + +@@ -205,6 +204,8 @@ &i2c6 { + + &mmc0 { + max-frequency = <100000000>; ++ assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO0_SDCARD>; ++ assigned-clock-rates = <50000000>; + bus-width = <8>; + cap-mmc-highspeed; + mmc-ddr-1_8v; +@@ -221,6 +222,8 @@ &mmc0 { + + &mmc1 { + max-frequency = <100000000>; ++ assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO1_SDCARD>; ++ assigned-clock-rates = <50000000>; + bus-width = <4>; + no-sdio; + no-mmc; +@@ -440,40 +443,6 @@ GPOEN_ENABLE, + }; + }; + +- tdm_pins: tdm-0 { +- tx-pins { +- pinmux = ; +- bias-pull-up; +- drive-strength = <2>; +- input-disable; +- input-schmitt-disable; +- slew-rate = <0>; +- }; +- +- rx-pins { +- pinmux = ; +- input-enable; +- }; +- +- sync-pins { +- pinmux = ; +- input-enable; +- }; +- +- pcmclk-pins { +- pinmux = ; +- input-enable; +- }; +- }; +- + uart0_pins: uart0-0 { + tx-pins { + pinmux = ; +- status = "okay"; +-}; +- + &uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; +diff --git a/arch/riscv/errata/andes/errata.c b/arch/riscv/errata/andes/errata.c +index 197db68cc8daf7..17a90486972468 100644 +--- a/arch/riscv/errata/andes/errata.c ++++ b/arch/riscv/errata/andes/errata.c +@@ -38,29 +38,35 @@ static long ax45mp_iocp_sw_workaround(void) + return ret.error ? 0 : ret.value; + } + +-static bool errata_probe_iocp(unsigned int stage, unsigned long arch_id, unsigned long impid) ++static void errata_probe_iocp(unsigned int stage, unsigned long arch_id, unsigned long impid) + { ++ static bool done; ++ + if (!IS_ENABLED(CONFIG_ERRATA_ANDES_CMO)) +- return false; ++ return; ++ ++ if (done) ++ return; ++ ++ done = true; + + if (arch_id != ANDESTECH_AX45MP_MARCHID || impid != ANDESTECH_AX45MP_MIMPID) +- return false; ++ return; + + if (!ax45mp_iocp_sw_workaround()) +- return false; ++ return; + + /* Set this just to make core cbo code happy */ + riscv_cbom_block_size = 1; + riscv_noncoherent_supported(); +- +- return true; + } + + void __init_or_module andes_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, + unsigned long archid, unsigned long impid, + unsigned int stage) + { +- errata_probe_iocp(stage, archid, impid); ++ if (stage == RISCV_ALTERNATIVES_BOOT) ++ errata_probe_iocp(stage, archid, impid); + + /* we have nothing to patch here ATM so just return back */ + } +diff --git a/arch/riscv/include/asm/asm-prototypes.h b/arch/riscv/include/asm/asm-prototypes.h +index 61ba8ed43d8feb..36b955c762ba08 100644 +--- a/arch/riscv/include/asm/asm-prototypes.h ++++ b/arch/riscv/include/asm/asm-prototypes.h +@@ -25,7 +25,6 @@ DECLARE_DO_ERROR_INFO(do_trap_ecall_s); + DECLARE_DO_ERROR_INFO(do_trap_ecall_m); + DECLARE_DO_ERROR_INFO(do_trap_break); + +-asmlinkage unsigned long get_overflow_stack(void); + asmlinkage void handle_bad_stack(struct pt_regs *regs); + asmlinkage void do_page_fault(struct pt_regs *regs); + asmlinkage void do_irq(struct pt_regs *regs); +diff --git a/arch/riscv/include/asm/asm.h b/arch/riscv/include/asm/asm.h +index 114bbadaef41eb..b5b84c6be01e16 100644 +--- a/arch/riscv/include/asm/asm.h ++++ b/arch/riscv/include/asm/asm.h +@@ -82,6 +82,28 @@ + .endr + .endm + ++#ifdef CONFIG_SMP ++#ifdef CONFIG_32BIT ++#define PER_CPU_OFFSET_SHIFT 2 ++#else ++#define PER_CPU_OFFSET_SHIFT 3 ++#endif ++ ++.macro asm_per_cpu dst sym tmp ++ REG_L \tmp, TASK_TI_CPU_NUM(tp) ++ slli \tmp, \tmp, PER_CPU_OFFSET_SHIFT ++ la \dst, __per_cpu_offset ++ add \dst, \dst, \tmp ++ REG_L \tmp, 0(\dst) ++ la \dst, \sym ++ add \dst, \dst, \tmp ++.endm ++#else /* CONFIG_SMP */ ++.macro asm_per_cpu dst sym tmp ++ la \dst, \sym ++.endm ++#endif /* CONFIG_SMP */ ++ + /* save all GPs except x1 ~ x5 */ + .macro save_from_x6_to_x31 + REG_S x6, PT_T1(sp) +@@ -142,6 +164,16 @@ + REG_L x31, PT_T6(sp) + .endm + ++/* Annotate a function as being unsuitable for kprobes. */ ++#ifdef CONFIG_KPROBES ++#define ASM_NOKPROBE(name) \ ++ .pushsection "_kprobe_blacklist", "aw"; \ ++ RISCV_PTR name; \ ++ .popsection ++#else ++#define ASM_NOKPROBE(name) ++#endif ++ + #endif /* __ASSEMBLY__ */ + + #endif /* _ASM_RISCV_ASM_H */ +diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h +index 3cb53c4df27cfe..a129dac4521d35 100644 +--- a/arch/riscv/include/asm/cacheflush.h ++++ b/arch/riscv/include/asm/cacheflush.h +@@ -37,7 +37,8 @@ static inline void flush_dcache_page(struct page *page) + flush_icache_mm(vma->vm_mm, 0) + + #ifdef CONFIG_64BIT +-#define flush_cache_vmap(start, end) flush_tlb_kernel_range(start, end) ++#define flush_cache_vmap(start, end) flush_tlb_kernel_range(start, end) ++#define flush_cache_vmap_early(start, end) local_flush_tlb_kernel_range(start, end) + #endif + + #ifndef CONFIG_SMP +diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h +index b55b434f005910..d3f3c237adad74 100644 +--- a/arch/riscv/include/asm/errata_list.h ++++ b/arch/riscv/include/asm/errata_list.h +@@ -44,11 +44,21 @@ ALTERNATIVE(__stringify(RISCV_PTR do_page_fault), \ + CONFIG_ERRATA_SIFIVE_CIP_453) + #else /* !__ASSEMBLY__ */ + +-#define ALT_FLUSH_TLB_PAGE(x) \ ++#define ALT_SFENCE_VMA_ASID(asid) \ ++asm(ALTERNATIVE("sfence.vma x0, %0", "sfence.vma", SIFIVE_VENDOR_ID, \ ++ ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200) \ ++ : : "r" (asid) : "memory") ++ ++#define ALT_SFENCE_VMA_ADDR(addr) \ + asm(ALTERNATIVE("sfence.vma %0", "sfence.vma", SIFIVE_VENDOR_ID, \ + ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200) \ + : : "r" (addr) : "memory") + ++#define ALT_SFENCE_VMA_ADDR_ASID(addr, asid) \ ++asm(ALTERNATIVE("sfence.vma %0, %1", "sfence.vma", SIFIVE_VENDOR_ID, \ ++ ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200) \ ++ : : "r" (addr), "r" (asid) : "memory") ++ + /* + * _val is marked as "will be overwritten", so need to set it to 0 + * in the default case. +diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h +index 2b2f5df7ef2c7d..42777f91a9c580 100644 +--- a/arch/riscv/include/asm/ftrace.h ++++ b/arch/riscv/include/asm/ftrace.h +@@ -25,6 +25,11 @@ + + #define ARCH_SUPPORTS_FTRACE_OPS 1 + #ifndef __ASSEMBLY__ ++ ++extern void *return_address(unsigned int level); ++ ++#define ftrace_return_address(n) return_address(n) ++ + void MCOUNT_NAME(void); + static inline unsigned long ftrace_call_adjust(unsigned long addr) + { +diff --git a/arch/riscv/include/asm/hugetlb.h b/arch/riscv/include/asm/hugetlb.h +index 4c5b0e929890fa..22deb7a2a6ec4e 100644 +--- a/arch/riscv/include/asm/hugetlb.h ++++ b/arch/riscv/include/asm/hugetlb.h +@@ -11,6 +11,11 @@ static inline void arch_clear_hugepage_flags(struct page *page) + } + #define arch_clear_hugepage_flags arch_clear_hugepage_flags + ++#ifdef CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION ++bool arch_hugetlb_migration_supported(struct hstate *h); ++#define arch_hugetlb_migration_supported arch_hugetlb_migration_supported ++#endif ++ + #ifdef CONFIG_RISCV_ISA_SVNAPOT + #define __HAVE_ARCH_HUGE_PTE_CLEAR + void huge_pte_clear(struct mm_struct *mm, unsigned long addr, +diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h +index b7b58258f6c7c0..f4157034efa9cb 100644 +--- a/arch/riscv/include/asm/hwcap.h ++++ b/arch/riscv/include/asm/hwcap.h +@@ -98,7 +98,7 @@ riscv_has_extension_likely(const unsigned long ext) + "ext must be < RISCV_ISA_EXT_MAX"); + + if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) { +- asm_volatile_goto( ++ asm goto( + ALTERNATIVE("j %l[l_no]", "nop", 0, %[ext], 1) + : + : [ext] "i" (ext) +@@ -121,7 +121,7 @@ riscv_has_extension_unlikely(const unsigned long ext) + "ext must be < RISCV_ISA_EXT_MAX"); + + if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) { +- asm_volatile_goto( ++ asm goto( + ALTERNATIVE("nop", "j %l[l_yes]", 0, %[ext], 1) + : + : [ext] "i" (ext) +diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h +index 78936f4ff51330..7cad513538d8d0 100644 +--- a/arch/riscv/include/asm/hwprobe.h ++++ b/arch/riscv/include/asm/hwprobe.h +@@ -10,4 +10,9 @@ + + #define RISCV_HWPROBE_MAX_KEY 5 + ++static inline bool riscv_hwprobe_key_is_valid(__s64 key) ++{ ++ return key >= 0 && key <= RISCV_HWPROBE_MAX_KEY; ++} ++ + #endif +diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h +index 06e439eeef9ada..09fde95a5e8f75 100644 +--- a/arch/riscv/include/asm/insn.h ++++ b/arch/riscv/include/asm/insn.h +@@ -145,7 +145,7 @@ + + /* parts of opcode for RVF, RVD and RVQ */ + #define RVFDQ_FL_FS_WIDTH_OFF 12 +-#define RVFDQ_FL_FS_WIDTH_MASK GENMASK(3, 0) ++#define RVFDQ_FL_FS_WIDTH_MASK GENMASK(2, 0) + #define RVFDQ_FL_FS_WIDTH_W 2 + #define RVFDQ_FL_FS_WIDTH_D 3 + #define RVFDQ_LS_FS_WIDTH_Q 4 +diff --git a/arch/riscv/include/asm/irq_work.h b/arch/riscv/include/asm/irq_work.h +index b53891964ae037..b27a4d64fc6a04 100644 +--- a/arch/riscv/include/asm/irq_work.h ++++ b/arch/riscv/include/asm/irq_work.h +@@ -6,5 +6,5 @@ static inline bool arch_irq_work_has_interrupt(void) + { + return IS_ENABLED(CONFIG_SMP); + } +-extern void arch_irq_work_raise(void); ++ + #endif /* _ASM_RISCV_IRQ_WORK_H */ +diff --git a/arch/riscv/include/asm/jump_label.h b/arch/riscv/include/asm/jump_label.h +index 14a5ea8d8ef0f4..4a35d787c01914 100644 +--- a/arch/riscv/include/asm/jump_label.h ++++ b/arch/riscv/include/asm/jump_label.h +@@ -17,7 +17,7 @@ + static __always_inline bool arch_static_branch(struct static_key * const key, + const bool branch) + { +- asm_volatile_goto( ++ asm goto( + " .align 2 \n\t" + " .option push \n\t" + " .option norelax \n\t" +@@ -39,7 +39,7 @@ static __always_inline bool arch_static_branch(struct static_key * const key, + static __always_inline bool arch_static_branch_jump(struct static_key * const key, + const bool branch) + { +- asm_volatile_goto( ++ asm goto( + " .align 2 \n\t" + " .option push \n\t" + " .option norelax \n\t" +diff --git a/arch/riscv/include/asm/kfence.h b/arch/riscv/include/asm/kfence.h +index 0bbffd528096d9..7388edd88986f9 100644 +--- a/arch/riscv/include/asm/kfence.h ++++ b/arch/riscv/include/asm/kfence.h +@@ -18,9 +18,9 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect) + pte_t *pte = virt_to_kpte(addr); + + if (protect) +- set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT)); ++ set_pte(pte, __pte(pte_val(ptep_get(pte)) & ~_PAGE_PRESENT)); + else +- set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT)); ++ set_pte(pte, __pte(pte_val(ptep_get(pte)) | _PAGE_PRESENT)); + + flush_tlb_kernel_range(addr, addr + PAGE_SIZE); + +diff --git a/arch/riscv/include/asm/kvm_vcpu_pmu.h b/arch/riscv/include/asm/kvm_vcpu_pmu.h +index 395518a1664e00..a50a1d23523fea 100644 +--- a/arch/riscv/include/asm/kvm_vcpu_pmu.h ++++ b/arch/riscv/include/asm/kvm_vcpu_pmu.h +@@ -10,6 +10,7 @@ + #define __KVM_VCPU_RISCV_PMU_H + + #include ++#include + #include + + #ifdef CONFIG_RISCV_PMU_SBI +@@ -57,11 +58,11 @@ struct kvm_pmu { + + #if defined(CONFIG_32BIT) + #define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ +-{.base = CSR_CYCLEH, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, \ +-{.base = CSR_CYCLE, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, ++{.base = CSR_CYCLEH, .count = 32, .func = kvm_riscv_vcpu_pmu_read_hpm }, \ ++{.base = CSR_CYCLE, .count = 32, .func = kvm_riscv_vcpu_pmu_read_hpm }, + #else + #define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ +-{.base = CSR_CYCLE, .count = 31, .func = kvm_riscv_vcpu_pmu_read_hpm }, ++{.base = CSR_CYCLE, .count = 32, .func = kvm_riscv_vcpu_pmu_read_hpm }, + #endif + + int kvm_riscv_vcpu_pmu_incr_fw(struct kvm_vcpu *vcpu, unsigned long fid); +@@ -92,8 +93,20 @@ void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu); + struct kvm_pmu { + }; + ++static inline int kvm_riscv_vcpu_pmu_read_legacy(struct kvm_vcpu *vcpu, unsigned int csr_num, ++ unsigned long *val, unsigned long new_val, ++ unsigned long wr_mask) ++{ ++ if (csr_num == CSR_CYCLE || csr_num == CSR_INSTRET) { ++ *val = 0; ++ return KVM_INSN_CONTINUE_NEXT_SEPC; ++ } else { ++ return KVM_INSN_ILLEGAL_TRAP; ++ } ++} ++ + #define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \ +-{.base = 0, .count = 0, .func = NULL }, ++{.base = CSR_CYCLE, .count = 3, .func = kvm_riscv_vcpu_pmu_read_legacy }, + + static inline void kvm_riscv_vcpu_pmu_init(struct kvm_vcpu *vcpu) {} + static inline int kvm_riscv_vcpu_pmu_incr_fw(struct kvm_vcpu *vcpu, unsigned long fid) +diff --git a/arch/riscv/include/asm/membarrier.h b/arch/riscv/include/asm/membarrier.h +new file mode 100644 +index 00000000000000..6c016ebb5020af +--- /dev/null ++++ b/arch/riscv/include/asm/membarrier.h +@@ -0,0 +1,31 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++#ifndef _ASM_RISCV_MEMBARRIER_H ++#define _ASM_RISCV_MEMBARRIER_H ++ ++static inline void membarrier_arch_switch_mm(struct mm_struct *prev, ++ struct mm_struct *next, ++ struct task_struct *tsk) ++{ ++ /* ++ * Only need the full barrier when switching between processes. ++ * Barrier when switching from kernel to userspace is not ++ * required here, given that it is implied by mmdrop(). Barrier ++ * when switching from userspace to kernel is not needed after ++ * store to rq->curr. ++ */ ++ if (IS_ENABLED(CONFIG_SMP) && ++ likely(!(atomic_read(&next->membarrier_state) & ++ (MEMBARRIER_STATE_PRIVATE_EXPEDITED | ++ MEMBARRIER_STATE_GLOBAL_EXPEDITED)) || !prev)) ++ return; ++ ++ /* ++ * The membarrier system call requires a full memory barrier ++ * after storing to rq->curr, before going back to user-space. ++ * Matches a full barrier in the proximity of the membarrier ++ * system call entry. ++ */ ++ smp_mb(); ++} ++ ++#endif /* _ASM_RISCV_MEMBARRIER_H */ +diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h +index 5488ecc337b63f..94b3d6930fc370 100644 +--- a/arch/riscv/include/asm/page.h ++++ b/arch/riscv/include/asm/page.h +@@ -33,8 +33,8 @@ + #define PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL) + #endif + /* +- * By default, CONFIG_PAGE_OFFSET value corresponds to SV48 address space so +- * define the PAGE_OFFSET value for SV39. ++ * By default, CONFIG_PAGE_OFFSET value corresponds to SV57 address space so ++ * define the PAGE_OFFSET value for SV48 and SV39. + */ + #define PAGE_OFFSET_L4 _AC(0xffffaf8000000000, UL) + #define PAGE_OFFSET_L3 _AC(0xffffffd800000000, UL) +@@ -89,7 +89,7 @@ typedef struct page *pgtable_t; + #define PTE_FMT "%08lx" + #endif + +-#ifdef CONFIG_64BIT ++#if defined(CONFIG_64BIT) && defined(CONFIG_MMU) + /* + * We override this value as its generic definition uses __pa too early in + * the boot process (before kernel_map.va_pa_offset is set). +diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h +index 7a5097202e1570..3272ca7a5270bf 100644 +--- a/arch/riscv/include/asm/pgtable-64.h ++++ b/arch/riscv/include/asm/pgtable-64.h +@@ -198,7 +198,7 @@ static inline int pud_user(pud_t pud) + + static inline void set_pud(pud_t *pudp, pud_t pud) + { +- *pudp = pud; ++ WRITE_ONCE(*pudp, pud); + } + + static inline void pud_clear(pud_t *pudp) +@@ -274,7 +274,7 @@ static inline unsigned long _pmd_pfn(pmd_t pmd) + static inline void set_p4d(p4d_t *p4dp, p4d_t p4d) + { + if (pgtable_l4_enabled) +- *p4dp = p4d; ++ WRITE_ONCE(*p4dp, p4d); + else + set_pud((pud_t *)p4dp, (pud_t){ p4d_val(p4d) }); + } +@@ -336,18 +336,12 @@ static inline struct page *p4d_page(p4d_t p4d) + #define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) + + #define pud_offset pud_offset +-static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address) +-{ +- if (pgtable_l4_enabled) +- return p4d_pgtable(*p4d) + pud_index(address); +- +- return (pud_t *)p4d; +-} ++pud_t *pud_offset(p4d_t *p4d, unsigned long address); + + static inline void set_pgd(pgd_t *pgdp, pgd_t pgd) + { + if (pgtable_l5_enabled) +- *pgdp = pgd; ++ WRITE_ONCE(*pgdp, pgd); + else + set_p4d((p4d_t *)pgdp, (p4d_t){ pgd_val(pgd) }); + } +@@ -400,12 +394,6 @@ static inline struct page *pgd_page(pgd_t pgd) + #define p4d_index(addr) (((addr) >> P4D_SHIFT) & (PTRS_PER_P4D - 1)) + + #define p4d_offset p4d_offset +-static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address) +-{ +- if (pgtable_l5_enabled) +- return pgd_pgtable(*pgd) + p4d_index(address); +- +- return (p4d_t *)pgd; +-} ++p4d_t *p4d_offset(pgd_t *pgd, unsigned long address); + + #endif /* _ASM_RISCV_PGTABLE_64_H */ +diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h +index b2ba3f79cfe9a7..37829dab4a0a48 100644 +--- a/arch/riscv/include/asm/pgtable.h ++++ b/arch/riscv/include/asm/pgtable.h +@@ -84,7 +84,7 @@ + * Define vmemmap for pfn_to_page & page_to_pfn calls. Needed if kernel + * is configured with CONFIG_SPARSEMEM_VMEMMAP enabled. + */ +-#define vmemmap ((struct page *)VMEMMAP_START) ++#define vmemmap ((struct page *)VMEMMAP_START - (phys_ram_base >> PAGE_SHIFT)) + + #define PCI_IO_SIZE SZ_16M + #define PCI_IO_END VMEMMAP_START +@@ -248,7 +248,7 @@ static inline int pmd_leaf(pmd_t pmd) + + static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) + { +- *pmdp = pmd; ++ WRITE_ONCE(*pmdp, pmd); + } + + static inline void pmd_clear(pmd_t *pmdp) +@@ -438,6 +438,12 @@ static inline pte_t pte_mkhuge(pte_t pte) + return pte; + } + ++#ifdef CONFIG_RISCV_ISA_SVNAPOT ++#define pte_leaf_size(pte) (pte_napot(pte) ? \ ++ napot_cont_size(napot_cont_order(pte)) :\ ++ PAGE_SIZE) ++#endif ++ + #ifdef CONFIG_NUMA_BALANCING + /* + * See the comment in include/asm-generic/pgtable.h +@@ -509,7 +515,7 @@ static inline int pte_same(pte_t pte_a, pte_t pte_b) + */ + static inline void set_pte(pte_t *ptep, pte_t pteval) + { +- *ptep = pteval; ++ WRITE_ONCE(*ptep, pteval); + } + + void flush_icache_pte(pte_t pte); +@@ -543,19 +549,12 @@ static inline void pte_clear(struct mm_struct *mm, + __set_pte_at(ptep, __pte(0)); + } + +-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS +-static inline int ptep_set_access_flags(struct vm_area_struct *vma, +- unsigned long address, pte_t *ptep, +- pte_t entry, int dirty) +-{ +- if (!pte_same(*ptep, entry)) +- __set_pte_at(ptep, entry); +- /* +- * update_mmu_cache will unconditionally execute, handling both +- * the case that the PTE changed and the spurious fault case. +- */ +- return true; +-} ++#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS /* defined in mm/pgtable.c */ ++extern int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address, ++ pte_t *ptep, pte_t entry, int dirty); ++#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG /* defined in mm/pgtable.c */ ++extern int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long address, ++ pte_t *ptep); + + #define __HAVE_ARCH_PTEP_GET_AND_CLEAR + static inline pte_t ptep_get_and_clear(struct mm_struct *mm, +@@ -568,16 +567,6 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, + return pte; + } + +-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG +-static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, +- unsigned long address, +- pte_t *ptep) +-{ +- if (!pte_young(*ptep)) +- return 0; +- return test_and_clear_bit(_PAGE_ACCESSED_OFFSET, &pte_val(*ptep)); +-} +- + #define __HAVE_ARCH_PTEP_SET_WRPROTECT + static inline void ptep_set_wrprotect(struct mm_struct *mm, + unsigned long address, pte_t *ptep) +@@ -880,7 +869,7 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte) + #define TASK_SIZE_MIN (PGDIR_SIZE_L3 * PTRS_PER_PGD / 2) + + #ifdef CONFIG_COMPAT +-#define TASK_SIZE_32 (_AC(0x80000000, UL) - PAGE_SIZE) ++#define TASK_SIZE_32 (_AC(0x80000000, UL)) + #define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \ + TASK_SIZE_32 : TASK_SIZE_64) + #else +@@ -897,8 +886,8 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte) + #define PAGE_SHARED __pgprot(0) + #define PAGE_KERNEL __pgprot(0) + #define swapper_pg_dir NULL +-#define TASK_SIZE 0xffffffffUL +-#define VMALLOC_START 0 ++#define TASK_SIZE _AC(-1, UL) ++#define VMALLOC_START _AC(0, UL) + #define VMALLOC_END TASK_SIZE + + #endif /* !CONFIG_MMU */ +diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h +index 3e23e1786d0521..4f6af8c6cfa060 100644 +--- a/arch/riscv/include/asm/processor.h ++++ b/arch/riscv/include/asm/processor.h +@@ -15,7 +15,7 @@ + + #ifdef CONFIG_64BIT + #define DEFAULT_MAP_WINDOW (UL(1) << (MMAP_VA_BITS - 1)) +-#define STACK_TOP_MAX TASK_SIZE_64 ++#define STACK_TOP_MAX TASK_SIZE + + #define arch_get_mmap_end(addr, len, flags) \ + ({ \ +diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h +index 5b4a1bf5f4395c..3ed853b8a8c858 100644 +--- a/arch/riscv/include/asm/sbi.h ++++ b/arch/riscv/include/asm/sbi.h +@@ -273,9 +273,6 @@ void sbi_set_timer(uint64_t stime_value); + void sbi_shutdown(void); + void sbi_send_ipi(unsigned int cpu); + int sbi_remote_fence_i(const struct cpumask *cpu_mask); +-int sbi_remote_sfence_vma(const struct cpumask *cpu_mask, +- unsigned long start, +- unsigned long size); + + int sbi_remote_sfence_vma_asid(const struct cpumask *cpu_mask, + unsigned long start, +@@ -330,6 +327,8 @@ static inline int sbi_remote_fence_i(const struct cpumask *cpu_mask) { return -1 + static inline void sbi_init(void) {} + #endif /* CONFIG_RISCV_SBI */ + ++unsigned long riscv_get_mvendorid(void); ++unsigned long riscv_get_marchid(void); + unsigned long riscv_cached_mvendorid(unsigned int cpu_id); + unsigned long riscv_cached_marchid(unsigned int cpu_id); + unsigned long riscv_cached_mimpid(unsigned int cpu_id); +diff --git a/arch/riscv/include/asm/sections.h b/arch/riscv/include/asm/sections.h +index 32336e8a17cb07..a393d5035c5433 100644 +--- a/arch/riscv/include/asm/sections.h ++++ b/arch/riscv/include/asm/sections.h +@@ -13,6 +13,7 @@ extern char _start_kernel[]; + extern char __init_data_begin[], __init_data_end[]; + extern char __init_text_begin[], __init_text_end[]; + extern char __alt_start[], __alt_end[]; ++extern char __exittext_begin[], __exittext_end[]; + + static inline bool is_va_kernel_text(uintptr_t va) + { +diff --git a/arch/riscv/include/asm/sparsemem.h b/arch/riscv/include/asm/sparsemem.h +index 63acaecc337478..2f901a410586d0 100644 +--- a/arch/riscv/include/asm/sparsemem.h ++++ b/arch/riscv/include/asm/sparsemem.h +@@ -7,7 +7,7 @@ + #ifdef CONFIG_64BIT + #define MAX_PHYSMEM_BITS 56 + #else +-#define MAX_PHYSMEM_BITS 34 ++#define MAX_PHYSMEM_BITS 32 + #endif /* CONFIG_64BIT */ + #define SECTION_SIZE_BITS 27 + #endif /* CONFIG_SPARSEMEM */ +diff --git a/arch/riscv/include/asm/stacktrace.h b/arch/riscv/include/asm/stacktrace.h +index f7e8ef2418b99f..b1495a7e06ce69 100644 +--- a/arch/riscv/include/asm/stacktrace.h ++++ b/arch/riscv/include/asm/stacktrace.h +@@ -21,4 +21,9 @@ static inline bool on_thread_stack(void) + return !(((unsigned long)(current->stack) ^ current_stack_pointer) & ~(THREAD_SIZE - 1)); + } + ++ ++#ifdef CONFIG_VMAP_STACK ++DECLARE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack); ++#endif /* CONFIG_VMAP_STACK */ ++ + #endif /* _ASM_RISCV_STACKTRACE_H */ +diff --git a/arch/riscv/include/asm/syscall_wrapper.h b/arch/riscv/include/asm/syscall_wrapper.h +index 1d7942c8a6cbae..eeec04b7dae67b 100644 +--- a/arch/riscv/include/asm/syscall_wrapper.h ++++ b/arch/riscv/include/asm/syscall_wrapper.h +@@ -46,9 +46,6 @@ asmlinkage long __riscv_sys_ni_syscall(const struct pt_regs *); + return sys_ni_syscall(); \ + } + +-#define COMPAT_SYS_NI(name) \ +- SYSCALL_ALIAS(__riscv_compat_sys_##name, sys_ni_posix_timers); +- + #endif /* CONFIG_COMPAT */ + + #define __SYSCALL_DEFINEx(x, name, ...) \ +@@ -82,6 +79,4 @@ asmlinkage long __riscv_sys_ni_syscall(const struct pt_regs *); + return sys_ni_syscall(); \ + } + +-#define SYS_NI(name) SYSCALL_ALIAS(__riscv_sys_##name, sys_ni_posix_timers); +- + #endif /* __ASM_SYSCALL_WRAPPER_H */ +diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h +index 1833beb00489c3..8c72d1bcdf141e 100644 +--- a/arch/riscv/include/asm/thread_info.h ++++ b/arch/riscv/include/asm/thread_info.h +@@ -12,7 +12,12 @@ + #include + + /* thread information allocation */ +-#define THREAD_SIZE_ORDER CONFIG_THREAD_SIZE_ORDER ++#ifdef CONFIG_KASAN ++#define KASAN_STACK_ORDER 1 ++#else ++#define KASAN_STACK_ORDER 0 ++#endif ++#define THREAD_SIZE_ORDER (CONFIG_THREAD_SIZE_ORDER + KASAN_STACK_ORDER) + #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) + + /* +@@ -28,15 +33,11 @@ + + #define THREAD_SHIFT (PAGE_SHIFT + THREAD_SIZE_ORDER) + #define OVERFLOW_STACK_SIZE SZ_4K +-#define SHADOW_OVERFLOW_STACK_SIZE (1024) + + #define IRQ_STACK_SIZE THREAD_SIZE + + #ifndef __ASSEMBLY__ + +-extern long shadow_stack[SHADOW_OVERFLOW_STACK_SIZE / sizeof(long)]; +-extern unsigned long spin_shadow_stack; +- + #include + #include + +diff --git a/arch/riscv/include/asm/tlb.h b/arch/riscv/include/asm/tlb.h +index 120bcf2ed8a878..50b63b5c15bd8b 100644 +--- a/arch/riscv/include/asm/tlb.h ++++ b/arch/riscv/include/asm/tlb.h +@@ -15,7 +15,13 @@ static void tlb_flush(struct mmu_gather *tlb); + + static inline void tlb_flush(struct mmu_gather *tlb) + { +- flush_tlb_mm(tlb->mm); ++#ifdef CONFIG_MMU ++ if (tlb->fullmm || tlb->need_flush_all || tlb->freed_tables) ++ flush_tlb_mm(tlb->mm); ++ else ++ flush_tlb_mm_range(tlb->mm, tlb->start, tlb->end, ++ tlb_get_unmap_size(tlb)); ++#endif + } + + #endif /* _ASM_RISCV_TLB_H */ +diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h +index a09196f8de688e..97711d5bd8ef9a 100644 +--- a/arch/riscv/include/asm/tlbflush.h ++++ b/arch/riscv/include/asm/tlbflush.h +@@ -11,6 +11,9 @@ + #include + #include + ++#define FLUSH_TLB_MAX_SIZE ((unsigned long)-1) ++#define FLUSH_TLB_NO_ASID ((unsigned long)-1) ++ + #ifdef CONFIG_MMU + extern unsigned long asid_mask; + +@@ -19,10 +22,27 @@ static inline void local_flush_tlb_all(void) + __asm__ __volatile__ ("sfence.vma" : : : "memory"); + } + ++static inline void local_flush_tlb_all_asid(unsigned long asid) ++{ ++ if (asid != FLUSH_TLB_NO_ASID) ++ ALT_SFENCE_VMA_ASID(asid); ++ else ++ local_flush_tlb_all(); ++} ++ + /* Flush one page from local TLB */ + static inline void local_flush_tlb_page(unsigned long addr) + { +- ALT_FLUSH_TLB_PAGE(__asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory")); ++ ALT_SFENCE_VMA_ADDR(addr); ++} ++ ++static inline void local_flush_tlb_page_asid(unsigned long addr, ++ unsigned long asid) ++{ ++ if (asid != FLUSH_TLB_NO_ASID) ++ ALT_SFENCE_VMA_ADDR_ASID(addr, asid); ++ else ++ local_flush_tlb_page(addr); + } + #else /* CONFIG_MMU */ + #define local_flush_tlb_all() do { } while (0) +@@ -32,9 +52,13 @@ static inline void local_flush_tlb_page(unsigned long addr) + #if defined(CONFIG_SMP) && defined(CONFIG_MMU) + void flush_tlb_all(void); + void flush_tlb_mm(struct mm_struct *mm); ++void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, ++ unsigned long end, unsigned int page_size); + void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr); + void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); ++void flush_tlb_kernel_range(unsigned long start, unsigned long end); ++void local_flush_tlb_kernel_range(unsigned long start, unsigned long end); + #ifdef CONFIG_TRANSPARENT_HUGEPAGE + #define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE + void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, +@@ -51,14 +75,16 @@ static inline void flush_tlb_range(struct vm_area_struct *vma, + local_flush_tlb_all(); + } + +-#define flush_tlb_mm(mm) flush_tlb_all() +-#endif /* !CONFIG_SMP || !CONFIG_MMU */ +- + /* Flush a range of kernel pages */ + static inline void flush_tlb_kernel_range(unsigned long start, + unsigned long end) + { +- flush_tlb_all(); ++ local_flush_tlb_all(); + } + ++#define flush_tlb_mm(mm) flush_tlb_all() ++#define flush_tlb_mm_range(mm, start, end, page_size) flush_tlb_all() ++#define local_flush_tlb_kernel_range(start, end) flush_tlb_all() ++#endif /* !CONFIG_SMP || !CONFIG_MMU */ ++ + #endif /* _ASM_RISCV_TLBFLUSH_H */ +diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h +index ec0cab9fbddd0d..72ec1d9bd3f312 100644 +--- a/arch/riscv/include/asm/uaccess.h ++++ b/arch/riscv/include/asm/uaccess.h +@@ -319,7 +319,7 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n) + + #define __get_kernel_nofault(dst, src, type, err_label) \ + do { \ +- long __kr_err; \ ++ long __kr_err = 0; \ + \ + __get_user_nocheck(*((type *)(dst)), (type *)(src), __kr_err); \ + if (unlikely(__kr_err)) \ +@@ -328,7 +328,7 @@ do { \ + + #define __put_kernel_nofault(dst, src, type, err_label) \ + do { \ +- long __kr_err; \ ++ long __kr_err = 0; \ + \ + __put_user_nocheck(*((type *)(src)), (type *)(dst), __kr_err); \ + if (unlikely(__kr_err)) \ +diff --git a/arch/riscv/include/asm/vdso/processor.h b/arch/riscv/include/asm/vdso/processor.h +index 14f5d27783b858..96b65a5396dfcf 100644 +--- a/arch/riscv/include/asm/vdso/processor.h ++++ b/arch/riscv/include/asm/vdso/processor.h +@@ -14,7 +14,7 @@ static inline void cpu_relax(void) + __asm__ __volatile__ ("div %0, %0, zero" : "=r" (dummy)); + #endif + +-#ifdef __riscv_zihintpause ++#ifdef CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE + /* + * Reduce instruction retirement. + * This assumes the PC changes. +diff --git a/arch/riscv/include/asm/vmalloc.h b/arch/riscv/include/asm/vmalloc.h +index 924d01b56c9a1e..51f6dfe19745aa 100644 +--- a/arch/riscv/include/asm/vmalloc.h ++++ b/arch/riscv/include/asm/vmalloc.h +@@ -19,65 +19,6 @@ static inline bool arch_vmap_pmd_supported(pgprot_t prot) + return true; + } + +-#ifdef CONFIG_RISCV_ISA_SVNAPOT +-#include ++#endif + +-#define arch_vmap_pte_range_map_size arch_vmap_pte_range_map_size +-static inline unsigned long arch_vmap_pte_range_map_size(unsigned long addr, unsigned long end, +- u64 pfn, unsigned int max_page_shift) +-{ +- unsigned long map_size = PAGE_SIZE; +- unsigned long size, order; +- +- if (!has_svnapot()) +- return map_size; +- +- for_each_napot_order_rev(order) { +- if (napot_cont_shift(order) > max_page_shift) +- continue; +- +- size = napot_cont_size(order); +- if (end - addr < size) +- continue; +- +- if (!IS_ALIGNED(addr, size)) +- continue; +- +- if (!IS_ALIGNED(PFN_PHYS(pfn), size)) +- continue; +- +- map_size = size; +- break; +- } +- +- return map_size; +-} +- +-#define arch_vmap_pte_supported_shift arch_vmap_pte_supported_shift +-static inline int arch_vmap_pte_supported_shift(unsigned long size) +-{ +- int shift = PAGE_SHIFT; +- unsigned long order; +- +- if (!has_svnapot()) +- return shift; +- +- WARN_ON_ONCE(size >= PMD_SIZE); +- +- for_each_napot_order_rev(order) { +- if (napot_cont_size(order) > size) +- continue; +- +- if (!IS_ALIGNED(size, napot_cont_size(order))) +- continue; +- +- shift = napot_cont_shift(order); +- break; +- } +- +- return shift; +-} +- +-#endif /* CONFIG_RISCV_ISA_SVNAPOT */ +-#endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */ + #endif /* _ASM_RISCV_VMALLOC_H */ +diff --git a/arch/riscv/include/asm/xip_fixup.h b/arch/riscv/include/asm/xip_fixup.h +index d4ffc3c37649ff..b65bf6306f69c6 100644 +--- a/arch/riscv/include/asm/xip_fixup.h ++++ b/arch/riscv/include/asm/xip_fixup.h +@@ -13,7 +13,7 @@ + add \reg, \reg, t0 + .endm + .macro XIP_FIXUP_FLASH_OFFSET reg +- la t1, __data_loc ++ la t0, __data_loc + REG_L t1, _xip_phys_offset + sub \reg, \reg, t1 + add \reg, \reg, t0 +diff --git a/arch/riscv/include/uapi/asm/auxvec.h b/arch/riscv/include/uapi/asm/auxvec.h +index 10aaa83db89ef7..95050ebe9ad00b 100644 +--- a/arch/riscv/include/uapi/asm/auxvec.h ++++ b/arch/riscv/include/uapi/asm/auxvec.h +@@ -34,7 +34,7 @@ + #define AT_L3_CACHEGEOMETRY 47 + + /* entries in ARCH_DLINFO */ +-#define AT_VECTOR_SIZE_ARCH 9 ++#define AT_VECTOR_SIZE_ARCH 10 + #define AT_MINSIGSTKSZ 51 + + #endif /* _UAPI_ASM_RISCV_AUXVEC_H */ +diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile +index 95cf25d484052e..03968c06258ceb 100644 +--- a/arch/riscv/kernel/Makefile ++++ b/arch/riscv/kernel/Makefile +@@ -7,6 +7,7 @@ ifdef CONFIG_FTRACE + CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) + CFLAGS_REMOVE_patch.o = $(CC_FLAGS_FTRACE) + CFLAGS_REMOVE_sbi.o = $(CC_FLAGS_FTRACE) ++CFLAGS_REMOVE_return_address.o = $(CC_FLAGS_FTRACE) + endif + CFLAGS_syscall_table.o += $(call cc-option,-Wno-override-init,) + CFLAGS_compat_syscall_table.o += $(call cc-option,-Wno-override-init,) +@@ -46,6 +47,7 @@ obj-y += irq.o + obj-y += process.o + obj-y += ptrace.o + obj-y += reset.o ++obj-y += return_address.o + obj-y += setup.o + obj-y += signal.o + obj-y += syscall_table.o +diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c +index d6a75aac1d27a5..9f535d5de33f93 100644 +--- a/arch/riscv/kernel/asm-offsets.c ++++ b/arch/riscv/kernel/asm-offsets.c +@@ -39,6 +39,7 @@ void asm_offsets(void) + OFFSET(TASK_TI_KERNEL_SP, task_struct, thread_info.kernel_sp); + OFFSET(TASK_TI_USER_SP, task_struct, thread_info.user_sp); + ++ OFFSET(TASK_TI_CPU_NUM, task_struct, thread_info.cpu); + OFFSET(TASK_THREAD_F0, task_struct, thread.fstate.f[0]); + OFFSET(TASK_THREAD_F1, task_struct, thread.fstate.f[1]); + OFFSET(TASK_THREAD_F2, task_struct, thread.fstate.f[2]); +diff --git a/arch/riscv/kernel/compat_vdso/Makefile b/arch/riscv/kernel/compat_vdso/Makefile +index b86e5e2c3aea94..62fa393b2eb2ea 100644 +--- a/arch/riscv/kernel/compat_vdso/Makefile ++++ b/arch/riscv/kernel/compat_vdso/Makefile +@@ -76,13 +76,3 @@ quiet_cmd_compat_vdsold = VDSOLD $@ + # actual build commands + quiet_cmd_compat_vdsoas = VDSOAS $@ + cmd_compat_vdsoas = $(COMPAT_CC) $(a_flags) $(COMPAT_CC_FLAGS) -c -o $@ $< +- +-# install commands for the unstripped file +-quiet_cmd_compat_vdso_install = INSTALL $@ +- cmd_compat_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/compat_vdso/$@ +- +-compat_vdso.so: $(obj)/compat_vdso.so.dbg +- @mkdir -p $(MODLIB)/compat_vdso +- $(call cmd,compat_vdso_install) +- +-compat_vdso_install: compat_vdso.so +diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c +index c17dacb1141cb3..88732abecd0230 100644 +--- a/arch/riscv/kernel/cpu.c ++++ b/arch/riscv/kernel/cpu.c +@@ -125,19 +125,48 @@ int __init riscv_early_of_processor_hartid(struct device_node *node, unsigned lo + */ + int riscv_of_parent_hartid(struct device_node *node, unsigned long *hartid) + { +- int rc; +- + for (; node; node = node->parent) { + if (of_device_is_compatible(node, "riscv")) { +- rc = riscv_of_processor_hartid(node, hartid); +- if (!rc) +- return 0; ++ *hartid = (unsigned long)of_get_cpu_hwid(node, 0); ++ if (*hartid == ~0UL) { ++ pr_warn("Found CPU without hart ID\n"); ++ return -ENODEV; ++ } ++ return 0; + } + } + + return -1; + } + ++unsigned long __init riscv_get_marchid(void) ++{ ++ struct riscv_cpuinfo *ci = this_cpu_ptr(&riscv_cpuinfo); ++ ++#if IS_ENABLED(CONFIG_RISCV_SBI) ++ ci->marchid = sbi_spec_is_0_1() ? 0 : sbi_get_marchid(); ++#elif IS_ENABLED(CONFIG_RISCV_M_MODE) ++ ci->marchid = csr_read(CSR_MARCHID); ++#else ++ ci->marchid = 0; ++#endif ++ return ci->marchid; ++} ++ ++unsigned long __init riscv_get_mvendorid(void) ++{ ++ struct riscv_cpuinfo *ci = this_cpu_ptr(&riscv_cpuinfo); ++ ++#if IS_ENABLED(CONFIG_RISCV_SBI) ++ ci->mvendorid = sbi_spec_is_0_1() ? 0 : sbi_get_mvendorid(); ++#elif IS_ENABLED(CONFIG_RISCV_M_MODE) ++ ci->mvendorid = csr_read(CSR_MVENDORID); ++#else ++ ci->mvendorid = 0; ++#endif ++ return ci->mvendorid; ++} ++ + DEFINE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo); + + unsigned long riscv_cached_mvendorid(unsigned int cpu_id) +@@ -169,12 +198,16 @@ static int riscv_cpuinfo_starting(unsigned int cpu) + struct riscv_cpuinfo *ci = this_cpu_ptr(&riscv_cpuinfo); + + #if IS_ENABLED(CONFIG_RISCV_SBI) +- ci->mvendorid = sbi_spec_is_0_1() ? 0 : sbi_get_mvendorid(); +- ci->marchid = sbi_spec_is_0_1() ? 0 : sbi_get_marchid(); ++ if (!ci->mvendorid) ++ ci->mvendorid = sbi_spec_is_0_1() ? 0 : sbi_get_mvendorid(); ++ if (!ci->marchid) ++ ci->marchid = sbi_spec_is_0_1() ? 0 : sbi_get_marchid(); + ci->mimpid = sbi_spec_is_0_1() ? 0 : sbi_get_mimpid(); + #elif IS_ENABLED(CONFIG_RISCV_M_MODE) +- ci->mvendorid = csr_read(CSR_MVENDORID); +- ci->marchid = csr_read(CSR_MARCHID); ++ if (!ci->mvendorid) ++ ci->mvendorid = csr_read(CSR_MVENDORID); ++ if (!ci->marchid) ++ ci->marchid = csr_read(CSR_MARCHID); + ci->mimpid = csr_read(CSR_MIMPID); + #else + ci->mvendorid = 0; +diff --git a/arch/riscv/kernel/cpu_ops_sbi.c b/arch/riscv/kernel/cpu_ops_sbi.c +index efa0f0816634c4..93cbc38d180571 100644 +--- a/arch/riscv/kernel/cpu_ops_sbi.c ++++ b/arch/riscv/kernel/cpu_ops_sbi.c +@@ -72,7 +72,7 @@ static int sbi_cpu_start(unsigned int cpuid, struct task_struct *tidle) + /* Make sure tidle is updated */ + smp_mb(); + bdata->task_ptr = tidle; +- bdata->stack_ptr = task_stack_page(tidle) + THREAD_SIZE; ++ bdata->stack_ptr = task_pt_regs(tidle); + /* Make sure boot data is updated */ + smp_mb(); + hsm_data = __pa(bdata); +diff --git a/arch/riscv/kernel/cpu_ops_spinwait.c b/arch/riscv/kernel/cpu_ops_spinwait.c +index d98d19226b5f51..691e0c5366d2bd 100644 +--- a/arch/riscv/kernel/cpu_ops_spinwait.c ++++ b/arch/riscv/kernel/cpu_ops_spinwait.c +@@ -34,8 +34,7 @@ static void cpu_update_secondary_bootdata(unsigned int cpuid, + + /* Make sure tidle is updated */ + smp_mb(); +- WRITE_ONCE(__cpu_spinwait_stack_pointer[hartid], +- task_stack_page(tidle) + THREAD_SIZE); ++ WRITE_ONCE(__cpu_spinwait_stack_pointer[hartid], task_pt_regs(tidle)); + WRITE_ONCE(__cpu_spinwait_task_pointer[hartid], tidle); + } + +diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c +index 1cfbba65d11ae3..bb5fb2b820a21e 100644 +--- a/arch/riscv/kernel/cpufeature.c ++++ b/arch/riscv/kernel/cpufeature.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + + #include "copy-unaligned.h" +@@ -350,6 +351,8 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap) + struct acpi_table_header *rhct; + acpi_status status; + unsigned int cpu; ++ u64 boot_vendorid; ++ u64 boot_archid; + + if (!acpi_disabled) { + status = acpi_get_table(ACPI_SIG_RHCT, 0, &rhct); +@@ -357,6 +360,9 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap) + return; + } + ++ boot_vendorid = riscv_get_mvendorid(); ++ boot_archid = riscv_get_marchid(); ++ + for_each_possible_cpu(cpu) { + struct riscv_isainfo *isainfo = &hart_isa[cpu]; + unsigned long this_hwcap = 0; +@@ -396,6 +402,19 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap) + set_bit(RISCV_ISA_EXT_ZIHPM, isainfo->isa); + } + ++ /* ++ * "V" in ISA strings is ambiguous in practice: it should mean ++ * just the standard V-1.0 but vendors aren't well behaved. ++ * Many vendors with T-Head CPU cores which implement the 0.7.1 ++ * version of the vector specification put "v" into their DTs. ++ * CPU cores with the ratified spec will contain non-zero ++ * marchid. ++ */ ++ if (acpi_disabled && boot_vendorid == THEAD_VENDOR_ID && boot_archid == 0x0) { ++ this_hwcap &= ~isa2hwcap[RISCV_ISA_EXT_v]; ++ clear_bit(RISCV_ISA_EXT_v, isainfo->isa); ++ } ++ + /* + * All "okay" hart should have same isa. Set HWCAP based on + * common capabilities of every "okay" hart, in case they don't +@@ -568,6 +587,10 @@ void check_unaligned_access(int cpu) + void *src; + long speed = RISCV_HWPROBE_MISALIGNED_SLOW; + ++ /* We are already set since the last check */ ++ if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_UNKNOWN) ++ return; ++ + page = alloc_pages(GFP_NOWAIT, get_order(MISALIGNED_BUFFER_SIZE)); + if (!page) { + pr_warn("Can't alloc pages to measure memcpy performance"); +diff --git a/arch/riscv/kernel/crash_core.c b/arch/riscv/kernel/crash_core.c +index 55f1d7856b5448..8706736fd4e2dc 100644 +--- a/arch/riscv/kernel/crash_core.c ++++ b/arch/riscv/kernel/crash_core.c +@@ -5,17 +5,19 @@ + + void arch_crash_save_vmcoreinfo(void) + { +- VMCOREINFO_NUMBER(VA_BITS); + VMCOREINFO_NUMBER(phys_ram_base); + + vmcoreinfo_append_str("NUMBER(PAGE_OFFSET)=0x%lx\n", PAGE_OFFSET); + vmcoreinfo_append_str("NUMBER(VMALLOC_START)=0x%lx\n", VMALLOC_START); + vmcoreinfo_append_str("NUMBER(VMALLOC_END)=0x%lx\n", VMALLOC_END); ++#ifdef CONFIG_MMU ++ VMCOREINFO_NUMBER(VA_BITS); + vmcoreinfo_append_str("NUMBER(VMEMMAP_START)=0x%lx\n", VMEMMAP_START); + vmcoreinfo_append_str("NUMBER(VMEMMAP_END)=0x%lx\n", VMEMMAP_END); + #ifdef CONFIG_64BIT + vmcoreinfo_append_str("NUMBER(MODULES_VADDR)=0x%lx\n", MODULES_VADDR); + vmcoreinfo_append_str("NUMBER(MODULES_END)=0x%lx\n", MODULES_END); ++#endif + #endif + vmcoreinfo_append_str("NUMBER(KERNEL_LINK_ADDR)=0x%lx\n", KERNEL_LINK_ADDR); + vmcoreinfo_append_str("NUMBER(va_kernel_pa_offset)=0x%lx\n", +diff --git a/arch/riscv/kernel/efi.c b/arch/riscv/kernel/efi.c +index aa6209a74c83ff..b64bf1624a0529 100644 +--- a/arch/riscv/kernel/efi.c ++++ b/arch/riscv/kernel/efi.c +@@ -60,7 +60,7 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md) + static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data) + { + efi_memory_desc_t *md = data; +- pte_t pte = READ_ONCE(*ptep); ++ pte_t pte = ptep_get(ptep); + unsigned long val; + + if (md->attribute & EFI_MEMORY_RO) { +diff --git a/arch/riscv/kernel/elf_kexec.c b/arch/riscv/kernel/elf_kexec.c +index e60fbd8660c4a5..8c32bf1eedda08 100644 +--- a/arch/riscv/kernel/elf_kexec.c ++++ b/arch/riscv/kernel/elf_kexec.c +@@ -444,6 +444,12 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi, + *(u32 *)loc = CLEAN_IMM(CJTYPE, *(u32 *)loc) | + ENCODE_CJTYPE_IMM(val - addr); + break; ++ case R_RISCV_ADD16: ++ *(u16 *)loc += val; ++ break; ++ case R_RISCV_SUB16: ++ *(u16 *)loc -= val; ++ break; + case R_RISCV_ADD32: + *(u32 *)loc += val; + break; +diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S +index 143a2bb3e69760..1f90fee24a8ba8 100644 +--- a/arch/riscv/kernel/entry.S ++++ b/arch/riscv/kernel/entry.S +@@ -10,9 +10,13 @@ + #include + #include + #include ++#include + #include + #include + #include ++#include ++ ++ .section .irqentry.text, "ax" + + SYM_CODE_START(handle_exception) + /* +@@ -101,6 +105,7 @@ _save_context: + 1: + tail do_trap_unknown + SYM_CODE_END(handle_exception) ++ASM_NOKPROBE(handle_exception) + + /* + * The ret_from_exception must be called with interrupt disabled. Here is the +@@ -167,70 +172,19 @@ SYM_CODE_START_NOALIGN(ret_from_exception) + sret + #endif + SYM_CODE_END(ret_from_exception) ++ASM_NOKPROBE(ret_from_exception) + + #ifdef CONFIG_VMAP_STACK + SYM_CODE_START_LOCAL(handle_kernel_stack_overflow) +- /* +- * Takes the psuedo-spinlock for the shadow stack, in case multiple +- * harts are concurrently overflowing their kernel stacks. We could +- * store any value here, but since we're overflowing the kernel stack +- * already we only have SP to use as a scratch register. So we just +- * swap in the address of the spinlock, as that's definately non-zero. +- * +- * Pairs with a store_release in handle_bad_stack(). +- */ +-1: la sp, spin_shadow_stack +- REG_AMOSWAP_AQ sp, sp, (sp) +- bnez sp, 1b +- +- la sp, shadow_stack +- addi sp, sp, SHADOW_OVERFLOW_STACK_SIZE +- +- //save caller register to shadow stack +- addi sp, sp, -(PT_SIZE_ON_STACK) +- REG_S x1, PT_RA(sp) +- REG_S x5, PT_T0(sp) +- REG_S x6, PT_T1(sp) +- REG_S x7, PT_T2(sp) +- REG_S x10, PT_A0(sp) +- REG_S x11, PT_A1(sp) +- REG_S x12, PT_A2(sp) +- REG_S x13, PT_A3(sp) +- REG_S x14, PT_A4(sp) +- REG_S x15, PT_A5(sp) +- REG_S x16, PT_A6(sp) +- REG_S x17, PT_A7(sp) +- REG_S x28, PT_T3(sp) +- REG_S x29, PT_T4(sp) +- REG_S x30, PT_T5(sp) +- REG_S x31, PT_T6(sp) ++ /* we reach here from kernel context, sscratch must be 0 */ ++ csrrw x31, CSR_SCRATCH, x31 ++ asm_per_cpu sp, overflow_stack, x31 ++ li x31, OVERFLOW_STACK_SIZE ++ add sp, sp, x31 ++ /* zero out x31 again and restore x31 */ ++ xor x31, x31, x31 ++ csrrw x31, CSR_SCRATCH, x31 + +- la ra, restore_caller_reg +- tail get_overflow_stack +- +-restore_caller_reg: +- //save per-cpu overflow stack +- REG_S a0, -8(sp) +- //restore caller register from shadow_stack +- REG_L x1, PT_RA(sp) +- REG_L x5, PT_T0(sp) +- REG_L x6, PT_T1(sp) +- REG_L x7, PT_T2(sp) +- REG_L x10, PT_A0(sp) +- REG_L x11, PT_A1(sp) +- REG_L x12, PT_A2(sp) +- REG_L x13, PT_A3(sp) +- REG_L x14, PT_A4(sp) +- REG_L x15, PT_A5(sp) +- REG_L x16, PT_A6(sp) +- REG_L x17, PT_A7(sp) +- REG_L x28, PT_T3(sp) +- REG_L x29, PT_T4(sp) +- REG_L x30, PT_T5(sp) +- REG_L x31, PT_T6(sp) +- +- //load per-cpu overflow stack +- REG_L sp, -8(sp) + addi sp, sp, -(PT_SIZE_ON_STACK) + + //save context to overflow stack +@@ -254,6 +208,7 @@ restore_caller_reg: + move a0, sp + tail handle_bad_stack + SYM_CODE_END(handle_kernel_stack_overflow) ++ASM_NOKPROBE(handle_kernel_stack_overflow) + #endif + + SYM_CODE_START(ret_from_fork) +@@ -264,8 +219,8 @@ SYM_CODE_START(ret_from_fork) + jalr s0 + 1: + move a0, sp /* pt_regs */ +- la ra, ret_from_exception +- tail syscall_exit_to_user_mode ++ call syscall_exit_to_user_mode ++ j ret_from_exception + SYM_CODE_END(ret_from_fork) + + /* +diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S +index 3710ea5d160f30..9691fa8f2faa7b 100644 +--- a/arch/riscv/kernel/head.S ++++ b/arch/riscv/kernel/head.S +@@ -88,6 +88,7 @@ relocate_enable_mmu: + /* Compute satp for kernel page tables, but don't load it yet */ + srl a2, a0, PAGE_SHIFT + la a1, satp_mode ++ XIP_FIXUP_OFFSET a1 + REG_L a1, 0(a1) + or a2, a2, a1 + +@@ -304,6 +305,9 @@ clear_bss_done: + #else + mv a0, a1 + #endif /* CONFIG_BUILTIN_DTB */ ++ /* Set trap vector to spin forever to help debug */ ++ la a3, .Lsecondary_park ++ csrw CSR_TVEC, a3 + call setup_vm + #ifdef CONFIG_MMU + la a0, early_pg_dir +diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c +index 2d139b724bc842..ccb0c5d5c63c42 100644 +--- a/arch/riscv/kernel/machine_kexec.c ++++ b/arch/riscv/kernel/machine_kexec.c +@@ -147,20 +147,12 @@ static void machine_kexec_mask_interrupts(void) + + for_each_irq_desc(i, desc) { + struct irq_chip *chip; +- int ret; + + chip = irq_desc_get_chip(desc); + if (!chip) + continue; + +- /* +- * First try to remove the active state. If this +- * fails, try to EOI the interrupt. +- */ +- ret = irq_set_irqchip_state(i, IRQCHIP_STATE_ACTIVE, false); +- +- if (ret && irqd_irq_inprogress(&desc->irq_data) && +- chip->irq_eoi) ++ if (chip->irq_eoi && irqd_irq_inprogress(&desc->irq_data)) + chip->irq_eoi(&desc->irq_data); + + if (chip->irq_mask) +diff --git a/arch/riscv/kernel/module.c b/arch/riscv/kernel/module.c +index 7c651d55fcbd2f..df4f6fec5d1740 100644 +--- a/arch/riscv/kernel/module.c ++++ b/arch/riscv/kernel/module.c +@@ -440,7 +440,8 @@ void *module_alloc(unsigned long size) + { + return __vmalloc_node_range(size, 1, MODULES_VADDR, + MODULES_END, GFP_KERNEL, +- PAGE_KERNEL, 0, NUMA_NO_NODE, ++ PAGE_KERNEL, VM_FLUSH_RESET_PERMS, ++ NUMA_NO_NODE, + __builtin_return_address(0)); + } + #endif +diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c +index 13ee7bf589a15e..30e12b310cab73 100644 +--- a/arch/riscv/kernel/patch.c ++++ b/arch/riscv/kernel/patch.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + struct patch_insn { + void *addr; +@@ -25,6 +26,14 @@ struct patch_insn { + int riscv_patch_in_stop_machine = false; + + #ifdef CONFIG_MMU ++ ++static inline bool is_kernel_exittext(uintptr_t addr) ++{ ++ return system_state < SYSTEM_RUNNING && ++ addr >= (uintptr_t)__exittext_begin && ++ addr < (uintptr_t)__exittext_end; ++} ++ + /* + * The fix_to_virt(, idx) needs a const value (not a dynamic variable of + * reg-a0) or BUILD_BUG_ON failed with "idx >= __end_of_fixed_addresses". +@@ -35,7 +44,7 @@ static __always_inline void *patch_map(void *addr, const unsigned int fixmap) + uintptr_t uintaddr = (uintptr_t) addr; + struct page *page; + +- if (core_kernel_text(uintaddr)) ++ if (core_kernel_text(uintaddr) || is_kernel_exittext(uintaddr)) + page = phys_to_page(__pa_symbol(addr)); + else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) + page = vmalloc_to_page(addr); +@@ -71,6 +80,8 @@ static int __patch_insn_set(void *addr, u8 c, size_t len) + */ + lockdep_assert_held(&text_mutex); + ++ preempt_disable(); ++ + if (across_pages) + patch_map(addr + PAGE_SIZE, FIX_TEXT_POKE1); + +@@ -83,6 +94,8 @@ static int __patch_insn_set(void *addr, u8 c, size_t len) + if (across_pages) + patch_unmap(FIX_TEXT_POKE1); + ++ preempt_enable(); ++ + return 0; + } + NOKPROBE_SYMBOL(__patch_insn_set); +@@ -113,6 +126,8 @@ static int __patch_insn_write(void *addr, const void *insn, size_t len) + if (!riscv_patch_in_stop_machine) + lockdep_assert_held(&text_mutex); + ++ preempt_disable(); ++ + if (across_pages) + patch_map(addr + PAGE_SIZE, FIX_TEXT_POKE1); + +@@ -125,6 +140,8 @@ static int __patch_insn_write(void *addr, const void *insn, size_t len) + if (across_pages) + patch_unmap(FIX_TEXT_POKE1); + ++ preempt_enable(); ++ + return ret; + } + NOKPROBE_SYMBOL(__patch_insn_write); +diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_callchain.c +index 3348a61de7d998..2932791e938821 100644 +--- a/arch/riscv/kernel/perf_callchain.c ++++ b/arch/riscv/kernel/perf_callchain.c +@@ -62,7 +62,7 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry, + perf_callchain_store(entry, regs->epc); + + fp = user_backtrace(entry, fp, regs->ra); +- while (fp && !(fp & 0x3) && entry->nr < entry->max_stack) ++ while (fp && !(fp & 0x7) && entry->nr < entry->max_stack) + fp = user_backtrace(entry, fp, 0); + } + +diff --git a/arch/riscv/kernel/pi/cmdline_early.c b/arch/riscv/kernel/pi/cmdline_early.c +index 68e786c84c949b..f6d4dedffb8422 100644 +--- a/arch/riscv/kernel/pi/cmdline_early.c ++++ b/arch/riscv/kernel/pi/cmdline_early.c +@@ -38,8 +38,7 @@ static char *get_early_cmdline(uintptr_t dtb_pa) + if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) || + IS_ENABLED(CONFIG_CMDLINE_FORCE) || + fdt_cmdline_size == 0 /* CONFIG_CMDLINE_FALLBACK */) { +- strncat(early_cmdline, CONFIG_CMDLINE, +- COMMAND_LINE_SIZE - fdt_cmdline_size); ++ strlcat(early_cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE); + } + + return early_cmdline; +diff --git a/arch/riscv/kernel/probes/ftrace.c b/arch/riscv/kernel/probes/ftrace.c +index 7142ec42e889f9..a69dfa610aa857 100644 +--- a/arch/riscv/kernel/probes/ftrace.c ++++ b/arch/riscv/kernel/probes/ftrace.c +@@ -11,6 +11,9 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, + struct kprobe_ctlblk *kcb; + int bit; + ++ if (unlikely(kprobe_ftrace_disabled)) ++ return; ++ + bit = ftrace_test_recursion_trylock(ip, parent_ip); + if (bit < 0) + return; +diff --git a/arch/riscv/kernel/probes/kprobes.c b/arch/riscv/kernel/probes/kprobes.c +index 2f08c14a933d05..fecbbcf40ac3fe 100644 +--- a/arch/riscv/kernel/probes/kprobes.c ++++ b/arch/riscv/kernel/probes/kprobes.c +@@ -28,9 +28,8 @@ static void __kprobes arch_prepare_ss_slot(struct kprobe *p) + + p->ainsn.api.restore = (unsigned long)p->addr + offset; + +- patch_text(p->ainsn.api.insn, &p->opcode, 1); +- patch_text((void *)((unsigned long)(p->ainsn.api.insn) + offset), +- &insn, 1); ++ patch_text_nosync(p->ainsn.api.insn, &p->opcode, 1); ++ patch_text_nosync(p->ainsn.api.insn + offset, &insn, 1); + } + + static void __kprobes arch_prepare_simulate(struct kprobe *p) +diff --git a/arch/riscv/kernel/probes/simulate-insn.c b/arch/riscv/kernel/probes/simulate-insn.c +index d3099d67816d05..6c166029079c42 100644 +--- a/arch/riscv/kernel/probes/simulate-insn.c ++++ b/arch/riscv/kernel/probes/simulate-insn.c +@@ -24,7 +24,7 @@ static inline bool rv_insn_reg_set_val(struct pt_regs *regs, u32 index, + unsigned long val) + { + if (index == 0) +- return false; ++ return true; + else if (index <= 31) + *((unsigned long *)regs + index) = val; + else +diff --git a/arch/riscv/kernel/probes/uprobes.c b/arch/riscv/kernel/probes/uprobes.c +index 194f166b2cc40e..4b3dc8beaf77d3 100644 +--- a/arch/riscv/kernel/probes/uprobes.c ++++ b/arch/riscv/kernel/probes/uprobes.c +@@ -3,6 +3,7 @@ + #include + #include + #include ++#include + + #include "decode-insn.h" + +@@ -17,6 +18,11 @@ bool is_swbp_insn(uprobe_opcode_t *insn) + #endif + } + ++bool is_trap_insn(uprobe_opcode_t *insn) ++{ ++ return riscv_insn_is_ebreak(*insn) || riscv_insn_is_c_ebreak(*insn); ++} ++ + unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) + { + return instruction_pointer(regs); +diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c +index e32d737e039fd4..83e223318822ae 100644 +--- a/arch/riscv/kernel/process.c ++++ b/arch/riscv/kernel/process.c +@@ -26,8 +26,6 @@ + #include + #include + +-register unsigned long gp_in_global __asm__("gp"); +- + #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_STACKPROTECTOR_PER_TASK) + #include + unsigned long __stack_chk_guard __read_mostly; +@@ -186,7 +184,6 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) + if (unlikely(args->fn)) { + /* Kernel thread */ + memset(childregs, 0, sizeof(struct pt_regs)); +- childregs->gp = gp_in_global; + /* Supervisor/Machine, irqs on: */ + childregs->status = SR_PP | SR_PIE; + +diff --git a/arch/riscv/kernel/return_address.c b/arch/riscv/kernel/return_address.c +new file mode 100644 +index 00000000000000..c8115ec8fb304b +--- /dev/null ++++ b/arch/riscv/kernel/return_address.c +@@ -0,0 +1,48 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * This code come from arch/arm64/kernel/return_address.c ++ * ++ * Copyright (C) 2023 SiFive. ++ */ ++ ++#include ++#include ++#include ++ ++struct return_address_data { ++ unsigned int level; ++ void *addr; ++}; ++ ++static bool save_return_addr(void *d, unsigned long pc) ++{ ++ struct return_address_data *data = d; ++ ++ if (!data->level) { ++ data->addr = (void *)pc; ++ return false; ++ } ++ ++ --data->level; ++ ++ return true; ++} ++NOKPROBE_SYMBOL(save_return_addr); ++ ++noinline void *return_address(unsigned int level) ++{ ++ struct return_address_data data; ++ ++ data.level = level + 3; ++ data.addr = NULL; ++ ++ arch_stack_walk(save_return_addr, &data, current, NULL); ++ ++ if (!data.level) ++ return data.addr; ++ else ++ return NULL; ++ ++} ++EXPORT_SYMBOL_GPL(return_address); ++NOKPROBE_SYMBOL(return_address); +diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c +index c672c8ba9a2a6b..5a62ed1da45332 100644 +--- a/arch/riscv/kernel/sbi.c ++++ b/arch/riscv/kernel/sbi.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + /* default SBI version is 0.1 */ + unsigned long sbi_spec_version __ro_after_init = SBI_SPEC_VERSION_DEFAULT; +@@ -376,32 +377,15 @@ int sbi_remote_fence_i(const struct cpumask *cpu_mask) + } + EXPORT_SYMBOL(sbi_remote_fence_i); + +-/** +- * sbi_remote_sfence_vma() - Execute SFENCE.VMA instructions on given remote +- * harts for the specified virtual address range. +- * @cpu_mask: A cpu mask containing all the target harts. +- * @start: Start of the virtual address +- * @size: Total size of the virtual address range. +- * +- * Return: 0 on success, appropriate linux error code otherwise. +- */ +-int sbi_remote_sfence_vma(const struct cpumask *cpu_mask, +- unsigned long start, +- unsigned long size) +-{ +- return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA, +- cpu_mask, start, size, 0, 0); +-} +-EXPORT_SYMBOL(sbi_remote_sfence_vma); +- + /** + * sbi_remote_sfence_vma_asid() - Execute SFENCE.VMA instructions on given +- * remote harts for a virtual address range belonging to a specific ASID. ++ * remote harts for a virtual address range belonging to a specific ASID or not. + * + * @cpu_mask: A cpu mask containing all the target harts. + * @start: Start of the virtual address + * @size: Total size of the virtual address range. +- * @asid: The value of address space identifier (ASID). ++ * @asid: The value of address space identifier (ASID), or FLUSH_TLB_NO_ASID ++ * for flushing all address spaces. + * + * Return: 0 on success, appropriate linux error code otherwise. + */ +@@ -410,8 +394,12 @@ int sbi_remote_sfence_vma_asid(const struct cpumask *cpu_mask, + unsigned long size, + unsigned long asid) + { +- return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID, +- cpu_mask, start, size, asid, 0); ++ if (asid == FLUSH_TLB_NO_ASID) ++ return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA, ++ cpu_mask, start, size, 0, 0); ++ else ++ return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID, ++ cpu_mask, start, size, asid, 0); + } + EXPORT_SYMBOL(sbi_remote_sfence_vma_asid); + +diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c +index aac853ae4eb74e..ddadee6621f0da 100644 +--- a/arch/riscv/kernel/setup.c ++++ b/arch/riscv/kernel/setup.c +@@ -40,15 +40,8 @@ + + #include "head.h" + +-#if defined(CONFIG_DUMMY_CONSOLE) || defined(CONFIG_EFI) +-struct screen_info screen_info __section(".data") = { +- .orig_video_lines = 30, +- .orig_video_cols = 80, +- .orig_video_mode = 0, +- .orig_video_ega_bx = 0, +- .orig_video_isVGA = 1, +- .orig_video_points = 8 +-}; ++#if defined(CONFIG_EFI) ++struct screen_info screen_info __section(".data"); + #endif + + /* +@@ -173,6 +166,19 @@ static void __init init_resources(void) + if (ret < 0) + goto error; + ++#ifdef CONFIG_KEXEC_CORE ++ if (crashk_res.start != crashk_res.end) { ++ ret = add_resource(&iomem_resource, &crashk_res); ++ if (ret < 0) ++ goto error; ++ } ++ if (crashk_low_res.start != crashk_low_res.end) { ++ ret = add_resource(&iomem_resource, &crashk_low_res); ++ if (ret < 0) ++ goto error; ++ } ++#endif ++ + #ifdef CONFIG_CRASH_DUMP + if (elfcorehdr_size > 0) { + elfcorehdr_res.start = elfcorehdr_addr; +diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c +index 21a4d0e111bc5f..88b6220b260879 100644 +--- a/arch/riscv/kernel/signal.c ++++ b/arch/riscv/kernel/signal.c +@@ -384,30 +384,6 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) + sigset_t *oldset = sigmask_to_save(); + int ret; + +- /* Are we from a system call? */ +- if (regs->cause == EXC_SYSCALL) { +- /* Avoid additional syscall restarting via ret_from_exception */ +- regs->cause = -1UL; +- /* If so, check system call restarting.. */ +- switch (regs->a0) { +- case -ERESTART_RESTARTBLOCK: +- case -ERESTARTNOHAND: +- regs->a0 = -EINTR; +- break; +- +- case -ERESTARTSYS: +- if (!(ksig->ka.sa.sa_flags & SA_RESTART)) { +- regs->a0 = -EINTR; +- break; +- } +- fallthrough; +- case -ERESTARTNOINTR: +- regs->a0 = regs->orig_a0; +- regs->epc -= 0x4; +- break; +- } +- } +- + rseq_signal_deliver(ksig, regs); + + /* Set up the stack frame */ +@@ -421,35 +397,66 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) + + void arch_do_signal_or_restart(struct pt_regs *regs) + { ++ unsigned long continue_addr = 0, restart_addr = 0; ++ int retval = 0; + struct ksignal ksig; ++ bool syscall = (regs->cause == EXC_SYSCALL); + +- if (get_signal(&ksig)) { +- /* Actually deliver the signal */ +- handle_signal(&ksig, regs); +- return; +- } ++ /* If we were from a system call, check for system call restarting */ ++ if (syscall) { ++ continue_addr = regs->epc; ++ restart_addr = continue_addr - 4; ++ retval = regs->a0; + +- /* Did we come from a system call? */ +- if (regs->cause == EXC_SYSCALL) { + /* Avoid additional syscall restarting via ret_from_exception */ + regs->cause = -1UL; + +- /* Restart the system call - no handlers present */ +- switch (regs->a0) { ++ /* ++ * Prepare for system call restart. We do this here so that a ++ * debugger will see the already changed PC. ++ */ ++ switch (retval) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: +- regs->a0 = regs->orig_a0; +- regs->epc -= 0x4; +- break; + case -ERESTART_RESTARTBLOCK: +- regs->a0 = regs->orig_a0; +- regs->a7 = __NR_restart_syscall; +- regs->epc -= 0x4; ++ regs->a0 = regs->orig_a0; ++ regs->epc = restart_addr; + break; + } + } + ++ /* ++ * Get the signal to deliver. When running under ptrace, at this point ++ * the debugger may change all of our registers. ++ */ ++ if (get_signal(&ksig)) { ++ /* ++ * Depending on the signal settings, we may need to revert the ++ * decision to restart the system call, but skip this if a ++ * debugger has chosen to restart at a different PC. ++ */ ++ if (regs->epc == restart_addr && ++ (retval == -ERESTARTNOHAND || ++ retval == -ERESTART_RESTARTBLOCK || ++ (retval == -ERESTARTSYS && ++ !(ksig.ka.sa.sa_flags & SA_RESTART)))) { ++ regs->a0 = -EINTR; ++ regs->epc = continue_addr; ++ } ++ ++ /* Actually deliver the signal */ ++ handle_signal(&ksig, regs); ++ return; ++ } ++ ++ /* ++ * Handle restarting a different system call. As above, if a debugger ++ * has chosen to restart at a different PC, ignore the restart. ++ */ ++ if (syscall && regs->epc == restart_addr && retval == -ERESTART_RESTARTBLOCK) ++ regs->a7 = __NR_restart_syscall; ++ + /* + * If there is no signal to deliver, we just put the saved + * sigmask back. +diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c +index 64a9c093aef93a..10e311b2759d39 100644 +--- a/arch/riscv/kernel/stacktrace.c ++++ b/arch/riscv/kernel/stacktrace.c +@@ -18,10 +18,21 @@ + + extern asmlinkage void ret_from_exception(void); + ++static inline int fp_is_valid(unsigned long fp, unsigned long sp) ++{ ++ unsigned long low, high; ++ ++ low = sp + sizeof(struct stackframe); ++ high = ALIGN(sp, THREAD_SIZE); ++ ++ return !(fp < low || fp > high || fp & 0x07); ++} ++ + void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, + bool (*fn)(void *, unsigned long), void *arg) + { + unsigned long fp, sp, pc; ++ int graph_idx = 0; + int level = 0; + + if (regs) { +@@ -41,26 +52,24 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, + } + + for (;;) { +- unsigned long low, high; + struct stackframe *frame; + + if (unlikely(!__kernel_text_address(pc) || (level++ >= 0 && !fn(arg, pc)))) + break; + +- /* Validate frame pointer */ +- low = sp + sizeof(struct stackframe); +- high = ALIGN(sp, THREAD_SIZE); +- if (unlikely(fp < low || fp > high || fp & 0x7)) ++ if (unlikely(!fp_is_valid(fp, sp))) + break; ++ + /* Unwind stack frame */ + frame = (struct stackframe *)fp - 1; + sp = fp; +- if (regs && (regs->epc == pc) && (frame->fp & 0x7)) { ++ if (regs && (regs->epc == pc) && fp_is_valid(frame->ra, sp)) { ++ /* We hit function where ra is not saved on the stack */ + fp = frame->ra; + pc = regs->ra; + } else { + fp = frame->fp; +- pc = ftrace_graph_ret_addr(current, NULL, frame->ra, ++ pc = ftrace_graph_ret_addr(current, &graph_idx, frame->ra, + &frame->ra); + if (pc == (unsigned long)ret_from_exception) { + if (unlikely(!__kernel_text_address(pc) || !fn(arg, pc))) +@@ -148,7 +157,7 @@ unsigned long __get_wchan(struct task_struct *task) + return pc; + } + +-noinline void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, ++noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, + struct task_struct *task, struct pt_regs *regs) + { + walk_stackframe(task, regs, consume_entry, cookie); +diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c +index fae8f610d867fd..2158b7a65d74f7 100644 +--- a/arch/riscv/kernel/traps.c ++++ b/arch/riscv/kernel/traps.c +@@ -311,6 +311,7 @@ asmlinkage __visible __trap_section void do_trap_ecall_u(struct pt_regs *regs) + + regs->epc += 4; + regs->orig_a0 = regs->a0; ++ regs->a0 = -ENOSYS; + + riscv_v_vstate_discard(regs); + +@@ -318,8 +319,6 @@ asmlinkage __visible __trap_section void do_trap_ecall_u(struct pt_regs *regs) + + if (syscall >= 0 && syscall < NR_syscalls) + syscall_handler(regs, syscall); +- else if (syscall != -1) +- regs->a0 = -ENOSYS; + + syscall_exit_to_user_mode(regs); + } else { +@@ -410,48 +409,14 @@ int is_valid_bugaddr(unsigned long pc) + #endif /* CONFIG_GENERIC_BUG */ + + #ifdef CONFIG_VMAP_STACK +-/* +- * Extra stack space that allows us to provide panic messages when the kernel +- * has overflowed its stack. +- */ +-static DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], ++DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], + overflow_stack)__aligned(16); +-/* +- * A temporary stack for use by handle_kernel_stack_overflow. This is used so +- * we can call into C code to get the per-hart overflow stack. Usage of this +- * stack must be protected by spin_shadow_stack. +- */ +-long shadow_stack[SHADOW_OVERFLOW_STACK_SIZE/sizeof(long)] __aligned(16); +- +-/* +- * A pseudo spinlock to protect the shadow stack from being used by multiple +- * harts concurrently. This isn't a real spinlock because the lock side must +- * be taken without a valid stack and only a single register, it's only taken +- * while in the process of panicing anyway so the performance and error +- * checking a proper spinlock gives us doesn't matter. +- */ +-unsigned long spin_shadow_stack; +- +-asmlinkage unsigned long get_overflow_stack(void) +-{ +- return (unsigned long)this_cpu_ptr(overflow_stack) + +- OVERFLOW_STACK_SIZE; +-} + + asmlinkage void handle_bad_stack(struct pt_regs *regs) + { + unsigned long tsk_stk = (unsigned long)current->stack; + unsigned long ovf_stk = (unsigned long)this_cpu_ptr(overflow_stack); + +- /* +- * We're done with the shadow stack by this point, as we're on the +- * overflow stack. Tell any other concurrent overflowing harts that +- * they can proceed with panicing by releasing the pseudo-spinlock. +- * +- * This pairs with an amoswap.aq in handle_kernel_stack_overflow. +- */ +- smp_store_release(&spin_shadow_stack, 0); +- + console_verbose(); + + pr_emerg("Insufficient stack space to handle exception!\n"); +diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c +index 378f5b15144356..e867fe465164e2 100644 +--- a/arch/riscv/kernel/traps_misaligned.c ++++ b/arch/riscv/kernel/traps_misaligned.c +@@ -151,51 +151,19 @@ + #define PRECISION_S 0 + #define PRECISION_D 1 + +-#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \ +-static inline type load_##type(const type *addr) \ +-{ \ +- type val; \ +- asm (#insn " %0, %1" \ +- : "=&r" (val) : "m" (*addr)); \ +- return val; \ +-} +- +-#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \ +-static inline void store_##type(type *addr, type val) \ +-{ \ +- asm volatile (#insn " %0, %1\n" \ +- : : "r" (val), "m" (*addr)); \ +-} ++static inline u8 load_u8(const u8 *addr) ++{ ++ u8 val; + +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw) +-DECLARE_UNPRIVILEGED_STORE_FUNCTION(u8, sb) +-DECLARE_UNPRIVILEGED_STORE_FUNCTION(u16, sh) +-DECLARE_UNPRIVILEGED_STORE_FUNCTION(u32, sw) +-#if defined(CONFIG_64BIT) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld) +-DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64, sd) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld) +-#else +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw) ++ asm volatile("lbu %0, %1" : "=&r" (val) : "m" (*addr)); + +-static inline u64 load_u64(const u64 *addr) +-{ +- return load_u32((u32 *)addr) +- + ((u64)load_u32((u32 *)addr + 1) << 32); ++ return val; + } + +-static inline void store_u64(u64 *addr, u64 val) ++static inline void store_u8(u8 *addr, u8 val) + { +- store_u32((u32 *)addr, val); +- store_u32((u32 *)addr + 1, val >> 32); ++ asm volatile ("sb %0, %1\n" : : "r" (val), "m" (*addr)); + } +-#endif + + static inline ulong get_insn(ulong mepc) + { +@@ -342,16 +310,14 @@ int handle_misaligned_store(struct pt_regs *regs) + } else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) { + len = 8; + val.data_ulong = GET_RS2S(insn, regs); +- } else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP && +- ((insn >> SH_RD) & 0x1f)) { ++ } else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP) { + len = 8; + val.data_ulong = GET_RS2C(insn, regs); + #endif + } else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) { + len = 4; + val.data_ulong = GET_RS2S(insn, regs); +- } else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP && +- ((insn >> SH_RD) & 0x1f)) { ++ } else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP) { + len = 4; + val.data_ulong = GET_RS2C(insn, regs); + } else { +diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile +index 6b1dba11bf6dcd..e8aa7c38000755 100644 +--- a/arch/riscv/kernel/vdso/Makefile ++++ b/arch/riscv/kernel/vdso/Makefile +@@ -73,13 +73,3 @@ quiet_cmd_vdsold = VDSOLD $@ + cmd_vdsold = $(LD) $(ld_flags) -T $(filter-out FORCE,$^) -o $@.tmp && \ + $(OBJCOPY) $(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@ && \ + rm $@.tmp +- +-# install commands for the unstripped file +-quiet_cmd_vdso_install = INSTALL $@ +- cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ +- +-vdso.so: $(obj)/vdso.so.dbg +- @mkdir -p $(MODLIB)/vdso +- $(call cmd,vdso_install) +- +-vdso_install: vdso.so +diff --git a/arch/riscv/kernel/vdso/hwprobe.c b/arch/riscv/kernel/vdso/hwprobe.c +index d40bec6ac07866..cadf725ef79837 100644 +--- a/arch/riscv/kernel/vdso/hwprobe.c ++++ b/arch/riscv/kernel/vdso/hwprobe.c +@@ -37,7 +37,7 @@ int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, + + /* This is something we can handle, fill out the pairs. */ + while (p < end) { +- if (p->key <= RISCV_HWPROBE_MAX_KEY) { ++ if (riscv_hwprobe_key_is_valid(p->key)) { + p->value = avd->all_cpu_hwprobe_values[p->key]; + + } else { +diff --git a/arch/riscv/kernel/vmlinux-xip.lds.S b/arch/riscv/kernel/vmlinux-xip.lds.S +index 50767647fbc649..8c3daa1b05313a 100644 +--- a/arch/riscv/kernel/vmlinux-xip.lds.S ++++ b/arch/riscv/kernel/vmlinux-xip.lds.S +@@ -29,10 +29,12 @@ SECTIONS + HEAD_TEXT_SECTION + INIT_TEXT_SECTION(PAGE_SIZE) + /* we have to discard exit text and such at runtime, not link time */ ++ __exittext_begin = .; + .exit.text : + { + EXIT_TEXT + } ++ __exittext_end = .; + + .text : { + _text = .; +diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S +index 492dd4b8f3d69a..002ca58dd998cb 100644 +--- a/arch/riscv/kernel/vmlinux.lds.S ++++ b/arch/riscv/kernel/vmlinux.lds.S +@@ -69,10 +69,12 @@ SECTIONS + __soc_builtin_dtb_table_end = .; + } + /* we have to discard exit text and such at runtime, not link time */ ++ __exittext_begin = .; + .exit.text : + { + EXIT_TEXT + } ++ __exittext_end = .; + + __init_text_end = .; + . = ALIGN(SECTION_ALIGN); +diff --git a/arch/riscv/kvm/aia_aplic.c b/arch/riscv/kvm/aia_aplic.c +index 39e72aa016a4cc..b467ba5ed91000 100644 +--- a/arch/riscv/kvm/aia_aplic.c ++++ b/arch/riscv/kvm/aia_aplic.c +@@ -137,11 +137,21 @@ static void aplic_write_pending(struct aplic *aplic, u32 irq, bool pending) + raw_spin_lock_irqsave(&irqd->lock, flags); + + sm = irqd->sourcecfg & APLIC_SOURCECFG_SM_MASK; +- if (!pending && +- ((sm == APLIC_SOURCECFG_SM_LEVEL_HIGH) || +- (sm == APLIC_SOURCECFG_SM_LEVEL_LOW))) ++ if (sm == APLIC_SOURCECFG_SM_INACTIVE) + goto skip_write_pending; + ++ if (sm == APLIC_SOURCECFG_SM_LEVEL_HIGH || ++ sm == APLIC_SOURCECFG_SM_LEVEL_LOW) { ++ if (!pending) ++ goto skip_write_pending; ++ if ((irqd->state & APLIC_IRQ_STATE_INPUT) && ++ sm == APLIC_SOURCECFG_SM_LEVEL_LOW) ++ goto skip_write_pending; ++ if (!(irqd->state & APLIC_IRQ_STATE_INPUT) && ++ sm == APLIC_SOURCECFG_SM_LEVEL_HIGH) ++ goto skip_write_pending; ++ } ++ + if (pending) + irqd->state |= APLIC_IRQ_STATE_PENDING; + else +@@ -187,16 +197,31 @@ static void aplic_write_enabled(struct aplic *aplic, u32 irq, bool enabled) + + static bool aplic_read_input(struct aplic *aplic, u32 irq) + { +- bool ret; +- unsigned long flags; ++ u32 sourcecfg, sm, raw_input, irq_inverted; + struct aplic_irq *irqd; ++ unsigned long flags; ++ bool ret = false; + + if (!irq || aplic->nr_irqs <= irq) + return false; + irqd = &aplic->irqs[irq]; + + raw_spin_lock_irqsave(&irqd->lock, flags); +- ret = (irqd->state & APLIC_IRQ_STATE_INPUT) ? true : false; ++ ++ sourcecfg = irqd->sourcecfg; ++ if (sourcecfg & APLIC_SOURCECFG_D) ++ goto skip; ++ ++ sm = sourcecfg & APLIC_SOURCECFG_SM_MASK; ++ if (sm == APLIC_SOURCECFG_SM_INACTIVE) ++ goto skip; ++ ++ raw_input = (irqd->state & APLIC_IRQ_STATE_INPUT) ? 1 : 0; ++ irq_inverted = (sm == APLIC_SOURCECFG_SM_LEVEL_LOW || ++ sm == APLIC_SOURCECFG_SM_EDGE_FALL) ? 1 : 0; ++ ret = !!(raw_input ^ irq_inverted); ++ ++skip: + raw_spin_unlock_irqrestore(&irqd->lock, flags); + + return ret; +diff --git a/arch/riscv/kvm/aia_device.c b/arch/riscv/kvm/aia_device.c +index 0eb689351b7d04..5cd407c6a8e4f8 100644 +--- a/arch/riscv/kvm/aia_device.c ++++ b/arch/riscv/kvm/aia_device.c +@@ -237,10 +237,11 @@ static gpa_t aia_imsic_ppn(struct kvm_aia *aia, gpa_t addr) + + static u32 aia_imsic_hart_index(struct kvm_aia *aia, gpa_t addr) + { +- u32 hart, group = 0; ++ u32 hart = 0, group = 0; + +- hart = (addr >> (aia->nr_guest_bits + IMSIC_MMIO_PAGE_SHIFT)) & +- GENMASK_ULL(aia->nr_hart_bits - 1, 0); ++ if (aia->nr_hart_bits) ++ hart = (addr >> (aia->nr_guest_bits + IMSIC_MMIO_PAGE_SHIFT)) & ++ GENMASK_ULL(aia->nr_hart_bits - 1, 0); + if (aia->nr_group_bits) + group = (addr >> aia->nr_group_shift) & + GENMASK_ULL(aia->nr_group_bits - 1, 0); +diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c +index 6cf23b8adb7129..e808723a85f1b1 100644 +--- a/arch/riscv/kvm/aia_imsic.c ++++ b/arch/riscv/kvm/aia_imsic.c +@@ -55,6 +55,7 @@ struct imsic { + /* IMSIC SW-file */ + struct imsic_mrif *swfile; + phys_addr_t swfile_pa; ++ spinlock_t swfile_extirq_lock; + }; + + #define imsic_vs_csr_read(__c) \ +@@ -613,12 +614,23 @@ static void imsic_swfile_extirq_update(struct kvm_vcpu *vcpu) + { + struct imsic *imsic = vcpu->arch.aia_context.imsic_state; + struct imsic_mrif *mrif = imsic->swfile; ++ unsigned long flags; ++ ++ /* ++ * The critical section is necessary during external interrupt ++ * updates to avoid the risk of losing interrupts due to potential ++ * interruptions between reading topei and updating pending status. ++ */ ++ ++ spin_lock_irqsave(&imsic->swfile_extirq_lock, flags); + + if (imsic_mrif_atomic_read(mrif, &mrif->eidelivery) && + imsic_mrif_topei(mrif, imsic->nr_eix, imsic->nr_msis)) + kvm_riscv_vcpu_set_interrupt(vcpu, IRQ_VS_EXT); + else + kvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_VS_EXT); ++ ++ spin_unlock_irqrestore(&imsic->swfile_extirq_lock, flags); + } + + static void imsic_swfile_read(struct kvm_vcpu *vcpu, bool clear, +@@ -1039,6 +1051,7 @@ int kvm_riscv_vcpu_aia_imsic_init(struct kvm_vcpu *vcpu) + } + imsic->swfile = page_to_virt(swfile_page); + imsic->swfile_pa = page_to_phys(swfile_page); ++ spin_lock_init(&imsic->swfile_extirq_lock); + + /* Setup IO device */ + kvm_iodevice_init(&imsic->iodev, &imsic_iodoev_ops); +diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c +index 068c7459387102..a9e2fd7245e1e9 100644 +--- a/arch/riscv/kvm/mmu.c ++++ b/arch/riscv/kvm/mmu.c +@@ -103,7 +103,7 @@ static bool gstage_get_leaf_entry(struct kvm *kvm, gpa_t addr, + *ptep_level = current_level; + ptep = (pte_t *)kvm->arch.pgd; + ptep = &ptep[gstage_pte_index(addr, current_level)]; +- while (ptep && pte_val(*ptep)) { ++ while (ptep && pte_val(ptep_get(ptep))) { + if (gstage_pte_leaf(ptep)) { + *ptep_level = current_level; + *ptepp = ptep; +@@ -113,7 +113,7 @@ static bool gstage_get_leaf_entry(struct kvm *kvm, gpa_t addr, + if (current_level) { + current_level--; + *ptep_level = current_level; +- ptep = (pte_t *)gstage_pte_page_vaddr(*ptep); ++ ptep = (pte_t *)gstage_pte_page_vaddr(ptep_get(ptep)); + ptep = &ptep[gstage_pte_index(addr, current_level)]; + } else { + ptep = NULL; +@@ -149,25 +149,25 @@ static int gstage_set_pte(struct kvm *kvm, u32 level, + if (gstage_pte_leaf(ptep)) + return -EEXIST; + +- if (!pte_val(*ptep)) { ++ if (!pte_val(ptep_get(ptep))) { + if (!pcache) + return -ENOMEM; + next_ptep = kvm_mmu_memory_cache_alloc(pcache); + if (!next_ptep) + return -ENOMEM; +- *ptep = pfn_pte(PFN_DOWN(__pa(next_ptep)), +- __pgprot(_PAGE_TABLE)); ++ set_pte(ptep, pfn_pte(PFN_DOWN(__pa(next_ptep)), ++ __pgprot(_PAGE_TABLE))); + } else { + if (gstage_pte_leaf(ptep)) + return -EEXIST; +- next_ptep = (pte_t *)gstage_pte_page_vaddr(*ptep); ++ next_ptep = (pte_t *)gstage_pte_page_vaddr(ptep_get(ptep)); + } + + current_level--; + ptep = &next_ptep[gstage_pte_index(addr, current_level)]; + } + +- *ptep = *new_pte; ++ set_pte(ptep, *new_pte); + if (gstage_pte_leaf(ptep)) + gstage_remote_tlb_flush(kvm, current_level, addr); + +@@ -239,11 +239,11 @@ static void gstage_op_pte(struct kvm *kvm, gpa_t addr, + + BUG_ON(addr & (page_size - 1)); + +- if (!pte_val(*ptep)) ++ if (!pte_val(ptep_get(ptep))) + return; + + if (ptep_level && !gstage_pte_leaf(ptep)) { +- next_ptep = (pte_t *)gstage_pte_page_vaddr(*ptep); ++ next_ptep = (pte_t *)gstage_pte_page_vaddr(ptep_get(ptep)); + next_ptep_level = ptep_level - 1; + ret = gstage_level_to_page_size(next_ptep_level, + &next_page_size); +@@ -261,7 +261,7 @@ static void gstage_op_pte(struct kvm *kvm, gpa_t addr, + if (op == GSTAGE_OP_CLEAR) + set_pte(ptep, __pte(0)); + else if (op == GSTAGE_OP_WP) +- set_pte(ptep, __pte(pte_val(*ptep) & ~_PAGE_WRITE)); ++ set_pte(ptep, __pte(pte_val(ptep_get(ptep)) & ~_PAGE_WRITE)); + gstage_remote_tlb_flush(kvm, ptep_level, addr); + } + } +@@ -603,7 +603,7 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) + &ptep, &ptep_level)) + return false; + +- return pte_young(*ptep); ++ return pte_young(ptep_get(ptep)); + } + + int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu, +diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c +index b7e0e03c69b1e5..d520b25d856167 100644 +--- a/arch/riscv/kvm/vcpu_onereg.c ++++ b/arch/riscv/kvm/vcpu_onereg.c +@@ -614,9 +614,9 @@ static int kvm_riscv_vcpu_set_reg_isa_ext(struct kvm_vcpu *vcpu, + switch (reg_subtype) { + case KVM_REG_RISCV_ISA_SINGLE: + return riscv_vcpu_set_isa_ext_single(vcpu, reg_num, reg_val); +- case KVM_REG_RISCV_SBI_MULTI_EN: ++ case KVM_REG_RISCV_ISA_MULTI_EN: + return riscv_vcpu_set_isa_ext_multi(vcpu, reg_num, reg_val, true); +- case KVM_REG_RISCV_SBI_MULTI_DIS: ++ case KVM_REG_RISCV_ISA_MULTI_DIS: + return riscv_vcpu_set_isa_ext_multi(vcpu, reg_num, reg_val, false); + default: + return -ENOENT; +diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c +index 86391a5061dda9..cee1b9ca4ec481 100644 +--- a/arch/riscv/kvm/vcpu_pmu.c ++++ b/arch/riscv/kvm/vcpu_pmu.c +@@ -39,7 +39,7 @@ static u64 kvm_pmu_get_sample_period(struct kvm_pmc *pmc) + u64 sample_period; + + if (!pmc->counter_val) +- sample_period = counter_val_mask + 1; ++ sample_period = counter_val_mask; + else + sample_period = (-pmc->counter_val) & counter_val_mask; + +diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c +index 9cd97091c72330..7a7fe40d0930be 100644 +--- a/arch/riscv/kvm/vcpu_sbi.c ++++ b/arch/riscv/kvm/vcpu_sbi.c +@@ -91,8 +91,8 @@ void kvm_riscv_vcpu_sbi_forward(struct kvm_vcpu *vcpu, struct kvm_run *run) + run->riscv_sbi.args[3] = cp->a3; + run->riscv_sbi.args[4] = cp->a4; + run->riscv_sbi.args[5] = cp->a5; +- run->riscv_sbi.ret[0] = cp->a0; +- run->riscv_sbi.ret[1] = cp->a1; ++ run->riscv_sbi.ret[0] = SBI_ERR_NOT_SUPPORTED; ++ run->riscv_sbi.ret[1] = 0; + } + + void kvm_riscv_vcpu_sbi_system_reset(struct kvm_vcpu *vcpu, +diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile +index 9c454f90fd3da2..2c869f8026a889 100644 +--- a/arch/riscv/mm/Makefile ++++ b/arch/riscv/mm/Makefile +@@ -13,10 +13,9 @@ endif + KCOV_INSTRUMENT_init.o := n + + obj-y += init.o +-obj-$(CONFIG_MMU) += extable.o fault.o pageattr.o ++obj-$(CONFIG_MMU) += extable.o fault.o pageattr.o pgtable.o + obj-y += cacheflush.o + obj-y += context.o +-obj-y += pgtable.o + obj-y += pmem.o + + ifeq ($(CONFIG_MMU),y) +@@ -36,3 +35,4 @@ endif + + obj-$(CONFIG_DEBUG_VIRTUAL) += physaddr.o + obj-$(CONFIG_RISCV_DMA_NONCOHERENT) += dma-noncoherent.o ++obj-$(CONFIG_RISCV_NONSTANDARD_CACHE_OPS) += cache-ops.o +diff --git a/arch/riscv/mm/cache-ops.c b/arch/riscv/mm/cache-ops.c +new file mode 100644 +index 00000000000000..a993ad11d0eca9 +--- /dev/null ++++ b/arch/riscv/mm/cache-ops.c +@@ -0,0 +1,17 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (c) 2021 Western Digital Corporation or its affiliates. ++ */ ++ ++#include ++ ++struct riscv_nonstd_cache_ops noncoherent_cache_ops __ro_after_init; ++ ++void ++riscv_noncoherent_register_cache_ops(const struct riscv_nonstd_cache_ops *ops) ++{ ++ if (!ops) ++ return; ++ noncoherent_cache_ops = *ops; ++} ++EXPORT_SYMBOL_GPL(riscv_noncoherent_register_cache_ops); +diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c +index 217fd4de613422..ba8eb3944687cf 100644 +--- a/arch/riscv/mm/context.c ++++ b/arch/riscv/mm/context.c +@@ -323,6 +323,8 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next, + if (unlikely(prev == next)) + return; + ++ membarrier_arch_switch_mm(prev, next, task); ++ + /* + * Mark the current MM context as inactive, and the next as + * active. This is at least used by the icache flushing +diff --git a/arch/riscv/mm/dma-noncoherent.c b/arch/riscv/mm/dma-noncoherent.c +index b76e7e192eb183..341bd6706b4c56 100644 +--- a/arch/riscv/mm/dma-noncoherent.c ++++ b/arch/riscv/mm/dma-noncoherent.c +@@ -15,12 +15,6 @@ static bool noncoherent_supported __ro_after_init; + int dma_cache_alignment __ro_after_init = ARCH_DMA_MINALIGN; + EXPORT_SYMBOL_GPL(dma_cache_alignment); + +-struct riscv_nonstd_cache_ops noncoherent_cache_ops __ro_after_init = { +- .wback = NULL, +- .inv = NULL, +- .wback_inv = NULL, +-}; +- + static inline void arch_dma_cache_wback(phys_addr_t paddr, size_t size) + { + void *vaddr = phys_to_virt(paddr); +@@ -162,12 +156,3 @@ void __init riscv_set_dma_cache_alignment(void) + if (!noncoherent_supported) + dma_cache_alignment = 1; + } +- +-void riscv_noncoherent_register_cache_ops(const struct riscv_nonstd_cache_ops *ops) +-{ +- if (!ops) +- return; +- +- noncoherent_cache_ops = *ops; +-} +-EXPORT_SYMBOL_GPL(riscv_noncoherent_register_cache_ops); +diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c +index 90d4ba36d1d062..8960f4c844976f 100644 +--- a/arch/riscv/mm/fault.c ++++ b/arch/riscv/mm/fault.c +@@ -61,26 +61,27 @@ static inline void no_context(struct pt_regs *regs, unsigned long addr) + + static inline void mm_fault_error(struct pt_regs *regs, unsigned long addr, vm_fault_t fault) + { ++ if (!user_mode(regs)) { ++ no_context(regs, addr); ++ return; ++ } ++ + if (fault & VM_FAULT_OOM) { + /* + * We ran out of memory, call the OOM killer, and return the userspace + * (which will retry the fault, or kill us if we got oom-killed). + */ +- if (!user_mode(regs)) { +- no_context(regs, addr); +- return; +- } + pagefault_out_of_memory(); + return; + } else if (fault & (VM_FAULT_SIGBUS | VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE)) { + /* Kernel mode? Handle exceptions or die */ +- if (!user_mode(regs)) { +- no_context(regs, addr); +- return; +- } + do_trap(regs, SIGBUS, BUS_ADRERR, addr); + return; ++ } else if (fault & VM_FAULT_SIGSEGV) { ++ do_trap(regs, SIGSEGV, SEGV_MAPERR, addr); ++ return; + } ++ + BUG(); + } + +@@ -136,24 +137,24 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a + pgd = (pgd_t *)pfn_to_virt(pfn) + index; + pgd_k = init_mm.pgd + index; + +- if (!pgd_present(*pgd_k)) { ++ if (!pgd_present(pgdp_get(pgd_k))) { + no_context(regs, addr); + return; + } +- set_pgd(pgd, *pgd_k); ++ set_pgd(pgd, pgdp_get(pgd_k)); + + p4d_k = p4d_offset(pgd_k, addr); +- if (!p4d_present(*p4d_k)) { ++ if (!p4d_present(p4dp_get(p4d_k))) { + no_context(regs, addr); + return; + } + + pud_k = pud_offset(p4d_k, addr); +- if (!pud_present(*pud_k)) { ++ if (!pud_present(pudp_get(pud_k))) { + no_context(regs, addr); + return; + } +- if (pud_leaf(*pud_k)) ++ if (pud_leaf(pudp_get(pud_k))) + goto flush_tlb; + + /* +@@ -161,11 +162,11 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a + * to copy individual PTEs + */ + pmd_k = pmd_offset(pud_k, addr); +- if (!pmd_present(*pmd_k)) { ++ if (!pmd_present(pmdp_get(pmd_k))) { + no_context(regs, addr); + return; + } +- if (pmd_leaf(*pmd_k)) ++ if (pmd_leaf(pmdp_get(pmd_k))) + goto flush_tlb; + + /* +@@ -175,7 +176,7 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a + * silently loop forever. + */ + pte_k = pte_offset_kernel(pmd_k, addr); +- if (!pte_present(*pte_k)) { ++ if (!pte_present(ptep_get(pte_k))) { + no_context(regs, addr); + return; + } +diff --git a/arch/riscv/mm/hugetlbpage.c b/arch/riscv/mm/hugetlbpage.c +index b52f0210481fac..5ef2a6891158a6 100644 +--- a/arch/riscv/mm/hugetlbpage.c ++++ b/arch/riscv/mm/hugetlbpage.c +@@ -54,7 +54,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, + } + + if (sz == PMD_SIZE) { +- if (want_pmd_share(vma, addr) && pud_none(*pud)) ++ if (want_pmd_share(vma, addr) && pud_none(pudp_get(pud))) + pte = huge_pmd_share(mm, vma, addr, pud); + else + pte = (pte_t *)pmd_alloc(mm, pud, addr); +@@ -93,11 +93,11 @@ pte_t *huge_pte_offset(struct mm_struct *mm, + pmd_t *pmd; + + pgd = pgd_offset(mm, addr); +- if (!pgd_present(*pgd)) ++ if (!pgd_present(pgdp_get(pgd))) + return NULL; + + p4d = p4d_offset(pgd, addr); +- if (!p4d_present(*p4d)) ++ if (!p4d_present(p4dp_get(p4d))) + return NULL; + + pud = pud_offset(p4d, addr); +@@ -105,7 +105,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm, + /* must be pud huge, non-present or none */ + return (pte_t *)pud; + +- if (!pud_present(*pud)) ++ if (!pud_present(pudp_get(pud))) + return NULL; + + pmd = pmd_offset(pud, addr); +@@ -113,7 +113,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm, + /* must be pmd huge, non-present or none */ + return (pte_t *)pmd; + +- if (!pmd_present(*pmd)) ++ if (!pmd_present(pmdp_get(pmd))) + return NULL; + + for_each_napot_order(order) { +@@ -125,6 +125,26 @@ pte_t *huge_pte_offset(struct mm_struct *mm, + return pte; + } + ++unsigned long hugetlb_mask_last_page(struct hstate *h) ++{ ++ unsigned long hp_size = huge_page_size(h); ++ ++ switch (hp_size) { ++#ifndef __PAGETABLE_PMD_FOLDED ++ case PUD_SIZE: ++ return P4D_SIZE - PUD_SIZE; ++#endif ++ case PMD_SIZE: ++ return PUD_SIZE - PMD_SIZE; ++ case napot_cont_size(NAPOT_CONT64KB_ORDER): ++ return PMD_SIZE - napot_cont_size(NAPOT_CONT64KB_ORDER); ++ default: ++ break; ++ } ++ ++ return 0UL; ++} ++ + static pte_t get_clear_contig(struct mm_struct *mm, + unsigned long addr, + pte_t *ptep, +@@ -177,13 +197,36 @@ pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags) + return entry; + } + ++static void clear_flush(struct mm_struct *mm, ++ unsigned long addr, ++ pte_t *ptep, ++ unsigned long pgsize, ++ unsigned long ncontig) ++{ ++ struct vm_area_struct vma = TLB_FLUSH_VMA(mm, 0); ++ unsigned long i, saddr = addr; ++ ++ for (i = 0; i < ncontig; i++, addr += pgsize, ptep++) ++ ptep_get_and_clear(mm, addr, ptep); ++ ++ flush_tlb_range(&vma, saddr, addr); ++} ++ ++/* ++ * When dealing with NAPOT mappings, the privileged specification indicates that ++ * "if an update needs to be made, the OS generally should first mark all of the ++ * PTEs invalid, then issue SFENCE.VMA instruction(s) covering all 4 KiB regions ++ * within the range, [...] then update the PTE(s), as described in Section ++ * 4.2.1.". That's the equivalent of the Break-Before-Make approach used by ++ * arm64. ++ */ + void set_huge_pte_at(struct mm_struct *mm, + unsigned long addr, + pte_t *ptep, + pte_t pte, + unsigned long sz) + { +- unsigned long hugepage_shift; ++ unsigned long hugepage_shift, pgsize; + int i, pte_num; + + if (sz >= PGDIR_SIZE) +@@ -198,7 +241,22 @@ void set_huge_pte_at(struct mm_struct *mm, + hugepage_shift = PAGE_SHIFT; + + pte_num = sz >> hugepage_shift; +- for (i = 0; i < pte_num; i++, ptep++, addr += (1 << hugepage_shift)) ++ pgsize = 1 << hugepage_shift; ++ ++ if (!pte_present(pte)) { ++ for (i = 0; i < pte_num; i++, ptep++, addr += pgsize) ++ set_ptes(mm, addr, ptep, pte, 1); ++ return; ++ } ++ ++ if (!pte_napot(pte)) { ++ set_ptes(mm, addr, ptep, pte, 1); ++ return; ++ } ++ ++ clear_flush(mm, addr, ptep, pgsize, pte_num); ++ ++ for (i = 0; i < pte_num; i++, ptep++, addr += pgsize) + set_pte_at(mm, addr, ptep, pte); + } + +@@ -293,7 +351,7 @@ void huge_pte_clear(struct mm_struct *mm, + pte_t *ptep, + unsigned long sz) + { +- pte_t pte = READ_ONCE(*ptep); ++ pte_t pte = ptep_get(ptep); + int i, pte_num; + + if (!pte_napot(pte)) { +@@ -306,7 +364,7 @@ void huge_pte_clear(struct mm_struct *mm, + pte_clear(mm, addr, ptep); + } + +-static __init bool is_napot_size(unsigned long size) ++static bool is_napot_size(unsigned long size) + { + unsigned long order; + +@@ -334,7 +392,7 @@ arch_initcall(napot_hugetlbpages_init); + + #else + +-static __init bool is_napot_size(unsigned long size) ++static bool is_napot_size(unsigned long size) + { + return false; + } +@@ -351,7 +409,7 @@ int pmd_huge(pmd_t pmd) + return pmd_leaf(pmd); + } + +-bool __init arch_hugetlb_valid_size(unsigned long size) ++static bool __hugetlb_valid_size(unsigned long size) + { + if (size == HPAGE_SIZE) + return true; +@@ -363,6 +421,18 @@ bool __init arch_hugetlb_valid_size(unsigned long size) + return false; + } + ++bool __init arch_hugetlb_valid_size(unsigned long size) ++{ ++ return __hugetlb_valid_size(size); ++} ++ ++#ifdef CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION ++bool arch_hugetlb_migration_supported(struct hstate *h) ++{ ++ return __hugetlb_valid_size(huge_page_size(h)); ++} ++#endif ++ + #ifdef CONFIG_CONTIG_ALLOC + static __init int gigantic_pages_init(void) + { +diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c +index 0798bd861dcb9a..3245bb525212e3 100644 +--- a/arch/riscv/mm/init.c ++++ b/arch/riscv/mm/init.c +@@ -172,6 +172,9 @@ void __init mem_init(void) + + /* Limit the memory size via mem. */ + static phys_addr_t memory_limit; ++#ifdef CONFIG_XIP_KERNEL ++#define memory_limit (*(phys_addr_t *)XIP_FIXUP(&memory_limit)) ++#endif /* CONFIG_XIP_KERNEL */ + + static int __init early_mem(char *p) + { +@@ -214,8 +217,6 @@ static void __init setup_bootmem(void) + */ + memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start); + +- phys_ram_end = memblock_end_of_DRAM(); +- + /* + * Make sure we align the start of the memory on a PMD boundary so that + * at worst, we map the linear mapping with PMD mappings. +@@ -227,24 +228,36 @@ static void __init setup_bootmem(void) + * In 64-bit, any use of __va/__pa before this point is wrong as we + * did not know the start of DRAM before. + */ +- if (IS_ENABLED(CONFIG_64BIT)) ++ if (IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_MMU)) + kernel_map.va_pa_offset = PAGE_OFFSET - phys_ram_base; + + /* +- * memblock allocator is not aware of the fact that last 4K bytes of +- * the addressable memory can not be mapped because of IS_ERR_VALUE +- * macro. Make sure that last 4k bytes are not usable by memblock +- * if end of dram is equal to maximum addressable memory. For 64-bit +- * kernel, this problem can't happen here as the end of the virtual +- * address space is occupied by the kernel mapping then this check must +- * be done as soon as the kernel mapping base address is determined. ++ * The size of the linear page mapping may restrict the amount of ++ * usable RAM. ++ */ ++ if (IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_MMU)) { ++ max_mapped_addr = __pa(PAGE_OFFSET) + KERN_VIRT_SIZE; ++ memblock_cap_memory_range(phys_ram_base, ++ max_mapped_addr - phys_ram_base); ++ } ++ ++ /* ++ * Reserve physical address space that would be mapped to virtual ++ * addresses greater than (void *)(-PAGE_SIZE) because: ++ * - This memory would overlap with ERR_PTR ++ * - This memory belongs to high memory, which is not supported ++ * ++ * This is not applicable to 64-bit kernel, because virtual addresses ++ * after (void *)(-PAGE_SIZE) are not linearly mapped: they are ++ * occupied by kernel mapping. Also it is unrealistic for high memory ++ * to exist on 64-bit platforms. + */ + if (!IS_ENABLED(CONFIG_64BIT)) { +- max_mapped_addr = __pa(~(ulong)0); +- if (max_mapped_addr == (phys_ram_end - 1)) +- memblock_set_current_limit(max_mapped_addr - 4096); ++ max_mapped_addr = __va_to_pa_nodebug(-PAGE_SIZE); ++ memblock_reserve(max_mapped_addr, (phys_addr_t)-max_mapped_addr); + } + ++ phys_ram_end = memblock_end_of_DRAM(); + min_low_pfn = PFN_UP(phys_ram_base); + max_low_pfn = max_pfn = PFN_DOWN(phys_ram_end); + high_memory = (void *)(__va(PFN_PHYS(max_low_pfn))); +@@ -664,16 +677,19 @@ void __init create_pgd_mapping(pgd_t *pgdp, + static uintptr_t __init best_map_size(phys_addr_t pa, uintptr_t va, + phys_addr_t size) + { +- if (!(pa & (PGDIR_SIZE - 1)) && !(va & (PGDIR_SIZE - 1)) && size >= PGDIR_SIZE) +- return PGDIR_SIZE; ++ if (debug_pagealloc_enabled()) ++ return PAGE_SIZE; + +- if (!(pa & (P4D_SIZE - 1)) && !(va & (P4D_SIZE - 1)) && size >= P4D_SIZE) ++ if (pgtable_l5_enabled && ++ !(pa & (P4D_SIZE - 1)) && !(va & (P4D_SIZE - 1)) && size >= P4D_SIZE) + return P4D_SIZE; + +- if (!(pa & (PUD_SIZE - 1)) && !(va & (PUD_SIZE - 1)) && size >= PUD_SIZE) ++ if (pgtable_l4_enabled && ++ !(pa & (PUD_SIZE - 1)) && !(va & (PUD_SIZE - 1)) && size >= PUD_SIZE) + return PUD_SIZE; + +- if (!(pa & (PMD_SIZE - 1)) && !(va & (PMD_SIZE - 1)) && size >= PMD_SIZE) ++ if (IS_ENABLED(CONFIG_64BIT) && ++ !(pa & (PMD_SIZE - 1)) && !(va & (PMD_SIZE - 1)) && size >= PMD_SIZE) + return PMD_SIZE; + + return PAGE_SIZE; +@@ -896,7 +912,7 @@ static void __init create_kernel_page_table(pgd_t *pgdir, + PMD_SIZE, PAGE_KERNEL_EXEC); + + /* Map the data in RAM */ +- end_va = kernel_map.virt_addr + XIP_OFFSET + kernel_map.size; ++ end_va = kernel_map.virt_addr + kernel_map.size; + for (va = kernel_map.virt_addr + XIP_OFFSET; va < end_va; va += PMD_SIZE) + create_pgd_mapping(pgdir, va, + kernel_map.phys_addr + (va - (kernel_map.virt_addr + XIP_OFFSET)), +@@ -950,7 +966,7 @@ static void __init create_fdt_early_page_table(uintptr_t fix_fdt_va, + * setup_vm_final installs the linear mapping. For 32-bit kernel, as the + * kernel is mapped in the linear mapping, that makes no difference. + */ +- dtb_early_va = kernel_mapping_pa_to_va(XIP_FIXUP(dtb_pa)); ++ dtb_early_va = kernel_mapping_pa_to_va(dtb_pa); + #endif + + dtb_early_pa = dtb_pa; +@@ -1053,18 +1069,23 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) + #endif + + kernel_map.virt_addr = KERNEL_LINK_ADDR + kernel_map.virt_offset; +- kernel_map.page_offset = _AC(CONFIG_PAGE_OFFSET, UL); + + #ifdef CONFIG_XIP_KERNEL ++#ifdef CONFIG_64BIT ++ kernel_map.page_offset = PAGE_OFFSET_L3; ++#else ++ kernel_map.page_offset = _AC(CONFIG_PAGE_OFFSET, UL); ++#endif + kernel_map.xiprom = (uintptr_t)CONFIG_XIP_PHYS_ADDR; + kernel_map.xiprom_sz = (uintptr_t)(&_exiprom) - (uintptr_t)(&_xiprom); + + phys_ram_base = CONFIG_PHYS_RAM_BASE; + kernel_map.phys_addr = (uintptr_t)CONFIG_PHYS_RAM_BASE; +- kernel_map.size = (uintptr_t)(&_end) - (uintptr_t)(&_sdata); ++ kernel_map.size = (uintptr_t)(&_end) - (uintptr_t)(&_start); + + kernel_map.va_kernel_xip_pa_offset = kernel_map.virt_addr - kernel_map.xiprom; + #else ++ kernel_map.page_offset = _AC(CONFIG_PAGE_OFFSET, UL); + kernel_map.phys_addr = (uintptr_t)(&_start); + kernel_map.size = (uintptr_t)(&_end) - kernel_map.phys_addr; + #endif +@@ -1257,8 +1278,6 @@ static void __init create_linear_mapping_page_table(void) + if (start <= __pa(PAGE_OFFSET) && + __pa(PAGE_OFFSET) < end) + start = __pa(PAGE_OFFSET); +- if (end >= __pa(PAGE_OFFSET) + memory_limit) +- end = __pa(PAGE_OFFSET) + memory_limit; + + create_linear_mapping_range(start, end, 0); + } +@@ -1494,6 +1513,10 @@ void __init misc_mem_init(void) + early_memtest(min_low_pfn << PAGE_SHIFT, max_low_pfn << PAGE_SHIFT); + arch_numa_init(); + sparse_init(); ++#ifdef CONFIG_SPARSEMEM_VMEMMAP ++ /* The entire VMEMMAP region has been populated. Flush TLB for this region */ ++ local_flush_tlb_kernel_range(VMEMMAP_START, VMEMMAP_END); ++#endif + zone_sizes_init(); + reserve_crashkernel(); + memblock_dump_all(); +diff --git a/arch/riscv/mm/kasan_init.c b/arch/riscv/mm/kasan_init.c +index 5e39dcf23fdbc1..e962518530373d 100644 +--- a/arch/riscv/mm/kasan_init.c ++++ b/arch/riscv/mm/kasan_init.c +@@ -31,7 +31,7 @@ static void __init kasan_populate_pte(pmd_t *pmd, unsigned long vaddr, unsigned + phys_addr_t phys_addr; + pte_t *ptep, *p; + +- if (pmd_none(*pmd)) { ++ if (pmd_none(pmdp_get(pmd))) { + p = memblock_alloc(PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE); + set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa(p)), PAGE_TABLE)); + } +@@ -39,7 +39,7 @@ static void __init kasan_populate_pte(pmd_t *pmd, unsigned long vaddr, unsigned + ptep = pte_offset_kernel(pmd, vaddr); + + do { +- if (pte_none(*ptep)) { ++ if (pte_none(ptep_get(ptep))) { + phys_addr = memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); + set_pte(ptep, pfn_pte(PFN_DOWN(phys_addr), PAGE_KERNEL)); + memset(__va(phys_addr), KASAN_SHADOW_INIT, PAGE_SIZE); +@@ -53,7 +53,7 @@ static void __init kasan_populate_pmd(pud_t *pud, unsigned long vaddr, unsigned + pmd_t *pmdp, *p; + unsigned long next; + +- if (pud_none(*pud)) { ++ if (pud_none(pudp_get(pud))) { + p = memblock_alloc(PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE); + set_pud(pud, pfn_pud(PFN_DOWN(__pa(p)), PAGE_TABLE)); + } +@@ -63,7 +63,8 @@ static void __init kasan_populate_pmd(pud_t *pud, unsigned long vaddr, unsigned + do { + next = pmd_addr_end(vaddr, end); + +- if (pmd_none(*pmdp) && IS_ALIGNED(vaddr, PMD_SIZE) && (next - vaddr) >= PMD_SIZE) { ++ if (pmd_none(pmdp_get(pmdp)) && IS_ALIGNED(vaddr, PMD_SIZE) && ++ (next - vaddr) >= PMD_SIZE) { + phys_addr = memblock_phys_alloc(PMD_SIZE, PMD_SIZE); + if (phys_addr) { + set_pmd(pmdp, pfn_pmd(PFN_DOWN(phys_addr), PAGE_KERNEL)); +@@ -83,7 +84,7 @@ static void __init kasan_populate_pud(p4d_t *p4d, + pud_t *pudp, *p; + unsigned long next; + +- if (p4d_none(*p4d)) { ++ if (p4d_none(p4dp_get(p4d))) { + p = memblock_alloc(PTRS_PER_PUD * sizeof(pud_t), PAGE_SIZE); + set_p4d(p4d, pfn_p4d(PFN_DOWN(__pa(p)), PAGE_TABLE)); + } +@@ -93,7 +94,8 @@ static void __init kasan_populate_pud(p4d_t *p4d, + do { + next = pud_addr_end(vaddr, end); + +- if (pud_none(*pudp) && IS_ALIGNED(vaddr, PUD_SIZE) && (next - vaddr) >= PUD_SIZE) { ++ if (pud_none(pudp_get(pudp)) && IS_ALIGNED(vaddr, PUD_SIZE) && ++ (next - vaddr) >= PUD_SIZE) { + phys_addr = memblock_phys_alloc(PUD_SIZE, PUD_SIZE); + if (phys_addr) { + set_pud(pudp, pfn_pud(PFN_DOWN(phys_addr), PAGE_KERNEL)); +@@ -113,7 +115,7 @@ static void __init kasan_populate_p4d(pgd_t *pgd, + p4d_t *p4dp, *p; + unsigned long next; + +- if (pgd_none(*pgd)) { ++ if (pgd_none(pgdp_get(pgd))) { + p = memblock_alloc(PTRS_PER_P4D * sizeof(p4d_t), PAGE_SIZE); + set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(p)), PAGE_TABLE)); + } +@@ -123,7 +125,8 @@ static void __init kasan_populate_p4d(pgd_t *pgd, + do { + next = p4d_addr_end(vaddr, end); + +- if (p4d_none(*p4dp) && IS_ALIGNED(vaddr, P4D_SIZE) && (next - vaddr) >= P4D_SIZE) { ++ if (p4d_none(p4dp_get(p4dp)) && IS_ALIGNED(vaddr, P4D_SIZE) && ++ (next - vaddr) >= P4D_SIZE) { + phys_addr = memblock_phys_alloc(P4D_SIZE, P4D_SIZE); + if (phys_addr) { + set_p4d(p4dp, pfn_p4d(PFN_DOWN(phys_addr), PAGE_KERNEL)); +@@ -145,7 +148,7 @@ static void __init kasan_populate_pgd(pgd_t *pgdp, + do { + next = pgd_addr_end(vaddr, end); + +- if (pgd_none(*pgdp) && IS_ALIGNED(vaddr, PGDIR_SIZE) && ++ if (pgd_none(pgdp_get(pgdp)) && IS_ALIGNED(vaddr, PGDIR_SIZE) && + (next - vaddr) >= PGDIR_SIZE) { + phys_addr = memblock_phys_alloc(PGDIR_SIZE, PGDIR_SIZE); + if (phys_addr) { +@@ -168,7 +171,7 @@ static void __init kasan_early_clear_pud(p4d_t *p4dp, + if (!pgtable_l4_enabled) { + pudp = (pud_t *)p4dp; + } else { +- base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(*p4dp))); ++ base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(p4dp_get(p4dp)))); + pudp = base_pud + pud_index(vaddr); + } + +@@ -193,7 +196,7 @@ static void __init kasan_early_clear_p4d(pgd_t *pgdp, + if (!pgtable_l5_enabled) { + p4dp = (p4d_t *)pgdp; + } else { +- base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(*pgdp))); ++ base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(pgdp_get(pgdp)))); + p4dp = base_p4d + p4d_index(vaddr); + } + +@@ -239,14 +242,14 @@ static void __init kasan_early_populate_pud(p4d_t *p4dp, + if (!pgtable_l4_enabled) { + pudp = (pud_t *)p4dp; + } else { +- base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(*p4dp))); ++ base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(p4dp_get(p4dp)))); + pudp = base_pud + pud_index(vaddr); + } + + do { + next = pud_addr_end(vaddr, end); + +- if (pud_none(*pudp) && IS_ALIGNED(vaddr, PUD_SIZE) && ++ if (pud_none(pudp_get(pudp)) && IS_ALIGNED(vaddr, PUD_SIZE) && + (next - vaddr) >= PUD_SIZE) { + phys_addr = __pa((uintptr_t)kasan_early_shadow_pmd); + set_pud(pudp, pfn_pud(PFN_DOWN(phys_addr), PAGE_TABLE)); +@@ -277,14 +280,14 @@ static void __init kasan_early_populate_p4d(pgd_t *pgdp, + if (!pgtable_l5_enabled) { + p4dp = (p4d_t *)pgdp; + } else { +- base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(*pgdp))); ++ base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(pgdp_get(pgdp)))); + p4dp = base_p4d + p4d_index(vaddr); + } + + do { + next = p4d_addr_end(vaddr, end); + +- if (p4d_none(*p4dp) && IS_ALIGNED(vaddr, P4D_SIZE) && ++ if (p4d_none(p4dp_get(p4dp)) && IS_ALIGNED(vaddr, P4D_SIZE) && + (next - vaddr) >= P4D_SIZE) { + phys_addr = __pa((uintptr_t)kasan_early_shadow_pud); + set_p4d(p4dp, pfn_p4d(PFN_DOWN(phys_addr), PAGE_TABLE)); +@@ -305,7 +308,7 @@ static void __init kasan_early_populate_pgd(pgd_t *pgdp, + do { + next = pgd_addr_end(vaddr, end); + +- if (pgd_none(*pgdp) && IS_ALIGNED(vaddr, PGDIR_SIZE) && ++ if (pgd_none(pgdp_get(pgdp)) && IS_ALIGNED(vaddr, PGDIR_SIZE) && + (next - vaddr) >= PGDIR_SIZE) { + phys_addr = __pa((uintptr_t)kasan_early_shadow_p4d); + set_pgd(pgdp, pfn_pgd(PFN_DOWN(phys_addr), PAGE_TABLE)); +@@ -381,7 +384,7 @@ static void __init kasan_shallow_populate_pud(p4d_t *p4d, + do { + next = pud_addr_end(vaddr, end); + +- if (pud_none(*pud_k)) { ++ if (pud_none(pudp_get(pud_k))) { + p = memblock_alloc(PAGE_SIZE, PAGE_SIZE); + set_pud(pud_k, pfn_pud(PFN_DOWN(__pa(p)), PAGE_TABLE)); + continue; +@@ -401,7 +404,7 @@ static void __init kasan_shallow_populate_p4d(pgd_t *pgd, + do { + next = p4d_addr_end(vaddr, end); + +- if (p4d_none(*p4d_k)) { ++ if (p4d_none(p4dp_get(p4d_k))) { + p = memblock_alloc(PAGE_SIZE, PAGE_SIZE); + set_p4d(p4d_k, pfn_p4d(PFN_DOWN(__pa(p)), PAGE_TABLE)); + continue; +@@ -420,7 +423,7 @@ static void __init kasan_shallow_populate_pgd(unsigned long vaddr, unsigned long + do { + next = pgd_addr_end(vaddr, end); + +- if (pgd_none(*pgd_k)) { ++ if (pgd_none(pgdp_get(pgd_k))) { + p = memblock_alloc(PAGE_SIZE, PAGE_SIZE); + set_pgd(pgd_k, pfn_pgd(PFN_DOWN(__pa(p)), PAGE_TABLE)); + continue; +@@ -451,7 +454,7 @@ static void __init create_tmp_mapping(void) + + /* Copy the last p4d since it is shared with the kernel mapping. */ + if (pgtable_l5_enabled) { +- ptr = (p4d_t *)pgd_page_vaddr(*pgd_offset_k(KASAN_SHADOW_END)); ++ ptr = (p4d_t *)pgd_page_vaddr(pgdp_get(pgd_offset_k(KASAN_SHADOW_END))); + memcpy(tmp_p4d, ptr, sizeof(p4d_t) * PTRS_PER_P4D); + set_pgd(&tmp_pg_dir[pgd_index(KASAN_SHADOW_END)], + pfn_pgd(PFN_DOWN(__pa(tmp_p4d)), PAGE_TABLE)); +@@ -462,7 +465,7 @@ static void __init create_tmp_mapping(void) + + /* Copy the last pud since it is shared with the kernel mapping. */ + if (pgtable_l4_enabled) { +- ptr = (pud_t *)p4d_page_vaddr(*(base_p4d + p4d_index(KASAN_SHADOW_END))); ++ ptr = (pud_t *)p4d_page_vaddr(p4dp_get(base_p4d + p4d_index(KASAN_SHADOW_END))); + memcpy(tmp_pud, ptr, sizeof(pud_t) * PTRS_PER_PUD); + set_p4d(&base_p4d[p4d_index(KASAN_SHADOW_END)], + pfn_p4d(PFN_DOWN(__pa(tmp_pud)), PAGE_TABLE)); +diff --git a/arch/riscv/mm/pageattr.c b/arch/riscv/mm/pageattr.c +index 161d0b34c2cb28..271d01a5ba4da1 100644 +--- a/arch/riscv/mm/pageattr.c ++++ b/arch/riscv/mm/pageattr.c +@@ -5,6 +5,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -25,23 +26,10 @@ static unsigned long set_pageattr_masks(unsigned long val, struct mm_walk *walk) + return new_val; + } + +-static int pageattr_pgd_entry(pgd_t *pgd, unsigned long addr, +- unsigned long next, struct mm_walk *walk) +-{ +- pgd_t val = READ_ONCE(*pgd); +- +- if (pgd_leaf(val)) { +- val = __pgd(set_pageattr_masks(pgd_val(val), walk)); +- set_pgd(pgd, val); +- } +- +- return 0; +-} +- + static int pageattr_p4d_entry(p4d_t *p4d, unsigned long addr, + unsigned long next, struct mm_walk *walk) + { +- p4d_t val = READ_ONCE(*p4d); ++ p4d_t val = p4dp_get(p4d); + + if (p4d_leaf(val)) { + val = __p4d(set_pageattr_masks(p4d_val(val), walk)); +@@ -54,7 +42,7 @@ static int pageattr_p4d_entry(p4d_t *p4d, unsigned long addr, + static int pageattr_pud_entry(pud_t *pud, unsigned long addr, + unsigned long next, struct mm_walk *walk) + { +- pud_t val = READ_ONCE(*pud); ++ pud_t val = pudp_get(pud); + + if (pud_leaf(val)) { + val = __pud(set_pageattr_masks(pud_val(val), walk)); +@@ -67,7 +55,7 @@ static int pageattr_pud_entry(pud_t *pud, unsigned long addr, + static int pageattr_pmd_entry(pmd_t *pmd, unsigned long addr, + unsigned long next, struct mm_walk *walk) + { +- pmd_t val = READ_ONCE(*pmd); ++ pmd_t val = pmdp_get(pmd); + + if (pmd_leaf(val)) { + val = __pmd(set_pageattr_masks(pmd_val(val), walk)); +@@ -80,7 +68,7 @@ static int pageattr_pmd_entry(pmd_t *pmd, unsigned long addr, + static int pageattr_pte_entry(pte_t *pte, unsigned long addr, + unsigned long next, struct mm_walk *walk) + { +- pte_t val = READ_ONCE(*pte); ++ pte_t val = ptep_get(pte); + + val = __pte(set_pageattr_masks(pte_val(val), walk)); + set_pte(pte, val); +@@ -96,7 +84,6 @@ static int pageattr_pte_hole(unsigned long addr, unsigned long next, + } + + static const struct mm_walk_ops pageattr_ops = { +- .pgd_entry = pageattr_pgd_entry, + .p4d_entry = pageattr_p4d_entry, + .pud_entry = pageattr_pud_entry, + .pmd_entry = pageattr_pmd_entry, +@@ -105,12 +92,181 @@ static const struct mm_walk_ops pageattr_ops = { + .walk_lock = PGWALK_RDLOCK, + }; + ++#ifdef CONFIG_64BIT ++static int __split_linear_mapping_pmd(pud_t *pudp, ++ unsigned long vaddr, unsigned long end) ++{ ++ pmd_t *pmdp; ++ unsigned long next; ++ ++ pmdp = pmd_offset(pudp, vaddr); ++ ++ do { ++ next = pmd_addr_end(vaddr, end); ++ ++ if (next - vaddr >= PMD_SIZE && ++ vaddr <= (vaddr & PMD_MASK) && end >= next) ++ continue; ++ ++ if (pmd_leaf(pmdp_get(pmdp))) { ++ struct page *pte_page; ++ unsigned long pfn = _pmd_pfn(pmdp_get(pmdp)); ++ pgprot_t prot = __pgprot(pmd_val(pmdp_get(pmdp)) & ~_PAGE_PFN_MASK); ++ pte_t *ptep_new; ++ int i; ++ ++ pte_page = alloc_page(GFP_KERNEL); ++ if (!pte_page) ++ return -ENOMEM; ++ ++ ptep_new = (pte_t *)page_address(pte_page); ++ for (i = 0; i < PTRS_PER_PTE; ++i, ++ptep_new) ++ set_pte(ptep_new, pfn_pte(pfn + i, prot)); ++ ++ smp_wmb(); ++ ++ set_pmd(pmdp, pfn_pmd(page_to_pfn(pte_page), PAGE_TABLE)); ++ } ++ } while (pmdp++, vaddr = next, vaddr != end); ++ ++ return 0; ++} ++ ++static int __split_linear_mapping_pud(p4d_t *p4dp, ++ unsigned long vaddr, unsigned long end) ++{ ++ pud_t *pudp; ++ unsigned long next; ++ int ret; ++ ++ pudp = pud_offset(p4dp, vaddr); ++ ++ do { ++ next = pud_addr_end(vaddr, end); ++ ++ if (next - vaddr >= PUD_SIZE && ++ vaddr <= (vaddr & PUD_MASK) && end >= next) ++ continue; ++ ++ if (pud_leaf(pudp_get(pudp))) { ++ struct page *pmd_page; ++ unsigned long pfn = _pud_pfn(pudp_get(pudp)); ++ pgprot_t prot = __pgprot(pud_val(pudp_get(pudp)) & ~_PAGE_PFN_MASK); ++ pmd_t *pmdp_new; ++ int i; ++ ++ pmd_page = alloc_page(GFP_KERNEL); ++ if (!pmd_page) ++ return -ENOMEM; ++ ++ pmdp_new = (pmd_t *)page_address(pmd_page); ++ for (i = 0; i < PTRS_PER_PMD; ++i, ++pmdp_new) ++ set_pmd(pmdp_new, ++ pfn_pmd(pfn + ((i * PMD_SIZE) >> PAGE_SHIFT), prot)); ++ ++ smp_wmb(); ++ ++ set_pud(pudp, pfn_pud(page_to_pfn(pmd_page), PAGE_TABLE)); ++ } ++ ++ ret = __split_linear_mapping_pmd(pudp, vaddr, next); ++ if (ret) ++ return ret; ++ } while (pudp++, vaddr = next, vaddr != end); ++ ++ return 0; ++} ++ ++static int __split_linear_mapping_p4d(pgd_t *pgdp, ++ unsigned long vaddr, unsigned long end) ++{ ++ p4d_t *p4dp; ++ unsigned long next; ++ int ret; ++ ++ p4dp = p4d_offset(pgdp, vaddr); ++ ++ do { ++ next = p4d_addr_end(vaddr, end); ++ ++ /* ++ * If [vaddr; end] contains [vaddr & P4D_MASK; next], we don't ++ * need to split, we'll change the protections on the whole P4D. ++ */ ++ if (next - vaddr >= P4D_SIZE && ++ vaddr <= (vaddr & P4D_MASK) && end >= next) ++ continue; ++ ++ if (p4d_leaf(p4dp_get(p4dp))) { ++ struct page *pud_page; ++ unsigned long pfn = _p4d_pfn(p4dp_get(p4dp)); ++ pgprot_t prot = __pgprot(p4d_val(p4dp_get(p4dp)) & ~_PAGE_PFN_MASK); ++ pud_t *pudp_new; ++ int i; ++ ++ pud_page = alloc_page(GFP_KERNEL); ++ if (!pud_page) ++ return -ENOMEM; ++ ++ /* ++ * Fill the pud level with leaf puds that have the same ++ * protections as the leaf p4d. ++ */ ++ pudp_new = (pud_t *)page_address(pud_page); ++ for (i = 0; i < PTRS_PER_PUD; ++i, ++pudp_new) ++ set_pud(pudp_new, ++ pfn_pud(pfn + ((i * PUD_SIZE) >> PAGE_SHIFT), prot)); ++ ++ /* ++ * Make sure the pud filling is not reordered with the ++ * p4d store which could result in seeing a partially ++ * filled pud level. ++ */ ++ smp_wmb(); ++ ++ set_p4d(p4dp, pfn_p4d(page_to_pfn(pud_page), PAGE_TABLE)); ++ } ++ ++ ret = __split_linear_mapping_pud(p4dp, vaddr, next); ++ if (ret) ++ return ret; ++ } while (p4dp++, vaddr = next, vaddr != end); ++ ++ return 0; ++} ++ ++static int __split_linear_mapping_pgd(pgd_t *pgdp, ++ unsigned long vaddr, ++ unsigned long end) ++{ ++ unsigned long next; ++ int ret; ++ ++ do { ++ next = pgd_addr_end(vaddr, end); ++ /* We never use PGD mappings for the linear mapping */ ++ ret = __split_linear_mapping_p4d(pgdp, vaddr, next); ++ if (ret) ++ return ret; ++ } while (pgdp++, vaddr = next, vaddr != end); ++ ++ return 0; ++} ++ ++static int split_linear_mapping(unsigned long start, unsigned long end) ++{ ++ return __split_linear_mapping_pgd(pgd_offset_k(start), start, end); ++} ++#endif /* CONFIG_64BIT */ ++ + static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask, + pgprot_t clear_mask) + { + int ret; + unsigned long start = addr; + unsigned long end = start + PAGE_SIZE * numpages; ++ unsigned long __maybe_unused lm_start; ++ unsigned long __maybe_unused lm_end; + struct pageattr_masks masks = { + .set_mask = set_mask, + .clear_mask = clear_mask +@@ -120,11 +276,72 @@ static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask, + return 0; + + mmap_write_lock(&init_mm); ++ ++#ifdef CONFIG_64BIT ++ /* ++ * We are about to change the permissions of a kernel mapping, we must ++ * apply the same changes to its linear mapping alias, which may imply ++ * splitting a huge mapping. ++ */ ++ ++ if (is_vmalloc_or_module_addr((void *)start)) { ++ struct vm_struct *area = NULL; ++ int i, page_start; ++ ++ area = find_vm_area((void *)start); ++ page_start = (start - (unsigned long)area->addr) >> PAGE_SHIFT; ++ ++ for (i = page_start; i < page_start + numpages; ++i) { ++ lm_start = (unsigned long)page_address(area->pages[i]); ++ lm_end = lm_start + PAGE_SIZE; ++ ++ ret = split_linear_mapping(lm_start, lm_end); ++ if (ret) ++ goto unlock; ++ ++ ret = walk_page_range_novma(&init_mm, lm_start, lm_end, ++ &pageattr_ops, NULL, &masks); ++ if (ret) ++ goto unlock; ++ } ++ } else if (is_kernel_mapping(start) || is_linear_mapping(start)) { ++ if (is_kernel_mapping(start)) { ++ lm_start = (unsigned long)lm_alias(start); ++ lm_end = (unsigned long)lm_alias(end); ++ } else { ++ lm_start = start; ++ lm_end = end; ++ } ++ ++ ret = split_linear_mapping(lm_start, lm_end); ++ if (ret) ++ goto unlock; ++ ++ ret = walk_page_range_novma(&init_mm, lm_start, lm_end, ++ &pageattr_ops, NULL, &masks); ++ if (ret) ++ goto unlock; ++ } ++ + ret = walk_page_range_novma(&init_mm, start, end, &pageattr_ops, NULL, + &masks); ++ ++unlock: ++ mmap_write_unlock(&init_mm); ++ ++ /* ++ * We can't use flush_tlb_kernel_range() here as we may have split a ++ * hugepage that is larger than that, so let's flush everything. ++ */ ++ flush_tlb_all(); ++#else ++ ret = walk_page_range_novma(&init_mm, start, end, &pageattr_ops, NULL, ++ &masks); ++ + mmap_write_unlock(&init_mm); + + flush_tlb_kernel_range(start, end); ++#endif + + return ret; + } +@@ -159,50 +376,44 @@ int set_memory_nx(unsigned long addr, int numpages) + + int set_direct_map_invalid_noflush(struct page *page) + { +- int ret; +- unsigned long start = (unsigned long)page_address(page); +- unsigned long end = start + PAGE_SIZE; +- struct pageattr_masks masks = { +- .set_mask = __pgprot(0), +- .clear_mask = __pgprot(_PAGE_PRESENT) +- }; +- +- mmap_read_lock(&init_mm); +- ret = walk_page_range(&init_mm, start, end, &pageattr_ops, &masks); +- mmap_read_unlock(&init_mm); +- +- return ret; ++ return __set_memory((unsigned long)page_address(page), 1, ++ __pgprot(0), __pgprot(_PAGE_PRESENT)); + } + + int set_direct_map_default_noflush(struct page *page) + { +- int ret; +- unsigned long start = (unsigned long)page_address(page); +- unsigned long end = start + PAGE_SIZE; +- struct pageattr_masks masks = { +- .set_mask = PAGE_KERNEL, +- .clear_mask = __pgprot(0) +- }; ++ return __set_memory((unsigned long)page_address(page), 1, ++ PAGE_KERNEL, __pgprot(_PAGE_EXEC)); ++} + +- mmap_read_lock(&init_mm); +- ret = walk_page_range(&init_mm, start, end, &pageattr_ops, &masks); +- mmap_read_unlock(&init_mm); ++#ifdef CONFIG_DEBUG_PAGEALLOC ++static int debug_pagealloc_set_page(pte_t *pte, unsigned long addr, void *data) ++{ ++ int enable = *(int *)data; + +- return ret; ++ unsigned long val = pte_val(ptep_get(pte)); ++ ++ if (enable) ++ val |= _PAGE_PRESENT; ++ else ++ val &= ~_PAGE_PRESENT; ++ ++ set_pte(pte, __pte(val)); ++ ++ return 0; + } + +-#ifdef CONFIG_DEBUG_PAGEALLOC + void __kernel_map_pages(struct page *page, int numpages, int enable) + { + if (!debug_pagealloc_enabled()) + return; + +- if (enable) +- __set_memory((unsigned long)page_address(page), numpages, +- __pgprot(_PAGE_PRESENT), __pgprot(0)); +- else +- __set_memory((unsigned long)page_address(page), numpages, +- __pgprot(0), __pgprot(_PAGE_PRESENT)); ++ unsigned long start = (unsigned long)page_address(page); ++ unsigned long size = PAGE_SIZE * numpages; ++ ++ apply_to_existing_page_range(&init_mm, start, size, debug_pagealloc_set_page, &enable); ++ ++ flush_tlb_kernel_range(start, start + size); + } + #endif + +@@ -216,29 +427,29 @@ bool kernel_page_present(struct page *page) + pte_t *pte; + + pgd = pgd_offset_k(addr); +- if (!pgd_present(*pgd)) ++ if (!pgd_present(pgdp_get(pgd))) + return false; +- if (pgd_leaf(*pgd)) ++ if (pgd_leaf(pgdp_get(pgd))) + return true; + + p4d = p4d_offset(pgd, addr); +- if (!p4d_present(*p4d)) ++ if (!p4d_present(p4dp_get(p4d))) + return false; +- if (p4d_leaf(*p4d)) ++ if (p4d_leaf(p4dp_get(p4d))) + return true; + + pud = pud_offset(p4d, addr); +- if (!pud_present(*pud)) ++ if (!pud_present(pudp_get(pud))) + return false; +- if (pud_leaf(*pud)) ++ if (pud_leaf(pudp_get(pud))) + return true; + + pmd = pmd_offset(pud, addr); +- if (!pmd_present(*pmd)) ++ if (!pmd_present(pmdp_get(pmd))) + return false; +- if (pmd_leaf(*pmd)) ++ if (pmd_leaf(pmdp_get(pmd))) + return true; + + pte = pte_offset_kernel(pmd, addr); +- return pte_present(*pte); ++ return pte_present(ptep_get(pte)); + } +diff --git a/arch/riscv/mm/pgtable.c b/arch/riscv/mm/pgtable.c +index fef4e7328e4905..ef887efcb67900 100644 +--- a/arch/riscv/mm/pgtable.c ++++ b/arch/riscv/mm/pgtable.c +@@ -5,6 +5,47 @@ + #include + #include + ++int ptep_set_access_flags(struct vm_area_struct *vma, ++ unsigned long address, pte_t *ptep, ++ pte_t entry, int dirty) ++{ ++ if (!pte_same(ptep_get(ptep), entry)) ++ __set_pte_at(ptep, entry); ++ /* ++ * update_mmu_cache will unconditionally execute, handling both ++ * the case that the PTE changed and the spurious fault case. ++ */ ++ return true; ++} ++ ++int ptep_test_and_clear_young(struct vm_area_struct *vma, ++ unsigned long address, ++ pte_t *ptep) ++{ ++ if (!pte_young(ptep_get(ptep))) ++ return 0; ++ return test_and_clear_bit(_PAGE_ACCESSED_OFFSET, &pte_val(*ptep)); ++} ++EXPORT_SYMBOL_GPL(ptep_test_and_clear_young); ++ ++#ifdef CONFIG_64BIT ++pud_t *pud_offset(p4d_t *p4d, unsigned long address) ++{ ++ if (pgtable_l4_enabled) ++ return p4d_pgtable(p4dp_get(p4d)) + pud_index(address); ++ ++ return (pud_t *)p4d; ++} ++ ++p4d_t *p4d_offset(pgd_t *pgd, unsigned long address) ++{ ++ if (pgtable_l5_enabled) ++ return pgd_pgtable(pgdp_get(pgd)) + p4d_index(address); ++ ++ return (p4d_t *)pgd; ++} ++#endif ++ + #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP + int p4d_set_huge(p4d_t *p4d, phys_addr_t addr, pgprot_t prot) + { +@@ -25,7 +66,7 @@ int pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot) + + int pud_clear_huge(pud_t *pud) + { +- if (!pud_leaf(READ_ONCE(*pud))) ++ if (!pud_leaf(pudp_get(pud))) + return 0; + pud_clear(pud); + return 1; +@@ -33,7 +74,7 @@ int pud_clear_huge(pud_t *pud) + + int pud_free_pmd_page(pud_t *pud, unsigned long addr) + { +- pmd_t *pmd = pud_pgtable(*pud); ++ pmd_t *pmd = pud_pgtable(pudp_get(pud)); + int i; + + pud_clear(pud); +@@ -63,7 +104,7 @@ int pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot) + + int pmd_clear_huge(pmd_t *pmd) + { +- if (!pmd_leaf(READ_ONCE(*pmd))) ++ if (!pmd_leaf(pmdp_get(pmd))) + return 0; + pmd_clear(pmd); + return 1; +@@ -71,7 +112,7 @@ int pmd_clear_huge(pmd_t *pmd) + + int pmd_free_pte_page(pmd_t *pmd, unsigned long addr) + { +- pte_t *pte = (pte_t *)pmd_page_vaddr(*pmd); ++ pte_t *pte = (pte_t *)pmd_page_vaddr(pmdp_get(pmd)); + + pmd_clear(pmd); + +@@ -88,7 +129,7 @@ pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, + pmd_t pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp); + + VM_BUG_ON(address & ~HPAGE_PMD_MASK); +- VM_BUG_ON(pmd_trans_huge(*pmdp)); ++ VM_BUG_ON(pmd_trans_huge(pmdp_get(pmdp))); + /* + * When leaf PTE entries (regular pages) are collapsed into a leaf + * PMD entry (huge page), a valid non-leaf PTE is converted into a +diff --git a/arch/riscv/mm/ptdump.c b/arch/riscv/mm/ptdump.c +index 20a9f991a6d746..e9090b38f8117c 100644 +--- a/arch/riscv/mm/ptdump.c ++++ b/arch/riscv/mm/ptdump.c +@@ -384,6 +384,9 @@ static int __init ptdump_init(void) + + kernel_ptd_info.base_addr = KERN_VIRT_START; + ++ pg_level[1].name = pgtable_l5_enabled ? "P4D" : "PGD"; ++ pg_level[2].name = pgtable_l4_enabled ? "PUD" : "PGD"; ++ + for (i = 0; i < ARRAY_SIZE(pg_level); i++) + for (j = 0; j < ARRAY_SIZE(pte_bits); j++) + pg_level[i].mask |= pte_bits[j].mask; +diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c +index 77be59aadc735e..324e8cd9b50228 100644 +--- a/arch/riscv/mm/tlbflush.c ++++ b/arch/riscv/mm/tlbflush.c +@@ -6,30 +6,29 @@ + #include + #include + +-static inline void local_flush_tlb_all_asid(unsigned long asid) ++/* ++ * Flush entire TLB if number of entries to be flushed is greater ++ * than the threshold below. ++ */ ++static unsigned long tlb_flush_all_threshold __read_mostly = 64; ++ ++static void local_flush_tlb_range_threshold_asid(unsigned long start, ++ unsigned long size, ++ unsigned long stride, ++ unsigned long asid) + { +- __asm__ __volatile__ ("sfence.vma x0, %0" +- : +- : "r" (asid) +- : "memory"); +-} ++ unsigned long nr_ptes_in_range = DIV_ROUND_UP(size, stride); ++ int i; + +-static inline void local_flush_tlb_page_asid(unsigned long addr, +- unsigned long asid) +-{ +- __asm__ __volatile__ ("sfence.vma %0, %1" +- : +- : "r" (addr), "r" (asid) +- : "memory"); +-} ++ if (nr_ptes_in_range > tlb_flush_all_threshold) { ++ local_flush_tlb_all_asid(asid); ++ return; ++ } + +-static inline void local_flush_tlb_range(unsigned long start, +- unsigned long size, unsigned long stride) +-{ +- if (size <= stride) +- local_flush_tlb_page(start); +- else +- local_flush_tlb_all(); ++ for (i = 0; i < nr_ptes_in_range; ++i) { ++ local_flush_tlb_page_asid(start, asid); ++ start += stride; ++ } + } + + static inline void local_flush_tlb_range_asid(unsigned long start, +@@ -37,8 +36,16 @@ static inline void local_flush_tlb_range_asid(unsigned long start, + { + if (size <= stride) + local_flush_tlb_page_asid(start, asid); +- else ++ else if (size == FLUSH_TLB_MAX_SIZE) + local_flush_tlb_all_asid(asid); ++ else ++ local_flush_tlb_range_threshold_asid(start, size, stride, asid); ++} ++ ++/* Flush a range of kernel pages without broadcasting */ ++void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) ++{ ++ local_flush_tlb_range_asid(start, end - start, PAGE_SIZE, FLUSH_TLB_NO_ASID); + } + + static void __ipi_flush_tlb_all(void *info) +@@ -51,7 +58,7 @@ void flush_tlb_all(void) + if (riscv_use_ipi_for_rfence()) + on_each_cpu(__ipi_flush_tlb_all, NULL, 1); + else +- sbi_remote_sfence_vma(NULL, 0, -1); ++ sbi_remote_sfence_vma_asid(NULL, 0, FLUSH_TLB_MAX_SIZE, FLUSH_TLB_NO_ASID); + } + + struct flush_tlb_range_data { +@@ -68,68 +75,62 @@ static void __ipi_flush_tlb_range_asid(void *info) + local_flush_tlb_range_asid(d->start, d->size, d->stride, d->asid); + } + +-static void __ipi_flush_tlb_range(void *info) +-{ +- struct flush_tlb_range_data *d = info; +- +- local_flush_tlb_range(d->start, d->size, d->stride); +-} +- + static void __flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long size, unsigned long stride) + { + struct flush_tlb_range_data ftd; +- struct cpumask *cmask = mm_cpumask(mm); +- unsigned int cpuid; ++ const struct cpumask *cmask; ++ unsigned long asid = FLUSH_TLB_NO_ASID; + bool broadcast; + +- if (cpumask_empty(cmask)) +- return; ++ if (mm) { ++ unsigned int cpuid; + +- cpuid = get_cpu(); +- /* check if the tlbflush needs to be sent to other CPUs */ +- broadcast = cpumask_any_but(cmask, cpuid) < nr_cpu_ids; +- if (static_branch_unlikely(&use_asid_allocator)) { +- unsigned long asid = atomic_long_read(&mm->context.id) & asid_mask; +- +- if (broadcast) { +- if (riscv_use_ipi_for_rfence()) { +- ftd.asid = asid; +- ftd.start = start; +- ftd.size = size; +- ftd.stride = stride; +- on_each_cpu_mask(cmask, +- __ipi_flush_tlb_range_asid, +- &ftd, 1); +- } else +- sbi_remote_sfence_vma_asid(cmask, +- start, size, asid); +- } else { +- local_flush_tlb_range_asid(start, size, stride, asid); +- } ++ cmask = mm_cpumask(mm); ++ if (cpumask_empty(cmask)) ++ return; ++ ++ cpuid = get_cpu(); ++ /* check if the tlbflush needs to be sent to other CPUs */ ++ broadcast = cpumask_any_but(cmask, cpuid) < nr_cpu_ids; ++ ++ if (static_branch_unlikely(&use_asid_allocator)) ++ asid = atomic_long_read(&mm->context.id) & asid_mask; + } else { +- if (broadcast) { +- if (riscv_use_ipi_for_rfence()) { +- ftd.asid = 0; +- ftd.start = start; +- ftd.size = size; +- ftd.stride = stride; +- on_each_cpu_mask(cmask, +- __ipi_flush_tlb_range, +- &ftd, 1); +- } else +- sbi_remote_sfence_vma(cmask, start, size); +- } else { +- local_flush_tlb_range(start, size, stride); +- } ++ cmask = cpu_online_mask; ++ broadcast = true; + } + +- put_cpu(); ++ if (broadcast) { ++ if (riscv_use_ipi_for_rfence()) { ++ ftd.asid = asid; ++ ftd.start = start; ++ ftd.size = size; ++ ftd.stride = stride; ++ on_each_cpu_mask(cmask, ++ __ipi_flush_tlb_range_asid, ++ &ftd, 1); ++ } else ++ sbi_remote_sfence_vma_asid(cmask, ++ start, size, asid); ++ } else { ++ local_flush_tlb_range_asid(start, size, stride, asid); ++ } ++ ++ if (mm) ++ put_cpu(); + } + + void flush_tlb_mm(struct mm_struct *mm) + { +- __flush_tlb_range(mm, 0, -1, PAGE_SIZE); ++ __flush_tlb_range(mm, 0, FLUSH_TLB_MAX_SIZE, PAGE_SIZE); ++} ++ ++void flush_tlb_mm_range(struct mm_struct *mm, ++ unsigned long start, unsigned long end, ++ unsigned int page_size) ++{ ++ __flush_tlb_range(mm, start, end - start, page_size); + } + + void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) +@@ -142,6 +143,12 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + { + __flush_tlb_range(vma->vm_mm, start, end - start, PAGE_SIZE); + } ++ ++void flush_tlb_kernel_range(unsigned long start, unsigned long end) ++{ ++ __flush_tlb_range(NULL, start, end - start, PAGE_SIZE); ++} ++ + #ifdef CONFIG_TRANSPARENT_HUGEPAGE + void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c +index 8581693e62d396..2f041b5cea970e 100644 +--- a/arch/riscv/net/bpf_jit_comp64.c ++++ b/arch/riscv/net/bpf_jit_comp64.c +@@ -516,33 +516,33 @@ static void emit_atomic(u8 rd, u8 rs, s16 off, s32 imm, bool is64, + break; + /* src_reg = atomic_fetch_(dst_reg + off16, src_reg) */ + case BPF_ADD | BPF_FETCH: +- emit(is64 ? rv_amoadd_d(rs, rs, rd, 0, 0) : +- rv_amoadd_w(rs, rs, rd, 0, 0), ctx); ++ emit(is64 ? rv_amoadd_d(rs, rs, rd, 1, 1) : ++ rv_amoadd_w(rs, rs, rd, 1, 1), ctx); + if (!is64) + emit_zext_32(rs, ctx); + break; + case BPF_AND | BPF_FETCH: +- emit(is64 ? rv_amoand_d(rs, rs, rd, 0, 0) : +- rv_amoand_w(rs, rs, rd, 0, 0), ctx); ++ emit(is64 ? rv_amoand_d(rs, rs, rd, 1, 1) : ++ rv_amoand_w(rs, rs, rd, 1, 1), ctx); + if (!is64) + emit_zext_32(rs, ctx); + break; + case BPF_OR | BPF_FETCH: +- emit(is64 ? rv_amoor_d(rs, rs, rd, 0, 0) : +- rv_amoor_w(rs, rs, rd, 0, 0), ctx); ++ emit(is64 ? rv_amoor_d(rs, rs, rd, 1, 1) : ++ rv_amoor_w(rs, rs, rd, 1, 1), ctx); + if (!is64) + emit_zext_32(rs, ctx); + break; + case BPF_XOR | BPF_FETCH: +- emit(is64 ? rv_amoxor_d(rs, rs, rd, 0, 0) : +- rv_amoxor_w(rs, rs, rd, 0, 0), ctx); ++ emit(is64 ? rv_amoxor_d(rs, rs, rd, 1, 1) : ++ rv_amoxor_w(rs, rs, rd, 1, 1), ctx); + if (!is64) + emit_zext_32(rs, ctx); + break; + /* src_reg = atomic_xchg(dst_reg + off16, src_reg); */ + case BPF_XCHG: +- emit(is64 ? rv_amoswap_d(rs, rs, rd, 0, 0) : +- rv_amoswap_w(rs, rs, rd, 0, 0), ctx); ++ emit(is64 ? rv_amoswap_d(rs, rs, rd, 1, 1) : ++ rv_amoswap_w(rs, rs, rd, 1, 1), ctx); + if (!is64) + emit_zext_32(rs, ctx); + break; +@@ -740,6 +740,9 @@ static int invoke_bpf_prog(struct bpf_tramp_link *l, int args_off, int retval_of + if (ret) + return ret; + ++ /* store prog start time */ ++ emit_mv(RV_REG_S1, RV_REG_A0, ctx); ++ + /* if (__bpf_prog_enter(prog) == 0) + * goto skip_exec_of_prog; + */ +@@ -747,9 +750,6 @@ static int invoke_bpf_prog(struct bpf_tramp_link *l, int args_off, int retval_of + /* nop reserved for conditional jump */ + emit(rv_nop(), ctx); + +- /* store prog start time */ +- emit_mv(RV_REG_S1, RV_REG_A0, ctx); +- + /* arg1: &args_off */ + emit_addi(RV_REG_A0, RV_REG_FP, -args_off, ctx); + if (!p->jited) +diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig +index ae29e4392664ad..bd4782f23f66df 100644 +--- a/arch/s390/Kconfig ++++ b/arch/s390/Kconfig +@@ -252,13 +252,13 @@ config ARCH_SUPPORTS_KEXEC + def_bool y + + config ARCH_SUPPORTS_KEXEC_FILE +- def_bool CRYPTO && CRYPTO_SHA256 && CRYPTO_SHA256_S390 ++ def_bool y + + config ARCH_SUPPORTS_KEXEC_SIG + def_bool MODULE_SIG_FORMAT + + config ARCH_SUPPORTS_KEXEC_PURGATORY +- def_bool KEXEC_FILE ++ def_bool y + + config ARCH_SUPPORTS_CRASH_DUMP + def_bool y +diff --git a/arch/s390/Makefile b/arch/s390/Makefile +index a53a36ee0731bb..73873e4516866a 100644 +--- a/arch/s390/Makefile ++++ b/arch/s390/Makefile +@@ -138,9 +138,6 @@ bzImage: vmlinux + zfcpdump: + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + +-vdso_install: +- $(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso64 $@ +- + archheaders: + $(Q)$(MAKE) $(build)=$(syscalls) uapi + +@@ -160,6 +157,9 @@ vdso_prepare: prepare0 + $(if $(CONFIG_COMPAT),$(Q)$(MAKE) \ + $(build)=arch/s390/kernel/vdso32 include/generated/vdso32-offsets.h) + ++vdso-install-y += arch/s390/kernel/vdso64/vdso64.so.dbg ++vdso-install-$(CONFIG_COMPAT) += arch/s390/kernel/vdso32/vdso32.so.dbg ++ + ifdef CONFIG_EXPOLINE_EXTERN + modules_prepare: expoline_prepare + expoline_prepare: scripts +diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c +index 7b7521762633f9..4230144645bc5d 100644 +--- a/arch/s390/boot/ipl_parm.c ++++ b/arch/s390/boot/ipl_parm.c +@@ -272,7 +272,7 @@ void parse_boot_command_line(void) + memory_limit = round_down(memparse(val, NULL), PAGE_SIZE); + + if (!strcmp(param, "vmalloc") && val) { +- vmalloc_size = round_up(memparse(val, NULL), PAGE_SIZE); ++ vmalloc_size = round_up(memparse(val, NULL), _SEGMENT_SIZE); + vmalloc_size_set = 1; + } + +diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c +index d3e48bd9c3944f..655bbcff81ffda 100644 +--- a/arch/s390/boot/startup.c ++++ b/arch/s390/boot/startup.c +@@ -31,7 +31,6 @@ unsigned long __bootdata_preserved(max_mappable); + unsigned long __bootdata(ident_map_size); + + u64 __bootdata_preserved(stfle_fac_list[16]); +-u64 __bootdata_preserved(alt_stfle_fac_list[16]); + struct oldmem_data __bootdata_preserved(oldmem_data); + + struct machine_info machine; +@@ -212,7 +211,8 @@ static unsigned long setup_kernel_memory_layout(void) + VMALLOC_END = MODULES_VADDR; + + /* allow vmalloc area to occupy up to about 1/2 of the rest virtual space left */ +- vmalloc_size = min(vmalloc_size, round_down(VMALLOC_END / 2, _REGION3_SIZE)); ++ vsize = round_down(VMALLOC_END / 2, _SEGMENT_SIZE); ++ vmalloc_size = min(vmalloc_size, vsize); + VMALLOC_START = VMALLOC_END - vmalloc_size; + + /* split remaining virtual space between 1:1 mapping & vmemmap array */ +diff --git a/arch/s390/boot/vmem.c b/arch/s390/boot/vmem.c +index 442a74f113cbfd..14e1a73ffcfe63 100644 +--- a/arch/s390/boot/vmem.c ++++ b/arch/s390/boot/vmem.c +@@ -360,7 +360,7 @@ static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long e + } + pmd = boot_crst_alloc(_SEGMENT_ENTRY_EMPTY); + pud_populate(&init_mm, pud, pmd); +- } else if (pud_large(*pud)) { ++ } else if (pud_leaf(*pud)) { + continue; + } + pgtable_pmd_populate(pud, addr, next, mode); +diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig +index 438cd92e60801b..dd06086293106e 100644 +--- a/arch/s390/configs/debug_defconfig ++++ b/arch/s390/configs/debug_defconfig +@@ -834,7 +834,6 @@ CONFIG_DEBUG_IRQFLAGS=y + CONFIG_DEBUG_LIST=y + CONFIG_DEBUG_SG=y + CONFIG_DEBUG_NOTIFIERS=y +-CONFIG_DEBUG_CREDENTIALS=y + CONFIG_RCU_TORTURE_TEST=m + CONFIG_RCU_REF_SCALE_TEST=m + CONFIG_RCU_CPU_STALL_TIMEOUT=300 +diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c +index c773820e4af90a..c6fe5405de4a4c 100644 +--- a/arch/s390/crypto/aes_s390.c ++++ b/arch/s390/crypto/aes_s390.c +@@ -597,7 +597,9 @@ static int ctr_aes_crypt(struct skcipher_request *req) + * final block may be < AES_BLOCK_SIZE, copy only nbytes + */ + if (nbytes) { +- cpacf_kmctr(sctx->fc, sctx->key, buf, walk.src.virt.addr, ++ memset(buf, 0, AES_BLOCK_SIZE); ++ memcpy(buf, walk.src.virt.addr, nbytes); ++ cpacf_kmctr(sctx->fc, sctx->key, buf, buf, + AES_BLOCK_SIZE, walk.iv); + memcpy(walk.dst.virt.addr, buf, nbytes); + crypto_inc(walk.iv, AES_BLOCK_SIZE); +diff --git a/arch/s390/crypto/paes_s390.c b/arch/s390/crypto/paes_s390.c +index 8b541e44151d4d..55ee5567a5ea92 100644 +--- a/arch/s390/crypto/paes_s390.c ++++ b/arch/s390/crypto/paes_s390.c +@@ -693,9 +693,11 @@ static int ctr_paes_crypt(struct skcipher_request *req) + * final block may be < AES_BLOCK_SIZE, copy only nbytes + */ + if (nbytes) { ++ memset(buf, 0, AES_BLOCK_SIZE); ++ memcpy(buf, walk.src.virt.addr, nbytes); + while (1) { + if (cpacf_kmctr(ctx->fc, ¶m, buf, +- walk.src.virt.addr, AES_BLOCK_SIZE, ++ buf, AES_BLOCK_SIZE, + walk.iv) == AES_BLOCK_SIZE) + break; + if (__paes_convert_key(ctx)) +diff --git a/arch/s390/include/asm/cpacf.h b/arch/s390/include/asm/cpacf.h +index b378e2b57ad875..c786538e397c08 100644 +--- a/arch/s390/include/asm/cpacf.h ++++ b/arch/s390/include/asm/cpacf.h +@@ -166,28 +166,86 @@ + + typedef struct { unsigned char bytes[16]; } cpacf_mask_t; + +-/** +- * cpacf_query() - check if a specific CPACF function is available +- * @opcode: the opcode of the crypto instruction +- * @func: the function code to test for +- * +- * Executes the query function for the given crypto instruction @opcode +- * and checks if @func is available +- * +- * Returns 1 if @func is available for @opcode, 0 otherwise ++/* ++ * Prototype for a not existing function to produce a link ++ * error if __cpacf_query() or __cpacf_check_opcode() is used ++ * with an invalid compile time const opcode. + */ +-static __always_inline void __cpacf_query(unsigned int opcode, cpacf_mask_t *mask) ++void __cpacf_bad_opcode(void); ++ ++static __always_inline void __cpacf_query_rre(u32 opc, u8 r1, u8 r2, ++ cpacf_mask_t *mask) + { + asm volatile( +- " lghi 0,0\n" /* query function */ +- " lgr 1,%[mask]\n" +- " spm 0\n" /* pckmo doesn't change the cc */ +- /* Parameter regs are ignored, but must be nonzero and unique */ +- "0: .insn rrf,%[opc] << 16,2,4,6,0\n" +- " brc 1,0b\n" /* handle partial completion */ +- : "=m" (*mask) +- : [mask] "d" ((unsigned long)mask), [opc] "i" (opcode) +- : "cc", "0", "1"); ++ " la %%r1,%[mask]\n" ++ " xgr %%r0,%%r0\n" ++ " .insn rre,%[opc] << 16,%[r1],%[r2]\n" ++ : [mask] "=R" (*mask) ++ : [opc] "i" (opc), ++ [r1] "i" (r1), [r2] "i" (r2) ++ : "cc", "r0", "r1"); ++} ++ ++static __always_inline void __cpacf_query_rrf(u32 opc, ++ u8 r1, u8 r2, u8 r3, u8 m4, ++ cpacf_mask_t *mask) ++{ ++ asm volatile( ++ " la %%r1,%[mask]\n" ++ " xgr %%r0,%%r0\n" ++ " .insn rrf,%[opc] << 16,%[r1],%[r2],%[r3],%[m4]\n" ++ : [mask] "=R" (*mask) ++ : [opc] "i" (opc), [r1] "i" (r1), [r2] "i" (r2), ++ [r3] "i" (r3), [m4] "i" (m4) ++ : "cc", "r0", "r1"); ++} ++ ++static __always_inline void __cpacf_query(unsigned int opcode, ++ cpacf_mask_t *mask) ++{ ++ switch (opcode) { ++ case CPACF_KDSA: ++ __cpacf_query_rre(CPACF_KDSA, 0, 2, mask); ++ break; ++ case CPACF_KIMD: ++ __cpacf_query_rre(CPACF_KIMD, 0, 2, mask); ++ break; ++ case CPACF_KLMD: ++ __cpacf_query_rre(CPACF_KLMD, 0, 2, mask); ++ break; ++ case CPACF_KM: ++ __cpacf_query_rre(CPACF_KM, 2, 4, mask); ++ break; ++ case CPACF_KMA: ++ __cpacf_query_rrf(CPACF_KMA, 2, 4, 6, 0, mask); ++ break; ++ case CPACF_KMAC: ++ __cpacf_query_rre(CPACF_KMAC, 0, 2, mask); ++ break; ++ case CPACF_KMC: ++ __cpacf_query_rre(CPACF_KMC, 2, 4, mask); ++ break; ++ case CPACF_KMCTR: ++ __cpacf_query_rrf(CPACF_KMCTR, 2, 4, 6, 0, mask); ++ break; ++ case CPACF_KMF: ++ __cpacf_query_rre(CPACF_KMF, 2, 4, mask); ++ break; ++ case CPACF_KMO: ++ __cpacf_query_rre(CPACF_KMO, 2, 4, mask); ++ break; ++ case CPACF_PCC: ++ __cpacf_query_rre(CPACF_PCC, 0, 0, mask); ++ break; ++ case CPACF_PCKMO: ++ __cpacf_query_rre(CPACF_PCKMO, 0, 0, mask); ++ break; ++ case CPACF_PRNO: ++ __cpacf_query_rre(CPACF_PRNO, 2, 4, mask); ++ break; ++ default: ++ __cpacf_bad_opcode(); ++ } + } + + static __always_inline int __cpacf_check_opcode(unsigned int opcode) +@@ -211,10 +269,21 @@ static __always_inline int __cpacf_check_opcode(unsigned int opcode) + case CPACF_KMA: + return test_facility(146); /* check for MSA8 */ + default: +- BUG(); ++ __cpacf_bad_opcode(); ++ return 0; + } + } + ++/** ++ * cpacf_query() - check if a specific CPACF function is available ++ * @opcode: the opcode of the crypto instruction ++ * @func: the function code to test for ++ * ++ * Executes the query function for the given crypto instruction @opcode ++ * and checks if @func is available ++ * ++ * Returns 1 if @func is available for @opcode, 0 otherwise ++ */ + static __always_inline int cpacf_query(unsigned int opcode, cpacf_mask_t *mask) + { + if (__cpacf_check_opcode(opcode)) { +diff --git a/arch/s390/include/asm/dwarf.h b/arch/s390/include/asm/dwarf.h +index 4f21ae561e4ddc..390906b8e386e6 100644 +--- a/arch/s390/include/asm/dwarf.h ++++ b/arch/s390/include/asm/dwarf.h +@@ -9,6 +9,7 @@ + #define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset + #define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset + #define CFI_RESTORE .cfi_restore ++#define CFI_REL_OFFSET .cfi_rel_offset + + #ifdef CONFIG_AS_CFI_VAL_OFFSET + #define CFI_VAL_OFFSET .cfi_val_offset +diff --git a/arch/s390/include/asm/entry-common.h b/arch/s390/include/asm/entry-common.h +index fdd319a622b065..622cd08e5f50fd 100644 +--- a/arch/s390/include/asm/entry-common.h ++++ b/arch/s390/include/asm/entry-common.h +@@ -55,7 +55,7 @@ static __always_inline void arch_exit_to_user_mode(void) + static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs, + unsigned long ti_work) + { +- choose_random_kstack_offset(get_tod_clock_fast() & 0xff); ++ choose_random_kstack_offset(get_tod_clock_fast()); + } + + #define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare +diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h +index 94b6919026dfb8..953d42205ea83e 100644 +--- a/arch/s390/include/asm/facility.h ++++ b/arch/s390/include/asm/facility.h +@@ -60,8 +60,10 @@ static inline int test_facility(unsigned long nr) + unsigned long facilities_als[] = { FACILITIES_ALS }; + + if (__builtin_constant_p(nr) && nr < sizeof(facilities_als) * 8) { +- if (__test_facility(nr, &facilities_als)) +- return 1; ++ if (__test_facility(nr, &facilities_als)) { ++ if (!__is_defined(__DECOMPRESSOR)) ++ return 1; ++ } + } + return __test_facility(nr, &stfle_fac_list); + } +diff --git a/arch/s390/include/asm/fpu/api.h b/arch/s390/include/asm/fpu/api.h +index b714ed0ef68853..9acf48e53a87fb 100644 +--- a/arch/s390/include/asm/fpu/api.h ++++ b/arch/s390/include/asm/fpu/api.h +@@ -79,7 +79,7 @@ static inline int test_fp_ctl(u32 fpc) + #define KERNEL_VXR_HIGH (KERNEL_VXR_V16V23|KERNEL_VXR_V24V31) + + #define KERNEL_VXR (KERNEL_VXR_LOW|KERNEL_VXR_HIGH) +-#define KERNEL_FPR (KERNEL_FPC|KERNEL_VXR_V0V7) ++#define KERNEL_FPR (KERNEL_FPC|KERNEL_VXR_LOW) + + struct kernel_fpu; + +diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h +index 5cc46e0dde620d..9725586f42597c 100644 +--- a/arch/s390/include/asm/gmap.h ++++ b/arch/s390/include/asm/gmap.h +@@ -146,7 +146,7 @@ int gmap_mprotect_notify(struct gmap *, unsigned long start, + + void gmap_sync_dirty_log_pmd(struct gmap *gmap, unsigned long dirty_bitmap[4], + unsigned long gaddr, unsigned long vmaddr); +-int gmap_mark_unmergeable(void); ++int s390_disable_cow_sharing(void); + void s390_unlist_old_asce(struct gmap *gmap); + int s390_replace_asce(struct gmap *gmap); + void s390_uv_destroy_pfns(unsigned long count, unsigned long *pfns); +diff --git a/arch/s390/include/asm/io.h b/arch/s390/include/asm/io.h +index 4453ad7c11aced..36a9c7740c437a 100644 +--- a/arch/s390/include/asm/io.h ++++ b/arch/s390/include/asm/io.h +@@ -16,8 +16,10 @@ + #include + + #define xlate_dev_mem_ptr xlate_dev_mem_ptr ++#define kc_xlate_dev_mem_ptr xlate_dev_mem_ptr + void *xlate_dev_mem_ptr(phys_addr_t phys); + #define unxlate_dev_mem_ptr unxlate_dev_mem_ptr ++#define kc_unxlate_dev_mem_ptr unxlate_dev_mem_ptr + void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr); + + #define IO_SPACE_LIMIT 0 +diff --git a/arch/s390/include/asm/irq_work.h b/arch/s390/include/asm/irq_work.h +index 603783766d0abb..f00c9f610d5a8e 100644 +--- a/arch/s390/include/asm/irq_work.h ++++ b/arch/s390/include/asm/irq_work.h +@@ -7,6 +7,4 @@ static inline bool arch_irq_work_has_interrupt(void) + return true; + } + +-void arch_irq_work_raise(void); +- + #endif /* _ASM_S390_IRQ_WORK_H */ +diff --git a/arch/s390/include/asm/jump_label.h b/arch/s390/include/asm/jump_label.h +index 895f774bbcc553..bf78cf381dfcda 100644 +--- a/arch/s390/include/asm/jump_label.h ++++ b/arch/s390/include/asm/jump_label.h +@@ -25,7 +25,7 @@ + */ + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) + { +- asm_volatile_goto("0: brcl 0,%l[label]\n" ++ asm goto("0: brcl 0,%l[label]\n" + ".pushsection __jump_table,\"aw\"\n" + ".balign 8\n" + ".long 0b-.,%l[label]-.\n" +@@ -39,7 +39,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran + + static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) + { +- asm_volatile_goto("0: brcl 15,%l[label]\n" ++ asm goto("0: brcl 15,%l[label]\n" + ".pushsection __jump_table,\"aw\"\n" + ".balign 8\n" + ".long 0b-.,%l[label]-.\n" +diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h +index 427f9528a7b694..b039881c277a79 100644 +--- a/arch/s390/include/asm/kvm_host.h ++++ b/arch/s390/include/asm/kvm_host.h +@@ -427,6 +427,7 @@ struct kvm_vcpu_stat { + u64 instruction_io_other; + u64 instruction_lpsw; + u64 instruction_lpswe; ++ u64 instruction_lpswey; + u64 instruction_pfmf; + u64 instruction_ptff; + u64 instruction_sck; +@@ -777,6 +778,13 @@ struct kvm_vm_stat { + u64 inject_service_signal; + u64 inject_virtio; + u64 aen_forward; ++ u64 gmap_shadow_create; ++ u64 gmap_shadow_reuse; ++ u64 gmap_shadow_r1_entry; ++ u64 gmap_shadow_r2_entry; ++ u64 gmap_shadow_r3_entry; ++ u64 gmap_shadow_sg_entry; ++ u64 gmap_shadow_pg_entry; + }; + + struct kvm_arch_memory_slot { +diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h +index 829d68e2c68582..a9e5db0f2836e4 100644 +--- a/arch/s390/include/asm/mmu.h ++++ b/arch/s390/include/asm/mmu.h +@@ -33,6 +33,11 @@ typedef struct { + unsigned int uses_skeys:1; + /* The mmu context uses CMM. */ + unsigned int uses_cmm:1; ++ /* ++ * The mmu context allows COW-sharing of memory pages (KSM, zeropage). ++ * Note that COW-sharing during fork() is currently always allowed. ++ */ ++ unsigned int allow_cow_sharing:1; + /* The gmaps associated with this context are allowed to use huge pages. */ + unsigned int allow_gmap_hpage_1m:1; + } mm_context_t; +diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h +index 2a38af5a00c2df..8df6d09e9ca871 100644 +--- a/arch/s390/include/asm/mmu_context.h ++++ b/arch/s390/include/asm/mmu_context.h +@@ -36,6 +36,7 @@ static inline int init_new_context(struct task_struct *tsk, + mm->context.has_pgste = 0; + mm->context.uses_skeys = 0; + mm->context.uses_cmm = 0; ++ mm->context.allow_cow_sharing = 1; + mm->context.allow_gmap_hpage_1m = 0; + #endif + switch (mm->context.asce_limit) { +diff --git a/arch/s390/include/asm/pci_io.h b/arch/s390/include/asm/pci_io.h +index 287bb88f76986e..2686bee800e3d5 100644 +--- a/arch/s390/include/asm/pci_io.h ++++ b/arch/s390/include/asm/pci_io.h +@@ -11,6 +11,8 @@ + /* I/O size constraints */ + #define ZPCI_MAX_READ_SIZE 8 + #define ZPCI_MAX_WRITE_SIZE 128 ++#define ZPCI_BOUNDARY_SIZE (1 << 12) ++#define ZPCI_BOUNDARY_MASK (ZPCI_BOUNDARY_SIZE - 1) + + /* I/O Map */ + #define ZPCI_IOMAP_SHIFT 48 +@@ -125,16 +127,18 @@ static inline int zpci_read_single(void *dst, const volatile void __iomem *src, + int zpci_write_block(volatile void __iomem *dst, const void *src, + unsigned long len); + +-static inline u8 zpci_get_max_write_size(u64 src, u64 dst, int len, int max) ++static inline int zpci_get_max_io_size(u64 src, u64 dst, int len, int max) + { +- int count = len > max ? max : len, size = 1; ++ int offset = dst & ZPCI_BOUNDARY_MASK; ++ int size; + +- while (!(src & 0x1) && !(dst & 0x1) && ((size << 1) <= count)) { +- dst = dst >> 1; +- src = src >> 1; +- size = size << 1; +- } +- return size; ++ size = min3(len, ZPCI_BOUNDARY_SIZE - offset, max); ++ if (IS_ALIGNED(src, 8) && IS_ALIGNED(dst, 8) && IS_ALIGNED(size, 8)) ++ return size; ++ ++ if (size >= 8) ++ return 8; ++ return rounddown_pow_of_two(size); + } + + static inline int zpci_memcpy_fromio(void *dst, +@@ -144,9 +148,9 @@ static inline int zpci_memcpy_fromio(void *dst, + int size, rc = 0; + + while (n > 0) { +- size = zpci_get_max_write_size((u64 __force) src, +- (u64) dst, n, +- ZPCI_MAX_READ_SIZE); ++ size = zpci_get_max_io_size((u64 __force) src, ++ (u64) dst, n, ++ ZPCI_MAX_READ_SIZE); + rc = zpci_read_single(dst, src, size); + if (rc) + break; +@@ -166,9 +170,9 @@ static inline int zpci_memcpy_toio(volatile void __iomem *dst, + return -EINVAL; + + while (n > 0) { +- size = zpci_get_max_write_size((u64 __force) dst, +- (u64) src, n, +- ZPCI_MAX_WRITE_SIZE); ++ size = zpci_get_max_io_size((u64 __force) dst, ++ (u64) src, n, ++ ZPCI_MAX_WRITE_SIZE); + if (size > 8) /* main path */ + rc = zpci_write_block(dst, src, size); + else +diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h +index fb3ee7758b7650..da2e91b5b19250 100644 +--- a/arch/s390/include/asm/pgtable.h ++++ b/arch/s390/include/asm/pgtable.h +@@ -565,10 +565,20 @@ static inline pud_t set_pud_bit(pud_t pud, pgprot_t prot) + } + + /* +- * In the case that a guest uses storage keys +- * faults should no longer be backed by zero pages ++ * As soon as the guest uses storage keys or enables PV, we deduplicate all ++ * mapped shared zeropages and prevent new shared zeropages from getting ++ * mapped. + */ +-#define mm_forbids_zeropage mm_has_pgste ++#define mm_forbids_zeropage mm_forbids_zeropage ++static inline int mm_forbids_zeropage(struct mm_struct *mm) ++{ ++#ifdef CONFIG_PGSTE ++ if (!mm->context.allow_cow_sharing) ++ return 1; ++#endif ++ return 0; ++} ++ + static inline int mm_uses_skeys(struct mm_struct *mm) + { + #ifdef CONFIG_PGSTE +@@ -729,7 +739,7 @@ static inline int pud_bad(pud_t pud) + { + unsigned long type = pud_val(pud) & _REGION_ENTRY_TYPE_MASK; + +- if (type > _REGION_ENTRY_TYPE_R3 || pud_large(pud)) ++ if (type > _REGION_ENTRY_TYPE_R3 || pud_leaf(pud)) + return 1; + if (type < _REGION_ENTRY_TYPE_R3) + return 0; +@@ -1396,7 +1406,7 @@ static inline unsigned long pud_deref(pud_t pud) + unsigned long origin_mask; + + origin_mask = _REGION_ENTRY_ORIGIN; +- if (pud_large(pud)) ++ if (pud_leaf(pud)) + origin_mask = _REGION3_ENTRY_ORIGIN_LARGE; + return (unsigned long)__va(pud_val(pud) & origin_mask); + } +@@ -1764,8 +1774,10 @@ static inline pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma, + static inline pmd_t pmdp_invalidate(struct vm_area_struct *vma, + unsigned long addr, pmd_t *pmdp) + { +- pmd_t pmd = __pmd(pmd_val(*pmdp) | _SEGMENT_ENTRY_INVALID); ++ pmd_t pmd; + ++ VM_WARN_ON_ONCE(!pmd_present(*pmdp)); ++ pmd = __pmd(pmd_val(*pmdp) | _SEGMENT_ENTRY_INVALID); + return pmdp_xchg_direct(vma->vm_mm, addr, pmdp, pmd); + } + +diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h +index dc17896a001a92..e7338ed540d8fc 100644 +--- a/arch/s390/include/asm/processor.h ++++ b/arch/s390/include/asm/processor.h +@@ -308,8 +308,8 @@ static inline void __load_psw(psw_t psw) + */ + static __always_inline void __load_psw_mask(unsigned long mask) + { ++ psw_t psw __uninitialized; + unsigned long addr; +- psw_t psw; + + psw.mask = mask; + +diff --git a/arch/s390/include/asm/syscall_wrapper.h b/arch/s390/include/asm/syscall_wrapper.h +index 9286430fe7290b..35c1d1b860d88a 100644 +--- a/arch/s390/include/asm/syscall_wrapper.h ++++ b/arch/s390/include/asm/syscall_wrapper.h +@@ -63,10 +63,6 @@ + cond_syscall(__s390x_sys_##name); \ + cond_syscall(__s390_sys_##name) + +-#define SYS_NI(name) \ +- SYSCALL_ALIAS(__s390x_sys_##name, sys_ni_posix_timers); \ +- SYSCALL_ALIAS(__s390_sys_##name, sys_ni_posix_timers) +- + #define COMPAT_SYSCALL_DEFINEx(x, name, ...) \ + long __s390_compat_sys##name(struct pt_regs *regs); \ + ALLOW_ERROR_INJECTION(__s390_compat_sys##name, ERRNO); \ +@@ -85,15 +81,11 @@ + + /* + * As some compat syscalls may not be implemented, we need to expand +- * COND_SYSCALL_COMPAT in kernel/sys_ni.c and COMPAT_SYS_NI in +- * kernel/time/posix-stubs.c to cover this case as well. ++ * COND_SYSCALL_COMPAT in kernel/sys_ni.c to cover this case as well. + */ + #define COND_SYSCALL_COMPAT(name) \ + cond_syscall(__s390_compat_sys_##name) + +-#define COMPAT_SYS_NI(name) \ +- SYSCALL_ALIAS(__s390_compat_sys_##name, sys_ni_posix_timers) +- + #define __S390_SYS_STUBx(x, name, ...) \ + long __s390_sys##name(struct pt_regs *regs); \ + ALLOW_ERROR_INJECTION(__s390_sys##name, ERRNO); \ +@@ -124,9 +116,6 @@ + #define COND_SYSCALL(name) \ + cond_syscall(__s390x_sys_##name) + +-#define SYS_NI(name) \ +- SYSCALL_ALIAS(__s390x_sys_##name, sys_ni_posix_timers) +- + #define __S390_SYS_STUBx(x, fullname, name, ...) + + #endif /* CONFIG_COMPAT */ +diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h +index 0e7bd3873907f7..b2e2f9a4163c5c 100644 +--- a/arch/s390/include/asm/uv.h ++++ b/arch/s390/include/asm/uv.h +@@ -442,7 +442,10 @@ static inline int share(unsigned long addr, u16 cmd) + + if (!uv_call(0, (u64)&uvcb)) + return 0; +- return -EINVAL; ++ pr_err("%s UVC failed (rc: 0x%x, rrc: 0x%x), possible hypervisor bug.\n", ++ uvcb.header.cmd == UVC_CMD_SET_SHARED_ACCESS ? "Share" : "Unshare", ++ uvcb.header.rc, uvcb.header.rrc); ++ panic("System security cannot be guaranteed unless the system panics now.\n"); + } + + /* +diff --git a/arch/s390/kernel/cache.c b/arch/s390/kernel/cache.c +index 56254fa06f9906..4f266903022091 100644 +--- a/arch/s390/kernel/cache.c ++++ b/arch/s390/kernel/cache.c +@@ -166,5 +166,6 @@ int populate_cache_leaves(unsigned int cpu) + ci_leaf_init(this_leaf++, pvt, ctype, level, cpu); + } + } ++ this_cpu_ci->cpu_map_populated = true; + return 0; + } +diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c +index 442ce0489e1a1e..3a54733e4fc65b 100644 +--- a/arch/s390/kernel/early.c ++++ b/arch/s390/kernel/early.c +@@ -258,15 +258,9 @@ static inline void save_vector_registers(void) + #endif + } + +-static inline void setup_control_registers(void) ++static inline void setup_low_address_protection(void) + { +- unsigned long reg; +- +- __ctl_store(reg, 0, 0); +- reg |= CR0_LOW_ADDRESS_PROTECTION; +- reg |= CR0_EMERGENCY_SIGNAL_SUBMASK; +- reg |= CR0_EXTERNAL_CALL_SUBMASK; +- __ctl_load(reg, 0, 0); ++ __ctl_set_bit(0, 28); + } + + static inline void setup_access_registers(void) +@@ -314,7 +308,7 @@ void __init startup_init(void) + save_vector_registers(); + setup_topology(); + sclp_early_detect(); +- setup_control_registers(); ++ setup_low_address_protection(); + setup_access_registers(); + lockdep_on(); + } +diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S +index 49a11f6dd7ae9a..26c08ee8774077 100644 +--- a/arch/s390/kernel/entry.S ++++ b/arch/s390/kernel/entry.S +@@ -653,6 +653,7 @@ SYM_DATA_START_LOCAL(daton_psw) + SYM_DATA_END(daton_psw) + + .section .rodata, "a" ++ .balign 8 + #define SYSCALL(esame,emu) .quad __s390x_ ## esame + SYM_DATA_START(sys_call_table) + #include "asm/syscall_table.h" +diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c +index c46381ea04ecb1..7f6f8c438c2654 100644 +--- a/arch/s390/kernel/ftrace.c ++++ b/arch/s390/kernel/ftrace.c +@@ -296,6 +296,9 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, + struct kprobe *p; + int bit; + ++ if (unlikely(kprobe_ftrace_disabled)) ++ return; ++ + bit = ftrace_test_recursion_trylock(ip, parent_ip); + if (bit < 0) + return; +diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c +index 05e51666db033f..a3d3cb39b021a7 100644 +--- a/arch/s390/kernel/ipl.c ++++ b/arch/s390/kernel/ipl.c +@@ -666,6 +666,7 @@ static int __init ipl_init(void) + &ipl_ccw_attr_group_lpar); + break; + case IPL_TYPE_ECKD: ++ case IPL_TYPE_ECKD_DUMP: + rc = sysfs_create_group(&ipl_kset->kobj, &ipl_eckd_attr_group); + break; + case IPL_TYPE_FCP: +@@ -961,8 +962,8 @@ static ssize_t reipl_nvme_scpdata_write(struct file *filp, struct kobject *kobj, + scpdata_len += padding; + } + +- reipl_block_nvme->hdr.len = IPL_BP_FCP_LEN + scpdata_len; +- reipl_block_nvme->nvme.len = IPL_BP0_FCP_LEN + scpdata_len; ++ reipl_block_nvme->hdr.len = IPL_BP_NVME_LEN + scpdata_len; ++ reipl_block_nvme->nvme.len = IPL_BP0_NVME_LEN + scpdata_len; + reipl_block_nvme->nvme.scp_data_len = scpdata_len; + + return count; +@@ -1857,9 +1858,9 @@ static int __init dump_nvme_init(void) + } + dump_block_nvme->hdr.len = IPL_BP_NVME_LEN; + dump_block_nvme->hdr.version = IPL_PARM_BLOCK_VERSION; +- dump_block_nvme->fcp.len = IPL_BP0_NVME_LEN; +- dump_block_nvme->fcp.pbt = IPL_PBT_NVME; +- dump_block_nvme->fcp.opt = IPL_PB0_NVME_OPT_DUMP; ++ dump_block_nvme->nvme.len = IPL_BP0_NVME_LEN; ++ dump_block_nvme->nvme.pbt = IPL_PBT_NVME; ++ dump_block_nvme->nvme.opt = IPL_PB0_NVME_OPT_DUMP; + dump_capabilities |= DUMP_TYPE_NVME; + return 0; + } +diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c +index 850c11ea631a6b..5466e7bada03d2 100644 +--- a/arch/s390/kernel/perf_cpum_cf.c ++++ b/arch/s390/kernel/perf_cpum_cf.c +@@ -556,25 +556,31 @@ static int cfdiag_diffctr(struct cpu_cf_events *cpuhw, unsigned long auth) + struct cf_trailer_entry *trailer_start, *trailer_stop; + struct cf_ctrset_entry *ctrstart, *ctrstop; + size_t offset = 0; ++ int i; + +- auth &= (1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1; +- do { ++ for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { + ctrstart = (struct cf_ctrset_entry *)(cpuhw->start + offset); + ctrstop = (struct cf_ctrset_entry *)(cpuhw->stop + offset); + ++ /* Counter set not authorized */ ++ if (!(auth & cpumf_ctr_ctl[i])) ++ continue; ++ /* Counter set size zero was not saved */ ++ if (!cpum_cf_read_setsize(i)) ++ continue; ++ + if (memcmp(ctrstop, ctrstart, sizeof(*ctrstop))) { + pr_err_once("cpum_cf_diag counter set compare error " + "in set %i\n", ctrstart->set); + return 0; + } +- auth &= ~cpumf_ctr_ctl[ctrstart->set]; + if (ctrstart->def == CF_DIAG_CTRSET_DEF) { + cfdiag_diffctrset((u64 *)(ctrstart + 1), + (u64 *)(ctrstop + 1), ctrstart->ctr); + offset += ctrstart->ctr * sizeof(u64) + + sizeof(*ctrstart); + } +- } while (ctrstart->def && auth); ++ } + + /* Save time_stamp from start of event in stop's trailer */ + trailer_start = (struct cf_trailer_entry *)(cpuhw->start + offset); +diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c +index 06efad5b4f931b..a3169193775f71 100644 +--- a/arch/s390/kernel/perf_cpum_sf.c ++++ b/arch/s390/kernel/perf_cpum_sf.c +@@ -1463,7 +1463,7 @@ static int aux_output_begin(struct perf_output_handle *handle, + unsigned long range, i, range_scan, idx, head, base, offset; + struct hws_trailer_entry *te; + +- if (WARN_ON_ONCE(handle->head & ~PAGE_MASK)) ++ if (handle->head & ~PAGE_MASK) + return -EINVAL; + + aux->head = handle->head >> PAGE_SHIFT; +@@ -1642,7 +1642,7 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw) + unsigned long num_sdb; + + aux = perf_get_aux(handle); +- if (WARN_ON_ONCE(!aux)) ++ if (!aux) + return; + + /* Inform user space new data arrived */ +@@ -1661,7 +1661,7 @@ static void hw_collect_aux(struct cpu_hw_sf *cpuhw) + num_sdb); + break; + } +- if (WARN_ON_ONCE(!aux)) ++ if (!aux) + return; + + /* Update head and alert_mark to new position */ +@@ -1896,12 +1896,8 @@ static void cpumsf_pmu_start(struct perf_event *event, int flags) + { + struct cpu_hw_sf *cpuhw = this_cpu_ptr(&cpu_hw_sf); + +- if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) ++ if (!(event->hw.state & PERF_HES_STOPPED)) + return; +- +- if (flags & PERF_EF_RELOAD) +- WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE)); +- + perf_pmu_disable(event->pmu); + event->hw.state = 0; + cpuhw->lsctl.cs = 1; +diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c +index fe7d1774ded184..4a4e914c283c80 100644 +--- a/arch/s390/kernel/perf_pai_crypto.c ++++ b/arch/s390/kernel/perf_pai_crypto.c +@@ -646,7 +646,7 @@ static int __init attr_event_init(void) + for (i = 0; i < ARRAY_SIZE(paicrypt_ctrnames); i++) { + ret = attr_event_init_one(attrs, i); + if (ret) { +- attr_event_free(attrs, i - 1); ++ attr_event_free(attrs, i); + return ret; + } + } +diff --git a/arch/s390/kernel/perf_pai_ext.c b/arch/s390/kernel/perf_pai_ext.c +index c57c1a203256fb..b5febe22d05464 100644 +--- a/arch/s390/kernel/perf_pai_ext.c ++++ b/arch/s390/kernel/perf_pai_ext.c +@@ -607,7 +607,7 @@ static int __init attr_event_init(void) + for (i = 0; i < ARRAY_SIZE(paiext_ctrnames); i++) { + ret = attr_event_init_one(attrs, i); + if (ret) { +- attr_event_free(attrs, i - 1); ++ attr_event_free(attrs, i); + return ret; + } + } +diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c +index ea244a73efad9d..512b8147375935 100644 +--- a/arch/s390/kernel/ptrace.c ++++ b/arch/s390/kernel/ptrace.c +@@ -385,6 +385,7 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) + /* + * floating point control reg. is in the thread structure + */ ++ save_fpu_regs(); + if ((unsigned int) data != 0 || + test_fp_ctl(data >> (BITS_PER_LONG - 32))) + return -EINVAL; +@@ -741,6 +742,7 @@ static int __poke_user_compat(struct task_struct *child, + /* + * floating point control reg. is in the thread structure + */ ++ save_fpu_regs(); + if (test_fp_ctl(tmp)) + return -EINVAL; + child->thread.fpu.fpc = data; +@@ -904,9 +906,7 @@ static int s390_fpregs_set(struct task_struct *target, + int rc = 0; + freg_t fprs[__NUM_FPRS]; + +- if (target == current) +- save_fpu_regs(); +- ++ save_fpu_regs(); + if (MACHINE_HAS_VX) + convert_vx_to_fp(fprs, target->thread.fpu.vxrs); + else +diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c +index de6ad0fb2328a1..d48c7afe97e628 100644 +--- a/arch/s390/kernel/setup.c ++++ b/arch/s390/kernel/setup.c +@@ -155,7 +155,7 @@ unsigned int __bootdata_preserved(zlib_dfltcc_support); + EXPORT_SYMBOL(zlib_dfltcc_support); + u64 __bootdata_preserved(stfle_fac_list[16]); + EXPORT_SYMBOL(stfle_fac_list); +-u64 __bootdata_preserved(alt_stfle_fac_list[16]); ++u64 alt_stfle_fac_list[16]; + struct oldmem_data __bootdata_preserved(oldmem_data); + + unsigned long VMALLOC_START; +diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c +index a4edb7ea66ea76..c63be2efd68952 100644 +--- a/arch/s390/kernel/smp.c ++++ b/arch/s390/kernel/smp.c +@@ -1013,12 +1013,12 @@ void __init smp_fill_possible_mask(void) + + void __init smp_prepare_cpus(unsigned int max_cpus) + { +- /* request the 0x1201 emergency signal external interrupt */ + if (register_external_irq(EXT_IRQ_EMERGENCY_SIG, do_ext_call_interrupt)) + panic("Couldn't request external interrupt 0x1201"); +- /* request the 0x1202 external call external interrupt */ ++ ctl_set_bit(0, 14); + if (register_external_irq(EXT_IRQ_EXTERNAL_CALL, do_ext_call_interrupt)) + panic("Couldn't request external interrupt 0x1202"); ++ ctl_set_bit(0, 13); + } + + void __init smp_prepare_boot_cpu(void) +diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl +index 0122cc156952cf..51cc3616d5f98a 100644 +--- a/arch/s390/kernel/syscalls/syscall.tbl ++++ b/arch/s390/kernel/syscalls/syscall.tbl +@@ -418,7 +418,7 @@ + 412 32 utimensat_time64 - sys_utimensat + 413 32 pselect6_time64 - compat_sys_pselect6_time64 + 414 32 ppoll_time64 - compat_sys_ppoll_time64 +-416 32 io_pgetevents_time64 - sys_io_pgetevents ++416 32 io_pgetevents_time64 - compat_sys_io_pgetevents_time64 + 417 32 recvmmsg_time64 - compat_sys_recvmmsg_time64 + 418 32 mq_timedsend_time64 - sys_mq_timedsend + 419 32 mq_timedreceive_time64 - sys_mq_timedreceive +diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c +index fc07bc39e69839..81fdee22a497df 100644 +--- a/arch/s390/kernel/uv.c ++++ b/arch/s390/kernel/uv.c +@@ -181,36 +181,36 @@ int uv_convert_owned_from_secure(unsigned long paddr) + } + + /* +- * Calculate the expected ref_count for a page that would otherwise have no ++ * Calculate the expected ref_count for a folio that would otherwise have no + * further pins. This was cribbed from similar functions in other places in + * the kernel, but with some slight modifications. We know that a secure +- * page can not be a huge page for example. ++ * folio can not be a large folio, for example. + */ +-static int expected_page_refs(struct page *page) ++static int expected_folio_refs(struct folio *folio) + { + int res; + +- res = page_mapcount(page); +- if (PageSwapCache(page)) { ++ res = folio_mapcount(folio); ++ if (folio_test_swapcache(folio)) { + res++; +- } else if (page_mapping(page)) { ++ } else if (folio_mapping(folio)) { + res++; +- if (page_has_private(page)) ++ if (folio->private) + res++; + } + return res; + } + +-static int make_page_secure(struct page *page, struct uv_cb_header *uvcb) ++static int make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb) + { + int expected, cc = 0; + +- if (PageWriteback(page)) ++ if (folio_test_writeback(folio)) + return -EAGAIN; +- expected = expected_page_refs(page); +- if (!page_ref_freeze(page, expected)) ++ expected = expected_folio_refs(folio); ++ if (!folio_ref_freeze(folio, expected)) + return -EBUSY; +- set_bit(PG_arch_1, &page->flags); ++ set_bit(PG_arch_1, &folio->flags); + /* + * If the UVC does not succeed or fail immediately, we don't want to + * loop for long, or we might get stall notifications. +@@ -220,9 +220,9 @@ static int make_page_secure(struct page *page, struct uv_cb_header *uvcb) + * -EAGAIN and we let the callers deal with it. + */ + cc = __uv_call(0, (u64)uvcb); +- page_ref_unfreeze(page, expected); ++ folio_ref_unfreeze(folio, expected); + /* +- * Return -ENXIO if the page was not mapped, -EINVAL for other errors. ++ * Return -ENXIO if the folio was not mapped, -EINVAL for other errors. + * If busy or partially completed, return -EAGAIN. + */ + if (cc == UVC_CC_OK) +@@ -277,7 +277,7 @@ int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb) + bool local_drain = false; + spinlock_t *ptelock; + unsigned long uaddr; +- struct page *page; ++ struct folio *folio; + pte_t *ptep; + int rc; + +@@ -306,15 +306,26 @@ int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb) + if (!ptep) + goto out; + if (pte_present(*ptep) && !(pte_val(*ptep) & _PAGE_INVALID) && pte_write(*ptep)) { +- page = pte_page(*ptep); ++ folio = page_folio(pte_page(*ptep)); ++ rc = -EINVAL; ++ if (folio_test_large(folio)) ++ goto unlock; + rc = -EAGAIN; +- if (trylock_page(page)) { ++ if (folio_trylock(folio)) { + if (should_export_before_import(uvcb, gmap->mm)) +- uv_convert_from_secure(page_to_phys(page)); +- rc = make_page_secure(page, uvcb); +- unlock_page(page); ++ uv_convert_from_secure(PFN_PHYS(folio_pfn(folio))); ++ rc = make_folio_secure(folio, uvcb); ++ folio_unlock(folio); + } ++ ++ /* ++ * Once we drop the PTL, the folio may get unmapped and ++ * freed immediately. We need a temporary reference. ++ */ ++ if (rc == -EAGAIN) ++ folio_get(folio); + } ++unlock: + pte_unmap_unlock(ptep, ptelock); + out: + mmap_read_unlock(gmap->mm); +@@ -324,10 +335,11 @@ int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb) + * If we are here because the UVC returned busy or partial + * completion, this is just a useless check, but it is safe. + */ +- wait_on_page_writeback(page); ++ folio_wait_writeback(folio); ++ folio_put(folio); + } else if (rc == -EBUSY) { + /* +- * If we have tried a local drain and the page refcount ++ * If we have tried a local drain and the folio refcount + * still does not match our expected safe value, try with a + * system wide drain. This is needed if the pagevecs holding + * the page are on a different CPU. +@@ -338,7 +350,7 @@ int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb) + return -EAGAIN; + } + /* +- * We are here if the page refcount does not match the ++ * We are here if the folio refcount does not match the + * expected safe value. The main culprits are usually + * pagevecs. With lru_add_drain() we drain the pagevecs + * on the local CPU so that hopefully the refcount will +diff --git a/arch/s390/kernel/vdso32/Makefile b/arch/s390/kernel/vdso32/Makefile +index 23e868b79a6c99..4800d80decee69 100644 +--- a/arch/s390/kernel/vdso32/Makefile ++++ b/arch/s390/kernel/vdso32/Makefile +@@ -19,10 +19,12 @@ KBUILD_AFLAGS_32 := $(filter-out -m64,$(KBUILD_AFLAGS)) + KBUILD_AFLAGS_32 += -m31 -s + + KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS)) ++KBUILD_CFLAGS_32 := $(filter-out -mpacked-stack,$(KBUILD_CFLAGS)) + KBUILD_CFLAGS_32 := $(filter-out -mno-pic-data-is-text-relative,$(KBUILD_CFLAGS_32)) +-KBUILD_CFLAGS_32 += -m31 -fPIC -shared -fno-common -fno-builtin ++KBUILD_CFLAGS_32 := $(filter-out -fno-asynchronous-unwind-tables,$(KBUILD_CFLAGS_32)) ++KBUILD_CFLAGS_32 += -m31 -fPIC -shared -fno-common -fno-builtin -fasynchronous-unwind-tables + +-LDFLAGS_vdso32.so.dbg += -fPIC -shared -soname=linux-vdso32.so.1 \ ++LDFLAGS_vdso32.so.dbg += -shared -soname=linux-vdso32.so.1 \ + --hash-style=both --build-id=sha1 -melf_s390 -T + + $(targets:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32) +@@ -61,16 +63,6 @@ quiet_cmd_vdso32as = VDSO32A $@ + quiet_cmd_vdso32cc = VDSO32C $@ + cmd_vdso32cc = $(CC) $(c_flags) -c -o $@ $< + +-# install commands for the unstripped file +-quiet_cmd_vdso_install = INSTALL $@ +- cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ +- +-vdso32.so: $(obj)/vdso32.so.dbg +- @mkdir -p $(MODLIB)/vdso +- $(call cmd,vdso_install) +- +-vdso_install: vdso32.so +- + # Generate VDSO offsets using helper script + gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh + quiet_cmd_vdsosym = VDSOSYM $@ +diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile +index fc1c6ff8178f59..2f2e4e997030c3 100644 +--- a/arch/s390/kernel/vdso64/Makefile ++++ b/arch/s390/kernel/vdso64/Makefile +@@ -24,9 +24,12 @@ KBUILD_AFLAGS_64 := $(filter-out -m64,$(KBUILD_AFLAGS)) + KBUILD_AFLAGS_64 += -m64 + + KBUILD_CFLAGS_64 := $(filter-out -m64,$(KBUILD_CFLAGS)) ++KBUILD_CFLAGS_64 := $(filter-out -mpacked-stack,$(KBUILD_CFLAGS_64)) + KBUILD_CFLAGS_64 := $(filter-out -mno-pic-data-is-text-relative,$(KBUILD_CFLAGS_64)) +-KBUILD_CFLAGS_64 += -m64 -fPIC -fno-common -fno-builtin +-ldflags-y := -fPIC -shared -soname=linux-vdso64.so.1 \ ++KBUILD_CFLAGS_64 := $(filter-out -munaligned-symbols,$(KBUILD_CFLAGS_64)) ++KBUILD_CFLAGS_64 := $(filter-out -fno-asynchronous-unwind-tables,$(KBUILD_CFLAGS_64)) ++KBUILD_CFLAGS_64 += -m64 -fPIC -fno-common -fno-builtin -fasynchronous-unwind-tables ++ldflags-y := -shared -soname=linux-vdso64.so.1 \ + --hash-style=both --build-id=sha1 -T + + $(targets:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_64) +@@ -70,16 +73,6 @@ quiet_cmd_vdso64as = VDSO64A $@ + quiet_cmd_vdso64cc = VDSO64C $@ + cmd_vdso64cc = $(CC) $(c_flags) -c -o $@ $< + +-# install commands for the unstripped file +-quiet_cmd_vdso_install = INSTALL $@ +- cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ +- +-vdso64.so: $(obj)/vdso64.so.dbg +- @mkdir -p $(MODLIB)/vdso +- $(call cmd,vdso_install) +- +-vdso_install: vdso64.so +- + # Generate VDSO offsets using helper script + gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh + quiet_cmd_vdsosym = VDSOSYM $@ +diff --git a/arch/s390/kernel/vdso64/vdso_user_wrapper.S b/arch/s390/kernel/vdso64/vdso_user_wrapper.S +index 57f62596e53b95..85247ef5a41b89 100644 +--- a/arch/s390/kernel/vdso64/vdso_user_wrapper.S ++++ b/arch/s390/kernel/vdso64/vdso_user_wrapper.S +@@ -24,8 +24,10 @@ __kernel_\func: + CFI_DEF_CFA_OFFSET (STACK_FRAME_OVERHEAD + WRAPPER_FRAME_SIZE) + CFI_VAL_OFFSET 15, -STACK_FRAME_OVERHEAD + stg %r14,STACK_FRAME_OVERHEAD(%r15) ++ CFI_REL_OFFSET 14, STACK_FRAME_OVERHEAD + brasl %r14,__s390_vdso_\func + lg %r14,STACK_FRAME_OVERHEAD(%r15) ++ CFI_RESTORE 14 + aghi %r15,WRAPPER_FRAME_SIZE + CFI_DEF_CFA_OFFSET STACK_FRAME_OVERHEAD + CFI_RESTORE 15 +diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S +index 2ae201ebf90b97..de5f9f623f5b27 100644 +--- a/arch/s390/kernel/vmlinux.lds.S ++++ b/arch/s390/kernel/vmlinux.lds.S +@@ -71,6 +71,15 @@ SECTIONS + . = ALIGN(PAGE_SIZE); + __end_ro_after_init = .; + ++ .data.rel.ro : { ++ *(.data.rel.ro .data.rel.ro.*) ++ } ++ .got : { ++ __got_start = .; ++ *(.got) ++ __got_end = .; ++ } ++ + RW_DATA(0x100, PAGE_SIZE, THREAD_SIZE) + BOOT_DATA_PRESERVED + +diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c +index e0a88dcaf5cb7a..24a18e5ef6e8e3 100644 +--- a/arch/s390/kernel/vtime.c ++++ b/arch/s390/kernel/vtime.c +@@ -210,13 +210,13 @@ void vtime_flush(struct task_struct *tsk) + virt_timer_expire(); + + steal = S390_lowcore.steal_timer; +- avg_steal = S390_lowcore.avg_steal_timer / 2; ++ avg_steal = S390_lowcore.avg_steal_timer; + if ((s64) steal > 0) { + S390_lowcore.steal_timer = 0; + account_steal_time(cputime_to_nsecs(steal)); + avg_steal += steal; + } +- S390_lowcore.avg_steal_timer = avg_steal; ++ S390_lowcore.avg_steal_timer = avg_steal / 2; + } + + static u64 vtime_delta(void) +diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c +index 3c65b8258ae67a..2cc3ec034046c9 100644 +--- a/arch/s390/kvm/diag.c ++++ b/arch/s390/kvm/diag.c +@@ -77,7 +77,7 @@ static int __diag_page_ref_service(struct kvm_vcpu *vcpu) + vcpu->stat.instruction_diagnose_258++; + if (vcpu->run->s.regs.gprs[rx] & 7) + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); +- rc = read_guest(vcpu, vcpu->run->s.regs.gprs[rx], rx, &parm, sizeof(parm)); ++ rc = read_guest_real(vcpu, vcpu->run->s.regs.gprs[rx], &parm, sizeof(parm)); + if (rc) + return kvm_s390_inject_prog_cond(vcpu, rc); + if (parm.parm_version != 2 || parm.parm_len < 5 || parm.code != 0x258) +diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c +index 6d6bc19b37dcbd..090dc38334336b 100644 +--- a/arch/s390/kvm/gaccess.c ++++ b/arch/s390/kvm/gaccess.c +@@ -1001,6 +1001,8 @@ static int access_guest_page(struct kvm *kvm, enum gacc_mode mode, gpa_t gpa, + const gfn_t gfn = gpa_to_gfn(gpa); + int rc; + ++ if (!gfn_to_memslot(kvm, gfn)) ++ return PGM_ADDRESSING; + if (mode == GACC_STORE) + rc = kvm_write_guest_page(kvm, gfn, data, offset, len); + else +@@ -1158,6 +1160,8 @@ int access_guest_real(struct kvm_vcpu *vcpu, unsigned long gra, + gra += fragment_len; + data += fragment_len; + } ++ if (rc > 0) ++ vcpu->arch.pgm.code = rc; + return rc; + } + +@@ -1382,6 +1386,7 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr, + unsigned long *pgt, int *dat_protection, + int *fake) + { ++ struct kvm *kvm; + struct gmap *parent; + union asce asce; + union vaddress vaddr; +@@ -1390,6 +1395,7 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr, + + *fake = 0; + *dat_protection = 0; ++ kvm = sg->private; + parent = sg->parent; + vaddr.addr = saddr; + asce.val = sg->orig_asce; +@@ -1450,6 +1456,7 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr, + rc = gmap_shadow_r2t(sg, saddr, rfte.val, *fake); + if (rc) + return rc; ++ kvm->stat.gmap_shadow_r1_entry++; + } + fallthrough; + case ASCE_TYPE_REGION2: { +@@ -1478,6 +1485,7 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr, + rc = gmap_shadow_r3t(sg, saddr, rste.val, *fake); + if (rc) + return rc; ++ kvm->stat.gmap_shadow_r2_entry++; + } + fallthrough; + case ASCE_TYPE_REGION3: { +@@ -1515,6 +1523,7 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr, + rc = gmap_shadow_sgt(sg, saddr, rtte.val, *fake); + if (rc) + return rc; ++ kvm->stat.gmap_shadow_r3_entry++; + } + fallthrough; + case ASCE_TYPE_SEGMENT: { +@@ -1548,6 +1557,7 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr, + rc = gmap_shadow_pgt(sg, saddr, ste.val, *fake); + if (rc) + return rc; ++ kvm->stat.gmap_shadow_sg_entry++; + } + } + /* Return the parent address of the page table */ +@@ -1618,6 +1628,7 @@ int kvm_s390_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg, + pte.p |= dat_protection; + if (!rc) + rc = gmap_shadow_page(sg, saddr, __pte(pte.val)); ++ vcpu->kvm->stat.gmap_shadow_pg_entry++; + ipte_unlock(vcpu->kvm); + mmap_read_unlock(sg->mm); + return rc; +diff --git a/arch/s390/kvm/gaccess.h b/arch/s390/kvm/gaccess.h +index b320d12aa04934..3fde45a151f22e 100644 +--- a/arch/s390/kvm/gaccess.h ++++ b/arch/s390/kvm/gaccess.h +@@ -405,11 +405,12 @@ int read_guest_abs(struct kvm_vcpu *vcpu, unsigned long gpa, void *data, + * @len: number of bytes to copy + * + * Copy @len bytes from @data (kernel space) to @gra (guest real address). +- * It is up to the caller to ensure that the entire guest memory range is +- * valid memory before calling this function. + * Guest low address and key protection are not checked. + * +- * Returns zero on success or -EFAULT on error. ++ * Returns zero on success, -EFAULT when copying from @data failed, or ++ * PGM_ADRESSING in case @gra is outside a memslot. In this case, pgm check info ++ * is also stored to allow injecting into the guest (if applicable) using ++ * kvm_s390_inject_prog_cond(). + * + * If an error occurs data may have been copied partially to guest memory. + */ +@@ -428,11 +429,12 @@ int write_guest_real(struct kvm_vcpu *vcpu, unsigned long gra, void *data, + * @len: number of bytes to copy + * + * Copy @len bytes from @gra (guest real address) to @data (kernel space). +- * It is up to the caller to ensure that the entire guest memory range is +- * valid memory before calling this function. + * Guest key protection is not checked. + * +- * Returns zero on success or -EFAULT on error. ++ * Returns zero on success, -EFAULT when copying to @data failed, or ++ * PGM_ADRESSING in case @gra is outside a memslot. In this case, pgm check info ++ * is also stored to allow injecting into the guest (if applicable) using ++ * kvm_s390_inject_prog_cond(). + * + * If an error occurs data may have been copied partially to kernel space. + */ +diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c +index b3f17e014cab5d..348d030d2660ca 100644 +--- a/arch/s390/kvm/kvm-s390.c ++++ b/arch/s390/kvm/kvm-s390.c +@@ -66,7 +66,14 @@ const struct _kvm_stats_desc kvm_vm_stats_desc[] = { + STATS_DESC_COUNTER(VM, inject_pfault_done), + STATS_DESC_COUNTER(VM, inject_service_signal), + STATS_DESC_COUNTER(VM, inject_virtio), +- STATS_DESC_COUNTER(VM, aen_forward) ++ STATS_DESC_COUNTER(VM, aen_forward), ++ STATS_DESC_COUNTER(VM, gmap_shadow_reuse), ++ STATS_DESC_COUNTER(VM, gmap_shadow_create), ++ STATS_DESC_COUNTER(VM, gmap_shadow_r1_entry), ++ STATS_DESC_COUNTER(VM, gmap_shadow_r2_entry), ++ STATS_DESC_COUNTER(VM, gmap_shadow_r3_entry), ++ STATS_DESC_COUNTER(VM, gmap_shadow_sg_entry), ++ STATS_DESC_COUNTER(VM, gmap_shadow_pg_entry), + }; + + const struct kvm_stats_header kvm_vm_stats_header = { +@@ -125,6 +132,7 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { + STATS_DESC_COUNTER(VCPU, instruction_io_other), + STATS_DESC_COUNTER(VCPU, instruction_lpsw), + STATS_DESC_COUNTER(VCPU, instruction_lpswe), ++ STATS_DESC_COUNTER(VCPU, instruction_lpswey), + STATS_DESC_COUNTER(VCPU, instruction_pfmf), + STATS_DESC_COUNTER(VCPU, instruction_ptff), + STATS_DESC_COUNTER(VCPU, instruction_sck), +@@ -2625,9 +2633,7 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) + if (r) + break; + +- mmap_write_lock(current->mm); +- r = gmap_mark_unmergeable(); +- mmap_write_unlock(current->mm); ++ r = s390_disable_cow_sharing(); + if (r) + break; + +@@ -4307,10 +4313,6 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) + + vcpu_load(vcpu); + +- if (test_fp_ctl(fpu->fpc)) { +- ret = -EINVAL; +- goto out; +- } + vcpu->run->s.regs.fpc = fpu->fpc; + if (MACHINE_HAS_VX) + convert_fp_to_vx((__vector128 *) vcpu->run->s.regs.vrs, +@@ -4318,7 +4320,6 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) + else + memcpy(vcpu->run->s.regs.fprs, &fpu->fprs, sizeof(fpu->fprs)); + +-out: + vcpu_put(vcpu); + return ret; + } +diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h +index a7ea80cfa445e1..0c0f47ec634477 100644 +--- a/arch/s390/kvm/kvm-s390.h ++++ b/arch/s390/kvm/kvm-s390.h +@@ -120,6 +120,21 @@ static inline u64 kvm_s390_get_base_disp_s(struct kvm_vcpu *vcpu, u8 *ar) + return (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2; + } + ++static inline u64 kvm_s390_get_base_disp_siy(struct kvm_vcpu *vcpu, u8 *ar) ++{ ++ u32 base1 = vcpu->arch.sie_block->ipb >> 28; ++ s64 disp1; ++ ++ /* The displacement is a 20bit _SIGNED_ value */ ++ disp1 = sign_extend64(((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16) + ++ ((vcpu->arch.sie_block->ipb & 0xff00) << 4), 19); ++ ++ if (ar) ++ *ar = base1; ++ ++ return (base1 ? vcpu->run->s.regs.gprs[base1] : 0) + disp1; ++} ++ + static inline void kvm_s390_get_base_disp_sse(struct kvm_vcpu *vcpu, + u64 *address1, u64 *address2, + u8 *ar_b1, u8 *ar_b2) +@@ -234,7 +249,12 @@ static inline unsigned long kvm_s390_get_gfn_end(struct kvm_memslots *slots) + + static inline u32 kvm_s390_get_gisa_desc(struct kvm *kvm) + { +- u32 gd = virt_to_phys(kvm->arch.gisa_int.origin); ++ u32 gd; ++ ++ if (!kvm->arch.gisa_int.origin) ++ return 0; ++ ++ gd = virt_to_phys(kvm->arch.gisa_int.origin); + + if (gd && sclp.has_gisaf) + gd |= GISA_FORMAT1; +diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c +index dc4cfa8795c08c..e5b220e686b09a 100644 +--- a/arch/s390/kvm/priv.c ++++ b/arch/s390/kvm/priv.c +@@ -793,6 +793,36 @@ static int handle_lpswe(struct kvm_vcpu *vcpu) + return 0; + } + ++static int handle_lpswey(struct kvm_vcpu *vcpu) ++{ ++ psw_t new_psw; ++ u64 addr; ++ int rc; ++ u8 ar; ++ ++ vcpu->stat.instruction_lpswey++; ++ ++ if (!test_kvm_facility(vcpu->kvm, 193)) ++ return kvm_s390_inject_program_int(vcpu, PGM_OPERATION); ++ ++ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) ++ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); ++ ++ addr = kvm_s390_get_base_disp_siy(vcpu, &ar); ++ if (addr & 7) ++ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); ++ ++ rc = read_guest(vcpu, addr, ar, &new_psw, sizeof(new_psw)); ++ if (rc) ++ return kvm_s390_inject_prog_cond(vcpu, rc); ++ ++ vcpu->arch.sie_block->gpsw = new_psw; ++ if (!is_valid_psw(&vcpu->arch.sie_block->gpsw)) ++ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); ++ ++ return 0; ++} ++ + static int handle_stidp(struct kvm_vcpu *vcpu) + { + u64 stidp_data = vcpu->kvm->arch.model.cpuid; +@@ -1458,6 +1488,8 @@ int kvm_s390_handle_eb(struct kvm_vcpu *vcpu) + case 0x61: + case 0x62: + return handle_ri(vcpu); ++ case 0x71: ++ return handle_lpswey(vcpu); + default: + return -EOPNOTSUPP; + } +diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c +index 61499293c2ac3b..db9a180de65f1f 100644 +--- a/arch/s390/kvm/vsie.c ++++ b/arch/s390/kvm/vsie.c +@@ -587,10 +587,6 @@ void kvm_s390_vsie_gmap_notifier(struct gmap *gmap, unsigned long start, + + if (!gmap_is_shadow(gmap)) + return; +- if (start >= 1UL << 31) +- /* We are only interested in prefix pages */ +- return; +- + /* + * Only new shadow blocks are added to the list during runtime, + * therefore we can safely reference them all the time. +@@ -1214,15 +1210,17 @@ static int acquire_gmap_shadow(struct kvm_vcpu *vcpu, + * we're holding has been unshadowed. If the gmap is still valid, + * we can safely reuse it. + */ +- if (vsie_page->gmap && gmap_shadow_valid(vsie_page->gmap, asce, edat)) ++ if (vsie_page->gmap && gmap_shadow_valid(vsie_page->gmap, asce, edat)) { ++ vcpu->kvm->stat.gmap_shadow_reuse++; + return 0; ++ } + + /* release the old shadow - if any, and mark the prefix as unmapped */ + release_gmap_shadow(vsie_page); + gmap = gmap_shadow(vcpu->arch.gmap, asce, edat); + if (IS_ERR(gmap)) + return PTR_ERR(gmap); +- gmap->private = vcpu->kvm; ++ vcpu->kvm->stat.gmap_shadow_create++; + WRITE_ONCE(vsie_page->gmap, gmap); + return 0; + } +diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c +index f47515313226c4..9af4d829649444 100644 +--- a/arch/s390/mm/cmm.c ++++ b/arch/s390/mm/cmm.c +@@ -95,11 +95,12 @@ static long cmm_alloc_pages(long nr, long *counter, + (*counter)++; + spin_unlock(&cmm_lock); + nr--; ++ cond_resched(); + } + return nr; + } + +-static long cmm_free_pages(long nr, long *counter, struct cmm_page_array **list) ++static long __cmm_free_pages(long nr, long *counter, struct cmm_page_array **list) + { + struct cmm_page_array *pa; + unsigned long addr; +@@ -123,6 +124,21 @@ static long cmm_free_pages(long nr, long *counter, struct cmm_page_array **list) + return nr; + } + ++static long cmm_free_pages(long nr, long *counter, struct cmm_page_array **list) ++{ ++ long inc = 0; ++ ++ while (nr) { ++ inc = min(256L, nr); ++ nr -= inc; ++ inc = __cmm_free_pages(inc, counter, list); ++ if (inc) ++ break; ++ cond_resched(); ++ } ++ return nr + inc; ++} ++ + static int cmm_oom_notify(struct notifier_block *self, + unsigned long dummy, void *parm) + { +diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c +index b678295931c315..1a231181a413bd 100644 +--- a/arch/s390/mm/fault.c ++++ b/arch/s390/mm/fault.c +@@ -331,14 +331,16 @@ static noinline void do_fault_error(struct pt_regs *regs, vm_fault_t fault) + do_no_context(regs, fault); + else + do_sigsegv(regs, SEGV_MAPERR); +- } else if (fault & VM_FAULT_SIGBUS) { ++ } else if (fault & (VM_FAULT_SIGBUS | VM_FAULT_HWPOISON)) { + /* Kernel mode? Handle exceptions or die */ + if (!user_mode(regs)) + do_no_context(regs, fault); + else + do_sigbus(regs); +- } else ++ } else { ++ pr_emerg("Unexpected fault flags: %08x\n", fault); + BUG(); ++ } + break; + } + } +diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c +index 906a7bfc2a7874..1a656db09c9fe3 100644 +--- a/arch/s390/mm/gmap.c ++++ b/arch/s390/mm/gmap.c +@@ -21,10 +21,22 @@ + + #include + #include ++#include + #include + + #define GMAP_SHADOW_FAKE_TABLE 1ULL + ++static struct page *gmap_alloc_crst(void) ++{ ++ struct page *page; ++ ++ page = alloc_pages(GFP_KERNEL_ACCOUNT, CRST_ALLOC_ORDER); ++ if (!page) ++ return NULL; ++ arch_set_page_dat(page, CRST_ALLOC_ORDER); ++ return page; ++} ++ + /** + * gmap_alloc - allocate and initialize a guest address space + * @limit: maximum address of the gmap address space +@@ -67,7 +79,7 @@ static struct gmap *gmap_alloc(unsigned long limit) + spin_lock_init(&gmap->guest_table_lock); + spin_lock_init(&gmap->shadow_lock); + refcount_set(&gmap->ref_count, 1); +- page = alloc_pages(GFP_KERNEL_ACCOUNT, CRST_ALLOC_ORDER); ++ page = gmap_alloc_crst(); + if (!page) + goto out_free; + page->index = 0; +@@ -308,7 +320,7 @@ static int gmap_alloc_table(struct gmap *gmap, unsigned long *table, + unsigned long *new; + + /* since we dont free the gmap table until gmap_free we can unlock */ +- page = alloc_pages(GFP_KERNEL_ACCOUNT, CRST_ALLOC_ORDER); ++ page = gmap_alloc_crst(); + if (!page) + return -ENOMEM; + new = page_to_virt(page); +@@ -584,7 +596,7 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr) + pud = pud_offset(p4d, vmaddr); + VM_BUG_ON(pud_none(*pud)); + /* large puds cannot yet be handled */ +- if (pud_large(*pud)) ++ if (pud_leaf(*pud)) + return -EFAULT; + pmd = pmd_offset(pud, vmaddr); + VM_BUG_ON(pmd_none(*pmd)); +@@ -1679,6 +1691,7 @@ struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce, + return ERR_PTR(-ENOMEM); + new->mm = parent->mm; + new->parent = gmap_get(parent); ++ new->private = parent->private; + new->orig_asce = asce; + new->edat_level = edat_level; + new->initialized = false; +@@ -1759,7 +1772,7 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t, + + BUG_ON(!gmap_is_shadow(sg)); + /* Allocate a shadow region second table */ +- page = alloc_pages(GFP_KERNEL_ACCOUNT, CRST_ALLOC_ORDER); ++ page = gmap_alloc_crst(); + if (!page) + return -ENOMEM; + page->index = r2t & _REGION_ENTRY_ORIGIN; +@@ -1843,7 +1856,7 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t, + + BUG_ON(!gmap_is_shadow(sg)); + /* Allocate a shadow region second table */ +- page = alloc_pages(GFP_KERNEL_ACCOUNT, CRST_ALLOC_ORDER); ++ page = gmap_alloc_crst(); + if (!page) + return -ENOMEM; + page->index = r3t & _REGION_ENTRY_ORIGIN; +@@ -1927,7 +1940,7 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt, + + BUG_ON(!gmap_is_shadow(sg) || (sgt & _REGION3_ENTRY_LARGE)); + /* Allocate a shadow segment table */ +- page = alloc_pages(GFP_KERNEL_ACCOUNT, CRST_ALLOC_ORDER); ++ page = gmap_alloc_crst(); + if (!page) + return -ENOMEM; + page->index = sgt & _REGION_ENTRY_ORIGIN; +@@ -2534,41 +2547,6 @@ static inline void thp_split_mm(struct mm_struct *mm) + } + #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + +-/* +- * Remove all empty zero pages from the mapping for lazy refaulting +- * - This must be called after mm->context.has_pgste is set, to avoid +- * future creation of zero pages +- * - This must be called after THP was disabled. +- * +- * mm contracts with s390, that even if mm were to remove a page table, +- * racing with the loop below and so causing pte_offset_map_lock() to fail, +- * it will never insert a page table containing empty zero pages once +- * mm_forbids_zeropage(mm) i.e. mm->context.has_pgste is set. +- */ +-static int __zap_zero_pages(pmd_t *pmd, unsigned long start, +- unsigned long end, struct mm_walk *walk) +-{ +- unsigned long addr; +- +- for (addr = start; addr != end; addr += PAGE_SIZE) { +- pte_t *ptep; +- spinlock_t *ptl; +- +- ptep = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); +- if (!ptep) +- break; +- if (is_zero_pfn(pte_pfn(*ptep))) +- ptep_xchg_direct(walk->mm, addr, ptep, __pte(_PAGE_INVALID)); +- pte_unmap_unlock(ptep, ptl); +- } +- return 0; +-} +- +-static const struct mm_walk_ops zap_zero_walk_ops = { +- .pmd_entry = __zap_zero_pages, +- .walk_lock = PGWALK_WRLOCK, +-}; +- + /* + * switch on pgstes for its userspace process (for kvm) + */ +@@ -2586,22 +2564,142 @@ int s390_enable_sie(void) + mm->context.has_pgste = 1; + /* split thp mappings and disable thp for future mappings */ + thp_split_mm(mm); +- walk_page_range(mm, 0, TASK_SIZE, &zap_zero_walk_ops, NULL); + mmap_write_unlock(mm); + return 0; + } + EXPORT_SYMBOL_GPL(s390_enable_sie); + +-int gmap_mark_unmergeable(void) ++static int find_zeropage_pte_entry(pte_t *pte, unsigned long addr, ++ unsigned long end, struct mm_walk *walk) ++{ ++ unsigned long *found_addr = walk->private; ++ ++ /* Return 1 of the page is a zeropage. */ ++ if (is_zero_pfn(pte_pfn(*pte))) { ++ /* ++ * Shared zeropage in e.g., a FS DAX mapping? We cannot do the ++ * right thing and likely don't care: FAULT_FLAG_UNSHARE ++ * currently only works in COW mappings, which is also where ++ * mm_forbids_zeropage() is checked. ++ */ ++ if (!is_cow_mapping(walk->vma->vm_flags)) ++ return -EFAULT; ++ ++ *found_addr = addr; ++ return 1; ++ } ++ return 0; ++} ++ ++static const struct mm_walk_ops find_zeropage_ops = { ++ .pte_entry = find_zeropage_pte_entry, ++ .walk_lock = PGWALK_WRLOCK, ++}; ++ ++/* ++ * Unshare all shared zeropages, replacing them by anonymous pages. Note that ++ * we cannot simply zap all shared zeropages, because this could later ++ * trigger unexpected userfaultfd missing events. ++ * ++ * This must be called after mm->context.allow_cow_sharing was ++ * set to 0, to avoid future mappings of shared zeropages. ++ * ++ * mm contracts with s390, that even if mm were to remove a page table, ++ * and racing with walk_page_range_vma() calling pte_offset_map_lock() ++ * would fail, it will never insert a page table containing empty zero ++ * pages once mm_forbids_zeropage(mm) i.e. ++ * mm->context.allow_cow_sharing is set to 0. ++ */ ++static int __s390_unshare_zeropages(struct mm_struct *mm) ++{ ++ struct vm_area_struct *vma; ++ VMA_ITERATOR(vmi, mm, 0); ++ unsigned long addr; ++ vm_fault_t fault; ++ int rc; ++ ++ for_each_vma(vmi, vma) { ++ /* ++ * We could only look at COW mappings, but it's more future ++ * proof to catch unexpected zeropages in other mappings and ++ * fail. ++ */ ++ if ((vma->vm_flags & VM_PFNMAP) || is_vm_hugetlb_page(vma)) ++ continue; ++ addr = vma->vm_start; ++ ++retry: ++ rc = walk_page_range_vma(vma, addr, vma->vm_end, ++ &find_zeropage_ops, &addr); ++ if (rc < 0) ++ return rc; ++ else if (!rc) ++ continue; ++ ++ /* addr was updated by find_zeropage_pte_entry() */ ++ fault = handle_mm_fault(vma, addr, ++ FAULT_FLAG_UNSHARE | FAULT_FLAG_REMOTE, ++ NULL); ++ if (fault & VM_FAULT_OOM) ++ return -ENOMEM; ++ /* ++ * See break_ksm(): even after handle_mm_fault() returned 0, we ++ * must start the lookup from the current address, because ++ * handle_mm_fault() may back out if there's any difficulty. ++ * ++ * VM_FAULT_SIGBUS and VM_FAULT_SIGSEGV are unexpected but ++ * maybe they could trigger in the future on concurrent ++ * truncation. In that case, the shared zeropage would be gone ++ * and we can simply retry and make progress. ++ */ ++ cond_resched(); ++ goto retry; ++ } ++ ++ return 0; ++} ++ ++static int __s390_disable_cow_sharing(struct mm_struct *mm) + { ++ int rc; ++ ++ if (!mm->context.allow_cow_sharing) ++ return 0; ++ ++ mm->context.allow_cow_sharing = 0; ++ ++ /* Replace all shared zeropages by anonymous pages. */ ++ rc = __s390_unshare_zeropages(mm); + /* + * Make sure to disable KSM (if enabled for the whole process or + * individual VMAs). Note that nothing currently hinders user space + * from re-enabling it. + */ +- return ksm_disable(current->mm); ++ if (!rc) ++ rc = ksm_disable(mm); ++ if (rc) ++ mm->context.allow_cow_sharing = 1; ++ return rc; + } +-EXPORT_SYMBOL_GPL(gmap_mark_unmergeable); ++ ++/* ++ * Disable most COW-sharing of memory pages for the whole process: ++ * (1) Disable KSM and unmerge/unshare any KSM pages. ++ * (2) Disallow shared zeropages and unshare any zerpages that are mapped. ++ * ++ * Not that we currently don't bother with COW-shared pages that are shared ++ * with parent/child processes due to fork(). ++ */ ++int s390_disable_cow_sharing(void) ++{ ++ int rc; ++ ++ mmap_write_lock(current->mm); ++ rc = __s390_disable_cow_sharing(current->mm); ++ mmap_write_unlock(current->mm); ++ return rc; ++} ++EXPORT_SYMBOL_GPL(s390_disable_cow_sharing); + + /* + * Enable storage key handling from now on and initialize the storage +@@ -2646,7 +2744,7 @@ static int __s390_enable_skey_hugetlb(pte_t *pte, unsigned long addr, + return 0; + + start = pmd_val(*pmd) & HPAGE_MASK; +- end = start + HPAGE_SIZE - 1; ++ end = start + HPAGE_SIZE; + __storage_key_init_range(start, end); + set_bit(PG_arch_1, &page->flags); + cond_resched(); +@@ -2670,7 +2768,7 @@ int s390_enable_skey(void) + goto out_up; + + mm->context.uses_skeys = 1; +- rc = gmap_mark_unmergeable(); ++ rc = __s390_disable_cow_sharing(mm); + if (rc) { + mm->context.uses_skeys = 0; + goto out_up; +@@ -2855,7 +2953,7 @@ int s390_replace_asce(struct gmap *gmap) + if ((gmap->asce & _ASCE_TYPE_MASK) == _ASCE_TYPE_SEGMENT) + return -EINVAL; + +- page = alloc_pages(GFP_KERNEL_ACCOUNT, CRST_ALLOC_ORDER); ++ page = gmap_alloc_crst(); + if (!page) + return -ENOMEM; + page->index = 0; +diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c +index 297a6d897d5a0c..763469e518eec8 100644 +--- a/arch/s390/mm/hugetlbpage.c ++++ b/arch/s390/mm/hugetlbpage.c +@@ -139,7 +139,7 @@ static void clear_huge_pte_skeys(struct mm_struct *mm, unsigned long rste) + } + + if (!test_and_set_bit(PG_arch_1, &page->flags)) +- __storage_key_init_range(paddr, paddr + size - 1); ++ __storage_key_init_range(paddr, paddr + size); + } + + void __set_huge_pte_at(struct mm_struct *mm, unsigned long addr, +@@ -224,7 +224,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm, + if (p4d_present(*p4dp)) { + pudp = pud_offset(p4dp, addr); + if (pud_present(*pudp)) { +- if (pud_large(*pudp)) ++ if (pud_leaf(*pudp)) + return (pte_t *) pudp; + pmdp = pmd_offset(pudp, addr); + } +@@ -240,7 +240,7 @@ int pmd_huge(pmd_t pmd) + + int pud_huge(pud_t pud) + { +- return pud_large(pud); ++ return pud_leaf(pud); + } + + bool __init arch_hugetlb_valid_size(unsigned long size) +diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c +index 1e2ea706aa2289..79a037f49f7070 100644 +--- a/arch/s390/mm/page-states.c ++++ b/arch/s390/mm/page-states.c +@@ -121,7 +121,7 @@ static void mark_kernel_pud(p4d_t *p4d, unsigned long addr, unsigned long end) + continue; + if (!pud_folded(*pud)) { + page = phys_to_page(pud_val(*pud)); +- for (i = 0; i < 3; i++) ++ for (i = 0; i < 4; i++) + set_bit(PG_arch_1, &page[i].flags); + } + mark_kernel_pmd(pud, addr, next); +@@ -142,7 +142,7 @@ static void mark_kernel_p4d(pgd_t *pgd, unsigned long addr, unsigned long end) + continue; + if (!p4d_folded(*p4d)) { + page = phys_to_page(p4d_val(*p4d)); +- for (i = 0; i < 3; i++) ++ for (i = 0; i < 4; i++) + set_bit(PG_arch_1, &page[i].flags); + } + mark_kernel_pud(p4d, addr, next); +@@ -164,7 +164,7 @@ static void mark_kernel_pgd(void) + continue; + if (!pgd_folded(*pgd)) { + page = phys_to_page(pgd_val(*pgd)); +- for (i = 0; i < 3; i++) ++ for (i = 0; i < 4; i++) + set_bit(PG_arch_1, &page[i].flags); + } + mark_kernel_p4d(pgd, addr, next); +@@ -181,6 +181,12 @@ void __init cmma_init_nodat(void) + return; + /* Mark pages used in kernel page tables */ + mark_kernel_pgd(); ++ page = virt_to_page(&swapper_pg_dir); ++ for (i = 0; i < 4; i++) ++ set_bit(PG_arch_1, &page[i].flags); ++ page = virt_to_page(&invalid_pg_dir); ++ for (i = 0; i < 4; i++) ++ set_bit(PG_arch_1, &page[i].flags); + + /* Set all kernel pages not used for page tables to stable/no-dat */ + for_each_mem_pfn_range(i, MAX_NUMNODES, &start, &end, NULL) { +diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c +index b87e96c64b61d2..441f654d048d20 100644 +--- a/arch/s390/mm/pageattr.c ++++ b/arch/s390/mm/pageattr.c +@@ -274,7 +274,7 @@ static int walk_pud_level(p4d_t *p4d, unsigned long addr, unsigned long end, + if (pud_none(*pudp)) + return -EINVAL; + next = pud_addr_end(addr, end); +- if (pud_large(*pudp)) { ++ if (pud_leaf(*pudp)) { + need_split = !!(flags & SET_MEMORY_4K); + need_split |= !!(addr & ~PUD_MASK); + need_split |= !!(addr + PUD_SIZE > next); +diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c +index 07fc660a24aa2f..9355fbe5f51e94 100644 +--- a/arch/s390/mm/pgalloc.c ++++ b/arch/s390/mm/pgalloc.c +@@ -53,6 +53,8 @@ unsigned long *crst_table_alloc(struct mm_struct *mm) + + void crst_table_free(struct mm_struct *mm, unsigned long *table) + { ++ if (!table) ++ return; + pagetable_free(virt_to_ptdesc(table)); + } + +@@ -146,6 +148,7 @@ struct page *page_table_alloc_pgste(struct mm_struct *mm) + ptdesc = pagetable_alloc(GFP_KERNEL, 0); + if (ptdesc) { + table = (u64 *)ptdesc_to_virt(ptdesc); ++ arch_set_page_dat(virt_to_page(table), 0); + memset64(table, _PAGE_INVALID, PTRS_PER_PTE); + memset64(table + PTRS_PER_PTE, 0, PTRS_PER_PTE); + } +@@ -499,6 +502,8 @@ static unsigned long *base_crst_alloc(unsigned long val) + + static void base_crst_free(unsigned long *table) + { ++ if (!table) ++ return; + pagetable_free(virt_to_ptdesc(table)); + } + +diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c +index 3bd2ab2a9a3449..5e349869590a83 100644 +--- a/arch/s390/mm/pgtable.c ++++ b/arch/s390/mm/pgtable.c +@@ -479,7 +479,7 @@ static int pmd_lookup(struct mm_struct *mm, unsigned long addr, pmd_t **pmdp) + return -ENOENT; + + /* Large PUDs are not supported yet. */ +- if (pud_large(*pud)) ++ if (pud_leaf(*pud)) + return -EFAULT; + + *pmdp = pmd_offset(pud, addr); +@@ -756,7 +756,7 @@ void ptep_zap_unused(struct mm_struct *mm, unsigned long addr, + pte_clear(mm, addr, ptep); + } + if (reset) +- pgste_val(pgste) &= ~_PGSTE_GPS_USAGE_MASK; ++ pgste_val(pgste) &= ~(_PGSTE_GPS_USAGE_MASK | _PGSTE_GPS_NODAT); + pgste_set_unlock(ptep, pgste); + preempt_enable(); + } +diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c +index 6957d2ed97bf0e..2d3f65da56eeaa 100644 +--- a/arch/s390/mm/vmem.c ++++ b/arch/s390/mm/vmem.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -45,8 +46,11 @@ void *vmem_crst_alloc(unsigned long val) + unsigned long *table; + + table = vmem_alloc_pages(CRST_ALLOC_ORDER); +- if (table) +- crst_table_init(table, val); ++ if (!table) ++ return NULL; ++ crst_table_init(table, val); ++ if (slab_is_available()) ++ arch_set_page_dat(virt_to_page(table), CRST_ALLOC_ORDER); + return table; + } + +@@ -318,7 +322,7 @@ static int modify_pud_table(p4d_t *p4d, unsigned long addr, unsigned long end, + if (!add) { + if (pud_none(*pud)) + continue; +- if (pud_large(*pud)) { ++ if (pud_leaf(*pud)) { + if (IS_ALIGNED(addr, PUD_SIZE) && + IS_ALIGNED(next, PUD_SIZE)) { + pud_clear(pud); +@@ -339,7 +343,7 @@ static int modify_pud_table(p4d_t *p4d, unsigned long addr, unsigned long end, + if (!pmd) + goto out; + pud_populate(&init_mm, pud, pmd); +- } else if (pud_large(*pud)) { ++ } else if (pud_leaf(*pud)) { + continue; + } + ret = modify_pmd_table(pud, addr, next, add, direct); +@@ -582,7 +586,7 @@ pte_t *vmem_get_alloc_pte(unsigned long addr, bool alloc) + if (!pmd) + goto out; + pud_populate(&init_mm, pud, pmd); +- } else if (WARN_ON_ONCE(pud_large(*pud))) { ++ } else if (WARN_ON_ONCE(pud_leaf(*pud))) { + goto out; + } + pmd = pmd_offset(pud, addr); +diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c +index e507692e51e71e..62ee557d4b4996 100644 +--- a/arch/s390/net/bpf_jit_comp.c ++++ b/arch/s390/net/bpf_jit_comp.c +@@ -516,11 +516,12 @@ static void bpf_skip(struct bpf_jit *jit, int size) + * PLT for hotpatchable calls. The calling convention is the same as for the + * ftrace hotpatch trampolines: %r0 is return address, %r1 is clobbered. + */ +-extern const char bpf_plt[]; +-extern const char bpf_plt_ret[]; +-extern const char bpf_plt_target[]; +-extern const char bpf_plt_end[]; +-#define BPF_PLT_SIZE 32 ++struct bpf_plt { ++ char code[16]; ++ void *ret; ++ void *target; ++} __packed; ++extern const struct bpf_plt bpf_plt; + asm( + ".pushsection .rodata\n" + " .balign 8\n" +@@ -531,15 +532,14 @@ asm( + " .balign 8\n" + "bpf_plt_ret: .quad 0\n" + "bpf_plt_target: .quad 0\n" +- "bpf_plt_end:\n" + " .popsection\n" + ); + +-static void bpf_jit_plt(void *plt, void *ret, void *target) ++static void bpf_jit_plt(struct bpf_plt *plt, void *ret, void *target) + { +- memcpy(plt, bpf_plt, BPF_PLT_SIZE); +- *(void **)((char *)plt + (bpf_plt_ret - bpf_plt)) = ret; +- *(void **)((char *)plt + (bpf_plt_target - bpf_plt)) = target ?: ret; ++ memcpy(plt, &bpf_plt, sizeof(*plt)); ++ plt->ret = ret; ++ plt->target = target; + } + + /* +@@ -662,9 +662,9 @@ static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth) + jit->prg = ALIGN(jit->prg, 8); + jit->prologue_plt = jit->prg; + if (jit->prg_buf) +- bpf_jit_plt(jit->prg_buf + jit->prg, ++ bpf_jit_plt((struct bpf_plt *)(jit->prg_buf + jit->prg), + jit->prg_buf + jit->prologue_plt_ret, NULL); +- jit->prg += BPF_PLT_SIZE; ++ jit->prg += sizeof(struct bpf_plt); + } + + static int get_probe_mem_regno(const u8 *insn) +@@ -1311,8 +1311,12 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, + EMIT6_DISP_LH(0xeb000000, is32 ? (op32) : (op64), \ + (insn->imm & BPF_FETCH) ? src_reg : REG_W0, \ + src_reg, dst_reg, off); \ +- if (is32 && (insn->imm & BPF_FETCH)) \ +- EMIT_ZERO(src_reg); \ ++ if (insn->imm & BPF_FETCH) { \ ++ /* bcr 14,0 - see atomic_fetch_{add,and,or,xor}() */ \ ++ _EMIT2(0x07e0); \ ++ if (is32) \ ++ EMIT_ZERO(src_reg); \ ++ } \ + } while (0) + case BPF_ADD: + case BPF_ADD | BPF_FETCH: +@@ -1901,9 +1905,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) + struct bpf_jit jit; + int pass; + +- if (WARN_ON_ONCE(bpf_plt_end - bpf_plt != BPF_PLT_SIZE)) +- return orig_fp; +- + if (!fp->jit_requested) + return orig_fp; + +@@ -2009,14 +2010,11 @@ bool bpf_jit_supports_far_kfunc_call(void) + int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t, + void *old_addr, void *new_addr) + { ++ struct bpf_plt expected_plt, current_plt, new_plt, *plt; + struct { + u16 opc; + s32 disp; + } __packed insn; +- char expected_plt[BPF_PLT_SIZE]; +- char current_plt[BPF_PLT_SIZE]; +- char new_plt[BPF_PLT_SIZE]; +- char *plt; + char *ret; + int err; + +@@ -2035,18 +2033,18 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t, + */ + } else { + /* Verify the PLT. */ +- plt = (char *)ip + (insn.disp << 1); +- err = copy_from_kernel_nofault(current_plt, plt, BPF_PLT_SIZE); ++ plt = ip + (insn.disp << 1); ++ err = copy_from_kernel_nofault(¤t_plt, plt, ++ sizeof(current_plt)); + if (err < 0) + return err; + ret = (char *)ip + 6; +- bpf_jit_plt(expected_plt, ret, old_addr); +- if (memcmp(current_plt, expected_plt, BPF_PLT_SIZE)) ++ bpf_jit_plt(&expected_plt, ret, old_addr); ++ if (memcmp(¤t_plt, &expected_plt, sizeof(current_plt))) + return -EINVAL; + /* Adjust the call address. */ +- bpf_jit_plt(new_plt, ret, new_addr); +- s390_kernel_write(plt + (bpf_plt_target - bpf_plt), +- new_plt + (bpf_plt_target - bpf_plt), ++ bpf_jit_plt(&new_plt, ret, new_addr); ++ s390_kernel_write(&plt->target, &new_plt.target, + sizeof(void *)); + } + +diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c +index d34d5813d00660..777362cb4ea80b 100644 +--- a/arch/s390/pci/pci.c ++++ b/arch/s390/pci/pci.c +@@ -241,7 +241,7 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, + /* combine single writes by using store-block insn */ + void __iowrite64_copy(void __iomem *to, const void *from, size_t count) + { +- zpci_memcpy_toio(to, from, count); ++ zpci_memcpy_toio(to, from, count * 8); + } + + void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size, +diff --git a/arch/s390/pci/pci_irq.c b/arch/s390/pci/pci_irq.c +index ff8f24854c6462..84482a92133220 100644 +--- a/arch/s390/pci/pci_irq.c ++++ b/arch/s390/pci/pci_irq.c +@@ -268,33 +268,20 @@ static void zpci_floating_irq_handler(struct airq_struct *airq, + } + } + +-int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) ++static int __alloc_airq(struct zpci_dev *zdev, int msi_vecs, ++ unsigned long *bit) + { +- struct zpci_dev *zdev = to_zpci(pdev); +- unsigned int hwirq, msi_vecs, cpu; +- unsigned long bit; +- struct msi_desc *msi; +- struct msi_msg msg; +- int cpu_addr; +- int rc, irq; +- +- zdev->aisb = -1UL; +- zdev->msi_first_bit = -1U; +- if (type == PCI_CAP_ID_MSI && nvec > 1) +- return 1; +- msi_vecs = min_t(unsigned int, nvec, zdev->max_msi); +- + if (irq_delivery == DIRECTED) { + /* Allocate cpu vector bits */ +- bit = airq_iv_alloc(zpci_ibv[0], msi_vecs); +- if (bit == -1UL) ++ *bit = airq_iv_alloc(zpci_ibv[0], msi_vecs); ++ if (*bit == -1UL) + return -EIO; + } else { + /* Allocate adapter summary indicator bit */ +- bit = airq_iv_alloc_bit(zpci_sbv); +- if (bit == -1UL) ++ *bit = airq_iv_alloc_bit(zpci_sbv); ++ if (*bit == -1UL) + return -EIO; +- zdev->aisb = bit; ++ zdev->aisb = *bit; + + /* Create adapter interrupt vector */ + zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK, NULL); +@@ -302,27 +289,66 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) + return -ENOMEM; + + /* Wire up shortcut pointer */ +- zpci_ibv[bit] = zdev->aibv; ++ zpci_ibv[*bit] = zdev->aibv; + /* Each function has its own interrupt vector */ +- bit = 0; ++ *bit = 0; + } ++ return 0; ++} + +- /* Request MSI interrupts */ ++int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) ++{ ++ unsigned int hwirq, msi_vecs, irqs_per_msi, i, cpu; ++ struct zpci_dev *zdev = to_zpci(pdev); ++ struct msi_desc *msi; ++ struct msi_msg msg; ++ unsigned long bit; ++ int cpu_addr; ++ int rc, irq; ++ ++ zdev->aisb = -1UL; ++ zdev->msi_first_bit = -1U; ++ ++ msi_vecs = min_t(unsigned int, nvec, zdev->max_msi); ++ if (msi_vecs < nvec) { ++ pr_info("%s requested %d irqs, allocate system limit of %d", ++ pci_name(pdev), nvec, zdev->max_msi); ++ } ++ ++ rc = __alloc_airq(zdev, msi_vecs, &bit); ++ if (rc < 0) ++ return rc; ++ ++ /* ++ * Request MSI interrupts: ++ * When using MSI, nvec_used interrupt sources and their irq ++ * descriptors are controlled through one msi descriptor. ++ * Thus the outer loop over msi descriptors shall run only once, ++ * while two inner loops iterate over the interrupt vectors. ++ * When using MSI-X, each interrupt vector/irq descriptor ++ * is bound to exactly one msi descriptor (nvec_used is one). ++ * So the inner loops are executed once, while the outer iterates ++ * over the MSI-X descriptors. ++ */ + hwirq = bit; + msi_for_each_desc(msi, &pdev->dev, MSI_DESC_NOTASSOCIATED) { +- rc = -EIO; + if (hwirq - bit >= msi_vecs) + break; +- irq = __irq_alloc_descs(-1, 0, 1, 0, THIS_MODULE, +- (irq_delivery == DIRECTED) ? +- msi->affinity : NULL); ++ irqs_per_msi = min_t(unsigned int, msi_vecs, msi->nvec_used); ++ irq = __irq_alloc_descs(-1, 0, irqs_per_msi, 0, THIS_MODULE, ++ (irq_delivery == DIRECTED) ? ++ msi->affinity : NULL); + if (irq < 0) + return -ENOMEM; +- rc = irq_set_msi_desc(irq, msi); +- if (rc) +- return rc; +- irq_set_chip_and_handler(irq, &zpci_irq_chip, +- handle_percpu_irq); ++ ++ for (i = 0; i < irqs_per_msi; i++) { ++ rc = irq_set_msi_desc_off(irq, i, msi); ++ if (rc) ++ return rc; ++ irq_set_chip_and_handler(irq + i, &zpci_irq_chip, ++ handle_percpu_irq); ++ } ++ + msg.data = hwirq - bit; + if (irq_delivery == DIRECTED) { + if (msi->affinity) +@@ -335,31 +361,35 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) + msg.address_lo |= (cpu_addr << 8); + + for_each_possible_cpu(cpu) { +- airq_iv_set_data(zpci_ibv[cpu], hwirq, irq); ++ for (i = 0; i < irqs_per_msi; i++) ++ airq_iv_set_data(zpci_ibv[cpu], ++ hwirq + i, irq + i); + } + } else { + msg.address_lo = zdev->msi_addr & 0xffffffff; +- airq_iv_set_data(zdev->aibv, hwirq, irq); ++ for (i = 0; i < irqs_per_msi; i++) ++ airq_iv_set_data(zdev->aibv, hwirq + i, irq + i); + } + msg.address_hi = zdev->msi_addr >> 32; + pci_write_msi_msg(irq, &msg); +- hwirq++; ++ hwirq += irqs_per_msi; + } + + zdev->msi_first_bit = bit; +- zdev->msi_nr_irqs = msi_vecs; ++ zdev->msi_nr_irqs = hwirq - bit; + + rc = zpci_set_irq(zdev); + if (rc) + return rc; + +- return (msi_vecs == nvec) ? 0 : msi_vecs; ++ return (zdev->msi_nr_irqs == nvec) ? 0 : zdev->msi_nr_irqs; + } + + void arch_teardown_msi_irqs(struct pci_dev *pdev) + { + struct zpci_dev *zdev = to_zpci(pdev); + struct msi_desc *msi; ++ unsigned int i; + int rc; + + /* Disable interrupts */ +@@ -369,8 +399,10 @@ void arch_teardown_msi_irqs(struct pci_dev *pdev) + + /* Release MSI interrupts */ + msi_for_each_desc(msi, &pdev->dev, MSI_DESC_ASSOCIATED) { +- irq_set_msi_desc(msi->irq, NULL); +- irq_free_desc(msi->irq); ++ for (i = 0; i < msi->nvec_used; i++) { ++ irq_set_msi_desc(msi->irq + i, NULL); ++ irq_free_desc(msi->irq + i); ++ } + msi->msg.address_lo = 0; + msi->msg.address_hi = 0; + msi->msg.data = 0; +@@ -410,7 +442,7 @@ static void __init cpu_enable_directed_irq(void *unused) + union zpci_sic_iib iib = {{0}}; + union zpci_sic_iib ziib = {{0}}; + +- iib.cdiib.dibv_addr = (u64) zpci_ibv[smp_processor_id()]->vector; ++ iib.cdiib.dibv_addr = virt_to_phys(zpci_ibv[smp_processor_id()]->vector); + + zpci_set_irq_ctrl(SIC_IRQ_MODE_SET_CPU, 0, &iib); + zpci_set_irq_ctrl(SIC_IRQ_MODE_D_SINGLE, PCI_ISC, &ziib); +diff --git a/arch/s390/pci/pci_mmio.c b/arch/s390/pci/pci_mmio.c +index 5880893329310d..a90499c087f0c5 100644 +--- a/arch/s390/pci/pci_mmio.c ++++ b/arch/s390/pci/pci_mmio.c +@@ -97,9 +97,9 @@ static inline int __memcpy_toio_inuser(void __iomem *dst, + return -EINVAL; + + while (n > 0) { +- size = zpci_get_max_write_size((u64 __force) dst, +- (u64 __force) src, n, +- ZPCI_MAX_WRITE_SIZE); ++ size = zpci_get_max_io_size((u64 __force) dst, ++ (u64 __force) src, n, ++ ZPCI_MAX_WRITE_SIZE); + if (size > 8) /* main path */ + rc = __pcistb_mio_inuser(dst, src, size, &status); + else +@@ -242,9 +242,9 @@ static inline int __memcpy_fromio_inuser(void __user *dst, + u8 status; + + while (n > 0) { +- size = zpci_get_max_write_size((u64 __force) src, +- (u64 __force) dst, n, +- ZPCI_MAX_READ_SIZE); ++ size = zpci_get_max_io_size((u64 __force) src, ++ (u64 __force) dst, n, ++ ZPCI_MAX_READ_SIZE); + rc = __pcilg_mio_inuser(dst, src, size, &status); + if (rc) + break; +diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug +index c449e7c1b20ff5..8bcd6c1431a95b 100644 +--- a/arch/sh/Kconfig.debug ++++ b/arch/sh/Kconfig.debug +@@ -22,6 +22,17 @@ config STACK_DEBUG + every function call and will therefore incur a major + performance hit. Most users should say N. + ++config EARLY_PRINTK ++ bool "Early printk" ++ depends on SH_STANDARD_BIOS ++ help ++ Say Y here to redirect kernel printk messages to the serial port ++ used by the SH-IPL bootloader, starting very early in the boot ++ process and ending when the kernel's serial console is initialised. ++ This option is only useful while porting the kernel to a new machine, ++ when the kernel may crash or hang before the serial console is ++ initialised. If unsure, say N. ++ + config 4KSTACKS + bool "Use 4Kb for kernel stacks instead of 8Kb" + depends on DEBUG_KERNEL && (MMU || BROKEN) && !PAGE_SIZE_64KB +diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c +index 3be293335de545..7a788d44cc7349 100644 +--- a/arch/sh/boards/mach-ecovec24/setup.c ++++ b/arch/sh/boards/mach-ecovec24/setup.c +@@ -1220,7 +1220,7 @@ static int __init arch_setup(void) + lcdc_info.ch[0].num_modes = ARRAY_SIZE(ecovec_dvi_modes); + + /* No backlight */ +- gpio_backlight_data.fbdev = NULL; ++ gpio_backlight_data.dev = NULL; + + gpio_set_value(GPIO_PTA2, 1); + gpio_set_value(GPIO_PTU1, 1); +diff --git a/arch/sh/include/asm/cacheflush.h b/arch/sh/include/asm/cacheflush.h +index 878b6b551bd2d0..51112f54552b32 100644 +--- a/arch/sh/include/asm/cacheflush.h ++++ b/arch/sh/include/asm/cacheflush.h +@@ -90,6 +90,7 @@ extern void copy_from_user_page(struct vm_area_struct *vma, + unsigned long len); + + #define flush_cache_vmap(start, end) local_flush_cache_all(NULL) ++#define flush_cache_vmap_early(start, end) do { } while (0) + #define flush_cache_vunmap(start, end) local_flush_cache_all(NULL) + + #define flush_dcache_mmap_lock(mapping) do { } while (0) +diff --git a/arch/sh/kernel/kprobes.c b/arch/sh/kernel/kprobes.c +index aed1ea8e2c2f06..74051b8ddf3e7b 100644 +--- a/arch/sh/kernel/kprobes.c ++++ b/arch/sh/kernel/kprobes.c +@@ -44,17 +44,12 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) + if (OPCODE_RTE(opcode)) + return -EFAULT; /* Bad breakpoint */ + ++ memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); + p->opcode = opcode; + + return 0; + } + +-void __kprobes arch_copy_kprobe(struct kprobe *p) +-{ +- memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); +- p->opcode = *p->addr; +-} +- + void __kprobes arch_arm_kprobe(struct kprobe *p) + { + *p->addr = BREAKPOINT_INSTRUCTION; +diff --git a/arch/sh/kernel/sys_sh32.c b/arch/sh/kernel/sys_sh32.c +index 9dca568509a5e5..d6f4afcb0e8705 100644 +--- a/arch/sh/kernel/sys_sh32.c ++++ b/arch/sh/kernel/sys_sh32.c +@@ -59,3 +59,14 @@ asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1, + (u64)len0 << 32 | len1, advice); + #endif + } ++ ++/* ++ * swap the arguments the way that libc wants them instead of ++ * moving flags ahead of the 64-bit nbytes argument ++ */ ++SYSCALL_DEFINE6(sh_sync_file_range6, int, fd, SC_ARG64(offset), ++ SC_ARG64(nbytes), unsigned int, flags) ++{ ++ return ksys_sync_file_range(fd, SC_VAL64(loff_t, offset), ++ SC_VAL64(loff_t, nbytes), flags); ++} +diff --git a/arch/sh/kernel/syscalls/syscall.tbl b/arch/sh/kernel/syscalls/syscall.tbl +index e90d585c4d3e73..7e1ceb2ba57211 100644 +--- a/arch/sh/kernel/syscalls/syscall.tbl ++++ b/arch/sh/kernel/syscalls/syscall.tbl +@@ -321,7 +321,7 @@ + 311 common set_robust_list sys_set_robust_list + 312 common get_robust_list sys_get_robust_list + 313 common splice sys_splice +-314 common sync_file_range sys_sync_file_range ++314 common sync_file_range sys_sh_sync_file_range6 + 315 common tee sys_tee + 316 common vmsplice sys_vmsplice + 317 common move_pages sys_move_pages +@@ -395,6 +395,7 @@ + 385 common pkey_alloc sys_pkey_alloc + 386 common pkey_free sys_pkey_free + 387 common rseq sys_rseq ++388 common sync_file_range2 sys_sync_file_range2 + # room for arch specific syscalls + 393 common semget sys_semget + 394 common semctl sys_semctl +diff --git a/arch/sh/lib/checksum.S b/arch/sh/lib/checksum.S +index 3e07074e009813..06fed5a21e8baa 100644 +--- a/arch/sh/lib/checksum.S ++++ b/arch/sh/lib/checksum.S +@@ -33,7 +33,8 @@ + */ + + /* +- * asmlinkage __wsum csum_partial(const void *buf, int len, __wsum sum); ++ * unsigned int csum_partial(const unsigned char *buf, int len, ++ * unsigned int sum); + */ + + .text +@@ -45,31 +46,11 @@ ENTRY(csum_partial) + * Fortunately, it is easy to convert 2-byte alignment to 4-byte + * alignment for the unrolled loop. + */ ++ mov r5, r1 + mov r4, r0 +- tst #3, r0 ! Check alignment. +- bt/s 2f ! Jump if alignment is ok. +- mov r4, r7 ! Keep a copy to check for alignment ++ tst #2, r0 ! Check alignment. ++ bt 2f ! Jump if alignment is ok. + ! +- tst #1, r0 ! Check alignment. +- bt 21f ! Jump if alignment is boundary of 2bytes. +- +- ! buf is odd +- tst r5, r5 +- add #-1, r5 +- bt 9f +- mov.b @r4+, r0 +- extu.b r0, r0 +- addc r0, r6 ! t=0 from previous tst +- mov r6, r0 +- shll8 r6 +- shlr16 r0 +- shlr8 r0 +- or r0, r6 +- mov r4, r0 +- tst #2, r0 +- bt 2f +-21: +- ! buf is 2 byte aligned (len could be 0) + add #-2, r5 ! Alignment uses up two bytes. + cmp/pz r5 ! + bt/s 1f ! Jump if we had at least two bytes. +@@ -77,17 +58,16 @@ ENTRY(csum_partial) + bra 6f + add #2, r5 ! r5 was < 2. Deal with it. + 1: ++ mov r5, r1 ! Save new len for later use. + mov.w @r4+, r0 + extu.w r0, r0 + addc r0, r6 + bf 2f + add #1, r6 + 2: +- ! buf is 4 byte aligned (len could be 0) +- mov r5, r1 + mov #-5, r0 +- shld r0, r1 +- tst r1, r1 ++ shld r0, r5 ++ tst r5, r5 + bt/s 4f ! if it's =0, go to 4f + clrt + .align 2 +@@ -109,31 +89,30 @@ ENTRY(csum_partial) + addc r0, r6 + addc r2, r6 + movt r0 +- dt r1 ++ dt r5 + bf/s 3b + cmp/eq #1, r0 +- ! here, we know r1==0 +- addc r1, r6 ! add carry to r6 ++ ! here, we know r5==0 ++ addc r5, r6 ! add carry to r6 + 4: +- mov r5, r0 ++ mov r1, r0 + and #0x1c, r0 + tst r0, r0 +- bt 6f +- ! 4 bytes or more remaining +- mov r0, r1 +- shlr2 r1 ++ bt/s 6f ++ mov r0, r5 ++ shlr2 r5 + mov #0, r2 + 5: + addc r2, r6 + mov.l @r4+, r2 + movt r0 +- dt r1 ++ dt r5 + bf/s 5b + cmp/eq #1, r0 + addc r2, r6 +- addc r1, r6 ! r1==0 here, so it means add carry-bit ++ addc r5, r6 ! r5==0 here, so it means add carry-bit + 6: +- ! 3 bytes or less remaining ++ mov r1, r5 + mov #3, r0 + and r0, r5 + tst r5, r5 +@@ -159,16 +138,6 @@ ENTRY(csum_partial) + mov #0, r0 + addc r0, r6 + 9: +- ! Check if the buffer was misaligned, if so realign sum +- mov r7, r0 +- tst #1, r0 +- bt 10f +- mov r6, r0 +- shll8 r6 +- shlr16 r0 +- shlr8 r0 +- or r0, r6 +-10: + rts + mov r6, r0 + +diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile +index 7417345c6639a3..2a03daa68f2857 100644 +--- a/arch/sparc/Makefile ++++ b/arch/sparc/Makefile +@@ -60,7 +60,7 @@ libs-y += arch/sparc/prom/ + libs-y += arch/sparc/lib/ + + drivers-$(CONFIG_PM) += arch/sparc/power/ +-drivers-$(CONFIG_FB) += arch/sparc/video/ ++drivers-$(CONFIG_FB_CORE) += arch/sparc/video/ + + boot := arch/sparc/boot + +@@ -76,9 +76,8 @@ install: + archheaders: + $(Q)$(MAKE) $(build)=arch/sparc/kernel/syscalls all + +-PHONY += vdso_install +-vdso_install: +- $(Q)$(MAKE) $(build)=arch/sparc/vdso $@ ++vdso-install-$(CONFIG_SPARC64) += arch/sparc/vdso/vdso64.so.dbg ++vdso-install-$(CONFIG_COMPAT) += arch/sparc/vdso/vdso32.so.dbg + + # This is the image used for packaging + KBUILD_IMAGE := $(boot)/zImage +diff --git a/arch/sparc/include/asm/cacheflush_32.h b/arch/sparc/include/asm/cacheflush_32.h +index f3b7270bf71b26..9fee0ccfccb8e1 100644 +--- a/arch/sparc/include/asm/cacheflush_32.h ++++ b/arch/sparc/include/asm/cacheflush_32.h +@@ -48,6 +48,7 @@ static inline void flush_dcache_page(struct page *page) + #define flush_dcache_mmap_unlock(mapping) do { } while (0) + + #define flush_cache_vmap(start, end) flush_cache_all() ++#define flush_cache_vmap_early(start, end) do { } while (0) + #define flush_cache_vunmap(start, end) flush_cache_all() + + /* When a context switch happens we must flush all user windows so that +diff --git a/arch/sparc/include/asm/cacheflush_64.h b/arch/sparc/include/asm/cacheflush_64.h +index 0e879004efff16..2b1261b77ecd1b 100644 +--- a/arch/sparc/include/asm/cacheflush_64.h ++++ b/arch/sparc/include/asm/cacheflush_64.h +@@ -75,6 +75,7 @@ void flush_ptrace_access(struct vm_area_struct *, struct page *, + #define flush_dcache_mmap_unlock(mapping) do { } while (0) + + #define flush_cache_vmap(start, end) do { } while (0) ++#define flush_cache_vmap_early(start, end) do { } while (0) + #define flush_cache_vunmap(start, end) do { } while (0) + + #endif /* !__ASSEMBLY__ */ +diff --git a/arch/sparc/include/asm/jump_label.h b/arch/sparc/include/asm/jump_label.h +index 94eb529dcb7762..2718cbea826a7d 100644 +--- a/arch/sparc/include/asm/jump_label.h ++++ b/arch/sparc/include/asm/jump_label.h +@@ -10,7 +10,7 @@ + + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + "nop\n\t" + "nop\n\t" + ".pushsection __jump_table, \"aw\"\n\t" +@@ -26,7 +26,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran + + static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + "b %l[l_yes]\n\t" + "nop\n\t" + ".pushsection __jump_table, \"aw\"\n\t" +diff --git a/arch/sparc/include/asm/oplib_64.h b/arch/sparc/include/asm/oplib_64.h +index a67abebd43592f..1b86d02a84556a 100644 +--- a/arch/sparc/include/asm/oplib_64.h ++++ b/arch/sparc/include/asm/oplib_64.h +@@ -247,6 +247,7 @@ void prom_sun4v_guest_soft_state(void); + int prom_ihandle2path(int handle, char *buffer, int bufsize); + + /* Client interface level routines. */ ++void prom_cif_init(void *cif_handler); + void p1275_cmd_direct(unsigned long *); + + #endif /* !(__SPARC64_OPLIB_H) */ +diff --git a/arch/sparc/include/asm/parport.h b/arch/sparc/include/asm/parport.h +index 0a7ffcfd59cda0..e2eed8f97665fb 100644 +--- a/arch/sparc/include/asm/parport.h ++++ b/arch/sparc/include/asm/parport.h +@@ -1,256 +1,11 @@ + /* SPDX-License-Identifier: GPL-2.0 */ +-/* parport.h: sparc64 specific parport initialization and dma. +- * +- * Copyright (C) 1999 Eddie C. Dost (ecd@skynet.be) +- */ ++#ifndef ___ASM_SPARC_PARPORT_H ++#define ___ASM_SPARC_PARPORT_H + +-#ifndef _ASM_SPARC64_PARPORT_H +-#define _ASM_SPARC64_PARPORT_H 1 +- +-#include +-#include +- +-#include +-#include +-#include +- +-#define PARPORT_PC_MAX_PORTS PARPORT_MAX +- +-/* +- * While sparc64 doesn't have an ISA DMA API, we provide something that looks +- * close enough to make parport_pc happy +- */ +-#define HAS_DMA +- +-#ifdef CONFIG_PARPORT_PC_FIFO +-static DEFINE_SPINLOCK(dma_spin_lock); +- +-#define claim_dma_lock() \ +-({ unsigned long flags; \ +- spin_lock_irqsave(&dma_spin_lock, flags); \ +- flags; \ +-}) +- +-#define release_dma_lock(__flags) \ +- spin_unlock_irqrestore(&dma_spin_lock, __flags); ++#if defined(__sparc__) && defined(__arch64__) ++#include ++#else ++#include ++#endif + #endif + +-static struct sparc_ebus_info { +- struct ebus_dma_info info; +- unsigned int addr; +- unsigned int count; +- int lock; +- +- struct parport *port; +-} sparc_ebus_dmas[PARPORT_PC_MAX_PORTS]; +- +-static DECLARE_BITMAP(dma_slot_map, PARPORT_PC_MAX_PORTS); +- +-static inline int request_dma(unsigned int dmanr, const char *device_id) +-{ +- if (dmanr >= PARPORT_PC_MAX_PORTS) +- return -EINVAL; +- if (xchg(&sparc_ebus_dmas[dmanr].lock, 1) != 0) +- return -EBUSY; +- return 0; +-} +- +-static inline void free_dma(unsigned int dmanr) +-{ +- if (dmanr >= PARPORT_PC_MAX_PORTS) { +- printk(KERN_WARNING "Trying to free DMA%d\n", dmanr); +- return; +- } +- if (xchg(&sparc_ebus_dmas[dmanr].lock, 0) == 0) { +- printk(KERN_WARNING "Trying to free free DMA%d\n", dmanr); +- return; +- } +-} +- +-static inline void enable_dma(unsigned int dmanr) +-{ +- ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 1); +- +- if (ebus_dma_request(&sparc_ebus_dmas[dmanr].info, +- sparc_ebus_dmas[dmanr].addr, +- sparc_ebus_dmas[dmanr].count)) +- BUG(); +-} +- +-static inline void disable_dma(unsigned int dmanr) +-{ +- ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 0); +-} +- +-static inline void clear_dma_ff(unsigned int dmanr) +-{ +- /* nothing */ +-} +- +-static inline void set_dma_mode(unsigned int dmanr, char mode) +-{ +- ebus_dma_prepare(&sparc_ebus_dmas[dmanr].info, (mode != DMA_MODE_WRITE)); +-} +- +-static inline void set_dma_addr(unsigned int dmanr, unsigned int addr) +-{ +- sparc_ebus_dmas[dmanr].addr = addr; +-} +- +-static inline void set_dma_count(unsigned int dmanr, unsigned int count) +-{ +- sparc_ebus_dmas[dmanr].count = count; +-} +- +-static inline unsigned int get_dma_residue(unsigned int dmanr) +-{ +- return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info); +-} +- +-static int ecpp_probe(struct platform_device *op) +-{ +- unsigned long base = op->resource[0].start; +- unsigned long config = op->resource[1].start; +- unsigned long d_base = op->resource[2].start; +- unsigned long d_len; +- struct device_node *parent; +- struct parport *p; +- int slot, err; +- +- parent = op->dev.of_node->parent; +- if (of_node_name_eq(parent, "dma")) { +- p = parport_pc_probe_port(base, base + 0x400, +- op->archdata.irqs[0], PARPORT_DMA_NOFIFO, +- op->dev.parent->parent, 0); +- if (!p) +- return -ENOMEM; +- dev_set_drvdata(&op->dev, p); +- return 0; +- } +- +- for (slot = 0; slot < PARPORT_PC_MAX_PORTS; slot++) { +- if (!test_and_set_bit(slot, dma_slot_map)) +- break; +- } +- err = -ENODEV; +- if (slot >= PARPORT_PC_MAX_PORTS) +- goto out_err; +- +- spin_lock_init(&sparc_ebus_dmas[slot].info.lock); +- +- d_len = (op->resource[2].end - d_base) + 1UL; +- sparc_ebus_dmas[slot].info.regs = +- of_ioremap(&op->resource[2], 0, d_len, "ECPP DMA"); +- +- if (!sparc_ebus_dmas[slot].info.regs) +- goto out_clear_map; +- +- sparc_ebus_dmas[slot].info.flags = 0; +- sparc_ebus_dmas[slot].info.callback = NULL; +- sparc_ebus_dmas[slot].info.client_cookie = NULL; +- sparc_ebus_dmas[slot].info.irq = 0xdeadbeef; +- strcpy(sparc_ebus_dmas[slot].info.name, "parport"); +- if (ebus_dma_register(&sparc_ebus_dmas[slot].info)) +- goto out_unmap_regs; +- +- ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 1); +- +- /* Configure IRQ to Push Pull, Level Low */ +- /* Enable ECP, set bit 2 of the CTR first */ +- outb(0x04, base + 0x02); +- ns87303_modify(config, PCR, +- PCR_EPP_ENABLE | +- PCR_IRQ_ODRAIN, +- PCR_ECP_ENABLE | +- PCR_ECP_CLK_ENA | +- PCR_IRQ_POLAR); +- +- /* CTR bit 5 controls direction of port */ +- ns87303_modify(config, PTR, +- 0, PTR_LPT_REG_DIR); +- +- p = parport_pc_probe_port(base, base + 0x400, +- op->archdata.irqs[0], +- slot, +- op->dev.parent, +- 0); +- err = -ENOMEM; +- if (!p) +- goto out_disable_irq; +- +- dev_set_drvdata(&op->dev, p); +- +- return 0; +- +-out_disable_irq: +- ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0); +- ebus_dma_unregister(&sparc_ebus_dmas[slot].info); +- +-out_unmap_regs: +- of_iounmap(&op->resource[2], sparc_ebus_dmas[slot].info.regs, d_len); +- +-out_clear_map: +- clear_bit(slot, dma_slot_map); +- +-out_err: +- return err; +-} +- +-static int ecpp_remove(struct platform_device *op) +-{ +- struct parport *p = dev_get_drvdata(&op->dev); +- int slot = p->dma; +- +- parport_pc_unregister_port(p); +- +- if (slot != PARPORT_DMA_NOFIFO) { +- unsigned long d_base = op->resource[2].start; +- unsigned long d_len; +- +- d_len = (op->resource[2].end - d_base) + 1UL; +- +- ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0); +- ebus_dma_unregister(&sparc_ebus_dmas[slot].info); +- of_iounmap(&op->resource[2], +- sparc_ebus_dmas[slot].info.regs, +- d_len); +- clear_bit(slot, dma_slot_map); +- } +- +- return 0; +-} +- +-static const struct of_device_id ecpp_match[] = { +- { +- .name = "ecpp", +- }, +- { +- .name = "parallel", +- .compatible = "ecpp", +- }, +- { +- .name = "parallel", +- .compatible = "ns87317-ecpp", +- }, +- { +- .name = "parallel", +- .compatible = "pnpALI,1533,3", +- }, +- {}, +-}; +- +-static struct platform_driver ecpp_driver = { +- .driver = { +- .name = "ecpp", +- .of_match_table = ecpp_match, +- }, +- .probe = ecpp_probe, +- .remove = ecpp_remove, +-}; +- +-static int parport_pc_find_nonpci_ports(int autoirq, int autodma) +-{ +- return platform_driver_register(&ecpp_driver); +-} +- +-#endif /* !(_ASM_SPARC64_PARPORT_H */ +diff --git a/arch/sparc/include/asm/parport_64.h b/arch/sparc/include/asm/parport_64.h +new file mode 100644 +index 00000000000000..0a7ffcfd59cda0 +--- /dev/null ++++ b/arch/sparc/include/asm/parport_64.h +@@ -0,0 +1,256 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* parport.h: sparc64 specific parport initialization and dma. ++ * ++ * Copyright (C) 1999 Eddie C. Dost (ecd@skynet.be) ++ */ ++ ++#ifndef _ASM_SPARC64_PARPORT_H ++#define _ASM_SPARC64_PARPORT_H 1 ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define PARPORT_PC_MAX_PORTS PARPORT_MAX ++ ++/* ++ * While sparc64 doesn't have an ISA DMA API, we provide something that looks ++ * close enough to make parport_pc happy ++ */ ++#define HAS_DMA ++ ++#ifdef CONFIG_PARPORT_PC_FIFO ++static DEFINE_SPINLOCK(dma_spin_lock); ++ ++#define claim_dma_lock() \ ++({ unsigned long flags; \ ++ spin_lock_irqsave(&dma_spin_lock, flags); \ ++ flags; \ ++}) ++ ++#define release_dma_lock(__flags) \ ++ spin_unlock_irqrestore(&dma_spin_lock, __flags); ++#endif ++ ++static struct sparc_ebus_info { ++ struct ebus_dma_info info; ++ unsigned int addr; ++ unsigned int count; ++ int lock; ++ ++ struct parport *port; ++} sparc_ebus_dmas[PARPORT_PC_MAX_PORTS]; ++ ++static DECLARE_BITMAP(dma_slot_map, PARPORT_PC_MAX_PORTS); ++ ++static inline int request_dma(unsigned int dmanr, const char *device_id) ++{ ++ if (dmanr >= PARPORT_PC_MAX_PORTS) ++ return -EINVAL; ++ if (xchg(&sparc_ebus_dmas[dmanr].lock, 1) != 0) ++ return -EBUSY; ++ return 0; ++} ++ ++static inline void free_dma(unsigned int dmanr) ++{ ++ if (dmanr >= PARPORT_PC_MAX_PORTS) { ++ printk(KERN_WARNING "Trying to free DMA%d\n", dmanr); ++ return; ++ } ++ if (xchg(&sparc_ebus_dmas[dmanr].lock, 0) == 0) { ++ printk(KERN_WARNING "Trying to free free DMA%d\n", dmanr); ++ return; ++ } ++} ++ ++static inline void enable_dma(unsigned int dmanr) ++{ ++ ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 1); ++ ++ if (ebus_dma_request(&sparc_ebus_dmas[dmanr].info, ++ sparc_ebus_dmas[dmanr].addr, ++ sparc_ebus_dmas[dmanr].count)) ++ BUG(); ++} ++ ++static inline void disable_dma(unsigned int dmanr) ++{ ++ ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 0); ++} ++ ++static inline void clear_dma_ff(unsigned int dmanr) ++{ ++ /* nothing */ ++} ++ ++static inline void set_dma_mode(unsigned int dmanr, char mode) ++{ ++ ebus_dma_prepare(&sparc_ebus_dmas[dmanr].info, (mode != DMA_MODE_WRITE)); ++} ++ ++static inline void set_dma_addr(unsigned int dmanr, unsigned int addr) ++{ ++ sparc_ebus_dmas[dmanr].addr = addr; ++} ++ ++static inline void set_dma_count(unsigned int dmanr, unsigned int count) ++{ ++ sparc_ebus_dmas[dmanr].count = count; ++} ++ ++static inline unsigned int get_dma_residue(unsigned int dmanr) ++{ ++ return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info); ++} ++ ++static int ecpp_probe(struct platform_device *op) ++{ ++ unsigned long base = op->resource[0].start; ++ unsigned long config = op->resource[1].start; ++ unsigned long d_base = op->resource[2].start; ++ unsigned long d_len; ++ struct device_node *parent; ++ struct parport *p; ++ int slot, err; ++ ++ parent = op->dev.of_node->parent; ++ if (of_node_name_eq(parent, "dma")) { ++ p = parport_pc_probe_port(base, base + 0x400, ++ op->archdata.irqs[0], PARPORT_DMA_NOFIFO, ++ op->dev.parent->parent, 0); ++ if (!p) ++ return -ENOMEM; ++ dev_set_drvdata(&op->dev, p); ++ return 0; ++ } ++ ++ for (slot = 0; slot < PARPORT_PC_MAX_PORTS; slot++) { ++ if (!test_and_set_bit(slot, dma_slot_map)) ++ break; ++ } ++ err = -ENODEV; ++ if (slot >= PARPORT_PC_MAX_PORTS) ++ goto out_err; ++ ++ spin_lock_init(&sparc_ebus_dmas[slot].info.lock); ++ ++ d_len = (op->resource[2].end - d_base) + 1UL; ++ sparc_ebus_dmas[slot].info.regs = ++ of_ioremap(&op->resource[2], 0, d_len, "ECPP DMA"); ++ ++ if (!sparc_ebus_dmas[slot].info.regs) ++ goto out_clear_map; ++ ++ sparc_ebus_dmas[slot].info.flags = 0; ++ sparc_ebus_dmas[slot].info.callback = NULL; ++ sparc_ebus_dmas[slot].info.client_cookie = NULL; ++ sparc_ebus_dmas[slot].info.irq = 0xdeadbeef; ++ strcpy(sparc_ebus_dmas[slot].info.name, "parport"); ++ if (ebus_dma_register(&sparc_ebus_dmas[slot].info)) ++ goto out_unmap_regs; ++ ++ ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 1); ++ ++ /* Configure IRQ to Push Pull, Level Low */ ++ /* Enable ECP, set bit 2 of the CTR first */ ++ outb(0x04, base + 0x02); ++ ns87303_modify(config, PCR, ++ PCR_EPP_ENABLE | ++ PCR_IRQ_ODRAIN, ++ PCR_ECP_ENABLE | ++ PCR_ECP_CLK_ENA | ++ PCR_IRQ_POLAR); ++ ++ /* CTR bit 5 controls direction of port */ ++ ns87303_modify(config, PTR, ++ 0, PTR_LPT_REG_DIR); ++ ++ p = parport_pc_probe_port(base, base + 0x400, ++ op->archdata.irqs[0], ++ slot, ++ op->dev.parent, ++ 0); ++ err = -ENOMEM; ++ if (!p) ++ goto out_disable_irq; ++ ++ dev_set_drvdata(&op->dev, p); ++ ++ return 0; ++ ++out_disable_irq: ++ ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0); ++ ebus_dma_unregister(&sparc_ebus_dmas[slot].info); ++ ++out_unmap_regs: ++ of_iounmap(&op->resource[2], sparc_ebus_dmas[slot].info.regs, d_len); ++ ++out_clear_map: ++ clear_bit(slot, dma_slot_map); ++ ++out_err: ++ return err; ++} ++ ++static int ecpp_remove(struct platform_device *op) ++{ ++ struct parport *p = dev_get_drvdata(&op->dev); ++ int slot = p->dma; ++ ++ parport_pc_unregister_port(p); ++ ++ if (slot != PARPORT_DMA_NOFIFO) { ++ unsigned long d_base = op->resource[2].start; ++ unsigned long d_len; ++ ++ d_len = (op->resource[2].end - d_base) + 1UL; ++ ++ ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0); ++ ebus_dma_unregister(&sparc_ebus_dmas[slot].info); ++ of_iounmap(&op->resource[2], ++ sparc_ebus_dmas[slot].info.regs, ++ d_len); ++ clear_bit(slot, dma_slot_map); ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id ecpp_match[] = { ++ { ++ .name = "ecpp", ++ }, ++ { ++ .name = "parallel", ++ .compatible = "ecpp", ++ }, ++ { ++ .name = "parallel", ++ .compatible = "ns87317-ecpp", ++ }, ++ { ++ .name = "parallel", ++ .compatible = "pnpALI,1533,3", ++ }, ++ {}, ++}; ++ ++static struct platform_driver ecpp_driver = { ++ .driver = { ++ .name = "ecpp", ++ .of_match_table = ecpp_match, ++ }, ++ .probe = ecpp_probe, ++ .remove = ecpp_remove, ++}; ++ ++static int parport_pc_find_nonpci_ports(int autoirq, int autodma) ++{ ++ return platform_driver_register(&ecpp_driver); ++} ++ ++#endif /* !(_ASM_SPARC64_PARPORT_H */ +diff --git a/arch/sparc/include/asm/smp_64.h b/arch/sparc/include/asm/smp_64.h +index 505b6700805dd6..0964fede0b2cc6 100644 +--- a/arch/sparc/include/asm/smp_64.h ++++ b/arch/sparc/include/asm/smp_64.h +@@ -47,7 +47,6 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask); + int hard_smp_processor_id(void); + #define raw_smp_processor_id() (current_thread_info()->cpu) + +-void smp_fill_in_cpu_possible_map(void); + void smp_fill_in_sib_core_maps(void); + void __noreturn cpu_play_dead(void); + +@@ -77,7 +76,6 @@ void __cpu_die(unsigned int cpu); + #define smp_fill_in_sib_core_maps() do { } while (0) + #define smp_fetch_global_regs() do { } while (0) + #define smp_fetch_global_pmu() do { } while (0) +-#define smp_fill_in_cpu_possible_map() do { } while (0) + #define smp_init_cpu_poke() do { } while (0) + #define scheduler_poke() do { } while (0) + +diff --git a/arch/sparc/include/uapi/asm/termbits.h b/arch/sparc/include/uapi/asm/termbits.h +index 4321322701fcfd..0da2b1adc0f526 100644 +--- a/arch/sparc/include/uapi/asm/termbits.h ++++ b/arch/sparc/include/uapi/asm/termbits.h +@@ -10,16 +10,6 @@ typedef unsigned int tcflag_t; + typedef unsigned long tcflag_t; + #endif + +-#define NCC 8 +-struct termio { +- unsigned short c_iflag; /* input mode flags */ +- unsigned short c_oflag; /* output mode flags */ +- unsigned short c_cflag; /* control mode flags */ +- unsigned short c_lflag; /* local mode flags */ +- unsigned char c_line; /* line discipline */ +- unsigned char c_cc[NCC]; /* control characters */ +-}; +- + #define NCCS 17 + struct termios { + tcflag_t c_iflag; /* input mode flags */ +diff --git a/arch/sparc/include/uapi/asm/termios.h b/arch/sparc/include/uapi/asm/termios.h +index ee86f4093d83e9..cceb32260881e7 100644 +--- a/arch/sparc/include/uapi/asm/termios.h ++++ b/arch/sparc/include/uapi/asm/termios.h +@@ -40,5 +40,14 @@ struct winsize { + unsigned short ws_ypixel; + }; + ++#define NCC 8 ++struct termio { ++ unsigned short c_iflag; /* input mode flags */ ++ unsigned short c_oflag; /* output mode flags */ ++ unsigned short c_cflag; /* control mode flags */ ++ unsigned short c_lflag; /* local mode flags */ ++ unsigned char c_line; /* line discipline */ ++ unsigned char c_cc[NCC]; /* control characters */ ++}; + + #endif /* _UAPI_SPARC_TERMIOS_H */ +diff --git a/arch/sparc/kernel/leon_pci_grpci1.c b/arch/sparc/kernel/leon_pci_grpci1.c +index 8700a0e3b0df7d..b2b639bee06848 100644 +--- a/arch/sparc/kernel/leon_pci_grpci1.c ++++ b/arch/sparc/kernel/leon_pci_grpci1.c +@@ -697,7 +697,7 @@ static int grpci1_of_probe(struct platform_device *ofdev) + return err; + } + +-static const struct of_device_id grpci1_of_match[] __initconst = { ++static const struct of_device_id grpci1_of_match[] = { + { + .name = "GAISLER_PCIFBRG", + }, +diff --git a/arch/sparc/kernel/leon_pci_grpci2.c b/arch/sparc/kernel/leon_pci_grpci2.c +index 60b6bdf7761fb3..ac2acd62a24ece 100644 +--- a/arch/sparc/kernel/leon_pci_grpci2.c ++++ b/arch/sparc/kernel/leon_pci_grpci2.c +@@ -889,7 +889,7 @@ static int grpci2_of_probe(struct platform_device *ofdev) + return err; + } + +-static const struct of_device_id grpci2_of_match[] __initconst = { ++static const struct of_device_id grpci2_of_match[] = { + { + .name = "GAISLER_GRPCI2", + }, +diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c +index 17cdfdbf1f3b78..149adc09475306 100644 +--- a/arch/sparc/kernel/nmi.c ++++ b/arch/sparc/kernel/nmi.c +@@ -279,7 +279,7 @@ static int __init setup_nmi_watchdog(char *str) + if (!strncmp(str, "panic", 5)) + panic_on_timeout = 1; + +- return 0; ++ return 1; + } + __setup("nmi_watchdog=", setup_nmi_watchdog); + +diff --git a/arch/sparc/kernel/prom_64.c b/arch/sparc/kernel/prom_64.c +index 998aa693d49125..ba82884cb92aa3 100644 +--- a/arch/sparc/kernel/prom_64.c ++++ b/arch/sparc/kernel/prom_64.c +@@ -483,7 +483,9 @@ static void *record_one_cpu(struct device_node *dp, int cpuid, int arg) + ncpus_probed++; + #ifdef CONFIG_SMP + set_cpu_present(cpuid, true); +- set_cpu_possible(cpuid, true); ++ ++ if (num_possible_cpus() < nr_cpu_ids) ++ set_cpu_possible(cpuid, true); + #endif + return NULL; + } +diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c +index 6546ca9d4d3f1f..bda81f314bc257 100644 +--- a/arch/sparc/kernel/setup_64.c ++++ b/arch/sparc/kernel/setup_64.c +@@ -684,7 +684,6 @@ void __init setup_arch(char **cmdline_p) + + paging_init(); + init_sparc64_elf_hwcap(); +- smp_fill_in_cpu_possible_map(); + /* + * Once the OF device tree and MDESC have been setup and nr_cpus has + * been parsed, we know the list of possible cpus. Therefore we can +diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c +index f3969a3600dbfe..e50c38eba2b876 100644 +--- a/arch/sparc/kernel/smp_64.c ++++ b/arch/sparc/kernel/smp_64.c +@@ -1220,20 +1220,6 @@ void __init smp_setup_processor_id(void) + xcall_deliver_impl = hypervisor_xcall_deliver; + } + +-void __init smp_fill_in_cpu_possible_map(void) +-{ +- int possible_cpus = num_possible_cpus(); +- int i; +- +- if (possible_cpus > nr_cpu_ids) +- possible_cpus = nr_cpu_ids; +- +- for (i = 0; i < possible_cpus; i++) +- set_cpu_possible(i, true); +- for (; i < NR_CPUS; i++) +- set_cpu_possible(i, false); +-} +- + void smp_fill_in_sib_core_maps(void) + { + unsigned int i; +diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S +index a45f0f31fe51ab..a3d308f2043e5f 100644 +--- a/arch/sparc/kernel/sys32.S ++++ b/arch/sparc/kernel/sys32.S +@@ -18,224 +18,3 @@ sys32_mmap2: + sethi %hi(sys_mmap), %g1 + jmpl %g1 + %lo(sys_mmap), %g0 + sllx %o5, 12, %o5 +- +- .align 32 +- .globl sys32_socketcall +-sys32_socketcall: /* %o0=call, %o1=args */ +- cmp %o0, 1 +- bl,pn %xcc, do_einval +- cmp %o0, 18 +- bg,pn %xcc, do_einval +- sub %o0, 1, %o0 +- sllx %o0, 5, %o0 +- sethi %hi(__socketcall_table_begin), %g2 +- or %g2, %lo(__socketcall_table_begin), %g2 +- jmpl %g2 + %o0, %g0 +- nop +-do_einval: +- retl +- mov -EINVAL, %o0 +- +- .align 32 +-__socketcall_table_begin: +- +- /* Each entry is exactly 32 bytes. */ +-do_sys_socket: /* sys_socket(int, int, int) */ +-1: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_socket), %g1 +-2: ldswa [%o1 + 0x8] %asi, %o2 +- jmpl %g1 + %lo(sys_socket), %g0 +-3: ldswa [%o1 + 0x4] %asi, %o1 +- nop +- nop +- nop +-do_sys_bind: /* sys_bind(int fd, struct sockaddr *, int) */ +-4: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_bind), %g1 +-5: ldswa [%o1 + 0x8] %asi, %o2 +- jmpl %g1 + %lo(sys_bind), %g0 +-6: lduwa [%o1 + 0x4] %asi, %o1 +- nop +- nop +- nop +-do_sys_connect: /* sys_connect(int, struct sockaddr *, int) */ +-7: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_connect), %g1 +-8: ldswa [%o1 + 0x8] %asi, %o2 +- jmpl %g1 + %lo(sys_connect), %g0 +-9: lduwa [%o1 + 0x4] %asi, %o1 +- nop +- nop +- nop +-do_sys_listen: /* sys_listen(int, int) */ +-10: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_listen), %g1 +- jmpl %g1 + %lo(sys_listen), %g0 +-11: ldswa [%o1 + 0x4] %asi, %o1 +- nop +- nop +- nop +- nop +-do_sys_accept: /* sys_accept(int, struct sockaddr *, int *) */ +-12: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_accept), %g1 +-13: lduwa [%o1 + 0x8] %asi, %o2 +- jmpl %g1 + %lo(sys_accept), %g0 +-14: lduwa [%o1 + 0x4] %asi, %o1 +- nop +- nop +- nop +-do_sys_getsockname: /* sys_getsockname(int, struct sockaddr *, int *) */ +-15: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_getsockname), %g1 +-16: lduwa [%o1 + 0x8] %asi, %o2 +- jmpl %g1 + %lo(sys_getsockname), %g0 +-17: lduwa [%o1 + 0x4] %asi, %o1 +- nop +- nop +- nop +-do_sys_getpeername: /* sys_getpeername(int, struct sockaddr *, int *) */ +-18: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_getpeername), %g1 +-19: lduwa [%o1 + 0x8] %asi, %o2 +- jmpl %g1 + %lo(sys_getpeername), %g0 +-20: lduwa [%o1 + 0x4] %asi, %o1 +- nop +- nop +- nop +-do_sys_socketpair: /* sys_socketpair(int, int, int, int *) */ +-21: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_socketpair), %g1 +-22: ldswa [%o1 + 0x8] %asi, %o2 +-23: lduwa [%o1 + 0xc] %asi, %o3 +- jmpl %g1 + %lo(sys_socketpair), %g0 +-24: ldswa [%o1 + 0x4] %asi, %o1 +- nop +- nop +-do_sys_send: /* sys_send(int, void *, size_t, unsigned int) */ +-25: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_send), %g1 +-26: lduwa [%o1 + 0x8] %asi, %o2 +-27: lduwa [%o1 + 0xc] %asi, %o3 +- jmpl %g1 + %lo(sys_send), %g0 +-28: lduwa [%o1 + 0x4] %asi, %o1 +- nop +- nop +-do_sys_recv: /* sys_recv(int, void *, size_t, unsigned int) */ +-29: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_recv), %g1 +-30: lduwa [%o1 + 0x8] %asi, %o2 +-31: lduwa [%o1 + 0xc] %asi, %o3 +- jmpl %g1 + %lo(sys_recv), %g0 +-32: lduwa [%o1 + 0x4] %asi, %o1 +- nop +- nop +-do_sys_sendto: /* sys_sendto(int, u32, compat_size_t, unsigned int, u32, int) */ +-33: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_sendto), %g1 +-34: lduwa [%o1 + 0x8] %asi, %o2 +-35: lduwa [%o1 + 0xc] %asi, %o3 +-36: lduwa [%o1 + 0x10] %asi, %o4 +-37: ldswa [%o1 + 0x14] %asi, %o5 +- jmpl %g1 + %lo(sys_sendto), %g0 +-38: lduwa [%o1 + 0x4] %asi, %o1 +-do_sys_recvfrom: /* sys_recvfrom(int, u32, compat_size_t, unsigned int, u32, u32) */ +-39: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_recvfrom), %g1 +-40: lduwa [%o1 + 0x8] %asi, %o2 +-41: lduwa [%o1 + 0xc] %asi, %o3 +-42: lduwa [%o1 + 0x10] %asi, %o4 +-43: lduwa [%o1 + 0x14] %asi, %o5 +- jmpl %g1 + %lo(sys_recvfrom), %g0 +-44: lduwa [%o1 + 0x4] %asi, %o1 +-do_sys_shutdown: /* sys_shutdown(int, int) */ +-45: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_shutdown), %g1 +- jmpl %g1 + %lo(sys_shutdown), %g0 +-46: ldswa [%o1 + 0x4] %asi, %o1 +- nop +- nop +- nop +- nop +-do_sys_setsockopt: /* sys_setsockopt(int, int, int, char *, int) */ +-47: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_setsockopt), %g1 +-48: ldswa [%o1 + 0x8] %asi, %o2 +-49: lduwa [%o1 + 0xc] %asi, %o3 +-50: ldswa [%o1 + 0x10] %asi, %o4 +- jmpl %g1 + %lo(sys_setsockopt), %g0 +-51: ldswa [%o1 + 0x4] %asi, %o1 +- nop +-do_sys_getsockopt: /* sys_getsockopt(int, int, int, u32, u32) */ +-52: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_getsockopt), %g1 +-53: ldswa [%o1 + 0x8] %asi, %o2 +-54: lduwa [%o1 + 0xc] %asi, %o3 +-55: lduwa [%o1 + 0x10] %asi, %o4 +- jmpl %g1 + %lo(sys_getsockopt), %g0 +-56: ldswa [%o1 + 0x4] %asi, %o1 +- nop +-do_sys_sendmsg: /* compat_sys_sendmsg(int, struct compat_msghdr *, unsigned int) */ +-57: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(compat_sys_sendmsg), %g1 +-58: lduwa [%o1 + 0x8] %asi, %o2 +- jmpl %g1 + %lo(compat_sys_sendmsg), %g0 +-59: lduwa [%o1 + 0x4] %asi, %o1 +- nop +- nop +- nop +-do_sys_recvmsg: /* compat_sys_recvmsg(int, struct compat_msghdr *, unsigned int) */ +-60: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(compat_sys_recvmsg), %g1 +-61: lduwa [%o1 + 0x8] %asi, %o2 +- jmpl %g1 + %lo(compat_sys_recvmsg), %g0 +-62: lduwa [%o1 + 0x4] %asi, %o1 +- nop +- nop +- nop +-do_sys_accept4: /* sys_accept4(int, struct sockaddr *, int *, int) */ +-63: ldswa [%o1 + 0x0] %asi, %o0 +- sethi %hi(sys_accept4), %g1 +-64: lduwa [%o1 + 0x8] %asi, %o2 +-65: ldswa [%o1 + 0xc] %asi, %o3 +- jmpl %g1 + %lo(sys_accept4), %g0 +-66: lduwa [%o1 + 0x4] %asi, %o1 +- nop +- nop +- +- .section __ex_table,"a" +- .align 4 +- .word 1b, __retl_efault, 2b, __retl_efault +- .word 3b, __retl_efault, 4b, __retl_efault +- .word 5b, __retl_efault, 6b, __retl_efault +- .word 7b, __retl_efault, 8b, __retl_efault +- .word 9b, __retl_efault, 10b, __retl_efault +- .word 11b, __retl_efault, 12b, __retl_efault +- .word 13b, __retl_efault, 14b, __retl_efault +- .word 15b, __retl_efault, 16b, __retl_efault +- .word 17b, __retl_efault, 18b, __retl_efault +- .word 19b, __retl_efault, 20b, __retl_efault +- .word 21b, __retl_efault, 22b, __retl_efault +- .word 23b, __retl_efault, 24b, __retl_efault +- .word 25b, __retl_efault, 26b, __retl_efault +- .word 27b, __retl_efault, 28b, __retl_efault +- .word 29b, __retl_efault, 30b, __retl_efault +- .word 31b, __retl_efault, 32b, __retl_efault +- .word 33b, __retl_efault, 34b, __retl_efault +- .word 35b, __retl_efault, 36b, __retl_efault +- .word 37b, __retl_efault, 38b, __retl_efault +- .word 39b, __retl_efault, 40b, __retl_efault +- .word 41b, __retl_efault, 42b, __retl_efault +- .word 43b, __retl_efault, 44b, __retl_efault +- .word 45b, __retl_efault, 46b, __retl_efault +- .word 47b, __retl_efault, 48b, __retl_efault +- .word 49b, __retl_efault, 50b, __retl_efault +- .word 51b, __retl_efault, 52b, __retl_efault +- .word 53b, __retl_efault, 54b, __retl_efault +- .word 55b, __retl_efault, 56b, __retl_efault +- .word 57b, __retl_efault, 58b, __retl_efault +- .word 59b, __retl_efault, 60b, __retl_efault +- .word 61b, __retl_efault, 62b, __retl_efault +- .word 63b, __retl_efault, 64b, __retl_efault +- .word 65b, __retl_efault, 66b, __retl_efault +- .previous +diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl +index 4ed06c71c43fb7..d0f535230ad8ba 100644 +--- a/arch/sparc/kernel/syscalls/syscall.tbl ++++ b/arch/sparc/kernel/syscalls/syscall.tbl +@@ -117,7 +117,7 @@ + 90 common dup2 sys_dup2 + 91 32 setfsuid32 sys_setfsuid + 92 common fcntl sys_fcntl compat_sys_fcntl +-93 common select sys_select ++93 common select sys_select compat_sys_select + 94 32 setfsgid32 sys_setfsgid + 95 common fsync sys_fsync + 96 common setpriority sys_setpriority +@@ -155,7 +155,7 @@ + 123 32 fchown sys_fchown16 + 123 64 fchown sys_fchown + 124 common fchmod sys_fchmod +-125 common recvfrom sys_recvfrom ++125 common recvfrom sys_recvfrom compat_sys_recvfrom + 126 32 setreuid sys_setreuid16 + 126 64 setreuid sys_setreuid + 127 32 setregid sys_setregid16 +@@ -247,7 +247,7 @@ + 204 32 readdir sys_old_readdir compat_sys_old_readdir + 204 64 readdir sys_nis_syscall + 205 common readahead sys_readahead compat_sys_readahead +-206 common socketcall sys_socketcall sys32_socketcall ++206 common socketcall sys_socketcall compat_sys_socketcall + 207 common syslog sys_syslog + 208 common lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie + 209 common fadvise64 sys_fadvise64 compat_sys_fadvise64 +@@ -461,7 +461,7 @@ + 412 32 utimensat_time64 sys_utimensat sys_utimensat + 413 32 pselect6_time64 sys_pselect6 compat_sys_pselect6_time64 + 414 32 ppoll_time64 sys_ppoll compat_sys_ppoll_time64 +-416 32 io_pgetevents_time64 sys_io_pgetevents sys_io_pgetevents ++416 32 io_pgetevents_time64 sys_io_pgetevents compat_sys_io_pgetevents_time64 + 417 32 recvmmsg_time64 sys_recvmmsg compat_sys_recvmmsg_time64 + 418 32 mq_timedsend_time64 sys_mq_timedsend sys_mq_timedsend + 419 32 mq_timedreceive_time64 sys_mq_timedreceive sys_mq_timedreceive +diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c +index 08ffd17d5ec340..523a6e5ee92519 100644 +--- a/arch/sparc/kernel/traps_64.c ++++ b/arch/sparc/kernel/traps_64.c +@@ -897,7 +897,7 @@ void __init cheetah_ecache_flush_init(void) + + /* Now allocate error trap reporting scoreboard. */ + sz = NR_CPUS * (2 * sizeof(struct cheetah_err_info)); +- for (order = 0; order <= MAX_ORDER; order++) { ++ for (order = 0; order < NR_PAGE_ORDERS; order++) { + if ((PAGE_SIZE << order) >= sz) + break; + } +diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c +index f83017992eaaeb..d7db4e737218c2 100644 +--- a/arch/sparc/mm/init_64.c ++++ b/arch/sparc/mm/init_64.c +@@ -1665,7 +1665,7 @@ bool kern_addr_valid(unsigned long addr) + if (pud_none(*pud)) + return false; + +- if (pud_large(*pud)) ++ if (pud_leaf(*pud)) + return pfn_valid(pud_pfn(*pud)); + + pmd = pmd_offset(pud, addr); +diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c +index b44d79d778c718..ef69127d7e5e8b 100644 +--- a/arch/sparc/mm/tlb.c ++++ b/arch/sparc/mm/tlb.c +@@ -249,6 +249,7 @@ pmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, + { + pmd_t old, entry; + ++ VM_WARN_ON_ONCE(!pmd_present(*pmdp)); + entry = __pmd(pmd_val(*pmdp) & ~_PAGE_VALID); + old = pmdp_establish(vma, address, pmdp, entry); + flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); +diff --git a/arch/sparc/prom/init_64.c b/arch/sparc/prom/init_64.c +index 103aa910431856..f7b8a1a865b8fe 100644 +--- a/arch/sparc/prom/init_64.c ++++ b/arch/sparc/prom/init_64.c +@@ -26,9 +26,6 @@ phandle prom_chosen_node; + * routines in the prom library. + * It gets passed the pointer to the PROM vector. + */ +- +-extern void prom_cif_init(void *); +- + void __init prom_init(void *cif_handler) + { + phandle node; +diff --git a/arch/sparc/prom/p1275.c b/arch/sparc/prom/p1275.c +index 889aa602f8d860..51c3f984bbf728 100644 +--- a/arch/sparc/prom/p1275.c ++++ b/arch/sparc/prom/p1275.c +@@ -49,7 +49,7 @@ void p1275_cmd_direct(unsigned long *args) + local_irq_restore(flags); + } + +-void prom_cif_init(void *cif_handler, void *cif_stack) ++void prom_cif_init(void *cif_handler) + { + p1275buf.prom_cif_handler = (void (*)(long *))cif_handler; + } +diff --git a/arch/sparc/vdso/Makefile b/arch/sparc/vdso/Makefile +index 77d7b9032158c7..d08c3a0443f3a7 100644 +--- a/arch/sparc/vdso/Makefile ++++ b/arch/sparc/vdso/Makefile +@@ -116,30 +116,3 @@ quiet_cmd_vdso = VDSO $@ + + VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic + GCOV_PROFILE := n +- +-# +-# Install the unstripped copies of vdso*.so. If our toolchain supports +-# build-id, install .build-id links as well. +-# +-quiet_cmd_vdso_install = INSTALL $(@:install_%=%) +-define cmd_vdso_install +- cp $< "$(MODLIB)/vdso/$(@:install_%=%)"; \ +- if readelf -n $< |grep -q 'Build ID'; then \ +- buildid=`readelf -n $< |grep 'Build ID' |sed -e 's/^.*Build ID: \(.*\)$$/\1/'`; \ +- first=`echo $$buildid | cut -b-2`; \ +- last=`echo $$buildid | cut -b3-`; \ +- mkdir -p "$(MODLIB)/vdso/.build-id/$$first"; \ +- ln -sf "../../$(@:install_%=%)" "$(MODLIB)/vdso/.build-id/$$first/$$last.debug"; \ +- fi +-endef +- +-vdso_img_insttargets := $(vdso_img_sodbg:%.dbg=install_%) +- +-$(MODLIB)/vdso: FORCE +- @mkdir -p $(MODLIB)/vdso +- +-$(vdso_img_insttargets): install_%: $(obj)/%.dbg $(MODLIB)/vdso FORCE +- $(call cmd,vdso_install) +- +-PHONY += vdso_install $(vdso_img_insttargets) +-vdso_install: $(vdso_img_insttargets) FORCE +diff --git a/arch/sparc/vdso/vma.c b/arch/sparc/vdso/vma.c +index 136c78f28f8ba2..1bbf4335de4540 100644 +--- a/arch/sparc/vdso/vma.c ++++ b/arch/sparc/vdso/vma.c +@@ -449,9 +449,8 @@ static __init int vdso_setup(char *s) + unsigned long val; + + err = kstrtoul(s, 10, &val); +- if (err) +- return err; +- vdso_enabled = val; +- return 0; ++ if (!err) ++ vdso_enabled = val; ++ return 1; + } + __setup("vdso=", vdso_setup); +diff --git a/arch/sparc/video/Makefile b/arch/sparc/video/Makefile +index 6baddbd58e4db3..d4d83f1702c61f 100644 +--- a/arch/sparc/video/Makefile ++++ b/arch/sparc/video/Makefile +@@ -1,3 +1,3 @@ + # SPDX-License-Identifier: GPL-2.0-only + +-obj-$(CONFIG_FB) += fbdev.o ++obj-$(CONFIG_FB_CORE) += fbdev.o +diff --git a/arch/um/Makefile b/arch/um/Makefile +index 82f05f25063480..34957dcb88b9c3 100644 +--- a/arch/um/Makefile ++++ b/arch/um/Makefile +@@ -115,7 +115,9 @@ archprepare: + $(Q)$(MAKE) $(build)=$(HOST_DIR)/um include/generated/user_constants.h + + LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static +-LINK-$(CONFIG_LD_SCRIPT_DYN) += $(call cc-option, -no-pie) ++ifdef CONFIG_LD_SCRIPT_DYN ++LINK-$(call gcc-min-version, 60100)$(CONFIG_CC_IS_CLANG) += -no-pie ++endif + LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib + + CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,) \ +diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c +index b98545f3edb503..2ba4e0d4e26b06 100644 +--- a/arch/um/drivers/line.c ++++ b/arch/um/drivers/line.c +@@ -383,6 +383,7 @@ int setup_one_line(struct line *lines, int n, char *init, + parse_chan_pair(NULL, line, n, opts, error_out); + err = 0; + } ++ *error_out = "configured as 'none'"; + } else { + char *new = kstrdup(init, GFP_KERNEL); + if (!new) { +@@ -406,6 +407,7 @@ int setup_one_line(struct line *lines, int n, char *init, + } + } + if (err) { ++ *error_out = "failed to parse channel pair"; + line->init_str = NULL; + line->valid = 0; + kfree(new); +@@ -673,24 +675,26 @@ void register_winch_irq(int fd, int tty_fd, int pid, struct tty_port *port, + goto cleanup; + } + +- *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list), +- .fd = fd, ++ *winch = ((struct winch) { .fd = fd, + .tty_fd = tty_fd, + .pid = pid, + .port = port, + .stack = stack }); + ++ spin_lock(&winch_handler_lock); ++ list_add(&winch->list, &winch_handlers); ++ spin_unlock(&winch_handler_lock); ++ + if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, + IRQF_SHARED, "winch", winch) < 0) { + printk(KERN_ERR "register_winch_irq - failed to register " + "IRQ\n"); ++ spin_lock(&winch_handler_lock); ++ list_del(&winch->list); ++ spin_unlock(&winch_handler_lock); + goto out_free; + } + +- spin_lock(&winch_handler_lock); +- list_add(&winch->list, &winch_handlers); +- spin_unlock(&winch_handler_lock); +- + return; + + out_free: +diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c +index 3d7836c4650701..cabcc501b448a3 100644 +--- a/arch/um/drivers/net_kern.c ++++ b/arch/um/drivers/net_kern.c +@@ -204,7 +204,7 @@ static int uml_net_close(struct net_device *dev) + return 0; + } + +-static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) ++static netdev_tx_t uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) + { + struct uml_net_private *lp = netdev_priv(dev); + unsigned long flags; +diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c +index 50206feac577d5..ef7b4b911a455a 100644 +--- a/arch/um/drivers/ubd_kern.c ++++ b/arch/um/drivers/ubd_kern.c +@@ -456,43 +456,31 @@ static int bulk_req_safe_read( + return n; + } + +-/* Called without dev->lock held, and only in interrupt context. */ +-static void ubd_handler(void) ++static void ubd_end_request(struct io_thread_req *io_req) + { +- int n; +- int count; +- +- while(1){ +- n = bulk_req_safe_read( +- thread_fd, +- irq_req_buffer, +- &irq_remainder, +- &irq_remainder_size, +- UBD_REQ_BUFFER_SIZE +- ); +- if (n < 0) { +- if(n == -EAGAIN) +- break; +- printk(KERN_ERR "spurious interrupt in ubd_handler, " +- "err = %d\n", -n); +- return; +- } +- for (count = 0; count < n/sizeof(struct io_thread_req *); count++) { +- struct io_thread_req *io_req = (*irq_req_buffer)[count]; +- +- if ((io_req->error == BLK_STS_NOTSUPP) && (req_op(io_req->req) == REQ_OP_DISCARD)) { +- blk_queue_max_discard_sectors(io_req->req->q, 0); +- blk_queue_max_write_zeroes_sectors(io_req->req->q, 0); +- } +- blk_mq_end_request(io_req->req, io_req->error); +- kfree(io_req); +- } ++ if (io_req->error == BLK_STS_NOTSUPP) { ++ if (req_op(io_req->req) == REQ_OP_DISCARD) ++ blk_queue_max_discard_sectors(io_req->req->q, 0); ++ else if (req_op(io_req->req) == REQ_OP_WRITE_ZEROES) ++ blk_queue_max_write_zeroes_sectors(io_req->req->q, 0); + } ++ blk_mq_end_request(io_req->req, io_req->error); ++ kfree(io_req); + } + + static irqreturn_t ubd_intr(int irq, void *dev) + { +- ubd_handler(); ++ int len, i; ++ ++ while ((len = bulk_req_safe_read(thread_fd, irq_req_buffer, ++ &irq_remainder, &irq_remainder_size, ++ UBD_REQ_BUFFER_SIZE)) >= 0) { ++ for (i = 0; i < len / sizeof(struct io_thread_req *); i++) ++ ubd_end_request((*irq_req_buffer)[i]); ++ } ++ ++ if (len < 0 && len != -EAGAIN) ++ pr_err("spurious interrupt in %s, err = %d\n", __func__, len); + return IRQ_HANDLED; + } + +@@ -1099,7 +1087,7 @@ static int __init ubd_init(void) + + if (irq_req_buffer == NULL) { + printk(KERN_ERR "Failed to initialize ubd buffering\n"); +- return -1; ++ return -ENOMEM; + } + io_req_buffer = kmalloc_array(UBD_REQ_BUFFER_SIZE, + sizeof(struct io_thread_req *), +@@ -1110,7 +1098,7 @@ static int __init ubd_init(void) + + if (io_req_buffer == NULL) { + printk(KERN_ERR "Failed to initialize ubd buffering\n"); +- return -1; ++ return -ENOMEM; + } + platform_driver_register(&ubd_driver); + mutex_lock(&ubd_lock); +diff --git a/arch/um/drivers/vector_kern.c b/arch/um/drivers/vector_kern.c +index 131b7cb2957672..94a4dfac6c2368 100644 +--- a/arch/um/drivers/vector_kern.c ++++ b/arch/um/drivers/vector_kern.c +@@ -141,7 +141,7 @@ static bool get_bpf_flash(struct arglist *def) + + if (allow != NULL) { + if (kstrtoul(allow, 10, &result) == 0) +- return (allow > 0); ++ return result > 0; + } + return false; + } +diff --git a/arch/um/drivers/virt-pci.c b/arch/um/drivers/virt-pci.c +index ffe2ee8a02465b..97a37c06299721 100644 +--- a/arch/um/drivers/virt-pci.c ++++ b/arch/um/drivers/virt-pci.c +@@ -971,7 +971,7 @@ static long um_pci_map_platform(unsigned long offset, size_t size, + *ops = &um_pci_device_bar_ops; + *priv = &um_pci_platform_device->resptr[0]; + +- return 0; ++ return offset; + } + + static const struct logic_iomem_region_ops um_pci_platform_ops = { +diff --git a/arch/um/include/asm/cpufeature.h b/arch/um/include/asm/cpufeature.h +index 4b6d1b526bc121..66fe06db872f05 100644 +--- a/arch/um/include/asm/cpufeature.h ++++ b/arch/um/include/asm/cpufeature.h +@@ -75,7 +75,7 @@ extern void setup_clear_cpu_cap(unsigned int bit); + */ + static __always_inline bool _static_cpu_has(u16 bit) + { +- asm_volatile_goto("1: jmp 6f\n" ++ asm goto("1: jmp 6f\n" + "2:\n" + ".skip -(((5f-4f) - (2b-1b)) > 0) * " + "((5f-4f) - (2b-1b)),0x90\n" +diff --git a/arch/um/include/asm/kasan.h b/arch/um/include/asm/kasan.h +index 0d6547f4ec85c4..f97bb1f7b8514a 100644 +--- a/arch/um/include/asm/kasan.h ++++ b/arch/um/include/asm/kasan.h +@@ -24,7 +24,6 @@ + + #ifdef CONFIG_KASAN + void kasan_init(void); +-void kasan_map_memory(void *start, unsigned long len); + extern int kasan_um_is_ready; + + #ifdef CONFIG_STATIC_LINK +diff --git a/arch/um/include/asm/mmu.h b/arch/um/include/asm/mmu.h +index 5b072aba5b658f..a7cb380c0b5c07 100644 +--- a/arch/um/include/asm/mmu.h ++++ b/arch/um/include/asm/mmu.h +@@ -15,8 +15,6 @@ typedef struct mm_context { + struct page *stub_pages[2]; + } mm_context_t; + +-extern void __switch_mm(struct mm_id * mm_idp); +- + /* Avoid tangled inclusion with asm/ldt.h */ + extern long init_new_ldt(struct mm_context *to_mm, struct mm_context *from_mm); + extern void free_ldt(struct mm_context *mm); +diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h +index 7414154b8e9aea..d34169883dbf0a 100644 +--- a/arch/um/include/asm/processor-generic.h ++++ b/arch/um/include/asm/processor-generic.h +@@ -95,7 +95,6 @@ extern struct cpuinfo_um boot_cpu_data; + #define current_cpu_data boot_cpu_data + #define cache_line_size() (boot_cpu_data.cache_alignment) + +-extern unsigned long get_thread_reg(int reg, jmp_buf *buf); + #define KSTK_REG(tsk, reg) get_thread_reg(reg, &tsk->thread.switch_buf) + extern unsigned long __get_wchan(struct task_struct *p); + +diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h +index d8b8b4f07e429d..7372746c168757 100644 +--- a/arch/um/include/shared/kern_util.h ++++ b/arch/um/include/shared/kern_util.h +@@ -50,7 +50,7 @@ extern void do_uml_exitcalls(void); + * Are we disallowed to sleep? Used to choose between GFP_KERNEL and + * GFP_ATOMIC. + */ +-extern int __cant_sleep(void); ++extern int __uml_cant_sleep(void); + extern int get_current_pid(void); + extern int copy_from_user_proc(void *to, void *from, int size); + extern char *uml_strdup(const char *string); +@@ -67,4 +67,6 @@ extern void fatal_sigsegv(void) __attribute__ ((noreturn)); + + void um_idle_sleep(void); + ++void kasan_map_memory(void *start, size_t len); ++ + #endif +diff --git a/arch/um/include/shared/skas/mm_id.h b/arch/um/include/shared/skas/mm_id.h +index e82e203f5f4194..92dbf727e3842a 100644 +--- a/arch/um/include/shared/skas/mm_id.h ++++ b/arch/um/include/shared/skas/mm_id.h +@@ -15,4 +15,6 @@ struct mm_id { + int kill; + }; + ++void __switch_mm(struct mm_id *mm_idp); ++ + #endif +diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c +index 106b7da2f8d6f7..6daffb9d8a8d74 100644 +--- a/arch/um/kernel/process.c ++++ b/arch/um/kernel/process.c +@@ -220,7 +220,7 @@ void arch_cpu_idle(void) + um_idle_sleep(); + } + +-int __cant_sleep(void) { ++int __uml_cant_sleep(void) { + return in_atomic() || irqs_disabled() || in_interrupt(); + /* Is in_interrupt() really needed? */ + } +diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c +index fddd1dec27e6d3..c8c4ef94c753f1 100644 +--- a/arch/um/kernel/time.c ++++ b/arch/um/kernel/time.c +@@ -432,9 +432,29 @@ static void time_travel_update_time(unsigned long long next, bool idle) + time_travel_del_event(&ne); + } + ++static void time_travel_update_time_rel(unsigned long long offs) ++{ ++ unsigned long flags; ++ ++ /* ++ * Disable interrupts before calculating the new time so ++ * that a real timer interrupt (signal) can't happen at ++ * a bad time e.g. after we read time_travel_time but ++ * before we've completed updating the time. ++ */ ++ local_irq_save(flags); ++ time_travel_update_time(time_travel_time + offs, false); ++ local_irq_restore(flags); ++} ++ + void time_travel_ndelay(unsigned long nsec) + { +- time_travel_update_time(time_travel_time + nsec, false); ++ /* ++ * Not strictly needed to use _rel() version since this is ++ * only used in INFCPU/EXT modes, but it doesn't hurt and ++ * is more readable too. ++ */ ++ time_travel_update_time_rel(nsec); + } + EXPORT_SYMBOL(time_travel_ndelay); + +@@ -568,7 +588,11 @@ static void time_travel_set_start(void) + #define time_travel_time 0 + #define time_travel_ext_waiting 0 + +-static inline void time_travel_update_time(unsigned long long ns, bool retearly) ++static inline void time_travel_update_time(unsigned long long ns, bool idle) ++{ ++} ++ ++static inline void time_travel_update_time_rel(unsigned long long offs) + { + } + +@@ -720,9 +744,7 @@ static u64 timer_read(struct clocksource *cs) + */ + if (!irqs_disabled() && !in_interrupt() && !in_softirq() && + !time_travel_ext_waiting) +- time_travel_update_time(time_travel_time + +- TIMER_MULTIPLIER, +- false); ++ time_travel_update_time_rel(TIMER_MULTIPLIER); + return time_travel_time / TIMER_MULTIPLIER; + } + +@@ -852,9 +874,9 @@ int setup_time_travel_start(char *str) + return 1; + } + +-__setup("time-travel-start", setup_time_travel_start); ++__setup("time-travel-start=", setup_time_travel_start); + __uml_help(setup_time_travel_start, +-"time-travel-start=\n" ++"time-travel-start=\n" + "Configure the UML instance's wall clock to start at this value rather than\n" + "the host's wall clock at the time of UML boot.\n"); + #endif +diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c +index b459745f52e248..3cb8ac63be6ed9 100644 +--- a/arch/um/os-Linux/helper.c ++++ b/arch/um/os-Linux/helper.c +@@ -46,7 +46,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) + unsigned long stack, sp; + int pid, fds[2], ret, n; + +- stack = alloc_stack(0, __cant_sleep()); ++ stack = alloc_stack(0, __uml_cant_sleep()); + if (stack == 0) + return -ENOMEM; + +@@ -70,7 +70,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) + data.pre_data = pre_data; + data.argv = argv; + data.fd = fds[1]; +- data.buf = __cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) : ++ data.buf = __uml_cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) : + uml_kmalloc(PATH_MAX, UM_GFP_KERNEL); + pid = clone(helper_child, (void *) sp, CLONE_VM, &data); + if (pid < 0) { +@@ -121,7 +121,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, + unsigned long stack, sp; + int pid, status, err; + +- stack = alloc_stack(0, __cant_sleep()); ++ stack = alloc_stack(0, __uml_cant_sleep()); + if (stack == 0) + return -ENOMEM; + +diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c +index 8530b2e086049b..c6c9495b143212 100644 +--- a/arch/um/os-Linux/mem.c ++++ b/arch/um/os-Linux/mem.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + + /* +diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c +index 24a403a70a0201..850d21e6473eec 100644 +--- a/arch/um/os-Linux/signal.c ++++ b/arch/um/os-Linux/signal.c +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -65,9 +66,7 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) + + int signals_enabled; + #ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT +-static int signals_blocked; +-#else +-#define signals_blocked 0 ++static int signals_blocked, signals_blocked_pending; + #endif + static unsigned int signals_pending; + static unsigned int signals_active = 0; +@@ -76,14 +75,27 @@ void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) + { + int enabled = signals_enabled; + +- if ((signals_blocked || !enabled) && (sig == SIGIO)) { ++#ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT ++ if ((signals_blocked || ++ __atomic_load_n(&signals_blocked_pending, __ATOMIC_SEQ_CST)) && ++ (sig == SIGIO)) { ++ /* increment so unblock will do another round */ ++ __atomic_add_fetch(&signals_blocked_pending, 1, ++ __ATOMIC_SEQ_CST); ++ return; ++ } ++#endif ++ ++ if (!enabled && (sig == SIGIO)) { + /* + * In TT_MODE_EXTERNAL, need to still call time-travel +- * handlers unless signals are also blocked for the +- * external time message processing. This will mark +- * signals_pending by itself (only if necessary.) ++ * handlers. This will mark signals_pending by itself ++ * (only if necessary.) ++ * Note we won't get here if signals are hard-blocked ++ * (which is handled above), in that case the hard- ++ * unblock will handle things. + */ +- if (!signals_blocked && time_travel_mode == TT_MODE_EXTERNAL) ++ if (time_travel_mode == TT_MODE_EXTERNAL) + sigio_run_timetravel_handlers(); + else + signals_pending |= SIGIO_MASK; +@@ -380,33 +392,99 @@ int um_set_signals_trace(int enable) + #ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT + void mark_sigio_pending(void) + { ++ /* ++ * It would seem that this should be atomic so ++ * it isn't a read-modify-write with a signal ++ * that could happen in the middle, losing the ++ * value set by the signal. ++ * ++ * However, this function is only called when in ++ * time-travel=ext simulation mode, in which case ++ * the only signal ever pending is SIGIO, which ++ * is blocked while this can be called, and the ++ * timer signal (SIGALRM) cannot happen. ++ */ + signals_pending |= SIGIO_MASK; + } + + void block_signals_hard(void) + { +- if (signals_blocked) +- return; +- signals_blocked = 1; ++ signals_blocked++; + barrier(); + } + + void unblock_signals_hard(void) + { ++ static bool unblocking; ++ + if (!signals_blocked) ++ panic("unblocking signals while not blocked"); ++ ++ if (--signals_blocked) + return; +- /* Must be set to 0 before we check the pending bits etc. */ +- signals_blocked = 0; ++ /* ++ * Must be set to 0 before we check pending so the ++ * SIGIO handler will run as normal unless we're still ++ * going to process signals_blocked_pending. ++ */ + barrier(); + +- if (signals_pending && signals_enabled) { +- /* this is a bit inefficient, but that's not really important */ +- block_signals(); +- unblock_signals(); +- } else if (signals_pending & SIGIO_MASK) { +- /* we need to run time-travel handlers even if not enabled */ +- sigio_run_timetravel_handlers(); ++ /* ++ * Note that block_signals_hard()/unblock_signals_hard() can be called ++ * within the unblock_signals()/sigio_run_timetravel_handlers() below. ++ * This would still be prone to race conditions since it's actually a ++ * call _within_ e.g. vu_req_read_message(), where we observed this ++ * issue, which loops. Thus, if the inner call handles the recorded ++ * pending signals, we can get out of the inner call with the real ++ * signal hander no longer blocked, and still have a race. Thus don't ++ * handle unblocking in the inner call, if it happens, but only in ++ * the outermost call - 'unblocking' serves as an ownership for the ++ * signals_blocked_pending decrement. ++ */ ++ if (unblocking) ++ return; ++ unblocking = true; ++ ++ while (__atomic_load_n(&signals_blocked_pending, __ATOMIC_SEQ_CST)) { ++ if (signals_enabled) { ++ /* signals are enabled so we can touch this */ ++ signals_pending |= SIGIO_MASK; ++ /* ++ * this is a bit inefficient, but that's ++ * not really important ++ */ ++ block_signals(); ++ unblock_signals(); ++ } else { ++ /* ++ * we need to run time-travel handlers even ++ * if not enabled ++ */ ++ sigio_run_timetravel_handlers(); ++ } ++ ++ /* ++ * The decrement of signals_blocked_pending must be atomic so ++ * that the signal handler will either happen before or after ++ * the decrement, not during a read-modify-write: ++ * - If it happens before, it can increment it and we'll ++ * decrement it and do another round in the loop. ++ * - If it happens after it'll see 0 for both signals_blocked ++ * and signals_blocked_pending and thus run the handler as ++ * usual (subject to signals_enabled, but that's unrelated.) ++ * ++ * Note that a call to unblock_signals_hard() within the calls ++ * to unblock_signals() or sigio_run_timetravel_handlers() above ++ * will do nothing due to the 'unblocking' state, so this cannot ++ * underflow as the only one decrementing will be the outermost ++ * one. ++ */ ++ if (__atomic_sub_fetch(&signals_blocked_pending, 1, ++ __ATOMIC_SEQ_CST) < 0) ++ panic("signals_blocked_pending underflow"); + } ++ ++ unblocking = false; + } + #endif + +diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c +index fc0f2a9dee5af9..1dca4ffbd572f7 100644 +--- a/arch/um/os-Linux/util.c ++++ b/arch/um/os-Linux/util.c +@@ -173,23 +173,38 @@ __uml_setup("quiet", quiet_cmd_param, + "quiet\n" + " Turns off information messages during boot.\n\n"); + ++/* ++ * The os_info/os_warn functions will be called by helper threads. These ++ * have a very limited stack size and using the libc formatting functions ++ * may overflow the stack. ++ * So pull in the kernel vscnprintf and use that instead with a fixed ++ * on-stack buffer. ++ */ ++int vscnprintf(char *buf, size_t size, const char *fmt, va_list args); ++ + void os_info(const char *fmt, ...) + { ++ char buf[256]; + va_list list; ++ int len; + + if (quiet_info) + return; + + va_start(list, fmt); +- vfprintf(stderr, fmt, list); ++ len = vscnprintf(buf, sizeof(buf), fmt, list); ++ fwrite(buf, len, 1, stderr); + va_end(list); + } + + void os_warn(const char *fmt, ...) + { ++ char buf[256]; + va_list list; ++ int len; + + va_start(list, fmt); +- vfprintf(stderr, fmt, list); ++ len = vscnprintf(buf, sizeof(buf), fmt, list); ++ fwrite(buf, len, 1, stderr); + va_end(list); + } +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index 66bfabae881491..82d12c93feabe6 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -62,6 +62,7 @@ config X86 + select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI + select ARCH_32BIT_OFF_T if X86_32 + select ARCH_CLOCKSOURCE_INIT ++ select ARCH_CONFIGURES_CPU_MITIGATIONS + select ARCH_CORRECT_STACKTRACE_ON_KRETPROBE + select ARCH_ENABLE_HUGEPAGE_MIGRATION if X86_64 && HUGETLB_PAGE && MIGRATION + select ARCH_ENABLE_MEMORY_HOTPLUG if X86_64 +@@ -1514,19 +1515,6 @@ config AMD_MEM_ENCRYPT + This requires an AMD processor that supports Secure Memory + Encryption (SME). + +-config AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT +- bool "Activate AMD Secure Memory Encryption (SME) by default" +- depends on AMD_MEM_ENCRYPT +- help +- Say yes to have system memory encrypted by default if running on +- an AMD processor that supports Secure Memory Encryption (SME). +- +- If set to Y, then the encryption of system memory can be +- deactivated with the mem_encrypt=off command line option. +- +- If set to N, then the encryption of system memory can be +- activated with the mem_encrypt=on command line option. +- + # Common NUMA Features + config NUMA + bool "NUMA Memory Allocation and Scheduler Support" +@@ -2034,7 +2022,7 @@ config ARCH_SUPPORTS_KEXEC + def_bool y + + config ARCH_SUPPORTS_KEXEC_FILE +- def_bool X86_64 && CRYPTO && CRYPTO_SHA256 ++ def_bool X86_64 + + config ARCH_SELECTS_KEXEC_FILE + def_bool y +@@ -2042,7 +2030,7 @@ config ARCH_SELECTS_KEXEC_FILE + select HAVE_IMA_KEXEC if IMA + + config ARCH_SUPPORTS_KEXEC_PURGATORY +- def_bool KEXEC_FILE ++ def_bool y + + config ARCH_SUPPORTS_KEXEC_SIG + def_bool y +@@ -2434,17 +2422,21 @@ config PREFIX_SYMBOLS + def_bool y + depends on CALL_PADDING && !CFI_CLANG + +-menuconfig SPECULATION_MITIGATIONS +- bool "Mitigations for speculative execution vulnerabilities" ++menuconfig CPU_MITIGATIONS ++ bool "Mitigations for CPU vulnerabilities" + default y + help +- Say Y here to enable options which enable mitigations for +- speculative execution hardware vulnerabilities. ++ Say Y here to enable options which enable mitigations for hardware ++ vulnerabilities (usually related to speculative execution). ++ Mitigations can be disabled or restricted to SMT systems at runtime ++ via the "mitigations" kernel parameter. + +- If you say N, all mitigations will be disabled. You really +- should know what you are doing to say so. ++ If you say N, all mitigations will be disabled. This CANNOT be ++ overridden at runtime. + +-if SPECULATION_MITIGATIONS ++ Say 'Y', unless you really know what you are doing. ++ ++if CPU_MITIGATIONS + + config PAGE_TABLE_ISOLATION + bool "Remove the kernel mapping in user mode" +@@ -2568,6 +2560,27 @@ config GDS_FORCE_MITIGATION + + If in doubt, say N. + ++config MITIGATION_RFDS ++ bool "RFDS Mitigation" ++ depends on CPU_SUP_INTEL ++ default y ++ help ++ Enable mitigation for Register File Data Sampling (RFDS) by default. ++ RFDS is a hardware vulnerability which affects Intel Atom CPUs. It ++ allows unprivileged speculative access to stale data previously ++ stored in floating point, vector and integer registers. ++ See also ++ ++config MITIGATION_SPECTRE_BHI ++ bool "Mitigate Spectre-BHB (Branch History Injection)" ++ depends on CPU_SUP_INTEL ++ default y ++ help ++ Enable BHI mitigations. BHI attacks are a form of Spectre V2 attacks ++ where the branch history buffer is poisoned to speculatively steer ++ indirect branches. ++ See ++ + endif + + config ARCH_HAS_ADD_PAGES +diff --git a/arch/x86/Kconfig.assembler b/arch/x86/Kconfig.assembler +index 8ad41da301e53c..16d0b022d6fff6 100644 +--- a/arch/x86/Kconfig.assembler ++++ b/arch/x86/Kconfig.assembler +@@ -26,6 +26,6 @@ config AS_GFNI + Supported by binutils >= 2.30 and LLVM integrated assembler + + config AS_WRUSS +- def_bool $(as-instr,wrussq %rax$(comma)(%rbx)) ++ def_bool $(as-instr64,wrussq %rax$(comma)(%rbx)) + help + Supported by binutils >= 2.31 and LLVM integrated assembler +diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu +index 00468adf180f1d..87396575cfa777 100644 +--- a/arch/x86/Kconfig.cpu ++++ b/arch/x86/Kconfig.cpu +@@ -375,7 +375,7 @@ config X86_CMOV + config X86_MINIMUM_CPU_FAMILY + int + default "64" if X86_64 +- default "6" if X86_32 && (MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MEFFICEON || MATOM || MCRUSOE || MCORE2 || MK7 || MK8) ++ default "6" if X86_32 && (MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MEFFICEON || MATOM || MCORE2 || MK7 || MK8) + default "5" if X86_32 && X86_CMPXCHG64 + default "4" + +diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug +index c5d614d28a7599..74777a97e394aa 100644 +--- a/arch/x86/Kconfig.debug ++++ b/arch/x86/Kconfig.debug +@@ -248,6 +248,7 @@ config UNWINDER_ORC + + config UNWINDER_FRAME_POINTER + bool "Frame pointer unwinder" ++ select ARCH_WANT_FRAME_POINTERS + select FRAME_POINTER + help + This option enables the frame pointer unwinder for unwinding kernel +@@ -271,7 +272,3 @@ config UNWINDER_GUESS + overhead. + + endchoice +- +-config FRAME_POINTER +- depends on !UNWINDER_ORC && !UNWINDER_GUESS +- bool +diff --git a/arch/x86/Makefile b/arch/x86/Makefile +index 5bfe5caaa444b3..3ff53a2d4ff084 100644 +--- a/arch/x86/Makefile ++++ b/arch/x86/Makefile +@@ -291,9 +291,10 @@ PHONY += install + install: + $(call cmd,install) + +-PHONY += vdso_install +-vdso_install: +- $(Q)$(MAKE) $(build)=arch/x86/entry/vdso $@ ++vdso-install-$(CONFIG_X86_64) += arch/x86/entry/vdso/vdso64.so.dbg ++vdso-install-$(CONFIG_X86_X32_ABI) += arch/x86/entry/vdso/vdsox32.so.dbg ++vdso-install-$(CONFIG_X86_32) += arch/x86/entry/vdso/vdso32.so.dbg ++vdso-install-$(CONFIG_IA32_EMULATION) += arch/x86/entry/vdso/vdso32.so.dbg + + archprepare: checkbin + checkbin: +diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile +index f33e45ed143765..3cece19b74732f 100644 +--- a/arch/x86/boot/Makefile ++++ b/arch/x86/boot/Makefile +@@ -89,7 +89,7 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE + + SETUP_OBJS = $(addprefix $(obj)/,$(setup-y)) + +-sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|efi32_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p' ++sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|efi.._stub_entry\|efi\(32\)\?_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|_e\?data\|z_.*\)$$/\#define ZO_\2 0x\1/p' + + quiet_cmd_zoffset = ZOFFSET $@ + cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@ +diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile +index 71fc531b95b4ee..658e9ec065c476 100644 +--- a/arch/x86/boot/compressed/Makefile ++++ b/arch/x86/boot/compressed/Makefile +@@ -84,7 +84,7 @@ LDFLAGS_vmlinux += -T + hostprogs := mkpiggy + HOST_EXTRACFLAGS += -I$(srctree)/tools/include + +-sed-voffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(_text\|__bss_start\|_end\)$$/\#define VO_\2 _AC(0x\1,UL)/p' ++sed-voffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(_text\|__start_rodata\|__bss_start\|_end\)$$/\#define VO_\2 _AC(0x\1,UL)/p' + + quiet_cmd_voffset = VOFFSET $@ + cmd_voffset = $(NM) $< | sed -n $(sed-voffset) > $@ +@@ -116,9 +116,9 @@ vmlinux-objs-$(CONFIG_UNACCEPTED_MEMORY) += $(obj)/mem.o + + vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o + vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o +-vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a ++vmlinux-libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a + +-$(obj)/vmlinux: $(vmlinux-objs-y) FORCE ++$(obj)/vmlinux: $(vmlinux-objs-y) $(vmlinux-libs-y) FORCE + $(call if_changed,ld) + + OBJCOPYFLAGS_vmlinux.bin := -R .comment -S +diff --git a/arch/x86/boot/compressed/efi_mixed.S b/arch/x86/boot/compressed/efi_mixed.S +index f4e22ef774ab6b..876fc6d46a1318 100644 +--- a/arch/x86/boot/compressed/efi_mixed.S ++++ b/arch/x86/boot/compressed/efi_mixed.S +@@ -15,10 +15,12 @@ + */ + + #include ++#include + #include + #include + #include + #include ++#include + + .code64 + .text +@@ -49,6 +51,11 @@ SYM_FUNC_START(startup_64_mixed_mode) + lea efi32_boot_args(%rip), %rdx + mov 0(%rdx), %edi + mov 4(%rdx), %esi ++ ++ /* Switch to the firmware's stack */ ++ movl efi32_boot_sp(%rip), %esp ++ andl $~7, %esp ++ + #ifdef CONFIG_EFI_HANDOVER_PROTOCOL + mov 8(%rdx), %edx // saved bootparams pointer + test %edx, %edx +@@ -144,6 +151,7 @@ SYM_FUNC_END(__efi64_thunk) + SYM_FUNC_START(efi32_stub_entry) + call 1f + 1: popl %ecx ++ leal (efi32_boot_args - 1b)(%ecx), %ebx + + /* Clear BSS */ + xorl %eax, %eax +@@ -158,6 +166,7 @@ SYM_FUNC_START(efi32_stub_entry) + popl %ecx + popl %edx + popl %esi ++ movl %esi, 8(%ebx) + jmp efi32_entry + SYM_FUNC_END(efi32_stub_entry) + #endif +@@ -234,8 +243,6 @@ SYM_FUNC_END(efi_enter32) + * + * Arguments: %ecx image handle + * %edx EFI system table pointer +- * %esi struct bootparams pointer (or NULL when not using +- * the EFI handover protocol) + * + * Since this is the point of no return for ordinary execution, no registers + * are considered live except for the function parameters. [Note that the EFI +@@ -254,13 +261,25 @@ SYM_FUNC_START_LOCAL(efi32_entry) + /* Store firmware IDT descriptor */ + sidtl (efi32_boot_idt - 1b)(%ebx) + ++ /* Store firmware stack pointer */ ++ movl %esp, (efi32_boot_sp - 1b)(%ebx) ++ + /* Store boot arguments */ + leal (efi32_boot_args - 1b)(%ebx), %ebx + movl %ecx, 0(%ebx) + movl %edx, 4(%ebx) +- movl %esi, 8(%ebx) + movb $0x0, 12(%ebx) // efi_is64 + ++ /* ++ * Allocate some memory for a temporary struct boot_params, which only ++ * needs the minimal pieces that startup_32() relies on. ++ */ ++ subl $PARAM_SIZE, %esp ++ movl %esp, %esi ++ movl $PAGE_SIZE, BP_kernel_alignment(%esi) ++ movl $_end - 1b, BP_init_size(%esi) ++ subl $startup_32 - 1b, BP_init_size(%esi) ++ + /* Disable paging */ + movl %cr0, %eax + btrl $X86_CR0_PG_BIT, %eax +@@ -286,8 +305,7 @@ SYM_FUNC_START(efi32_pe_entry) + + movl 8(%ebp), %ecx // image_handle + movl 12(%ebp), %edx // sys_table +- xorl %esi, %esi +- jmp efi32_entry // pass %ecx, %edx, %esi ++ jmp efi32_entry // pass %ecx, %edx + // no other registers remain live + + 2: popl %edi // restore callee-save registers +@@ -318,5 +336,6 @@ SYM_DATA_END(efi32_boot_idt) + + SYM_DATA_LOCAL(efi32_boot_cs, .word 0) + SYM_DATA_LOCAL(efi32_boot_ds, .word 0) ++SYM_DATA_LOCAL(efi32_boot_sp, .long 0) + SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0, 0) + SYM_DATA(efi_is64, .byte 1) +diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S +index bf4a10a5794f1c..1dcb794c5479ed 100644 +--- a/arch/x86/boot/compressed/head_64.S ++++ b/arch/x86/boot/compressed/head_64.S +@@ -398,6 +398,11 @@ SYM_CODE_START(startup_64) + call sev_enable + #endif + ++ /* Preserve only the CR4 bits that must be preserved, and clear the rest */ ++ movq %cr4, %rax ++ andl $(X86_CR4_PAE | X86_CR4_MCE | X86_CR4_LA57), %eax ++ movq %rax, %cr4 ++ + /* + * configure_5level_paging() updates the number of paging levels using + * a trampoline in 32-bit addressable memory if the current number does +diff --git a/arch/x86/boot/compressed/ident_map_64.c b/arch/x86/boot/compressed/ident_map_64.c +index 08f93b0401bbd3..aead80ec70a0bf 100644 +--- a/arch/x86/boot/compressed/ident_map_64.c ++++ b/arch/x86/boot/compressed/ident_map_64.c +@@ -385,3 +385,8 @@ void do_boot_page_fault(struct pt_regs *regs, unsigned long error_code) + */ + kernel_add_identity_map(address, end); + } ++ ++void do_boot_nmi_trap(struct pt_regs *regs, unsigned long error_code) ++{ ++ /* Empty handler to ignore NMI during early boot */ ++} +diff --git a/arch/x86/boot/compressed/idt_64.c b/arch/x86/boot/compressed/idt_64.c +index 3cdf94b4145674..d100284bbef47b 100644 +--- a/arch/x86/boot/compressed/idt_64.c ++++ b/arch/x86/boot/compressed/idt_64.c +@@ -61,6 +61,7 @@ void load_stage2_idt(void) + boot_idt_desc.address = (unsigned long)boot_idt; + + set_idt_entry(X86_TRAP_PF, boot_page_fault); ++ set_idt_entry(X86_TRAP_NMI, boot_nmi_trap); + + #ifdef CONFIG_AMD_MEM_ENCRYPT + /* +diff --git a/arch/x86/boot/compressed/idt_handlers_64.S b/arch/x86/boot/compressed/idt_handlers_64.S +index 22890e199f5b44..4d03c8562f637d 100644 +--- a/arch/x86/boot/compressed/idt_handlers_64.S ++++ b/arch/x86/boot/compressed/idt_handlers_64.S +@@ -70,6 +70,7 @@ SYM_FUNC_END(\name) + .code64 + + EXCEPTION_HANDLER boot_page_fault do_boot_page_fault error_code=1 ++EXCEPTION_HANDLER boot_nmi_trap do_boot_nmi_trap error_code=0 + + #ifdef CONFIG_AMD_MEM_ENCRYPT + EXCEPTION_HANDLER boot_stage1_vc do_vc_no_ghcb error_code=1 +diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c +index f711f2a85862e9..b5ecbd32a46fac 100644 +--- a/arch/x86/boot/compressed/misc.c ++++ b/arch/x86/boot/compressed/misc.c +@@ -330,6 +330,7 @@ static size_t parse_elf(void *output) + return ehdr.e_entry - LOAD_PHYSICAL_ADDR; + } + ++const unsigned long kernel_text_size = VO___start_rodata - VO__text; + const unsigned long kernel_total_size = VO__end - VO__text; + + static u8 boot_heap[BOOT_HEAP_SIZE] __aligned(4); +@@ -357,6 +358,19 @@ unsigned long decompress_kernel(unsigned char *outbuf, unsigned long virt_addr, + return entry; + } + ++/* ++ * Set the memory encryption xloadflag based on the mem_encrypt= command line ++ * parameter, if provided. ++ */ ++static void parse_mem_encrypt(struct setup_header *hdr) ++{ ++ int on = cmdline_find_option_bool("mem_encrypt=on"); ++ int off = cmdline_find_option_bool("mem_encrypt=off"); ++ ++ if (on > off) ++ hdr->xloadflags |= XLF_MEM_ENCRYPTION; ++} ++ + /* + * The compressed kernel image (ZO), has been moved so that its position + * is against the end of the buffer used to hold the uncompressed kernel +@@ -387,6 +401,8 @@ asmlinkage __visible void *extract_kernel(void *rmode, unsigned char *output) + /* Clear flags intended for solely in-kernel use. */ + boot_params->hdr.loadflags &= ~KASLR_FLAG; + ++ parse_mem_encrypt(&boot_params->hdr); ++ + sanitize_boot_params(boot_params); + + if (boot_params->screen_info.orig_video_mode == 7) { +diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h +index cc70d3fb90497e..aae1a2db425103 100644 +--- a/arch/x86/boot/compressed/misc.h ++++ b/arch/x86/boot/compressed/misc.h +@@ -197,6 +197,7 @@ static inline void cleanup_exception_handling(void) { } + + /* IDT Entry Points */ + void boot_page_fault(void); ++void boot_nmi_trap(void); + void boot_stage1_vc(void); + void boot_stage2_vc(void); + +diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c +index 80d76aea1f7bf1..0a49218a516a28 100644 +--- a/arch/x86/boot/compressed/sev.c ++++ b/arch/x86/boot/compressed/sev.c +@@ -116,6 +116,9 @@ static bool fault_in_kernel_space(unsigned long address) + #undef __init + #define __init + ++#undef __head ++#define __head ++ + #define __BOOT_COMPRESSED + + /* Basic instruction decoding support needed */ +diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S +index b22f34b8684a72..083ec6d7722a16 100644 +--- a/arch/x86/boot/compressed/vmlinux.lds.S ++++ b/arch/x86/boot/compressed/vmlinux.lds.S +@@ -43,11 +43,13 @@ SECTIONS + *(.rodata.*) + _erodata = . ; + } +- .data : { ++ .data : ALIGN(0x1000) { + _data = . ; + *(.data) + *(.data.*) +- *(.bss.efistub) ++ ++ /* Add 4 bytes of extra space for a CRC-32 checksum */ ++ . = ALIGN(. + 4, 0x200); + _edata = . ; + } + . = ALIGN(L1_CACHE_BYTES); +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index b04ca8e2b213c6..a1bbedd989e42e 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -36,66 +36,20 @@ SYSSEG = 0x1000 /* historical load address >> 4 */ + #define ROOT_RDONLY 1 + #endif + ++ .set salign, 0x1000 ++ .set falign, 0x200 ++ + .code16 + .section ".bstext", "ax" +- +- .global bootsect_start +-bootsect_start: + #ifdef CONFIG_EFI_STUB + # "MZ", MS-DOS header + .word MZ_MAGIC +-#endif +- +- # Normalize the start address +- ljmp $BOOTSEG, $start2 +- +-start2: +- movw %cs, %ax +- movw %ax, %ds +- movw %ax, %es +- movw %ax, %ss +- xorw %sp, %sp +- sti +- cld +- +- movw $bugger_off_msg, %si +- +-msg_loop: +- lodsb +- andb %al, %al +- jz bs_die +- movb $0xe, %ah +- movw $7, %bx +- int $0x10 +- jmp msg_loop +- +-bs_die: +- # Allow the user to press a key, then reboot +- xorw %ax, %ax +- int $0x16 +- int $0x19 +- +- # int 0x19 should never return. In case it does anyway, +- # invoke the BIOS reset code... +- ljmp $0xf000,$0xfff0 +- +-#ifdef CONFIG_EFI_STUB + .org 0x38 + # + # Offset to the PE header. + # + .long LINUX_PE_MAGIC + .long pe_header +-#endif /* CONFIG_EFI_STUB */ +- +- .section ".bsdata", "a" +-bugger_off_msg: +- .ascii "Use a boot loader.\r\n" +- .ascii "\n" +- .ascii "Remove disk and press any key to reboot...\r\n" +- .byte 0 +- +-#ifdef CONFIG_EFI_STUB + pe_header: + .long PE_MAGIC + +@@ -124,30 +78,26 @@ optional_header: + .byte 0x02 # MajorLinkerVersion + .byte 0x14 # MinorLinkerVersion + +- # Filled in by build.c +- .long 0 # SizeOfCode ++ .long ZO__data # SizeOfCode + +- .long 0 # SizeOfInitializedData ++ .long ZO__end - ZO__data # SizeOfInitializedData + .long 0 # SizeOfUninitializedData + +- # Filled in by build.c +- .long 0x0000 # AddressOfEntryPoint ++ .long setup_size + ZO_efi_pe_entry # AddressOfEntryPoint + +- .long 0x0200 # BaseOfCode ++ .long setup_size # BaseOfCode + #ifdef CONFIG_X86_32 + .long 0 # data + #endif + + extra_header_fields: +- # PE specification requires ImageBase to be 64k aligned +- .set image_base, (LOAD_PHYSICAL_ADDR + 0xffff) & ~0xffff + #ifdef CONFIG_X86_32 +- .long image_base # ImageBase ++ .long 0 # ImageBase + #else +- .quad image_base # ImageBase ++ .quad 0 # ImageBase + #endif +- .long 0x20 # SectionAlignment +- .long 0x20 # FileAlignment ++ .long salign # SectionAlignment ++ .long falign # FileAlignment + .word 0 # MajorOperatingSystemVersion + .word 0 # MinorOperatingSystemVersion + .word LINUX_EFISTUB_MAJOR_VERSION # MajorImageVersion +@@ -156,12 +106,9 @@ extra_header_fields: + .word 0 # MinorSubsystemVersion + .long 0 # Win32VersionValue + +- # +- # The size of the bzImage is written in tools/build.c +- # +- .long 0 # SizeOfImage ++ .long setup_size + ZO__end # SizeOfImage + +- .long 0x200 # SizeOfHeaders ++ .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) + #ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES +@@ -192,87 +139,77 @@ extra_header_fields: + + # Section table + section_table: +- # +- # The offset & size fields are filled in by build.c. +- # + .ascii ".setup" + .byte 0 + .byte 0 +- .long 0 +- .long 0x0 # startup_{32,64} +- .long 0 # Size of initialized data +- # on disk +- .long 0x0 # startup_{32,64} +- .long 0 # PointerToRelocations +- .long 0 # PointerToLineNumbers +- .word 0 # NumberOfRelocations +- .word 0 # NumberOfLineNumbers +- .long IMAGE_SCN_CNT_CODE | \ +- IMAGE_SCN_MEM_READ | \ +- IMAGE_SCN_MEM_EXECUTE | \ +- IMAGE_SCN_ALIGN_16BYTES # Characteristics ++ .long pecompat_fstart - salign # VirtualSize ++ .long salign # VirtualAddress ++ .long pecompat_fstart - salign # SizeOfRawData ++ .long salign # PointerToRawData + +- # +- # The EFI application loader requires a relocation section +- # because EFI applications must be relocatable. The .reloc +- # offset & size fields are filled in by build.c. +- # +- .ascii ".reloc" +- .byte 0 +- .byte 0 +- .long 0 +- .long 0 +- .long 0 # SizeOfRawData +- .long 0 # PointerToRawData +- .long 0 # PointerToRelocations +- .long 0 # PointerToLineNumbers +- .word 0 # NumberOfRelocations +- .word 0 # NumberOfLineNumbers ++ .long 0, 0, 0 + .long IMAGE_SCN_CNT_INITIALIZED_DATA | \ + IMAGE_SCN_MEM_READ | \ +- IMAGE_SCN_MEM_DISCARDABLE | \ +- IMAGE_SCN_ALIGN_1BYTES # Characteristics ++ IMAGE_SCN_MEM_DISCARDABLE # Characteristics + + #ifdef CONFIG_EFI_MIXED +- # +- # The offset & size fields are filled in by build.c. +- # + .asciz ".compat" +- .long 0 +- .long 0x0 +- .long 0 # Size of initialized data +- # on disk +- .long 0x0 +- .long 0 # PointerToRelocations +- .long 0 # PointerToLineNumbers +- .word 0 # NumberOfRelocations +- .word 0 # NumberOfLineNumbers ++ ++ .long pecompat_fsize # VirtualSize ++ .long pecompat_fstart # VirtualAddress ++ .long pecompat_fsize # SizeOfRawData ++ .long pecompat_fstart # PointerToRawData ++ ++ .long 0, 0, 0 + .long IMAGE_SCN_CNT_INITIALIZED_DATA | \ + IMAGE_SCN_MEM_READ | \ +- IMAGE_SCN_MEM_DISCARDABLE | \ +- IMAGE_SCN_ALIGN_1BYTES # Characteristics ++ IMAGE_SCN_MEM_DISCARDABLE # Characteristics ++ ++ /* ++ * Put the IA-32 machine type and the associated entry point address in ++ * the .compat section, so loaders can figure out which other execution ++ * modes this image supports. ++ */ ++ .pushsection ".pecompat", "a", @progbits ++ .balign salign ++ .globl pecompat_fstart ++pecompat_fstart: ++ .byte 0x1 # Version ++ .byte 8 # Size ++ .word IMAGE_FILE_MACHINE_I386 # PE machine type ++ .long setup_size + ZO_efi32_pe_entry # Entrypoint ++ .byte 0x0 # Sentinel ++ .popsection ++#else ++ .set pecompat_fstart, setup_size + #endif +- +- # +- # The offset & size fields are filled in by build.c. +- # + .ascii ".text" + .byte 0 + .byte 0 + .byte 0 +- .long 0 +- .long 0x0 # startup_{32,64} +- .long 0 # Size of initialized data ++ .long ZO__data ++ .long setup_size ++ .long ZO__data # Size of initialized data + # on disk +- .long 0x0 # startup_{32,64} ++ .long setup_size + .long 0 # PointerToRelocations + .long 0 # PointerToLineNumbers + .word 0 # NumberOfRelocations + .word 0 # NumberOfLineNumbers + .long IMAGE_SCN_CNT_CODE | \ + IMAGE_SCN_MEM_READ | \ +- IMAGE_SCN_MEM_EXECUTE | \ +- IMAGE_SCN_ALIGN_16BYTES # Characteristics ++ IMAGE_SCN_MEM_EXECUTE # Characteristics ++ ++ .ascii ".data\0\0\0" ++ .long ZO__end - ZO__data # VirtualSize ++ .long setup_size + ZO__data # VirtualAddress ++ .long ZO__edata - ZO__data # SizeOfRawData ++ .long setup_size + ZO__data # PointerToRawData ++ ++ .long 0, 0, 0 ++ .long IMAGE_SCN_CNT_INITIALIZED_DATA | \ ++ IMAGE_SCN_MEM_READ | \ ++ IMAGE_SCN_MEM_WRITE # Characteristics + + .set section_count, (. - section_table) / 40 + #endif /* CONFIG_EFI_STUB */ +@@ -286,12 +223,12 @@ sentinel: .byte 0xff, 0xff /* Used to detect broken loaders */ + + .globl hdr + hdr: +-setup_sects: .byte 0 /* Filled in by build.c */ ++ .byte setup_sects - 1 + root_flags: .word ROOT_RDONLY +-syssize: .long 0 /* Filled in by build.c */ ++syssize: .long ZO__edata / 16 + ram_size: .word 0 /* Obsolete */ + vid_mode: .word SVGA_MODE +-root_dev: .word 0 /* Filled in by build.c */ ++root_dev: .word 0 /* Default to major/minor 0/0 */ + boot_flag: .word 0xAA55 + + # offset 512, entry point +@@ -579,9 +516,25 @@ pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr + # define INIT_SIZE VO_INIT_SIZE + #endif + ++ .macro __handover_offset ++#ifndef CONFIG_EFI_HANDOVER_PROTOCOL ++ .long 0 ++#elif !defined(CONFIG_X86_64) ++ .long ZO_efi32_stub_entry ++#else ++ /* Yes, this is really how we defined it :( */ ++ .long ZO_efi64_stub_entry - 0x200 ++#ifdef CONFIG_EFI_MIXED ++ .if ZO_efi32_stub_entry != ZO_efi64_stub_entry - 0x200 ++ .error "32-bit and 64-bit EFI entry points do not match" ++ .endif ++#endif ++#endif ++ .endm ++ + init_size: .long INIT_SIZE # kernel initialization size +-handover_offset: .long 0 # Filled in by build.c +-kernel_info_offset: .long 0 # Filled in by build.c ++handover_offset: __handover_offset ++kernel_info_offset: .long ZO_kernel_info + + # End of setup header ##################################################### + +diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c +index c4ea5258ab558f..9049f390d8347f 100644 +--- a/arch/x86/boot/main.c ++++ b/arch/x86/boot/main.c +@@ -119,8 +119,8 @@ static void init_heap(void) + char *stack_end; + + if (boot_params.hdr.loadflags & CAN_USE_HEAP) { +- asm("leal %P1(%%esp),%0" +- : "=r" (stack_end) : "i" (-STACK_SIZE)); ++ asm("leal %n1(%%esp),%0" ++ : "=r" (stack_end) : "i" (STACK_SIZE)); + + heap_end = (char *) + ((size_t)boot_params.hdr.heap_end_ptr + 0x200); +diff --git a/arch/x86/boot/setup.ld b/arch/x86/boot/setup.ld +index 49546c247ae25e..3a2d1360abb016 100644 +--- a/arch/x86/boot/setup.ld ++++ b/arch/x86/boot/setup.ld +@@ -10,10 +10,11 @@ ENTRY(_start) + SECTIONS + { + . = 0; +- .bstext : { *(.bstext) } +- .bsdata : { *(.bsdata) } ++ .bstext : { ++ *(.bstext) ++ . = 495; ++ } =0xffffffff + +- . = 495; + .header : { *(.header) } + .entrytext : { *(.entrytext) } + .inittext : { *(.inittext) } +@@ -23,6 +24,9 @@ SECTIONS + .text : { *(.text .text.*) } + .text32 : { *(.text32) } + ++ .pecompat : { *(.pecompat) } ++ PROVIDE(pecompat_fsize = setup_size - pecompat_fstart); ++ + . = ALIGN(16); + .rodata : { *(.rodata*) } + +@@ -38,8 +42,10 @@ SECTIONS + .signature : { + setup_sig = .; + LONG(0x5a5aaa55) +- } + ++ setup_size = ALIGN(ABSOLUTE(.), 4096); ++ setup_sects = ABSOLUTE(setup_size / 512); ++ } + + . = ALIGN(16); + .bss : +diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c +index bd247692b70174..10311d77c67f8f 100644 +--- a/arch/x86/boot/tools/build.c ++++ b/arch/x86/boot/tools/build.c +@@ -40,10 +40,6 @@ typedef unsigned char u8; + typedef unsigned short u16; + typedef unsigned int u32; + +-#define DEFAULT_MAJOR_ROOT 0 +-#define DEFAULT_MINOR_ROOT 0 +-#define DEFAULT_ROOT_DEV (DEFAULT_MAJOR_ROOT << 8 | DEFAULT_MINOR_ROOT) +- + /* Minimal number of setup sectors */ + #define SETUP_SECT_MIN 5 + #define SETUP_SECT_MAX 64 +@@ -51,22 +47,7 @@ typedef unsigned int u32; + /* This must be large enough to hold the entire setup */ + u8 buf[SETUP_SECT_MAX*512]; + +-#define PECOFF_RELOC_RESERVE 0x20 +- +-#ifdef CONFIG_EFI_MIXED +-#define PECOFF_COMPAT_RESERVE 0x20 +-#else +-#define PECOFF_COMPAT_RESERVE 0x0 +-#endif +- +-static unsigned long efi32_stub_entry; +-static unsigned long efi64_stub_entry; +-static unsigned long efi_pe_entry; +-static unsigned long efi32_pe_entry; +-static unsigned long kernel_info; +-static unsigned long startup_64; +-static unsigned long _ehead; +-static unsigned long _end; ++static unsigned long _edata; + + /*----------------------------------------------------------------------*/ + +@@ -152,180 +133,6 @@ static void usage(void) + die("Usage: build setup system zoffset.h image"); + } + +-#ifdef CONFIG_EFI_STUB +- +-static void update_pecoff_section_header_fields(char *section_name, u32 vma, u32 size, u32 datasz, u32 offset) +-{ +- unsigned int pe_header; +- unsigned short num_sections; +- u8 *section; +- +- pe_header = get_unaligned_le32(&buf[0x3c]); +- num_sections = get_unaligned_le16(&buf[pe_header + 6]); +- +-#ifdef CONFIG_X86_32 +- section = &buf[pe_header + 0xa8]; +-#else +- section = &buf[pe_header + 0xb8]; +-#endif +- +- while (num_sections > 0) { +- if (strncmp((char*)section, section_name, 8) == 0) { +- /* section header size field */ +- put_unaligned_le32(size, section + 0x8); +- +- /* section header vma field */ +- put_unaligned_le32(vma, section + 0xc); +- +- /* section header 'size of initialised data' field */ +- put_unaligned_le32(datasz, section + 0x10); +- +- /* section header 'file offset' field */ +- put_unaligned_le32(offset, section + 0x14); +- +- break; +- } +- section += 0x28; +- num_sections--; +- } +-} +- +-static void update_pecoff_section_header(char *section_name, u32 offset, u32 size) +-{ +- update_pecoff_section_header_fields(section_name, offset, size, size, offset); +-} +- +-static void update_pecoff_setup_and_reloc(unsigned int size) +-{ +- u32 setup_offset = 0x200; +- u32 reloc_offset = size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE; +-#ifdef CONFIG_EFI_MIXED +- u32 compat_offset = reloc_offset + PECOFF_RELOC_RESERVE; +-#endif +- u32 setup_size = reloc_offset - setup_offset; +- +- update_pecoff_section_header(".setup", setup_offset, setup_size); +- update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE); +- +- /* +- * Modify .reloc section contents with a single entry. The +- * relocation is applied to offset 10 of the relocation section. +- */ +- put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]); +- put_unaligned_le32(10, &buf[reloc_offset + 4]); +- +-#ifdef CONFIG_EFI_MIXED +- update_pecoff_section_header(".compat", compat_offset, PECOFF_COMPAT_RESERVE); +- +- /* +- * Put the IA-32 machine type (0x14c) and the associated entry point +- * address in the .compat section, so loaders can figure out which other +- * execution modes this image supports. +- */ +- buf[compat_offset] = 0x1; +- buf[compat_offset + 1] = 0x8; +- put_unaligned_le16(0x14c, &buf[compat_offset + 2]); +- put_unaligned_le32(efi32_pe_entry + size, &buf[compat_offset + 4]); +-#endif +-} +- +-static void update_pecoff_text(unsigned int text_start, unsigned int file_sz, +- unsigned int init_sz) +-{ +- unsigned int pe_header; +- unsigned int text_sz = file_sz - text_start; +- unsigned int bss_sz = init_sz - file_sz; +- +- pe_header = get_unaligned_le32(&buf[0x3c]); +- +- /* +- * The PE/COFF loader may load the image at an address which is +- * misaligned with respect to the kernel_alignment field in the setup +- * header. +- * +- * In order to avoid relocating the kernel to correct the misalignment, +- * add slack to allow the buffer to be aligned within the declared size +- * of the image. +- */ +- bss_sz += CONFIG_PHYSICAL_ALIGN; +- init_sz += CONFIG_PHYSICAL_ALIGN; +- +- /* +- * Size of code: Subtract the size of the first sector (512 bytes) +- * which includes the header. +- */ +- put_unaligned_le32(file_sz - 512 + bss_sz, &buf[pe_header + 0x1c]); +- +- /* Size of image */ +- put_unaligned_le32(init_sz, &buf[pe_header + 0x50]); +- +- /* +- * Address of entry point for PE/COFF executable +- */ +- put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]); +- +- update_pecoff_section_header_fields(".text", text_start, text_sz + bss_sz, +- text_sz, text_start); +-} +- +-static int reserve_pecoff_reloc_section(int c) +-{ +- /* Reserve 0x20 bytes for .reloc section */ +- memset(buf+c, 0, PECOFF_RELOC_RESERVE); +- return PECOFF_RELOC_RESERVE; +-} +- +-static void efi_stub_defaults(void) +-{ +- /* Defaults for old kernel */ +-#ifdef CONFIG_X86_32 +- efi_pe_entry = 0x10; +-#else +- efi_pe_entry = 0x210; +- startup_64 = 0x200; +-#endif +-} +- +-static void efi_stub_entry_update(void) +-{ +- unsigned long addr = efi32_stub_entry; +- +-#ifdef CONFIG_EFI_HANDOVER_PROTOCOL +-#ifdef CONFIG_X86_64 +- /* Yes, this is really how we defined it :( */ +- addr = efi64_stub_entry - 0x200; +-#endif +- +-#ifdef CONFIG_EFI_MIXED +- if (efi32_stub_entry != addr) +- die("32-bit and 64-bit EFI entry points do not match\n"); +-#endif +-#endif +- put_unaligned_le32(addr, &buf[0x264]); +-} +- +-#else +- +-static inline void update_pecoff_setup_and_reloc(unsigned int size) {} +-static inline void update_pecoff_text(unsigned int text_start, +- unsigned int file_sz, +- unsigned int init_sz) {} +-static inline void efi_stub_defaults(void) {} +-static inline void efi_stub_entry_update(void) {} +- +-static inline int reserve_pecoff_reloc_section(int c) +-{ +- return 0; +-} +-#endif /* CONFIG_EFI_STUB */ +- +-static int reserve_pecoff_compat_section(int c) +-{ +- /* Reserve 0x20 bytes for .compat section */ +- memset(buf+c, 0, PECOFF_COMPAT_RESERVE); +- return PECOFF_COMPAT_RESERVE; +-} +- + /* + * Parse zoffset.h and find the entry points. We could just #include zoffset.h + * but that would mean tools/build would have to be rebuilt every time. It's +@@ -354,14 +161,7 @@ static void parse_zoffset(char *fname) + p = (char *)buf; + + while (p && *p) { +- PARSE_ZOFS(p, efi32_stub_entry); +- PARSE_ZOFS(p, efi64_stub_entry); +- PARSE_ZOFS(p, efi_pe_entry); +- PARSE_ZOFS(p, efi32_pe_entry); +- PARSE_ZOFS(p, kernel_info); +- PARSE_ZOFS(p, startup_64); +- PARSE_ZOFS(p, _ehead); +- PARSE_ZOFS(p, _end); ++ PARSE_ZOFS(p, _edata); + + p = strchr(p, '\n'); + while (p && (*p == '\r' || *p == '\n')) +@@ -371,17 +171,14 @@ static void parse_zoffset(char *fname) + + int main(int argc, char ** argv) + { +- unsigned int i, sz, setup_sectors, init_sz; ++ unsigned int i, sz, setup_sectors; + int c; +- u32 sys_size; + struct stat sb; + FILE *file, *dest; + int fd; + void *kernel; + u32 crc = 0xffffffffUL; + +- efi_stub_defaults(); +- + if (argc != 5) + usage(); + parse_zoffset(argv[3]); +@@ -403,72 +200,27 @@ int main(int argc, char ** argv) + die("Boot block hasn't got boot flag (0xAA55)"); + fclose(file); + +- c += reserve_pecoff_compat_section(c); +- c += reserve_pecoff_reloc_section(c); +- + /* Pad unused space with zeros */ +- setup_sectors = (c + 511) / 512; ++ setup_sectors = (c + 4095) / 4096; ++ setup_sectors *= 8; + if (setup_sectors < SETUP_SECT_MIN) + setup_sectors = SETUP_SECT_MIN; + i = setup_sectors*512; + memset(buf+c, 0, i-c); + +- update_pecoff_setup_and_reloc(i); +- +- /* Set the default root device */ +- put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]); +- + /* Open and stat the kernel file */ + fd = open(argv[2], O_RDONLY); + if (fd < 0) + die("Unable to open `%s': %m", argv[2]); + if (fstat(fd, &sb)) + die("Unable to stat `%s': %m", argv[2]); +- sz = sb.st_size; ++ if (_edata != sb.st_size) ++ die("Unexpected file size `%s': %u != %u", argv[2], _edata, ++ sb.st_size); ++ sz = _edata - 4; + kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0); + if (kernel == MAP_FAILED) + die("Unable to mmap '%s': %m", argv[2]); +- /* Number of 16-byte paragraphs, including space for a 4-byte CRC */ +- sys_size = (sz + 15 + 4) / 16; +-#ifdef CONFIG_EFI_STUB +- /* +- * COFF requires minimum 32-byte alignment of sections, and +- * adding a signature is problematic without that alignment. +- */ +- sys_size = (sys_size + 1) & ~1; +-#endif +- +- /* Patch the setup code with the appropriate size parameters */ +- buf[0x1f1] = setup_sectors-1; +- put_unaligned_le32(sys_size, &buf[0x1f4]); +- +- init_sz = get_unaligned_le32(&buf[0x260]); +-#ifdef CONFIG_EFI_STUB +- /* +- * The decompression buffer will start at ImageBase. When relocating +- * the compressed kernel to its end, we must ensure that the head +- * section does not get overwritten. The head section occupies +- * [i, i + _ehead), and the destination is [init_sz - _end, init_sz). +- * +- * At present these should never overlap, because 'i' is at most 32k +- * because of SETUP_SECT_MAX, '_ehead' is less than 1k, and the +- * calculation of INIT_SIZE in boot/header.S ensures that +- * 'init_sz - _end' is at least 64k. +- * +- * For future-proofing, increase init_sz if necessary. +- */ +- +- if (init_sz - _end < i + _ehead) { +- init_sz = (i + _ehead + _end + 4095) & ~4095; +- put_unaligned_le32(init_sz, &buf[0x260]); +- } +-#endif +- update_pecoff_text(setup_sectors * 512, i + (sys_size * 16), init_sz); +- +- efi_stub_entry_update(); +- +- /* Update kernel_info offset. */ +- put_unaligned_le32(kernel_info, &buf[0x268]); + + crc = partial_crc32(buf, i, crc); + if (fwrite(buf, 1, i, dest) != i) +@@ -479,13 +231,6 @@ int main(int argc, char ** argv) + if (fwrite(kernel, 1, sz, dest) != sz) + die("Writing kernel failed"); + +- /* Add padding leaving 4 bytes for the checksum */ +- while (sz++ < (sys_size*16) - 4) { +- crc = partial_crc32_one('\0', crc); +- if (fwrite("\0", 1, 1, dest) != 1) +- die("Writing padding failed"); +- } +- + /* Write the CRC */ + put_unaligned_le32(crc, buf); + if (fwrite(buf, 1, 4, dest) != 4) +diff --git a/arch/x86/coco/core.c b/arch/x86/coco/core.c +index eeec9986570ed0..ddd4efdc79d668 100644 +--- a/arch/x86/coco/core.c ++++ b/arch/x86/coco/core.c +@@ -3,18 +3,22 @@ + * Confidential Computing Platform Capability checks + * + * Copyright (C) 2021 Advanced Micro Devices, Inc. ++ * Copyright (C) 2024 Jason A. Donenfeld . All Rights Reserved. + * + * Author: Tom Lendacky + */ + + #include + #include ++#include ++#include + ++#include + #include + #include + + enum cc_vendor cc_vendor __ro_after_init = CC_VENDOR_NONE; +-static u64 cc_mask __ro_after_init; ++u64 cc_mask __ro_after_init; + + static bool noinstr intel_cc_platform_has(enum cc_attr attr) + { +@@ -149,7 +153,39 @@ u64 cc_mkdec(u64 val) + } + EXPORT_SYMBOL_GPL(cc_mkdec); + +-__init void cc_set_mask(u64 mask) ++__init void cc_random_init(void) + { +- cc_mask = mask; ++ /* ++ * The seed is 32 bytes (in units of longs), which is 256 bits, which ++ * is the security level that the RNG is targeting. ++ */ ++ unsigned long rng_seed[32 / sizeof(long)]; ++ size_t i, longs; ++ ++ if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) ++ return; ++ ++ /* ++ * Since the CoCo threat model includes the host, the only reliable ++ * source of entropy that can be neither observed nor manipulated is ++ * RDRAND. Usually, RDRAND failure is considered tolerable, but since ++ * CoCo guests have no other unobservable source of entropy, it's ++ * important to at least ensure the RNG gets some initial random seeds. ++ */ ++ for (i = 0; i < ARRAY_SIZE(rng_seed); i += longs) { ++ longs = arch_get_random_longs(&rng_seed[i], ARRAY_SIZE(rng_seed) - i); ++ ++ /* ++ * A zero return value means that the guest doesn't have RDRAND ++ * or the CPU is physically broken, and in both cases that ++ * means most crypto inside of the CoCo instance will be ++ * broken, defeating the purpose of CoCo in the first place. So ++ * just panic here because it's absolutely unsafe to continue ++ * executing. ++ */ ++ if (longs == 0) ++ panic("RDRAND is defective."); ++ } ++ add_device_randomness(rng_seed, sizeof(rng_seed)); ++ memzero_explicit(rng_seed, sizeof(rng_seed)); + } +diff --git a/arch/x86/coco/tdx/tdcall.S b/arch/x86/coco/tdx/tdcall.S +index b193c0a1d8db38..2eca5f43734feb 100644 +--- a/arch/x86/coco/tdx/tdcall.S ++++ b/arch/x86/coco/tdx/tdcall.S +@@ -195,6 +195,7 @@ SYM_FUNC_END(__tdx_module_call) + xor %r10d, %r10d + xor %r11d, %r11d + xor %rdi, %rdi ++ xor %rsi, %rsi + xor %rdx, %rdx + + /* Restore callee-saved GPRs as mandated by the x86_64 ABI */ +diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c +index 1d6b863c42b001..905ac8a3f7165c 100644 +--- a/arch/x86/coco/tdx/tdx.c ++++ b/arch/x86/coco/tdx/tdx.c +@@ -10,9 +10,11 @@ + #include + #include + #include ++#include + #include + #include + #include ++#include + + /* MMIO direction */ + #define EPT_READ 0 +@@ -361,7 +363,6 @@ static bool mmio_read(int size, unsigned long addr, unsigned long *val) + .r12 = size, + .r13 = EPT_READ, + .r14 = addr, +- .r15 = *val, + }; + + if (__tdx_hypercall_ret(&args)) +@@ -405,6 +406,11 @@ static int handle_mmio(struct pt_regs *regs, struct ve_info *ve) + return -EINVAL; + } + ++ if (!fault_in_kernel_space(ve->gla)) { ++ WARN_ONCE(1, "Access to userspace address is not supported"); ++ return -EINVAL; ++ } ++ + /* + * Reject EPT violation #VEs that split pages. + * +diff --git a/arch/x86/crypto/nh-avx2-x86_64.S b/arch/x86/crypto/nh-avx2-x86_64.S +index ef73a3ab87263e..791386d9a83aa1 100644 +--- a/arch/x86/crypto/nh-avx2-x86_64.S ++++ b/arch/x86/crypto/nh-avx2-x86_64.S +@@ -154,5 +154,6 @@ SYM_TYPED_FUNC_START(nh_avx2) + vpaddq T1, T0, T0 + vpaddq T4, T0, T0 + vmovdqu T0, (HASH) ++ vzeroupper + RET + SYM_FUNC_END(nh_avx2) +diff --git a/arch/x86/crypto/sha1_ssse3_glue.c b/arch/x86/crypto/sha1_ssse3_glue.c +index 44340a1139e0b7..959afa705e95ca 100644 +--- a/arch/x86/crypto/sha1_ssse3_glue.c ++++ b/arch/x86/crypto/sha1_ssse3_glue.c +@@ -24,8 +24,17 @@ + #include + #include + #include ++#include + #include + ++static const struct x86_cpu_id module_cpu_ids[] = { ++ X86_MATCH_FEATURE(X86_FEATURE_AVX2, NULL), ++ X86_MATCH_FEATURE(X86_FEATURE_AVX, NULL), ++ X86_MATCH_FEATURE(X86_FEATURE_SSSE3, NULL), ++ {} ++}; ++MODULE_DEVICE_TABLE(x86cpu, module_cpu_ids); ++ + static int sha1_update(struct shash_desc *desc, const u8 *data, + unsigned int len, sha1_block_fn *sha1_xform) + { +@@ -301,6 +310,9 @@ static inline void unregister_sha1_ni(void) { } + + static int __init sha1_ssse3_mod_init(void) + { ++ if (!x86_match_cpu(module_cpu_ids)) ++ return -ENODEV; ++ + if (register_sha1_ssse3()) + goto fail; + +diff --git a/arch/x86/crypto/sha256-avx2-asm.S b/arch/x86/crypto/sha256-avx2-asm.S +index 9918212faf914f..0bbec1c75cd0be 100644 +--- a/arch/x86/crypto/sha256-avx2-asm.S ++++ b/arch/x86/crypto/sha256-avx2-asm.S +@@ -592,22 +592,22 @@ SYM_TYPED_FUNC_START(sha256_transform_rorx) + leaq K256+0*32(%rip), INP ## reuse INP as scratch reg + vpaddd (INP, SRND), X0, XFER + vmovdqa XFER, 0*32+_XFER(%rsp, SRND) +- FOUR_ROUNDS_AND_SCHED _XFER + 0*32 ++ FOUR_ROUNDS_AND_SCHED (_XFER + 0*32) + + leaq K256+1*32(%rip), INP + vpaddd (INP, SRND), X0, XFER + vmovdqa XFER, 1*32+_XFER(%rsp, SRND) +- FOUR_ROUNDS_AND_SCHED _XFER + 1*32 ++ FOUR_ROUNDS_AND_SCHED (_XFER + 1*32) + + leaq K256+2*32(%rip), INP + vpaddd (INP, SRND), X0, XFER + vmovdqa XFER, 2*32+_XFER(%rsp, SRND) +- FOUR_ROUNDS_AND_SCHED _XFER + 2*32 ++ FOUR_ROUNDS_AND_SCHED (_XFER + 2*32) + + leaq K256+3*32(%rip), INP + vpaddd (INP, SRND), X0, XFER + vmovdqa XFER, 3*32+_XFER(%rsp, SRND) +- FOUR_ROUNDS_AND_SCHED _XFER + 3*32 ++ FOUR_ROUNDS_AND_SCHED (_XFER + 3*32) + + add $4*32, SRND + cmp $3*4*32, SRND +@@ -618,12 +618,12 @@ SYM_TYPED_FUNC_START(sha256_transform_rorx) + leaq K256+0*32(%rip), INP + vpaddd (INP, SRND), X0, XFER + vmovdqa XFER, 0*32+_XFER(%rsp, SRND) +- DO_4ROUNDS _XFER + 0*32 ++ DO_4ROUNDS (_XFER + 0*32) + + leaq K256+1*32(%rip), INP + vpaddd (INP, SRND), X1, XFER + vmovdqa XFER, 1*32+_XFER(%rsp, SRND) +- DO_4ROUNDS _XFER + 1*32 ++ DO_4ROUNDS (_XFER + 1*32) + add $2*32, SRND + + vmovdqa X2, X0 +@@ -651,8 +651,8 @@ SYM_TYPED_FUNC_START(sha256_transform_rorx) + xor SRND, SRND + .align 16 + .Lloop3: +- DO_4ROUNDS _XFER + 0*32 + 16 +- DO_4ROUNDS _XFER + 1*32 + 16 ++ DO_4ROUNDS (_XFER + 0*32 + 16) ++ DO_4ROUNDS (_XFER + 1*32 + 16) + add $2*32, SRND + cmp $4*4*32, SRND + jb .Lloop3 +@@ -716,6 +716,7 @@ SYM_TYPED_FUNC_START(sha256_transform_rorx) + popq %r13 + popq %r12 + popq %rbx ++ vzeroupper + RET + SYM_FUNC_END(sha256_transform_rorx) + +diff --git a/arch/x86/crypto/sha256_ssse3_glue.c b/arch/x86/crypto/sha256_ssse3_glue.c +index 3a5f6be7dbba4e..d25235f0ccafc3 100644 +--- a/arch/x86/crypto/sha256_ssse3_glue.c ++++ b/arch/x86/crypto/sha256_ssse3_glue.c +@@ -38,11 +38,20 @@ + #include + #include + #include ++#include + #include + + asmlinkage void sha256_transform_ssse3(struct sha256_state *state, + const u8 *data, int blocks); + ++static const struct x86_cpu_id module_cpu_ids[] = { ++ X86_MATCH_FEATURE(X86_FEATURE_AVX2, NULL), ++ X86_MATCH_FEATURE(X86_FEATURE_AVX, NULL), ++ X86_MATCH_FEATURE(X86_FEATURE_SSSE3, NULL), ++ {} ++}; ++MODULE_DEVICE_TABLE(x86cpu, module_cpu_ids); ++ + static int _sha256_update(struct shash_desc *desc, const u8 *data, + unsigned int len, sha256_block_fn *sha256_xform) + { +@@ -366,6 +375,9 @@ static inline void unregister_sha256_ni(void) { } + + static int __init sha256_ssse3_mod_init(void) + { ++ if (!x86_match_cpu(module_cpu_ids)) ++ return -ENODEV; ++ + if (register_sha256_ssse3()) + goto fail; + +diff --git a/arch/x86/crypto/sha512-avx2-asm.S b/arch/x86/crypto/sha512-avx2-asm.S +index f08496cd68708f..24973f42c43ff4 100644 +--- a/arch/x86/crypto/sha512-avx2-asm.S ++++ b/arch/x86/crypto/sha512-avx2-asm.S +@@ -680,6 +680,7 @@ SYM_TYPED_FUNC_START(sha512_transform_rorx) + pop %r12 + pop %rbx + ++ vzeroupper + RET + SYM_FUNC_END(sha512_transform_rorx) + +diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c +index 93c60c0c9d4a7a..e72dac092245a5 100644 +--- a/arch/x86/entry/common.c ++++ b/arch/x86/entry/common.c +@@ -25,6 +25,7 @@ + #include + #endif + ++#include + #include + #include + #include +@@ -47,7 +48,7 @@ static __always_inline bool do_syscall_x64(struct pt_regs *regs, int nr) + + if (likely(unr < NR_syscalls)) { + unr = array_index_nospec(unr, NR_syscalls); +- regs->ax = sys_call_table[unr](regs); ++ regs->ax = x64_sys_call(regs, unr); + return true; + } + return false; +@@ -64,7 +65,7 @@ static __always_inline bool do_syscall_x32(struct pt_regs *regs, int nr) + + if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(xnr < X32_NR_syscalls)) { + xnr = array_index_nospec(xnr, X32_NR_syscalls); +- regs->ax = x32_sys_call_table[xnr](regs); ++ regs->ax = x32_sys_call(regs, xnr); + return true; + } + return false; +@@ -96,6 +97,10 @@ static __always_inline int syscall_32_enter(struct pt_regs *regs) + return (int)regs->orig_ax; + } + ++#ifdef CONFIG_IA32_EMULATION ++bool __ia32_enabled __ro_after_init = true; ++#endif ++ + /* + * Invoke a 32-bit syscall. Called with IRQs on in CONTEXT_KERNEL. + */ +@@ -109,13 +114,102 @@ static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, int nr) + + if (likely(unr < IA32_NR_syscalls)) { + unr = array_index_nospec(unr, IA32_NR_syscalls); +- regs->ax = ia32_sys_call_table[unr](regs); ++ regs->ax = ia32_sys_call(regs, unr); + } else if (nr != -1) { + regs->ax = __ia32_sys_ni_syscall(regs); + } + } + +-/* Handles int $0x80 */ ++#ifdef CONFIG_IA32_EMULATION ++static __always_inline bool int80_is_external(void) ++{ ++ const unsigned int offs = (0x80 / 32) * 0x10; ++ const u32 bit = BIT(0x80 % 32); ++ ++ /* The local APIC on XENPV guests is fake */ ++ if (cpu_feature_enabled(X86_FEATURE_XENPV)) ++ return false; ++ ++ /* ++ * If vector 0x80 is set in the APIC ISR then this is an external ++ * interrupt. Either from broken hardware or injected by a VMM. ++ * ++ * Note: In guest mode this is only valid for secure guests where ++ * the secure module fully controls the vAPIC exposed to the guest. ++ */ ++ return apic_read(APIC_ISR + offs) & bit; ++} ++ ++/** ++ * do_int80_emulation - 32-bit legacy syscall C entry from asm ++ * ++ * This entry point can be used by 32-bit and 64-bit programs to perform ++ * 32-bit system calls. Instances of INT $0x80 can be found inline in ++ * various programs and libraries. It is also used by the vDSO's ++ * __kernel_vsyscall fallback for hardware that doesn't support a faster ++ * entry method. Restarted 32-bit system calls also fall back to INT ++ * $0x80 regardless of what instruction was originally used to do the ++ * system call. ++ * ++ * This is considered a slow path. It is not used by most libc ++ * implementations on modern hardware except during process startup. ++ * ++ * The arguments for the INT $0x80 based syscall are on stack in the ++ * pt_regs structure: ++ * eax: system call number ++ * ebx, ecx, edx, esi, edi, ebp: arg1 - arg 6 ++ */ ++__visible noinstr void do_int80_emulation(struct pt_regs *regs) ++{ ++ int nr; ++ ++ /* Kernel does not use INT $0x80! */ ++ if (unlikely(!user_mode(regs))) { ++ irqentry_enter(regs); ++ instrumentation_begin(); ++ panic("Unexpected external interrupt 0x80\n"); ++ } ++ ++ /* ++ * Establish kernel context for instrumentation, including for ++ * int80_is_external() below which calls into the APIC driver. ++ * Identical for soft and external interrupts. ++ */ ++ enter_from_user_mode(regs); ++ ++ instrumentation_begin(); ++ add_random_kstack_offset(); ++ ++ /* Validate that this is a soft interrupt to the extent possible */ ++ if (unlikely(int80_is_external())) ++ panic("Unexpected external interrupt 0x80\n"); ++ ++ /* ++ * The low level idtentry code pushed -1 into regs::orig_ax ++ * and regs::ax contains the syscall number. ++ * ++ * User tracing code (ptrace or signal handlers) might assume ++ * that the regs::orig_ax contains a 32-bit number on invoking ++ * a 32-bit syscall. ++ * ++ * Establish the syscall convention by saving the 32bit truncated ++ * syscall number in regs::orig_ax and by invalidating regs::ax. ++ */ ++ regs->orig_ax = regs->ax & GENMASK(31, 0); ++ regs->ax = -ENOSYS; ++ ++ nr = syscall_32_enter(regs); ++ ++ local_irq_enable(); ++ nr = syscall_enter_from_user_mode_work(regs, nr); ++ do_syscall_32_irqs_on(regs, nr); ++ ++ instrumentation_end(); ++ syscall_exit_to_user_mode(regs); ++} ++#else /* CONFIG_IA32_EMULATION */ ++ ++/* Handles int $0x80 on a 32bit kernel */ + __visible noinstr void do_int80_syscall_32(struct pt_regs *regs) + { + int nr = syscall_32_enter(regs); +@@ -134,6 +228,7 @@ __visible noinstr void do_int80_syscall_32(struct pt_regs *regs) + instrumentation_end(); + syscall_exit_to_user_mode(regs); + } ++#endif /* !CONFIG_IA32_EMULATION */ + + static noinstr bool __do_fast_syscall_32(struct pt_regs *regs) + { +diff --git a/arch/x86/entry/entry.S b/arch/x86/entry/entry.S +index bfb7bcb362bcfc..34eca8015b64bc 100644 +--- a/arch/x86/entry/entry.S ++++ b/arch/x86/entry/entry.S +@@ -6,6 +6,11 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++#include + + .pushsection .noinstr.text, "ax" + +@@ -14,9 +19,32 @@ SYM_FUNC_START(entry_ibpb) + movl $PRED_CMD_IBPB, %eax + xorl %edx, %edx + wrmsr ++ ++ /* Make sure IBPB clears return stack preductions too. */ ++ FILL_RETURN_BUFFER %rax, RSB_CLEAR_LOOPS, X86_BUG_IBPB_NO_RET + RET + SYM_FUNC_END(entry_ibpb) + /* For KVM */ + EXPORT_SYMBOL_GPL(entry_ibpb); + + .popsection ++ ++/* ++ * Define the VERW operand that is disguised as entry code so that ++ * it can be referenced with KPTI enabled. This ensure VERW can be ++ * used late in exit-to-user path after page tables are switched. ++ */ ++.pushsection .entry.text, "ax" ++ ++.align L1_CACHE_BYTES, 0xcc ++SYM_CODE_START_NOALIGN(mds_verw_sel) ++ UNWIND_HINT_UNDEFINED ++ ANNOTATE_NOENDBR ++ .word __KERNEL_DS ++.align L1_CACHE_BYTES, 0xcc ++SYM_CODE_END(mds_verw_sel); ++/* For KVM */ ++EXPORT_SYMBOL_GPL(mds_verw_sel); ++ ++.popsection ++ +diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S +index 6e6af42e044a20..3894acc54b79c4 100644 +--- a/arch/x86/entry/entry_32.S ++++ b/arch/x86/entry/entry_32.S +@@ -875,6 +875,8 @@ SYM_FUNC_START(entry_SYSENTER_32) + + /* Now ready to switch the cr3 */ + SWITCH_TO_USER_CR3 scratch_reg=%eax ++ /* Clobbers ZF */ ++ CLEAR_CPU_BUFFERS + + /* + * Restore all flags except IF. (We restore IF separately because +@@ -954,6 +956,7 @@ restore_all_switch_stack: + + /* Restore user state */ + RESTORE_REGS pop=4 # skip orig_eax/error_code ++ CLEAR_CPU_BUFFERS + .Lirq_return: + /* + * ARCH_HAS_MEMBARRIER_SYNC_CORE rely on IRET core serialization +@@ -1166,6 +1169,7 @@ SYM_CODE_START(asm_exc_nmi) + + CHECK_AND_APPLY_ESPFIX + RESTORE_ALL_NMI cr3_reg=%edi pop=4 ++ CLEAR_CPU_BUFFERS + jmp .Lirq_return + + #ifdef CONFIG_X86_ESPFIX32 +@@ -1207,6 +1211,7 @@ SYM_CODE_START(asm_exc_nmi) + * 1 - orig_ax + */ + lss (1+5+6)*4(%esp), %esp # back to espfix stack ++ CLEAR_CPU_BUFFERS + jmp .Lirq_return + #endif + SYM_CODE_END(asm_exc_nmi) +diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S +index 43606de225117d..2192b6c33ea009 100644 +--- a/arch/x86/entry/entry_64.S ++++ b/arch/x86/entry/entry_64.S +@@ -116,6 +116,7 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL) + /* clobbers %rax, make sure it is after saving the syscall nr */ + IBRS_ENTER + UNTRAIN_RET ++ CLEAR_BRANCH_HISTORY + + call do_syscall_64 /* returns with IRQs disabled */ + +@@ -166,22 +167,9 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL) + jne swapgs_restore_regs_and_return_to_usermode + + /* +- * SYSCALL clears RF when it saves RFLAGS in R11 and SYSRET cannot +- * restore RF properly. If the slowpath sets it for whatever reason, we +- * need to restore it correctly. +- * +- * SYSRET can restore TF, but unlike IRET, restoring TF results in a +- * trap from userspace immediately after SYSRET. This would cause an +- * infinite loop whenever #DB happens with register state that satisfies +- * the opportunistic SYSRET conditions. For example, single-stepping +- * this user code: +- * +- * movq $stuck_here, %rcx +- * pushfq +- * popq %r11 +- * stuck_here: +- * +- * would never get past 'stuck_here'. ++ * SYSRET cannot restore RF. It can restore TF, but unlike IRET, ++ * restoring TF results in a trap from userspace immediately after ++ * SYSRET. + */ + testq $(X86_EFLAGS_RF|X86_EFLAGS_TF), %r11 + jnz swapgs_restore_regs_and_return_to_usermode +@@ -223,6 +211,7 @@ syscall_return_via_sysret: + SYM_INNER_LABEL(entry_SYSRETQ_unsafe_stack, SYM_L_GLOBAL) + ANNOTATE_NOENDBR + swapgs ++ CLEAR_CPU_BUFFERS + sysretq + SYM_INNER_LABEL(entry_SYSRETQ_end, SYM_L_GLOBAL) + ANNOTATE_NOENDBR +@@ -663,6 +652,7 @@ SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL) + /* Restore RDI. */ + popq %rdi + swapgs ++ CLEAR_CPU_BUFFERS + jmp .Lnative_iret + + +@@ -774,6 +764,8 @@ native_irq_return_ldt: + */ + popq %rax /* Restore user RAX */ + ++ CLEAR_CPU_BUFFERS ++ + /* + * RSP now points to an ordinary IRET frame, except that the page + * is read-only and RSP[31:16] are preloaded with the userspace +@@ -1502,6 +1494,12 @@ nmi_restore: + std + movq $0, 5*8(%rsp) /* clear "NMI executing" */ + ++ /* ++ * Skip CLEAR_CPU_BUFFERS here, since it only helps in rare cases like ++ * NMI in kernel after user state is restored. For an unprivileged user ++ * these conditions are hard to meet. ++ */ ++ + /* + * iretq reads the "iret" frame and exits the NMI stack in a + * single instruction. We are returning to kernel mode, so this +@@ -1516,12 +1514,13 @@ SYM_CODE_END(asm_exc_nmi) + * This handles SYSCALL from 32-bit code. There is no way to program + * MSRs to fully disable 32-bit SYSCALL. + */ +-SYM_CODE_START(ignore_sysret) ++SYM_CODE_START(entry_SYSCALL32_ignore) + UNWIND_HINT_END_OF_STACK + ENDBR + mov $-ENOSYS, %eax ++ CLEAR_CPU_BUFFERS + sysretl +-SYM_CODE_END(ignore_sysret) ++SYM_CODE_END(entry_SYSCALL32_ignore) + #endif + + .pushsection .text, "ax" +@@ -1538,3 +1537,63 @@ SYM_CODE_START_NOALIGN(rewind_stack_and_make_dead) + call make_task_dead + SYM_CODE_END(rewind_stack_and_make_dead) + .popsection ++ ++/* ++ * This sequence executes branches in order to remove user branch information ++ * from the branch history tracker in the Branch Predictor, therefore removing ++ * user influence on subsequent BTB lookups. ++ * ++ * It should be used on parts prior to Alder Lake. Newer parts should use the ++ * BHI_DIS_S hardware control instead. If a pre-Alder Lake part is being ++ * virtualized on newer hardware the VMM should protect against BHI attacks by ++ * setting BHI_DIS_S for the guests. ++ * ++ * CALLs/RETs are necessary to prevent Loop Stream Detector(LSD) from engaging ++ * and not clearing the branch history. The call tree looks like: ++ * ++ * call 1 ++ * call 2 ++ * call 2 ++ * call 2 ++ * call 2 ++ * call 2 ++ * ret ++ * ret ++ * ret ++ * ret ++ * ret ++ * ret ++ * ++ * This means that the stack is non-constant and ORC can't unwind it with %rsp ++ * alone. Therefore we unconditionally set up the frame pointer, which allows ++ * ORC to unwind properly. ++ * ++ * The alignment is for performance and not for safety, and may be safely ++ * refactored in the future if needed. ++ */ ++SYM_FUNC_START(clear_bhb_loop) ++ push %rbp ++ mov %rsp, %rbp ++ movl $5, %ecx ++ ANNOTATE_INTRA_FUNCTION_CALL ++ call 1f ++ jmp 5f ++ .align 64, 0xcc ++ ANNOTATE_INTRA_FUNCTION_CALL ++1: call 2f ++ RET ++ .align 64, 0xcc ++2: movl $5, %eax ++3: jmp 4f ++ nop ++4: sub $1, %eax ++ jnz 3b ++ sub $1, %ecx ++ jnz 1b ++ RET ++5: lfence ++ pop %rbp ++ RET ++SYM_FUNC_END(clear_bhb_loop) ++EXPORT_SYMBOL_GPL(clear_bhb_loop) ++STACK_FRAME_NON_STANDARD(clear_bhb_loop) +diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S +index 70150298f8bdf5..ebfccadf918cb4 100644 +--- a/arch/x86/entry/entry_64_compat.S ++++ b/arch/x86/entry/entry_64_compat.S +@@ -90,9 +90,6 @@ SYM_INNER_LABEL(entry_SYSENTER_compat_after_hwframe, SYM_L_GLOBAL) + + cld + +- IBRS_ENTER +- UNTRAIN_RET +- + /* + * SYSENTER doesn't filter flags, so we need to clear NT and AC + * ourselves. To save a few cycles, we can check whether +@@ -116,6 +113,16 @@ SYM_INNER_LABEL(entry_SYSENTER_compat_after_hwframe, SYM_L_GLOBAL) + jnz .Lsysenter_fix_flags + .Lsysenter_flags_fixed: + ++ /* ++ * CPU bugs mitigations mechanisms can call other functions. They ++ * should be invoked after making sure TF is cleared because ++ * single-step is ignored only for instructions inside the ++ * entry_SYSENTER_compat function. ++ */ ++ IBRS_ENTER ++ UNTRAIN_RET ++ CLEAR_BRANCH_HISTORY ++ + movq %rsp, %rdi + call do_SYSENTER_32 + /* XEN PV guests always use IRET path */ +@@ -209,6 +216,7 @@ SYM_INNER_LABEL(entry_SYSCALL_compat_after_hwframe, SYM_L_GLOBAL) + + IBRS_ENTER + UNTRAIN_RET ++ CLEAR_BRANCH_HISTORY + + movq %rsp, %rdi + call do_fast_syscall_32 +@@ -271,6 +279,7 @@ SYM_INNER_LABEL(entry_SYSRETL_compat_unsafe_stack, SYM_L_GLOBAL) + xorl %r9d, %r9d + xorl %r10d, %r10d + swapgs ++ CLEAR_CPU_BUFFERS + sysretl + SYM_INNER_LABEL(entry_SYSRETL_compat_end, SYM_L_GLOBAL) + ANNOTATE_NOENDBR +@@ -278,78 +287,15 @@ SYM_INNER_LABEL(entry_SYSRETL_compat_end, SYM_L_GLOBAL) + SYM_CODE_END(entry_SYSCALL_compat) + + /* +- * 32-bit legacy system call entry. +- * +- * 32-bit x86 Linux system calls traditionally used the INT $0x80 +- * instruction. INT $0x80 lands here. +- * +- * This entry point can be used by 32-bit and 64-bit programs to perform +- * 32-bit system calls. Instances of INT $0x80 can be found inline in +- * various programs and libraries. It is also used by the vDSO's +- * __kernel_vsyscall fallback for hardware that doesn't support a faster +- * entry method. Restarted 32-bit system calls also fall back to INT +- * $0x80 regardless of what instruction was originally used to do the +- * system call. +- * +- * This is considered a slow path. It is not used by most libc +- * implementations on modern hardware except during process startup. +- * +- * Arguments: +- * eax system call number +- * ebx arg1 +- * ecx arg2 +- * edx arg3 +- * esi arg4 +- * edi arg5 +- * ebp arg6 ++ * int 0x80 is used by 32 bit mode as a system call entry. Normally idt entries ++ * point to C routines, however since this is a system call interface the branch ++ * history needs to be scrubbed to protect against BHI attacks, and that ++ * scrubbing needs to take place in assembly code prior to entering any C ++ * routines. + */ +-SYM_CODE_START(entry_INT80_compat) +- UNWIND_HINT_ENTRY +- ENDBR +- /* +- * Interrupts are off on entry. +- */ +- ASM_CLAC /* Do this early to minimize exposure */ +- ALTERNATIVE "swapgs", "", X86_FEATURE_XENPV +- +- /* +- * User tracing code (ptrace or signal handlers) might assume that +- * the saved RAX contains a 32-bit number when we're invoking a 32-bit +- * syscall. Just in case the high bits are nonzero, zero-extend +- * the syscall number. (This could almost certainly be deleted +- * with no ill effects.) +- */ +- movl %eax, %eax +- +- /* switch to thread stack expects orig_ax and rdi to be pushed */ +- pushq %rax /* pt_regs->orig_ax */ +- +- /* Need to switch before accessing the thread stack. */ +- SWITCH_TO_KERNEL_CR3 scratch_reg=%rax +- +- /* In the Xen PV case we already run on the thread stack. */ +- ALTERNATIVE "", "jmp .Lint80_keep_stack", X86_FEATURE_XENPV +- +- movq %rsp, %rax +- movq PER_CPU_VAR(pcpu_hot + X86_top_of_stack), %rsp +- +- pushq 5*8(%rax) /* regs->ss */ +- pushq 4*8(%rax) /* regs->rsp */ +- pushq 3*8(%rax) /* regs->eflags */ +- pushq 2*8(%rax) /* regs->cs */ +- pushq 1*8(%rax) /* regs->ip */ +- pushq 0*8(%rax) /* regs->orig_ax */ +-.Lint80_keep_stack: +- +- PUSH_AND_CLEAR_REGS rax=$-ENOSYS +- UNWIND_HINT_REGS +- +- cld +- +- IBRS_ENTER +- UNTRAIN_RET +- +- movq %rsp, %rdi +- call do_int80_syscall_32 +- jmp swapgs_restore_regs_and_return_to_usermode +-SYM_CODE_END(entry_INT80_compat) ++SYM_CODE_START(int80_emulation) ++ ANNOTATE_NOENDBR ++ UNWIND_HINT_FUNC ++ CLEAR_BRANCH_HISTORY ++ jmp do_int80_emulation ++SYM_CODE_END(int80_emulation) +diff --git a/arch/x86/entry/syscall_32.c b/arch/x86/entry/syscall_32.c +index 8cfc9bc73e7f8b..c2235bae17ef66 100644 +--- a/arch/x86/entry/syscall_32.c ++++ b/arch/x86/entry/syscall_32.c +@@ -18,8 +18,25 @@ + #include + #undef __SYSCALL + ++/* ++ * The sys_call_table[] is no longer used for system calls, but ++ * kernel/trace/trace_syscalls.c still wants to know the system ++ * call address. ++ */ ++#ifdef CONFIG_X86_32 + #define __SYSCALL(nr, sym) __ia32_##sym, +- +-__visible const sys_call_ptr_t ia32_sys_call_table[] = { ++const sys_call_ptr_t sys_call_table[] = { + #include + }; ++#undef __SYSCALL ++#endif ++ ++#define __SYSCALL(nr, sym) case nr: return __ia32_##sym(regs); ++ ++long ia32_sys_call(const struct pt_regs *regs, unsigned int nr) ++{ ++ switch (nr) { ++ #include ++ default: return __ia32_sys_ni_syscall(regs); ++ } ++}; +diff --git a/arch/x86/entry/syscall_64.c b/arch/x86/entry/syscall_64.c +index be120eec1fc9f9..33b3f09e6f151e 100644 +--- a/arch/x86/entry/syscall_64.c ++++ b/arch/x86/entry/syscall_64.c +@@ -11,8 +11,23 @@ + #include + #undef __SYSCALL + ++/* ++ * The sys_call_table[] is no longer used for system calls, but ++ * kernel/trace/trace_syscalls.c still wants to know the system ++ * call address. ++ */ + #define __SYSCALL(nr, sym) __x64_##sym, +- +-asmlinkage const sys_call_ptr_t sys_call_table[] = { ++const sys_call_ptr_t sys_call_table[] = { + #include + }; ++#undef __SYSCALL ++ ++#define __SYSCALL(nr, sym) case nr: return __x64_##sym(regs); ++ ++long x64_sys_call(const struct pt_regs *regs, unsigned int nr) ++{ ++ switch (nr) { ++ #include ++ default: return __x64_sys_ni_syscall(regs); ++ } ++}; +diff --git a/arch/x86/entry/syscall_x32.c b/arch/x86/entry/syscall_x32.c +index bdd0e03a1265d2..03de4a93213182 100644 +--- a/arch/x86/entry/syscall_x32.c ++++ b/arch/x86/entry/syscall_x32.c +@@ -11,8 +11,12 @@ + #include + #undef __SYSCALL + +-#define __SYSCALL(nr, sym) __x64_##sym, ++#define __SYSCALL(nr, sym) case nr: return __x64_##sym(regs); + +-asmlinkage const sys_call_ptr_t x32_sys_call_table[] = { +-#include ++long x32_sys_call(const struct pt_regs *regs, unsigned int nr) ++{ ++ switch (nr) { ++ #include ++ default: return __x64_sys_ni_syscall(regs); ++ } + }; +diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl +index 2d0b1bd866ead6..38db5ef2329f3c 100644 +--- a/arch/x86/entry/syscalls/syscall_32.tbl ++++ b/arch/x86/entry/syscalls/syscall_32.tbl +@@ -420,7 +420,7 @@ + 412 i386 utimensat_time64 sys_utimensat + 413 i386 pselect6_time64 sys_pselect6 compat_sys_pselect6_time64 + 414 i386 ppoll_time64 sys_ppoll compat_sys_ppoll_time64 +-416 i386 io_pgetevents_time64 sys_io_pgetevents ++416 i386 io_pgetevents_time64 sys_io_pgetevents compat_sys_io_pgetevents_time64 + 417 i386 recvmmsg_time64 sys_recvmmsg compat_sys_recvmmsg_time64 + 418 i386 mq_timedsend_time64 sys_mq_timedsend + 419 i386 mq_timedreceive_time64 sys_mq_timedreceive +diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile +index 6a1821bd7d5e9b..c197efd829228c 100644 +--- a/arch/x86/entry/vdso/Makefile ++++ b/arch/x86/entry/vdso/Makefile +@@ -190,31 +190,4 @@ GCOV_PROFILE := n + quiet_cmd_vdso_and_check = VDSO $@ + cmd_vdso_and_check = $(cmd_vdso); $(cmd_vdso_check) + +-# +-# Install the unstripped copies of vdso*.so. If our toolchain supports +-# build-id, install .build-id links as well. +-# +-quiet_cmd_vdso_install = INSTALL $(@:install_%=%) +-define cmd_vdso_install +- cp $< "$(MODLIB)/vdso/$(@:install_%=%)"; \ +- if readelf -n $< |grep -q 'Build ID'; then \ +- buildid=`readelf -n $< |grep 'Build ID' |sed -e 's/^.*Build ID: \(.*\)$$/\1/'`; \ +- first=`echo $$buildid | cut -b-2`; \ +- last=`echo $$buildid | cut -b3-`; \ +- mkdir -p "$(MODLIB)/vdso/.build-id/$$first"; \ +- ln -sf "../../$(@:install_%=%)" "$(MODLIB)/vdso/.build-id/$$first/$$last.debug"; \ +- fi +-endef +- +-vdso_img_insttargets := $(vdso_img_sodbg:%.dbg=install_%) +- +-$(MODLIB)/vdso: FORCE +- @mkdir -p $(MODLIB)/vdso +- +-$(vdso_img_insttargets): install_%: $(obj)/%.dbg $(MODLIB)/vdso +- $(call cmd,vdso_install) +- +-PHONY += vdso_install $(vdso_img_insttargets) +-vdso_install: $(vdso_img_insttargets) +- + clean-files := vdso32.so vdso32.so.dbg vdso64* vdso-image-*.c vdsox32.so* +diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c +index e0ca8120aea876..1245000a8792fd 100644 +--- a/arch/x86/entry/vsyscall/vsyscall_64.c ++++ b/arch/x86/entry/vsyscall/vsyscall_64.c +@@ -98,11 +98,6 @@ static int addr_to_vsyscall_nr(unsigned long addr) + + static bool write_ok_or_segv(unsigned long ptr, size_t size) + { +- /* +- * XXX: if access_ok, get_user, and put_user handled +- * sig_on_uaccess_err, this could go away. +- */ +- + if (!access_ok((void __user *)ptr, size)) { + struct thread_struct *thread = ¤t->thread; + +@@ -120,10 +115,8 @@ static bool write_ok_or_segv(unsigned long ptr, size_t size) + bool emulate_vsyscall(unsigned long error_code, + struct pt_regs *regs, unsigned long address) + { +- struct task_struct *tsk; + unsigned long caller; + int vsyscall_nr, syscall_nr, tmp; +- int prev_sig_on_uaccess_err; + long ret; + unsigned long orig_dx; + +@@ -172,8 +165,6 @@ bool emulate_vsyscall(unsigned long error_code, + goto sigsegv; + } + +- tsk = current; +- + /* + * Check for access_ok violations and find the syscall nr. + * +@@ -234,12 +225,8 @@ bool emulate_vsyscall(unsigned long error_code, + goto do_ret; /* skip requested */ + + /* +- * With a real vsyscall, page faults cause SIGSEGV. We want to +- * preserve that behavior to make writing exploits harder. ++ * With a real vsyscall, page faults cause SIGSEGV. + */ +- prev_sig_on_uaccess_err = current->thread.sig_on_uaccess_err; +- current->thread.sig_on_uaccess_err = 1; +- + ret = -EFAULT; + switch (vsyscall_nr) { + case 0: +@@ -262,23 +249,12 @@ bool emulate_vsyscall(unsigned long error_code, + break; + } + +- current->thread.sig_on_uaccess_err = prev_sig_on_uaccess_err; +- + check_fault: + if (ret == -EFAULT) { + /* Bad news -- userspace fed a bad pointer to a vsyscall. */ + warn_bad_vsyscall(KERN_INFO, regs, + "vsyscall fault (exploit attempt?)"); +- +- /* +- * If we failed to generate a signal for any reason, +- * generate one here. (This should be impossible.) +- */ +- if (WARN_ON_ONCE(!sigismember(&tsk->pending.signal, SIGBUS) && +- !sigismember(&tsk->pending.signal, SIGSEGV))) +- goto sigsegv; +- +- return true; /* Don't emulate the ret. */ ++ goto sigsegv; + } + + regs->ax = ret; +diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c +index e24976593a298a..8ed10366c4a27b 100644 +--- a/arch/x86/events/amd/core.c ++++ b/arch/x86/events/amd/core.c +@@ -250,7 +250,7 @@ static const u64 amd_perfmon_event_map[PERF_COUNT_HW_MAX] = + /* + * AMD Performance Monitor Family 17h and later: + */ +-static const u64 amd_f17h_perfmon_event_map[PERF_COUNT_HW_MAX] = ++static const u64 amd_zen1_perfmon_event_map[PERF_COUNT_HW_MAX] = + { + [PERF_COUNT_HW_CPU_CYCLES] = 0x0076, + [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, +@@ -262,10 +262,24 @@ static const u64 amd_f17h_perfmon_event_map[PERF_COUNT_HW_MAX] = + [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x0187, + }; + ++static const u64 amd_zen2_perfmon_event_map[PERF_COUNT_HW_MAX] = ++{ ++ [PERF_COUNT_HW_CPU_CYCLES] = 0x0076, ++ [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, ++ [PERF_COUNT_HW_CACHE_REFERENCES] = 0xff60, ++ [PERF_COUNT_HW_CACHE_MISSES] = 0x0964, ++ [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c2, ++ [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c3, ++ [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x00a9, ++}; ++ + static u64 amd_pmu_event_map(int hw_event) + { +- if (boot_cpu_data.x86 >= 0x17) +- return amd_f17h_perfmon_event_map[hw_event]; ++ if (cpu_feature_enabled(X86_FEATURE_ZEN2) || boot_cpu_data.x86 >= 0x19) ++ return amd_zen2_perfmon_event_map[hw_event]; ++ ++ if (cpu_feature_enabled(X86_FEATURE_ZEN1)) ++ return amd_zen1_perfmon_event_map[hw_event]; + + return amd_perfmon_event_map[hw_event]; + } +@@ -604,7 +618,6 @@ static void amd_pmu_cpu_dead(int cpu) + + kfree(cpuhw->lbr_sel); + cpuhw->lbr_sel = NULL; +- amd_pmu_cpu_reset(cpu); + + if (!x86_pmu.amd_nb_constraints) + return; +@@ -905,8 +918,8 @@ static int amd_pmu_v2_handle_irq(struct pt_regs *regs) + if (!status) + goto done; + +- /* Read branch records before unfreezing */ +- if (status & GLOBAL_STATUS_LBRS_FROZEN) { ++ /* Read branch records */ ++ if (x86_pmu.lbr_nr) { + amd_pmu_lbr_read(); + status &= ~GLOBAL_STATUS_LBRS_FROZEN; + } +diff --git a/arch/x86/events/amd/lbr.c b/arch/x86/events/amd/lbr.c +index eb31f850841a89..5149830c7c4fa6 100644 +--- a/arch/x86/events/amd/lbr.c ++++ b/arch/x86/events/amd/lbr.c +@@ -173,9 +173,11 @@ void amd_pmu_lbr_read(void) + + /* + * Check if a branch has been logged; if valid = 0, spec = 0 +- * then no branch was recorded ++ * then no branch was recorded; if reserved = 1 then an ++ * erroneous branch was recorded (see Erratum 1452) + */ +- if (!entry.to.split.valid && !entry.to.split.spec) ++ if ((!entry.to.split.valid && !entry.to.split.spec) || ++ entry.to.split.reserved) + continue; + + perf_clear_branch_entry_bitfields(br + out); +@@ -400,10 +402,12 @@ void amd_pmu_lbr_enable_all(void) + wrmsrl(MSR_AMD64_LBR_SELECT, lbr_select); + } + +- rdmsrl(MSR_IA32_DEBUGCTLMSR, dbg_ctl); +- rdmsrl(MSR_AMD_DBG_EXTN_CFG, dbg_extn_cfg); ++ if (cpu_feature_enabled(X86_FEATURE_AMD_LBR_PMC_FREEZE)) { ++ rdmsrl(MSR_IA32_DEBUGCTLMSR, dbg_ctl); ++ wrmsrl(MSR_IA32_DEBUGCTLMSR, dbg_ctl | DEBUGCTLMSR_FREEZE_LBRS_ON_PMI); ++ } + +- wrmsrl(MSR_IA32_DEBUGCTLMSR, dbg_ctl | DEBUGCTLMSR_FREEZE_LBRS_ON_PMI); ++ rdmsrl(MSR_AMD_DBG_EXTN_CFG, dbg_extn_cfg); + wrmsrl(MSR_AMD_DBG_EXTN_CFG, dbg_extn_cfg | DBG_EXTN_CFG_LBRV2EN); + } + +@@ -416,10 +420,12 @@ void amd_pmu_lbr_disable_all(void) + return; + + rdmsrl(MSR_AMD_DBG_EXTN_CFG, dbg_extn_cfg); +- rdmsrl(MSR_IA32_DEBUGCTLMSR, dbg_ctl); +- + wrmsrl(MSR_AMD_DBG_EXTN_CFG, dbg_extn_cfg & ~DBG_EXTN_CFG_LBRV2EN); +- wrmsrl(MSR_IA32_DEBUGCTLMSR, dbg_ctl & ~DEBUGCTLMSR_FREEZE_LBRS_ON_PMI); ++ ++ if (cpu_feature_enabled(X86_FEATURE_AMD_LBR_PMC_FREEZE)) { ++ rdmsrl(MSR_IA32_DEBUGCTLMSR, dbg_ctl); ++ wrmsrl(MSR_IA32_DEBUGCTLMSR, dbg_ctl & ~DEBUGCTLMSR_FREEZE_LBRS_ON_PMI); ++ } + } + + __init int amd_pmu_lbr_init(void) +diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c +index 185f902e5f2859..150a365b4fbc89 100644 +--- a/arch/x86/events/core.c ++++ b/arch/x86/events/core.c +@@ -41,6 +41,8 @@ + #include + #include + #include ++#include ++#include + + #include "perf_event.h" + +@@ -1644,6 +1646,7 @@ static void x86_pmu_del(struct perf_event *event, int flags) + while (++i < cpuc->n_events) { + cpuc->event_list[i-1] = cpuc->event_list[i]; + cpuc->event_constraint[i-1] = cpuc->event_constraint[i]; ++ cpuc->assign[i-1] = cpuc->assign[i]; + } + cpuc->event_constraint[i-1] = NULL; + --cpuc->n_events; +@@ -2546,6 +2549,7 @@ static ssize_t set_attr_rdpmc(struct device *cdev, + struct device_attribute *attr, + const char *buf, size_t count) + { ++ static DEFINE_MUTEX(rdpmc_mutex); + unsigned long val; + ssize_t ret; + +@@ -2559,6 +2563,8 @@ static ssize_t set_attr_rdpmc(struct device *cdev, + if (x86_pmu.attr_rdpmc_broken) + return -ENOTSUPP; + ++ guard(mutex)(&rdpmc_mutex); ++ + if (val != x86_pmu.attr_rdpmc) { + /* + * Changing into or out of never available or always available, +@@ -2812,6 +2818,46 @@ static unsigned long get_segment_base(unsigned int segment) + return get_desc_base(desc); + } + ++#ifdef CONFIG_UPROBES ++/* ++ * Heuristic-based check if uprobe is installed at the function entry. ++ * ++ * Under assumption of user code being compiled with frame pointers, ++ * `push %rbp/%ebp` is a good indicator that we indeed are. ++ * ++ * Similarly, `endbr64` (assuming 64-bit mode) is also a common pattern. ++ * If we get this wrong, captured stack trace might have one extra bogus ++ * entry, but the rest of stack trace will still be meaningful. ++ */ ++static bool is_uprobe_at_func_entry(struct pt_regs *regs) ++{ ++ struct arch_uprobe *auprobe; ++ ++ if (!current->utask) ++ return false; ++ ++ auprobe = current->utask->auprobe; ++ if (!auprobe) ++ return false; ++ ++ /* push %rbp/%ebp */ ++ if (auprobe->insn[0] == 0x55) ++ return true; ++ ++ /* endbr64 (64-bit only) */ ++ if (user_64bit_mode(regs) && is_endbr(*(u32 *)auprobe->insn)) ++ return true; ++ ++ return false; ++} ++ ++#else ++static bool is_uprobe_at_func_entry(struct pt_regs *regs) ++{ ++ return false; ++} ++#endif /* CONFIG_UPROBES */ ++ + #ifdef CONFIG_IA32_EMULATION + + #include +@@ -2823,6 +2869,7 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent + unsigned long ss_base, cs_base; + struct stack_frame_ia32 frame; + const struct stack_frame_ia32 __user *fp; ++ u32 ret_addr; + + if (user_64bit_mode(regs)) + return 0; +@@ -2832,6 +2879,12 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent + + fp = compat_ptr(ss_base + regs->bp); + pagefault_disable(); ++ ++ /* see perf_callchain_user() below for why we do this */ ++ if (is_uprobe_at_func_entry(regs) && ++ !get_user(ret_addr, (const u32 __user *)regs->sp)) ++ perf_callchain_store(entry, ret_addr); ++ + while (entry->nr < entry->max_stack) { + if (!valid_user_frame(fp, sizeof(frame))) + break; +@@ -2860,6 +2913,7 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs + { + struct stack_frame frame; + const struct stack_frame __user *fp; ++ unsigned long ret_addr; + + if (perf_guest_state()) { + /* TODO: We don't support guest os callchain now */ +@@ -2883,6 +2937,19 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs + return; + + pagefault_disable(); ++ ++ /* ++ * If we are called from uprobe handler, and we are indeed at the very ++ * entry to user function (which is normally a `push %rbp` instruction, ++ * under assumption of application being compiled with frame pointers), ++ * we should read return address from *regs->sp before proceeding ++ * to follow frame pointers, otherwise we'll skip immediate caller ++ * as %rbp is not yet setup. ++ */ ++ if (is_uprobe_at_func_entry(regs) && ++ !get_user(ret_addr, (const unsigned long __user *)regs->sp)) ++ perf_callchain_store(entry, ret_addr); ++ + while (entry->nr < entry->max_stack) { + if (!valid_user_frame(fp, sizeof(frame))) + break; +diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c +index fa355d3658a652..688550e336ce17 100644 +--- a/arch/x86/events/intel/core.c ++++ b/arch/x86/events/intel/core.c +@@ -4062,12 +4062,17 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data) + u64 pebs_mask = cpuc->pebs_enabled & x86_pmu.pebs_capable; + int global_ctrl, pebs_enable; + ++ /* ++ * In addition to obeying exclude_guest/exclude_host, remove bits being ++ * used for PEBS when running a guest, because PEBS writes to virtual ++ * addresses (not physical addresses). ++ */ + *nr = 0; + global_ctrl = (*nr)++; + arr[global_ctrl] = (struct perf_guest_switch_msr){ + .msr = MSR_CORE_PERF_GLOBAL_CTRL, + .host = intel_ctrl & ~cpuc->intel_ctrl_guest_mask, +- .guest = intel_ctrl & (~cpuc->intel_ctrl_host_mask | ~pebs_mask), ++ .guest = intel_ctrl & ~cpuc->intel_ctrl_host_mask & ~pebs_mask, + }; + + if (!x86_pmu.pebs) +@@ -4460,6 +4465,25 @@ static u8 adl_get_hybrid_cpu_type(void) + return hybrid_big; + } + ++static inline bool erratum_hsw11(struct perf_event *event) ++{ ++ return (event->hw.config & INTEL_ARCH_EVENT_MASK) == ++ X86_CONFIG(.event=0xc0, .umask=0x01); ++} ++ ++/* ++ * The HSW11 requires a period larger than 100 which is the same as the BDM11. ++ * A minimum period of 128 is enforced as well for the INST_RETIRED.ALL. ++ * ++ * The message 'interrupt took too long' can be observed on any counter which ++ * was armed with a period < 32 and two events expired in the same NMI. ++ * A minimum period of 32 is enforced for the rest of the events. ++ */ ++static void hsw_limit_period(struct perf_event *event, s64 *left) ++{ ++ *left = max(*left, erratum_hsw11(event) ? 128 : 32); ++} ++ + /* + * Broadwell: + * +@@ -4477,8 +4501,7 @@ static u8 adl_get_hybrid_cpu_type(void) + */ + static void bdw_limit_period(struct perf_event *event, s64 *left) + { +- if ((event->hw.config & INTEL_ARCH_EVENT_MASK) == +- X86_CONFIG(.event=0xc0, .umask=0x01)) { ++ if (erratum_hsw11(event)) { + if (*left < 128) + *left = 128; + *left &= ~0x3fULL; +@@ -6387,6 +6410,7 @@ __init int intel_pmu_init(void) + + x86_pmu.hw_config = hsw_hw_config; + x86_pmu.get_event_constraints = hsw_get_event_constraints; ++ x86_pmu.limit_period = hsw_limit_period; + x86_pmu.lbr_double_abort = true; + extra_attr = boot_cpu_has(X86_FEATURE_RTM) ? + hsw_format_attr : nhm_format_attr; +diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c +index 96fffb2d521d2a..cc6609cbfc8dad 100644 +--- a/arch/x86/events/intel/cstate.c ++++ b/arch/x86/events/intel/cstate.c +@@ -80,7 +80,7 @@ + * MSR_PKG_C7_RESIDENCY: Package C7 Residency Counter. + * perf code: 0x03 + * Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,CNL, +- * KBL,CML,ICL,TGL,RKL,ADL,RPL,MTL ++ * KBL,CML,ICL,TGL,RKL + * Scope: Package (physical package) + * MSR_PKG_C8_RESIDENCY: Package C8 Residency Counter. + * perf code: 0x04 +@@ -89,8 +89,7 @@ + * Scope: Package (physical package) + * MSR_PKG_C9_RESIDENCY: Package C9 Residency Counter. + * perf code: 0x05 +- * Available model: HSW ULT,KBL,CNL,CML,ICL,TGL,RKL, +- * ADL,RPL,MTL ++ * Available model: HSW ULT,KBL,CNL,CML,ICL,TGL,RKL + * Scope: Package (physical package) + * MSR_PKG_C10_RESIDENCY: Package C10 Residency Counter. + * perf code: 0x06 +@@ -582,9 +581,7 @@ static const struct cstate_model adl_cstates __initconst = { + .pkg_events = BIT(PERF_CSTATE_PKG_C2_RES) | + BIT(PERF_CSTATE_PKG_C3_RES) | + BIT(PERF_CSTATE_PKG_C6_RES) | +- BIT(PERF_CSTATE_PKG_C7_RES) | + BIT(PERF_CSTATE_PKG_C8_RES) | +- BIT(PERF_CSTATE_PKG_C9_RES) | + BIT(PERF_CSTATE_PKG_C10_RES), + }; + +diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c +index eb8dd8b8a1e860..b592bed9ebcc46 100644 +--- a/arch/x86/events/intel/ds.c ++++ b/arch/x86/events/intel/ds.c +@@ -1236,11 +1236,11 @@ pebs_update_state(bool needed_cb, struct cpu_hw_events *cpuc, + struct pmu *pmu = event->pmu; + + /* +- * Make sure we get updated with the first PEBS +- * event. It will trigger also during removal, but +- * that does not hurt: ++ * Make sure we get updated with the first PEBS event. ++ * During removal, ->pebs_data_cfg is still valid for ++ * the last PEBS event. Don't clear it. + */ +- if (cpuc->n_pebs == 1) ++ if ((cpuc->n_pebs == 1) && add) + cpuc->pebs_data_cfg = PEBS_UPDATE_DS_SW; + + if (needed_cb != pebs_needs_sched_cb(cpuc)) { +@@ -1830,8 +1830,12 @@ static void setup_pebs_adaptive_sample_data(struct perf_event *event, + set_linear_ip(regs, basic->ip); + regs->flags = PERF_EFLAGS_EXACT; + +- if ((sample_type & PERF_SAMPLE_WEIGHT_STRUCT) && (x86_pmu.flags & PMU_FL_RETIRE_LATENCY)) +- data->weight.var3_w = format_size >> PEBS_RETIRE_LATENCY_OFFSET & PEBS_LATENCY_MASK; ++ if (sample_type & PERF_SAMPLE_WEIGHT_STRUCT) { ++ if (x86_pmu.flags & PMU_FL_RETIRE_LATENCY) ++ data->weight.var3_w = format_size >> PEBS_RETIRE_LATENCY_OFFSET & PEBS_LATENCY_MASK; ++ else ++ data->weight.var3_w = 0; ++ } + + /* + * The record for MEMINFO is in front of GP +diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c +index 42a55794004a7a..4110246aba12c3 100644 +--- a/arch/x86/events/intel/pt.c ++++ b/arch/x86/events/intel/pt.c +@@ -877,7 +877,7 @@ static void pt_update_head(struct pt *pt) + */ + static void *pt_buffer_region(struct pt_buffer *buf) + { +- return phys_to_virt(TOPA_ENTRY(buf->cur, buf->cur_idx)->base << TOPA_SHIFT); ++ return phys_to_virt((phys_addr_t)TOPA_ENTRY(buf->cur, buf->cur_idx)->base << TOPA_SHIFT); + } + + /** +@@ -989,7 +989,7 @@ pt_topa_entry_for_page(struct pt_buffer *buf, unsigned int pg) + * order allocations, there shouldn't be many of these. + */ + list_for_each_entry(topa, &buf->tables, list) { +- if (topa->offset + topa->size > pg << PAGE_SHIFT) ++ if (topa->offset + topa->size > (unsigned long)pg << PAGE_SHIFT) + goto found; + } + +@@ -1602,6 +1602,7 @@ static void pt_event_stop(struct perf_event *event, int mode) + * see comment in intel_pt_interrupt(). + */ + WRITE_ONCE(pt->handle_nmi, 0); ++ barrier(); + + pt_config_stop(event); + +@@ -1653,11 +1654,10 @@ static long pt_event_snapshot_aux(struct perf_event *event, + return 0; + + /* +- * Here, handle_nmi tells us if the tracing is on ++ * There is no PT interrupt in this mode, so stop the trace and it will ++ * remain stopped while the buffer is copied. + */ +- if (READ_ONCE(pt->handle_nmi)) +- pt_config_stop(event); +- ++ pt_config_stop(event); + pt_read_offset(buf); + pt_update_head(pt); + +@@ -1669,11 +1669,10 @@ static long pt_event_snapshot_aux(struct perf_event *event, + ret = perf_output_copy_aux(&pt->handle, handle, from, to); + + /* +- * If the tracing was on when we turned up, restart it. +- * Compiler barrier not needed as we couldn't have been +- * preempted by anything that touches pt->handle_nmi. ++ * Here, handle_nmi tells us if the tracing was on. ++ * If the tracing was on, restart it. + */ +- if (pt->handle_nmi) ++ if (READ_ONCE(pt->handle_nmi)) + pt_config_start(event); + + return ret; +diff --git a/arch/x86/events/intel/pt.h b/arch/x86/events/intel/pt.h +index 96906a62aacdad..f5e46c04c145d0 100644 +--- a/arch/x86/events/intel/pt.h ++++ b/arch/x86/events/intel/pt.h +@@ -33,8 +33,8 @@ struct topa_entry { + u64 rsvd2 : 1; + u64 size : 4; + u64 rsvd3 : 2; +- u64 base : 36; +- u64 rsvd4 : 16; ++ u64 base : 40; ++ u64 rsvd4 : 12; + }; + + /* TSC to Core Crystal Clock Ratio */ +diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c +index 8250f0f59c2bbe..a8f11e60b98794 100644 +--- a/arch/x86/events/intel/uncore_snbep.c ++++ b/arch/x86/events/intel/uncore_snbep.c +@@ -461,6 +461,7 @@ + #define SPR_UBOX_DID 0x3250 + + /* SPR CHA */ ++#define SPR_CHA_EVENT_MASK_EXT 0xffffffff + #define SPR_CHA_PMON_CTL_TID_EN (1 << 16) + #define SPR_CHA_PMON_EVENT_MASK (SNBEP_PMON_RAW_EVENT_MASK | \ + SPR_CHA_PMON_CTL_TID_EN) +@@ -477,6 +478,7 @@ DEFINE_UNCORE_FORMAT_ATTR(umask_ext, umask, "config:8-15,32-43,45-55"); + DEFINE_UNCORE_FORMAT_ATTR(umask_ext2, umask, "config:8-15,32-57"); + DEFINE_UNCORE_FORMAT_ATTR(umask_ext3, umask, "config:8-15,32-39"); + DEFINE_UNCORE_FORMAT_ATTR(umask_ext4, umask, "config:8-15,32-55"); ++DEFINE_UNCORE_FORMAT_ATTR(umask_ext5, umask, "config:8-15,32-63"); + DEFINE_UNCORE_FORMAT_ATTR(qor, qor, "config:16"); + DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); + DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19"); +@@ -5596,7 +5598,7 @@ static int discover_upi_topology(struct intel_uncore_type *type, int ubox_did, i + struct pci_dev *ubox = NULL; + struct pci_dev *dev = NULL; + u32 nid, gid; +- int i, idx, ret = -EPERM; ++ int i, idx, lgc_pkg, ret = -EPERM; + struct intel_uncore_topology *upi; + unsigned int devfn; + +@@ -5614,8 +5616,13 @@ static int discover_upi_topology(struct intel_uncore_type *type, int ubox_did, i + for (i = 0; i < 8; i++) { + if (nid != GIDNIDMAP(gid, i)) + continue; ++ lgc_pkg = topology_phys_to_logical_pkg(i); ++ if (lgc_pkg < 0) { ++ ret = -EPERM; ++ goto err; ++ } + for (idx = 0; idx < type->num_boxes; idx++) { +- upi = &type->topology[nid][idx]; ++ upi = &type->topology[lgc_pkg][idx]; + devfn = PCI_DEVFN(dev_link0 + idx, ICX_UPI_REGS_ADDR_FUNCTION); + dev = pci_get_domain_bus_and_slot(pci_domain_nr(ubox->bus), + ubox->bus->number, +@@ -5626,6 +5633,7 @@ static int discover_upi_topology(struct intel_uncore_type *type, int ubox_did, i + goto err; + } + } ++ break; + } + } + err: +@@ -5948,7 +5956,7 @@ static struct intel_uncore_ops spr_uncore_chabox_ops = { + + static struct attribute *spr_uncore_cha_formats_attr[] = { + &format_attr_event.attr, +- &format_attr_umask_ext4.attr, ++ &format_attr_umask_ext5.attr, + &format_attr_tid_en2.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, +@@ -5984,7 +5992,7 @@ ATTRIBUTE_GROUPS(uncore_alias); + static struct intel_uncore_type spr_uncore_chabox = { + .name = "cha", + .event_mask = SPR_CHA_PMON_EVENT_MASK, +- .event_mask_ext = SPR_RAW_EVENT_MASK_EXT, ++ .event_mask_ext = SPR_CHA_EVENT_MASK_EXT, + .num_shared_regs = 1, + .constraints = skx_uncore_chabox_constraints, + .ops = &spr_uncore_chabox_ops, +diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c +index 21556ad87f4ba8..d1e2d12279e268 100644 +--- a/arch/x86/hyperv/hv_init.c ++++ b/arch/x86/hyperv/hv_init.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -34,7 +35,6 @@ + #include + #include + +-int hyperv_init_cpuhp; + u64 hv_current_partition_id = ~0ull; + EXPORT_SYMBOL_GPL(hv_current_partition_id); + +@@ -286,15 +286,31 @@ static int hv_cpu_die(unsigned int cpu) + + static int __init hv_pci_init(void) + { +- int gen2vm = efi_enabled(EFI_BOOT); ++ bool gen2vm = efi_enabled(EFI_BOOT); + + /* +- * For Generation-2 VM, we exit from pci_arch_init() by returning 0. +- * The purpose is to suppress the harmless warning: ++ * A Generation-2 VM doesn't support legacy PCI/PCIe, so both ++ * raw_pci_ops and raw_pci_ext_ops are NULL, and pci_subsys_init() -> ++ * pcibios_init() doesn't call pcibios_resource_survey() -> ++ * e820__reserve_resources_late(); as a result, any emulated persistent ++ * memory of E820_TYPE_PRAM (12) via the kernel parameter ++ * memmap=nn[KMG]!ss is not added into iomem_resource and hence can't be ++ * detected by register_e820_pmem(). Fix this by directly calling ++ * e820__reserve_resources_late() here: e820__reserve_resources_late() ++ * depends on e820__reserve_resources(), which has been called earlier ++ * from setup_arch(). Note: e820__reserve_resources_late() also adds ++ * any memory of E820_TYPE_PMEM (7) into iomem_resource, and ++ * acpi_nfit_register_region() -> acpi_nfit_insert_resource() -> ++ * region_intersects() returns REGION_INTERSECTS, so the memory of ++ * E820_TYPE_PMEM won't get added twice. ++ * ++ * We return 0 here so that pci_arch_init() won't print the warning: + * "PCI: Fatal: No config space access function found" + */ +- if (gen2vm) ++ if (gen2vm) { ++ e820__reserve_resources_late(); + return 0; ++ } + + /* For Generation-1 VM, we'll proceed in pci_arch_init(). */ + return 1; +@@ -590,8 +606,6 @@ void __init hyperv_init(void) + + register_syscore_ops(&hv_syscore_ops); + +- hyperv_init_cpuhp = cpuhp; +- + if (cpuid_ebx(HYPERV_CPUID_FEATURES) & HV_ACCESS_PARTITION_ID) + hv_get_partition_id(); + +@@ -620,7 +634,7 @@ void __init hyperv_init(void) + clean_guest_os_id: + wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); + hv_ivm_msr_write(HV_X64_MSR_GUEST_OS_ID, 0); +- cpuhp_remove_state(cpuhp); ++ cpuhp_remove_state(CPUHP_AP_HYPERV_ONLINE); + free_ghcb_page: + free_percpu(hv_ghcb_pg); + free_vp_assist_page: +diff --git a/arch/x86/hyperv/hv_vtl.c b/arch/x86/hyperv/hv_vtl.c +index 999f5ac82fe900..c2f78fabc865bb 100644 +--- a/arch/x86/hyperv/hv_vtl.c ++++ b/arch/x86/hyperv/hv_vtl.c +@@ -12,10 +12,16 @@ + #include + #include + #include ++#include <../kernel/smpboot.h> + + extern struct boot_params boot_params; + static struct real_mode_header hv_vtl_real_mode_header; + ++static bool __init hv_vtl_msi_ext_dest_id(void) ++{ ++ return true; ++} ++ + void __init hv_vtl_init_platform(void) + { + pr_info("Linux runs in Hyper-V Virtual Trust Level\n"); +@@ -38,6 +44,8 @@ void __init hv_vtl_init_platform(void) + x86_platform.legacy.warm_reset = 0; + x86_platform.legacy.reserve_bios_regions = 0; + x86_platform.legacy.devices.pnpbios = 0; ++ ++ x86_init.hyper.msi_ext_dest_id = hv_vtl_msi_ext_dest_id; + } + + static inline u64 hv_vtl_system_desc_base(struct ldttss_desc *desc) +@@ -57,7 +65,7 @@ static void hv_vtl_ap_entry(void) + ((secondary_startup_64_fn)secondary_startup_64)(&boot_params, &boot_params); + } + +-static int hv_vtl_bringup_vcpu(u32 target_vp_index, u64 eip_ignored) ++static int hv_vtl_bringup_vcpu(u32 target_vp_index, int cpu, u64 eip_ignored) + { + u64 status; + int ret = 0; +@@ -71,7 +79,9 @@ static int hv_vtl_bringup_vcpu(u32 target_vp_index, u64 eip_ignored) + struct ldttss_desc *ldt; + struct desc_struct *gdt; + +- u64 rsp = current->thread.sp; ++ struct task_struct *idle = idle_thread_get(cpu); ++ u64 rsp = (unsigned long)idle->thread.sp; ++ + u64 rip = (u64)&hv_vtl_ap_entry; + + native_store_gdt(&gdt_ptr); +@@ -198,7 +208,15 @@ static int hv_vtl_apicid_to_vp_id(u32 apic_id) + + static int hv_vtl_wakeup_secondary_cpu(int apicid, unsigned long start_eip) + { +- int vp_id; ++ int vp_id, cpu; ++ ++ /* Find the logical CPU for the APIC ID */ ++ for_each_present_cpu(cpu) { ++ if (arch_match_cpu_phys_id(cpu, apicid)) ++ break; ++ } ++ if (cpu >= nr_cpu_ids) ++ return -EINVAL; + + pr_debug("Bringing up CPU with APIC ID %d in VTL2...\n", apicid); + vp_id = hv_vtl_apicid_to_vp_id(apicid); +@@ -212,7 +230,7 @@ static int hv_vtl_wakeup_secondary_cpu(int apicid, unsigned long start_eip) + return -EINVAL; + } + +- return hv_vtl_bringup_vcpu(vp_id, start_eip); ++ return hv_vtl_bringup_vcpu(vp_id, cpu, start_eip); + } + + int __init hv_vtl_early_init(void) +diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h +index c8a7fc23f63c67..529c36a98d9ea0 100644 +--- a/arch/x86/include/asm/acpi.h ++++ b/arch/x86/include/asm/acpi.h +@@ -16,6 +16,9 @@ + #include + #include + #include ++#include ++ ++#include + + #ifdef CONFIG_ACPI_APEI + # include +@@ -127,6 +130,17 @@ static inline void arch_acpi_set_proc_cap_bits(u32 *cap) + if (!cpu_has(c, X86_FEATURE_MWAIT) || + boot_option_idle_override == IDLE_NOMWAIT) + *cap &= ~(ACPI_PROC_CAP_C_C1_FFH | ACPI_PROC_CAP_C_C2C3_FFH); ++ ++ if (xen_initial_domain()) { ++ /* ++ * When Linux is running as Xen dom0, the hypervisor is the ++ * entity in charge of the processor power management, and so ++ * Xen needs to check the OS capabilities reported in the ++ * processor capabilities buffer matches what the hypervisor ++ * driver supports. ++ */ ++ xen_sanitize_proc_cap_bits(cap); ++ } + } + + static inline bool acpi_has_cpu_in_madt(void) +@@ -151,6 +165,14 @@ void acpi_generic_reduced_hw_init(void); + void x86_default_set_root_pointer(u64 addr); + u64 x86_default_get_root_pointer(void); + ++#ifdef CONFIG_XEN_PV ++/* A Xen PV domain needs a special acpi_os_ioremap() handling. */ ++extern void __iomem * (*acpi_os_ioremap)(acpi_physical_address phys, ++ acpi_size size); ++void __iomem *x86_acpi_os_ioremap(acpi_physical_address phys, acpi_size size); ++#define acpi_os_ioremap acpi_os_ioremap ++#endif ++ + #else /* !CONFIG_ACPI */ + + #define acpi_lapic 0 +diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h +index 9c4da699e11aff..cb9ce0f9e78e05 100644 +--- a/arch/x86/include/asm/alternative.h ++++ b/arch/x86/include/asm/alternative.h +@@ -58,7 +58,7 @@ + #define ANNOTATE_IGNORE_ALTERNATIVE \ + "999:\n\t" \ + ".pushsection .discard.ignore_alts\n\t" \ +- ".long 999b - .\n\t" \ ++ ".long 999b\n\t" \ + ".popsection\n\t" + + /* +@@ -288,10 +288,10 @@ static inline int alternatives_text_reserved(void *start, void *end) + * Otherwise, if CPU has feature1, newinstr1 is used. + * Otherwise, oldinstr is used. + */ +-#define alternative_input_2(oldinstr, newinstr1, ft_flags1, newinstr2, \ +- ft_flags2, input...) \ +- asm_inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, ft_flags1, \ +- newinstr2, ft_flags2) \ ++#define alternative_input_2(oldinstr, newinstr1, ft_flags1, newinstr2, \ ++ ft_flags2, input...) \ ++ asm_inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, ft_flags1, \ ++ newinstr2, ft_flags2) \ + : : "i" (0), ## input) + + /* Like alternative_input, but with a single output argument */ +@@ -301,7 +301,7 @@ static inline int alternatives_text_reserved(void *start, void *end) + + /* Like alternative_io, but for replacing a direct call with another one. */ + #define alternative_call(oldfunc, newfunc, ft_flags, output, input...) \ +- asm_inline volatile (ALTERNATIVE("call %P[old]", "call %P[new]", ft_flags) \ ++ asm_inline volatile (ALTERNATIVE("call %c[old]", "call %c[new]", ft_flags) \ + : output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input) + + /* +@@ -310,12 +310,12 @@ static inline int alternatives_text_reserved(void *start, void *end) + * Otherwise, if CPU has feature1, function1 is used. + * Otherwise, old function is used. + */ +-#define alternative_call_2(oldfunc, newfunc1, ft_flags1, newfunc2, ft_flags2, \ +- output, input...) \ +- asm_inline volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", ft_flags1,\ +- "call %P[new2]", ft_flags2) \ +- : output, ASM_CALL_CONSTRAINT \ +- : [old] "i" (oldfunc), [new1] "i" (newfunc1), \ ++#define alternative_call_2(oldfunc, newfunc1, ft_flags1, newfunc2, ft_flags2, \ ++ output, input...) \ ++ asm_inline volatile (ALTERNATIVE_2("call %c[old]", "call %c[new1]", ft_flags1, \ ++ "call %c[new2]", ft_flags2) \ ++ : output, ASM_CALL_CONSTRAINT \ ++ : [old] "i" (oldfunc), [new1] "i" (newfunc1), \ + [new2] "i" (newfunc2), ## input) + + /* +@@ -352,7 +352,7 @@ static inline int alternatives_text_reserved(void *start, void *end) + .macro ANNOTATE_IGNORE_ALTERNATIVE + .Lannotate_\@: + .pushsection .discard.ignore_alts +- .long .Lannotate_\@ - . ++ .long .Lannotate_\@ + .popsection + .endm + +diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h +index 5af4ec1a0f71cf..33aa0c31c21cf1 100644 +--- a/arch/x86/include/asm/apic.h ++++ b/arch/x86/include/asm/apic.h +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #define ARCH_APICTIMER_STOPS_ON_C3 1 + +@@ -96,7 +97,7 @@ static inline void native_apic_mem_write(u32 reg, u32 v) + + static inline u32 native_apic_mem_read(u32 reg) + { +- return *((volatile u32 *)(APIC_BASE + reg)); ++ return readl((void __iomem *)(APIC_BASE + reg)); + } + + static inline void native_apic_mem_eoi(void) +diff --git a/arch/x86/include/asm/asm-prototypes.h b/arch/x86/include/asm/asm-prototypes.h +index b1a98fa38828e2..0e82074517f6b7 100644 +--- a/arch/x86/include/asm/asm-prototypes.h ++++ b/arch/x86/include/asm/asm-prototypes.h +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #ifndef CONFIG_X86_CMPXCHG64 + extern void cmpxchg8b_emu(void); +diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h +index fbcfec4dc4ccd7..ca8eed1d496ab4 100644 +--- a/arch/x86/include/asm/asm.h ++++ b/arch/x86/include/asm/asm.h +@@ -113,6 +113,20 @@ + + #endif + ++#ifndef __ASSEMBLY__ ++#ifndef __pic__ ++static __always_inline __pure void *rip_rel_ptr(void *p) ++{ ++ asm("leaq %c1(%%rip), %0" : "=r"(p) : "i"(p)); ++ ++ return p; ++} ++#define RIP_REL_REF(var) (*(typeof(&(var)))rip_rel_ptr(&(var))) ++#else ++#define RIP_REL_REF(var) (var) ++#endif ++#endif ++ + /* + * Macros to generate condition code outputs from inline assembly, + * The output operand must be type "bool". +diff --git a/arch/x86/include/asm/atomic64_32.h b/arch/x86/include/asm/atomic64_32.h +index 3486d91b8595f1..d510405e4e1de2 100644 +--- a/arch/x86/include/asm/atomic64_32.h ++++ b/arch/x86/include/asm/atomic64_32.h +@@ -24,7 +24,7 @@ typedef struct { + + #ifdef CONFIG_X86_CMPXCHG64 + #define __alternative_atomic64(f, g, out, in...) \ +- asm volatile("call %P[func]" \ ++ asm volatile("call %c[func]" \ + : out : [func] "i" (atomic64_##g##_cx8), ## in) + + #define ATOMIC64_DECL(sym) ATOMIC64_DECL_ONE(sym##_cx8) +diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h +index 35389b2af88ee8..d0795b5fab46ad 100644 +--- a/arch/x86/include/asm/barrier.h ++++ b/arch/x86/include/asm/barrier.h +@@ -79,24 +79,9 @@ do { \ + #define __smp_mb__before_atomic() do { } while (0) + #define __smp_mb__after_atomic() do { } while (0) + +-#include ++/* Writing to CR3 provides a full memory barrier in switch_mm(). */ ++#define smp_mb__after_switch_mm() do { } while (0) + +-/* +- * Make previous memory operations globally visible before +- * a WRMSR. +- * +- * MFENCE makes writes visible, but only affects load/store +- * instructions. WRMSR is unfortunately not a load/store +- * instruction and is unaffected by MFENCE. The LFENCE ensures +- * that the WRMSR is not reordered. +- * +- * Most WRMSRs are full serializing instructions themselves and +- * do not require this barrier. This is only required for the +- * IA32_TSC_DEADLINE and X2APIC MSRs. +- */ +-static inline void weak_wrmsr_fence(void) +-{ +- asm volatile("mfence; lfence" : : : "memory"); +-} ++#include + + #endif /* _ASM_X86_BARRIER_H */ +diff --git a/arch/x86/include/asm/boot.h b/arch/x86/include/asm/boot.h +index b3a7cfb0d99e01..c945c893c52e0a 100644 +--- a/arch/x86/include/asm/boot.h ++++ b/arch/x86/include/asm/boot.h +@@ -81,6 +81,7 @@ + + #ifndef __ASSEMBLY__ + extern unsigned int output_len; ++extern const unsigned long kernel_text_size; + extern const unsigned long kernel_total_size; + + unsigned long decompress_kernel(unsigned char *outbuf, unsigned long virt_addr, +diff --git a/arch/x86/include/asm/cmpxchg_64.h b/arch/x86/include/asm/cmpxchg_64.h +index 44b08b53ab32fc..c1d6cd58f80940 100644 +--- a/arch/x86/include/asm/cmpxchg_64.h ++++ b/arch/x86/include/asm/cmpxchg_64.h +@@ -62,7 +62,7 @@ static __always_inline u128 arch_cmpxchg128_local(volatile u128 *ptr, u128 old, + asm volatile(_lock "cmpxchg16b %[ptr]" \ + CC_SET(e) \ + : CC_OUT(e) (ret), \ +- [ptr] "+m" (*ptr), \ ++ [ptr] "+m" (*(_ptr)), \ + "+a" (o.low), "+d" (o.high) \ + : "b" (n.low), "c" (n.high) \ + : "memory"); \ +diff --git a/arch/x86/include/asm/coco.h b/arch/x86/include/asm/coco.h +index 6ae2d16a7613b7..c72b3553081c3c 100644 +--- a/arch/x86/include/asm/coco.h ++++ b/arch/x86/include/asm/coco.h +@@ -2,6 +2,7 @@ + #ifndef _ASM_X86_COCO_H + #define _ASM_X86_COCO_H + ++#include + #include + + enum cc_vendor { +@@ -13,10 +14,19 @@ enum cc_vendor { + extern enum cc_vendor cc_vendor; + + #ifdef CONFIG_ARCH_HAS_CC_PLATFORM +-void cc_set_mask(u64 mask); ++extern u64 cc_mask; ++ ++static inline void cc_set_mask(u64 mask) ++{ ++ RIP_REL_REF(cc_mask) = mask; ++} ++ + u64 cc_mkenc(u64 val); + u64 cc_mkdec(u64 val); ++void cc_random_init(void); + #else ++static const u64 cc_mask = 0; ++ + static inline u64 cc_mkenc(u64 val) + { + return val; +@@ -26,6 +36,7 @@ static inline u64 cc_mkdec(u64 val) + { + return val; + } ++static inline void cc_random_init(void) { } + #endif + + #endif /* _ASM_X86_COCO_H */ +diff --git a/arch/x86/include/asm/cpu_device_id.h b/arch/x86/include/asm/cpu_device_id.h +index eb8fcede9e3bf4..e8e3dbe7f17306 100644 +--- a/arch/x86/include/asm/cpu_device_id.h ++++ b/arch/x86/include/asm/cpu_device_id.h +@@ -2,6 +2,39 @@ + #ifndef _ASM_X86_CPU_DEVICE_ID + #define _ASM_X86_CPU_DEVICE_ID + ++/* ++ * Can't use because it generates expressions that ++ * cannot be used in structure initializers. Bitfield construction ++ * here must match the union in struct cpuinfo_86: ++ * union { ++ * struct { ++ * __u8 x86_model; ++ * __u8 x86; ++ * __u8 x86_vendor; ++ * __u8 x86_reserved; ++ * }; ++ * __u32 x86_vfm; ++ * }; ++ */ ++#define VFM_MODEL_BIT 0 ++#define VFM_FAMILY_BIT 8 ++#define VFM_VENDOR_BIT 16 ++#define VFM_RSVD_BIT 24 ++ ++#define VFM_MODEL_MASK GENMASK(VFM_FAMILY_BIT - 1, VFM_MODEL_BIT) ++#define VFM_FAMILY_MASK GENMASK(VFM_VENDOR_BIT - 1, VFM_FAMILY_BIT) ++#define VFM_VENDOR_MASK GENMASK(VFM_RSVD_BIT - 1, VFM_VENDOR_BIT) ++ ++#define VFM_MODEL(vfm) (((vfm) & VFM_MODEL_MASK) >> VFM_MODEL_BIT) ++#define VFM_FAMILY(vfm) (((vfm) & VFM_FAMILY_MASK) >> VFM_FAMILY_BIT) ++#define VFM_VENDOR(vfm) (((vfm) & VFM_VENDOR_MASK) >> VFM_VENDOR_BIT) ++ ++#define VFM_MAKE(_vendor, _family, _model) ( \ ++ ((_model) << VFM_MODEL_BIT) | \ ++ ((_family) << VFM_FAMILY_BIT) | \ ++ ((_vendor) << VFM_VENDOR_BIT) \ ++) ++ + /* + * Declare drivers belonging to specific x86 CPUs + * Similar in spirit to pci_device_id and related PCI functions +@@ -20,6 +53,9 @@ + #define X86_CENTAUR_FAM6_C7_D 0xd + #define X86_CENTAUR_FAM6_NANO 0xf + ++/* x86_cpu_id::flags */ ++#define X86_CPU_ID_FLAG_ENTRY_VALID BIT(0) ++ + #define X86_STEPPINGS(mins, maxs) GENMASK(maxs, mins) + /** + * X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE - Base macro for CPU matching +@@ -46,6 +82,18 @@ + .model = _model, \ + .steppings = _steppings, \ + .feature = _feature, \ ++ .flags = X86_CPU_ID_FLAG_ENTRY_VALID, \ ++ .driver_data = (unsigned long) _data \ ++} ++ ++#define X86_MATCH_VENDORID_FAM_MODEL_STEPPINGS_FEATURE(_vendor, _family, _model, \ ++ _steppings, _feature, _data) { \ ++ .vendor = _vendor, \ ++ .family = _family, \ ++ .model = _model, \ ++ .steppings = _steppings, \ ++ .feature = _feature, \ ++ .flags = X86_CPU_ID_FLAG_ENTRY_VALID, \ + .driver_data = (unsigned long) _data \ + } + +@@ -164,6 +212,56 @@ + X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE(INTEL, 6, INTEL_FAM6_##model, \ + steppings, X86_FEATURE_ANY, data) + ++/** ++ * X86_MATCH_VFM - Match encoded vendor/family/model ++ * @vfm: Encoded 8-bits each for vendor, family, model ++ * @data: Driver specific data or NULL. The internal storage ++ * format is unsigned long. The supplied value, pointer ++ * etc. is cast to unsigned long internally. ++ * ++ * Stepping and feature are set to wildcards ++ */ ++#define X86_MATCH_VFM(vfm, data) \ ++ X86_MATCH_VENDORID_FAM_MODEL_STEPPINGS_FEATURE( \ ++ VFM_VENDOR(vfm), \ ++ VFM_FAMILY(vfm), \ ++ VFM_MODEL(vfm), \ ++ X86_STEPPING_ANY, X86_FEATURE_ANY, data) ++ ++/** ++ * X86_MATCH_VFM_STEPPINGS - Match encoded vendor/family/model/stepping ++ * @vfm: Encoded 8-bits each for vendor, family, model ++ * @steppings: Bitmask of steppings to match ++ * @data: Driver specific data or NULL. The internal storage ++ * format is unsigned long. The supplied value, pointer ++ * etc. is cast to unsigned long internally. ++ * ++ * feature is set to wildcard ++ */ ++#define X86_MATCH_VFM_STEPPINGS(vfm, steppings, data) \ ++ X86_MATCH_VENDORID_FAM_MODEL_STEPPINGS_FEATURE( \ ++ VFM_VENDOR(vfm), \ ++ VFM_FAMILY(vfm), \ ++ VFM_MODEL(vfm), \ ++ steppings, X86_FEATURE_ANY, data) ++ ++/** ++ * X86_MATCH_VFM_FEATURE - Match encoded vendor/family/model/feature ++ * @vfm: Encoded 8-bits each for vendor, family, model ++ * @feature: A X86_FEATURE bit ++ * @data: Driver specific data or NULL. The internal storage ++ * format is unsigned long. The supplied value, pointer ++ * etc. is cast to unsigned long internally. ++ * ++ * Steppings is set to wildcard ++ */ ++#define X86_MATCH_VFM_FEATURE(vfm, feature, data) \ ++ X86_MATCH_VENDORID_FAM_MODEL_STEPPINGS_FEATURE( \ ++ VFM_VENDOR(vfm), \ ++ VFM_FAMILY(vfm), \ ++ VFM_MODEL(vfm), \ ++ X86_STEPPING_ANY, feature, data) ++ + /* + * Match specific microcode revisions. + * +diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h +index a26bebbdff87ed..3508f3fc928d4d 100644 +--- a/arch/x86/include/asm/cpufeature.h ++++ b/arch/x86/include/asm/cpufeature.h +@@ -33,6 +33,8 @@ enum cpuid_leafs + CPUID_7_EDX, + CPUID_8000_001F_EAX, + CPUID_8000_0021_EAX, ++ CPUID_LNX_5, ++ NR_CPUID_WORDS, + }; + + #define X86_CAP_FMT_NUM "%d:%d" +@@ -91,8 +93,9 @@ extern const char * const x86_bug_flags[NBUGINTS*32]; + CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 18, feature_bit) || \ + CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 19, feature_bit) || \ + CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 20, feature_bit) || \ ++ CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 21, feature_bit) || \ + REQUIRED_MASK_CHECK || \ +- BUILD_BUG_ON_ZERO(NCAPINTS != 21)) ++ BUILD_BUG_ON_ZERO(NCAPINTS != 22)) + + #define DISABLED_MASK_BIT_SET(feature_bit) \ + ( CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 0, feature_bit) || \ +@@ -116,8 +119,9 @@ extern const char * const x86_bug_flags[NBUGINTS*32]; + CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 18, feature_bit) || \ + CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 19, feature_bit) || \ + CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 20, feature_bit) || \ ++ CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 21, feature_bit) || \ + DISABLED_MASK_CHECK || \ +- BUILD_BUG_ON_ZERO(NCAPINTS != 21)) ++ BUILD_BUG_ON_ZERO(NCAPINTS != 22)) + + #define cpu_has(c, bit) \ + (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ +@@ -168,8 +172,8 @@ extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit); + */ + static __always_inline bool _static_cpu_has(u16 bit) + { +- asm_volatile_goto( +- ALTERNATIVE_TERNARY("jmp 6f", %P[feature], "", "jmp %l[t_no]") ++ asm goto( ++ ALTERNATIVE_TERNARY("jmp 6f", %c[feature], "", "jmp %l[t_no]") + ".pushsection .altinstr_aux,\"ax\"\n" + "6:\n" + " testb %[bitnum]," _ASM_RIP(%P[cap_byte]) "\n" +diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h +index 58cb9495e40f42..55d18eef6775a6 100644 +--- a/arch/x86/include/asm/cpufeatures.h ++++ b/arch/x86/include/asm/cpufeatures.h +@@ -13,7 +13,7 @@ + /* + * Defines x86 CPU feature bits + */ +-#define NCAPINTS 21 /* N 32-bit words worth of info */ ++#define NCAPINTS 22 /* N 32-bit words worth of info */ + #define NBUGINTS 2 /* N 32-bit bug flags */ + + /* +@@ -97,7 +97,7 @@ + #define X86_FEATURE_SYSENTER32 ( 3*32+15) /* "" sysenter in IA32 userspace */ + #define X86_FEATURE_REP_GOOD ( 3*32+16) /* REP microcode works well */ + #define X86_FEATURE_AMD_LBR_V2 ( 3*32+17) /* AMD Last Branch Record Extension Version 2 */ +-/* FREE, was #define X86_FEATURE_LFENCE_RDTSC ( 3*32+18) "" LFENCE synchronizes RDTSC */ ++#define X86_FEATURE_CLEAR_CPU_BUF ( 3*32+18) /* "" Clear CPU buffers using VERW */ + #define X86_FEATURE_ACC_POWER ( 3*32+19) /* AMD Accumulated Power Mechanism */ + #define X86_FEATURE_NOPL ( 3*32+20) /* The NOPL (0F 1F) instructions */ + #define X86_FEATURE_ALWAYS ( 3*32+21) /* "" Always-present feature */ +@@ -216,9 +216,9 @@ + #define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE ( 7*32+23) /* "" Disable Speculative Store Bypass. */ + #define X86_FEATURE_LS_CFG_SSBD ( 7*32+24) /* "" AMD SSBD implementation via LS_CFG MSR */ + #define X86_FEATURE_IBRS ( 7*32+25) /* Indirect Branch Restricted Speculation */ +-#define X86_FEATURE_IBPB ( 7*32+26) /* Indirect Branch Prediction Barrier */ ++#define X86_FEATURE_IBPB ( 7*32+26) /* "ibpb" Indirect Branch Prediction Barrier without a guaranteed RSB flush */ + #define X86_FEATURE_STIBP ( 7*32+27) /* Single Thread Indirect Branch Predictors */ +-#define X86_FEATURE_ZEN (7*32+28) /* "" CPU based on Zen microarchitecture */ ++#define X86_FEATURE_ZEN ( 7*32+28) /* "" Generic flag for all Zen and newer */ + #define X86_FEATURE_L1TF_PTEINV ( 7*32+29) /* "" L1TF workaround PTE inversion */ + #define X86_FEATURE_IBRS_ENHANCED ( 7*32+30) /* Enhanced IBRS */ + #define X86_FEATURE_MSR_IA32_FEAT_CTL ( 7*32+31) /* "" MSR IA32_FEAT_CTL configured */ +@@ -308,10 +308,14 @@ + #define X86_FEATURE_SMBA (11*32+21) /* "" Slow Memory Bandwidth Allocation */ + #define X86_FEATURE_BMEC (11*32+22) /* "" Bandwidth Monitoring Event Configuration */ + #define X86_FEATURE_USER_SHSTK (11*32+23) /* Shadow stack support for user mode applications */ +- + #define X86_FEATURE_SRSO (11*32+24) /* "" AMD BTB untrain RETs */ + #define X86_FEATURE_SRSO_ALIAS (11*32+25) /* "" AMD BTB untrain RETs through aliasing */ + #define X86_FEATURE_IBPB_ON_VMEXIT (11*32+26) /* "" Issue an IBPB only on VMEXIT */ ++#define X86_FEATURE_APIC_MSRS_FENCE (11*32+27) /* "" IA32_TSC_DEADLINE and X2APIC MSRs need fencing */ ++#define X86_FEATURE_ZEN2 (11*32+28) /* "" CPU based on Zen2 microarchitecture */ ++#define X86_FEATURE_ZEN3 (11*32+29) /* "" CPU based on Zen3 microarchitecture */ ++#define X86_FEATURE_ZEN4 (11*32+30) /* "" CPU based on Zen4 microarchitecture */ ++#define X86_FEATURE_ZEN1 (11*32+31) /* "" CPU based on Zen1 microarchitecture */ + + /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */ + #define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */ +@@ -343,6 +347,7 @@ + #define X86_FEATURE_CPPC (13*32+27) /* Collaborative Processor Performance Control */ + #define X86_FEATURE_AMD_PSFD (13*32+28) /* "" Predictive Store Forwarding Disable */ + #define X86_FEATURE_BTC_NO (13*32+29) /* "" Not vulnerable to Branch Type Confusion */ ++#define X86_FEATURE_AMD_IBPB_RET (13*32+30) /* "" IBPB clears return address predictor */ + #define X86_FEATURE_BRS (13*32+31) /* Branch Sampling available */ + + /* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */ +@@ -452,6 +457,18 @@ + #define X86_FEATURE_IBPB_BRTYPE (20*32+28) /* "" MSR_PRED_CMD[IBPB] flushes all branch type predictions */ + #define X86_FEATURE_SRSO_NO (20*32+29) /* "" CPU is not affected by SRSO */ + ++/* ++ * Extended auxiliary flags: Linux defined - for features scattered in various ++ * CPUID levels like 0x80000022, etc and Linux defined features. ++ * ++ * Reuse free bits when adding new feature flags! ++ */ ++#define X86_FEATURE_AMD_LBR_PMC_FREEZE (21*32+ 0) /* AMD LBR and PMC Freeze */ ++#define X86_FEATURE_CLEAR_BHB_LOOP (21*32+ 1) /* "" Clear branch history at syscall entry using SW loop */ ++#define X86_FEATURE_BHI_CTRL (21*32+ 2) /* "" BHI_DIS_S HW control available */ ++#define X86_FEATURE_CLEAR_BHB_HW (21*32+ 3) /* "" BHI_DIS_S HW control enabled */ ++#define X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT (21*32+ 4) /* "" Clear branch history at vmexit using SW loop */ ++ + /* + * BUG word(s) + */ +@@ -498,4 +515,7 @@ + /* BUG word 2 */ + #define X86_BUG_SRSO X86_BUG(1*32 + 0) /* AMD SRSO bug */ + #define X86_BUG_DIV0 X86_BUG(1*32 + 1) /* AMD DIV0 speculation bug */ ++#define X86_BUG_RFDS X86_BUG(1*32 + 2) /* CPU is vulnerable to Register File Data Sampling */ ++#define X86_BUG_BHI X86_BUG(1*32 + 3) /* CPU is affected by Branch History Injection */ ++#define X86_BUG_IBPB_NO_RET X86_BUG(1*32 + 4) /* "ibpb_no_ret" IBPB omits return target predictions */ + #endif /* _ASM_X86_CPUFEATURES_H */ +diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h +index 702d93fdd10e8d..88fcf08458d9cd 100644 +--- a/arch/x86/include/asm/disabled-features.h ++++ b/arch/x86/include/asm/disabled-features.h +@@ -143,6 +143,7 @@ + #define DISABLED_MASK18 (DISABLE_IBT) + #define DISABLED_MASK19 0 + #define DISABLED_MASK20 0 +-#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 21) ++#define DISABLED_MASK21 0 ++#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 22) + + #endif /* _ASM_X86_DISABLED_FEATURES_H */ +diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h +index c4555b269a1b24..a050d329e34bfd 100644 +--- a/arch/x86/include/asm/efi.h ++++ b/arch/x86/include/asm/efi.h +@@ -410,7 +410,6 @@ extern int __init efi_memmap_alloc(unsigned int num_entries, + struct efi_memory_map_data *data); + extern void __efi_memmap_free(u64 phys, unsigned long size, + unsigned long flags); +-#define __efi_memmap_free __efi_memmap_free + + extern int __init efi_memmap_install(struct efi_memory_map_data *data); + extern int __init efi_memmap_split_count(efi_memory_desc_t *md, +diff --git a/arch/x86/include/asm/entry-common.h b/arch/x86/include/asm/entry-common.h +index ce8f50192ae3e4..fb2809b20b0ac4 100644 +--- a/arch/x86/include/asm/entry-common.h ++++ b/arch/x86/include/asm/entry-common.h +@@ -73,25 +73,21 @@ static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs, + #endif + + /* +- * Ultimately, this value will get limited by KSTACK_OFFSET_MAX(), +- * but not enough for x86 stack utilization comfort. To keep +- * reasonable stack head room, reduce the maximum offset to 8 bits. +- * +- * The actual entropy will be further reduced by the compiler when +- * applying stack alignment constraints (see cc_stack_align4/8 in ++ * This value will get limited by KSTACK_OFFSET_MAX(), which is 10 ++ * bits. The actual entropy will be further reduced by the compiler ++ * when applying stack alignment constraints (see cc_stack_align4/8 in + * arch/x86/Makefile), which will remove the 3 (x86_64) or 2 (ia32) + * low bits from any entropy chosen here. + * +- * Therefore, final stack offset entropy will be 5 (x86_64) or +- * 6 (ia32) bits. ++ * Therefore, final stack offset entropy will be 7 (x86_64) or ++ * 8 (ia32) bits. + */ +- choose_random_kstack_offset(rdtsc() & 0xFF); ++ choose_random_kstack_offset(rdtsc()); + } + #define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare + + static __always_inline void arch_exit_to_user_mode(void) + { +- mds_user_clear_cpu_buffers(); + amd_clear_divider(); + } + #define arch_exit_to_user_mode arch_exit_to_user_mode +diff --git a/arch/x86/include/asm/fpu/signal.h b/arch/x86/include/asm/fpu/signal.h +index 611fa41711affd..eccc75bc9c4f3d 100644 +--- a/arch/x86/include/asm/fpu/signal.h ++++ b/arch/x86/include/asm/fpu/signal.h +@@ -29,7 +29,7 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame, + + unsigned long fpu__get_fpstate_size(void); + +-extern bool copy_fpstate_to_sigframe(void __user *buf, void __user *fp, int size); ++extern bool copy_fpstate_to_sigframe(void __user *buf, void __user *fp, int size, u32 pkru); + extern void fpu__clear_user_states(struct fpu *fpu); + extern bool fpu__restore_sig(void __user *buf, int ia32_frame); + +diff --git a/arch/x86/include/asm/fpu/types.h b/arch/x86/include/asm/fpu/types.h +index eb810074f1e745..fd5fb43d920b44 100644 +--- a/arch/x86/include/asm/fpu/types.h ++++ b/arch/x86/include/asm/fpu/types.h +@@ -589,6 +589,13 @@ struct fpu_state_config { + * even without XSAVE support, i.e. legacy features FP + SSE + */ + u64 legacy_features; ++ /* ++ * @independent_features: ++ * ++ * Features that are supported by XSAVES, but not managed as part of ++ * the FPU core, such as LBR ++ */ ++ u64 independent_features; + }; + + /* FPU state configuration information */ +diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h +index 66837b8c67f1a9..f2e245741afc2c 100644 +--- a/arch/x86/include/asm/hardirq.h ++++ b/arch/x86/include/asm/hardirq.h +@@ -63,7 +63,11 @@ extern u64 arch_irq_stat(void); + #define local_softirq_pending_ref pcpu_hot.softirq_pending + + #if IS_ENABLED(CONFIG_KVM_INTEL) +-static inline void kvm_set_cpu_l1tf_flush_l1d(void) ++/* ++ * This function is called from noinstr interrupt contexts ++ * and must be inlined to not get instrumentation. ++ */ ++static __always_inline void kvm_set_cpu_l1tf_flush_l1d(void) + { + __this_cpu_write(irq_stat.kvm_cpu_l1tf_flush_l1d, 1); + } +@@ -78,7 +82,7 @@ static __always_inline bool kvm_get_cpu_l1tf_flush_l1d(void) + return __this_cpu_read(irq_stat.kvm_cpu_l1tf_flush_l1d); + } + #else /* !IS_ENABLED(CONFIG_KVM_INTEL) */ +-static inline void kvm_set_cpu_l1tf_flush_l1d(void) { } ++static __always_inline void kvm_set_cpu_l1tf_flush_l1d(void) { } + #endif /* IS_ENABLED(CONFIG_KVM_INTEL) */ + + #endif /* _ASM_X86_HARDIRQ_H */ +diff --git a/arch/x86/include/asm/ia32.h b/arch/x86/include/asm/ia32.h +index fada857f0a1edf..9805629479d968 100644 +--- a/arch/x86/include/asm/ia32.h ++++ b/arch/x86/include/asm/ia32.h +@@ -68,6 +68,27 @@ extern void ia32_pick_mmap_layout(struct mm_struct *mm); + + #endif + +-#endif /* CONFIG_IA32_EMULATION */ ++extern bool __ia32_enabled; ++ ++static inline bool ia32_enabled(void) ++{ ++ return __ia32_enabled; ++} ++ ++static inline void ia32_disable(void) ++{ ++ __ia32_enabled = false; ++} ++ ++#else /* !CONFIG_IA32_EMULATION */ ++ ++static inline bool ia32_enabled(void) ++{ ++ return IS_ENABLED(CONFIG_X86_32); ++} ++ ++static inline void ia32_disable(void) {} ++ ++#endif + + #endif /* _ASM_X86_IA32_H */ +diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h +index 05fd175cec7d5c..10603e185111d5 100644 +--- a/arch/x86/include/asm/idtentry.h ++++ b/arch/x86/include/asm/idtentry.h +@@ -13,15 +13,18 @@ + + #include + ++typedef void (*idtentry_t)(struct pt_regs *regs); ++ + /** + * DECLARE_IDTENTRY - Declare functions for simple IDT entry points + * No error code pushed by hardware + * @vector: Vector number (ignored for C) + * @func: Function name of the entry point + * +- * Declares three functions: ++ * Declares four functions: + * - The ASM entry point: asm_##func + * - The XEN PV trap entry point: xen_##func (maybe unused) ++ * - The C handler called from the FRED event dispatcher (maybe unused) + * - The C handler called from the ASM entry point + * + * Note: This is the C variant of DECLARE_IDTENTRY(). As the name says it +@@ -31,6 +34,7 @@ + #define DECLARE_IDTENTRY(vector, func) \ + asmlinkage void asm_##func(void); \ + asmlinkage void xen_asm_##func(void); \ ++ void fred_##func(struct pt_regs *regs); \ + __visible void func(struct pt_regs *regs) + + /** +@@ -137,6 +141,17 @@ static __always_inline void __##func(struct pt_regs *regs, \ + #define DEFINE_IDTENTRY_RAW(func) \ + __visible noinstr void func(struct pt_regs *regs) + ++/** ++ * DEFINE_FREDENTRY_RAW - Emit code for raw FRED entry points ++ * @func: Function name of the entry point ++ * ++ * @func is called from the FRED event dispatcher with interrupts disabled. ++ * ++ * See @DEFINE_IDTENTRY_RAW for further details. ++ */ ++#define DEFINE_FREDENTRY_RAW(func) \ ++noinstr void fred_##func(struct pt_regs *regs) ++ + /** + * DECLARE_IDTENTRY_RAW_ERRORCODE - Declare functions for raw IDT entry points + * Error code pushed by hardware +@@ -197,8 +212,8 @@ __visible noinstr void func(struct pt_regs *regs, \ + irqentry_state_t state = irqentry_enter(regs); \ + u32 vector = (u32)(u8)error_code; \ + \ ++ kvm_set_cpu_l1tf_flush_l1d(); \ + instrumentation_begin(); \ +- kvm_set_cpu_l1tf_flush_l1d(); \ + run_irq_on_irqstack_cond(__##func, regs, vector); \ + instrumentation_end(); \ + irqentry_exit(regs, state); \ +@@ -233,17 +248,27 @@ static noinline void __##func(struct pt_regs *regs, u32 vector) + #define DEFINE_IDTENTRY_SYSVEC(func) \ + static void __##func(struct pt_regs *regs); \ + \ ++static __always_inline void instr_##func(struct pt_regs *regs) \ ++{ \ ++ run_sysvec_on_irqstack_cond(__##func, regs); \ ++} \ ++ \ + __visible noinstr void func(struct pt_regs *regs) \ + { \ + irqentry_state_t state = irqentry_enter(regs); \ + \ ++ kvm_set_cpu_l1tf_flush_l1d(); \ + instrumentation_begin(); \ +- kvm_set_cpu_l1tf_flush_l1d(); \ +- run_sysvec_on_irqstack_cond(__##func, regs); \ ++ instr_##func (regs); \ + instrumentation_end(); \ + irqentry_exit(regs, state); \ + } \ + \ ++void fred_##func(struct pt_regs *regs) \ ++{ \ ++ instr_##func (regs); \ ++} \ ++ \ + static noinline void __##func(struct pt_regs *regs) + + /** +@@ -260,19 +285,29 @@ static noinline void __##func(struct pt_regs *regs) + #define DEFINE_IDTENTRY_SYSVEC_SIMPLE(func) \ + static __always_inline void __##func(struct pt_regs *regs); \ + \ ++static __always_inline void instr_##func(struct pt_regs *regs) \ ++{ \ ++ __irq_enter_raw(); \ ++ __##func (regs); \ ++ __irq_exit_raw(); \ ++} \ ++ \ + __visible noinstr void func(struct pt_regs *regs) \ + { \ + irqentry_state_t state = irqentry_enter(regs); \ + \ ++ kvm_set_cpu_l1tf_flush_l1d(); \ + instrumentation_begin(); \ +- __irq_enter_raw(); \ +- kvm_set_cpu_l1tf_flush_l1d(); \ +- __##func (regs); \ +- __irq_exit_raw(); \ ++ instr_##func (regs); \ + instrumentation_end(); \ + irqentry_exit(regs, state); \ + } \ + \ ++void fred_##func(struct pt_regs *regs) \ ++{ \ ++ instr_##func (regs); \ ++} \ ++ \ + static __always_inline void __##func(struct pt_regs *regs) + + /** +@@ -410,15 +445,18 @@ __visible noinstr void func(struct pt_regs *regs, \ + /* C-Code mapping */ + #define DECLARE_IDTENTRY_NMI DECLARE_IDTENTRY_RAW + #define DEFINE_IDTENTRY_NMI DEFINE_IDTENTRY_RAW ++#define DEFINE_FREDENTRY_NMI DEFINE_FREDENTRY_RAW + + #ifdef CONFIG_X86_64 + #define DECLARE_IDTENTRY_MCE DECLARE_IDTENTRY_IST + #define DEFINE_IDTENTRY_MCE DEFINE_IDTENTRY_IST + #define DEFINE_IDTENTRY_MCE_USER DEFINE_IDTENTRY_NOIST ++#define DEFINE_FREDENTRY_MCE DEFINE_FREDENTRY_RAW + + #define DECLARE_IDTENTRY_DEBUG DECLARE_IDTENTRY_IST + #define DEFINE_IDTENTRY_DEBUG DEFINE_IDTENTRY_IST + #define DEFINE_IDTENTRY_DEBUG_USER DEFINE_IDTENTRY_NOIST ++#define DEFINE_FREDENTRY_DEBUG DEFINE_FREDENTRY_RAW + #endif + + #else /* !__ASSEMBLY__ */ +@@ -569,6 +607,10 @@ DECLARE_IDTENTRY_RAW(X86_TRAP_UD, exc_invalid_op); + DECLARE_IDTENTRY_RAW(X86_TRAP_BP, exc_int3); + DECLARE_IDTENTRY_RAW_ERRORCODE(X86_TRAP_PF, exc_page_fault); + ++#if defined(CONFIG_IA32_EMULATION) ++DECLARE_IDTENTRY_RAW(IA32_SYSCALL_VECTOR, int80_emulation); ++#endif ++ + #ifdef CONFIG_X86_MCE + #ifdef CONFIG_X86_64 + DECLARE_IDTENTRY_MCE(X86_TRAP_MC, exc_machine_check); +@@ -651,23 +693,36 @@ DECLARE_IDTENTRY(RESCHEDULE_VECTOR, sysvec_reschedule_ipi); + DECLARE_IDTENTRY_SYSVEC(REBOOT_VECTOR, sysvec_reboot); + DECLARE_IDTENTRY_SYSVEC(CALL_FUNCTION_SINGLE_VECTOR, sysvec_call_function_single); + DECLARE_IDTENTRY_SYSVEC(CALL_FUNCTION_VECTOR, sysvec_call_function); ++#else ++# define fred_sysvec_reschedule_ipi NULL ++# define fred_sysvec_reboot NULL ++# define fred_sysvec_call_function_single NULL ++# define fred_sysvec_call_function NULL + #endif + + #ifdef CONFIG_X86_LOCAL_APIC + # ifdef CONFIG_X86_MCE_THRESHOLD + DECLARE_IDTENTRY_SYSVEC(THRESHOLD_APIC_VECTOR, sysvec_threshold); ++# else ++# define fred_sysvec_threshold NULL + # endif + + # ifdef CONFIG_X86_MCE_AMD + DECLARE_IDTENTRY_SYSVEC(DEFERRED_ERROR_VECTOR, sysvec_deferred_error); ++# else ++# define fred_sysvec_deferred_error NULL + # endif + + # ifdef CONFIG_X86_THERMAL_VECTOR + DECLARE_IDTENTRY_SYSVEC(THERMAL_APIC_VECTOR, sysvec_thermal); ++# else ++# define fred_sysvec_thermal NULL + # endif + + # ifdef CONFIG_IRQ_WORK + DECLARE_IDTENTRY_SYSVEC(IRQ_WORK_VECTOR, sysvec_irq_work); ++# else ++# define fred_sysvec_irq_work NULL + # endif + #endif + +@@ -675,12 +730,16 @@ DECLARE_IDTENTRY_SYSVEC(IRQ_WORK_VECTOR, sysvec_irq_work); + DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_VECTOR, sysvec_kvm_posted_intr_ipi); + DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_WAKEUP_VECTOR, sysvec_kvm_posted_intr_wakeup_ipi); + DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_NESTED_VECTOR, sysvec_kvm_posted_intr_nested_ipi); ++#else ++# define fred_sysvec_kvm_posted_intr_ipi NULL ++# define fred_sysvec_kvm_posted_intr_wakeup_ipi NULL ++# define fred_sysvec_kvm_posted_intr_nested_ipi NULL + #endif + + #if IS_ENABLED(CONFIG_HYPERV) + DECLARE_IDTENTRY_SYSVEC(HYPERVISOR_CALLBACK_VECTOR, sysvec_hyperv_callback); + DECLARE_IDTENTRY_SYSVEC(HYPERV_REENLIGHTENMENT_VECTOR, sysvec_hyperv_reenlightenment); +-DECLARE_IDTENTRY_SYSVEC(HYPERV_STIMER0_VECTOR, sysvec_hyperv_stimer0); ++DECLARE_IDTENTRY_SYSVEC(HYPERV_STIMER0_VECTOR, sysvec_hyperv_stimer0); + #endif + + #if IS_ENABLED(CONFIG_ACRN_GUEST) +diff --git a/arch/x86/include/asm/init.h b/arch/x86/include/asm/init.h +index 5f1d3c421f6860..cc9ccf61b6bd11 100644 +--- a/arch/x86/include/asm/init.h ++++ b/arch/x86/include/asm/init.h +@@ -2,6 +2,8 @@ + #ifndef _ASM_X86_INIT_H + #define _ASM_X86_INIT_H + ++#define __head __section(".head.text") ++ + struct x86_mapping_info { + void *(*alloc_pgt_page)(void *); /* allocate buf for page table */ + void *context; /* context for alloc_pgt_page */ +diff --git a/arch/x86/include/asm/irq_stack.h b/arch/x86/include/asm/irq_stack.h +index 798183867d7896..b71ad173f8776f 100644 +--- a/arch/x86/include/asm/irq_stack.h ++++ b/arch/x86/include/asm/irq_stack.h +@@ -100,7 +100,7 @@ + } + + #define ASM_CALL_ARG0 \ +- "call %P[__func] \n" \ ++ "call %c[__func] \n" \ + ASM_REACHABLE + + #define ASM_CALL_ARG1 \ +diff --git a/arch/x86/include/asm/irq_work.h b/arch/x86/include/asm/irq_work.h +index 800ffce0db29e3..6b4d36c9516557 100644 +--- a/arch/x86/include/asm/irq_work.h ++++ b/arch/x86/include/asm/irq_work.h +@@ -9,7 +9,6 @@ static inline bool arch_irq_work_has_interrupt(void) + { + return boot_cpu_has(X86_FEATURE_APIC); + } +-extern void arch_irq_work_raise(void); + #else + static inline bool arch_irq_work_has_interrupt(void) + { +diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h +index 071572e23d3a06..cbbef32517f004 100644 +--- a/arch/x86/include/asm/jump_label.h ++++ b/arch/x86/include/asm/jump_label.h +@@ -24,7 +24,7 @@ + + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) + { +- asm_volatile_goto("1:" ++ asm goto("1:" + "jmp %l[l_yes] # objtool NOPs this \n\t" + JUMP_TABLE_ENTRY + : : "i" (key), "i" (2 | branch) : : l_yes); +@@ -38,7 +38,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran + + static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch) + { +- asm_volatile_goto("1:" ++ asm goto("1:" + ".byte " __stringify(BYTES_NOP5) "\n\t" + JUMP_TABLE_ENTRY + : : "i" (key), "i" (branch) : : l_yes); +@@ -52,7 +52,7 @@ static __always_inline bool arch_static_branch(struct static_key * const key, co + + static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch) + { +- asm_volatile_goto("1:" ++ asm goto("1:" + "jmp %l[l_yes]\n\t" + JUMP_TABLE_ENTRY + : : "i" (key), "i" (branch) : : l_yes); +diff --git a/arch/x86/include/asm/kmsan.h b/arch/x86/include/asm/kmsan.h +index 8fa6ac0e2d7665..d91b37f5b4bb45 100644 +--- a/arch/x86/include/asm/kmsan.h ++++ b/arch/x86/include/asm/kmsan.h +@@ -64,6 +64,7 @@ static inline bool kmsan_virt_addr_valid(void *addr) + { + unsigned long x = (unsigned long)addr; + unsigned long y = x - __START_KERNEL_map; ++ bool ret; + + /* use the carry flag to determine if x was < __START_KERNEL_map */ + if (unlikely(x > y)) { +@@ -79,7 +80,21 @@ static inline bool kmsan_virt_addr_valid(void *addr) + return false; + } + +- return pfn_valid(x >> PAGE_SHIFT); ++ /* ++ * pfn_valid() relies on RCU, and may call into the scheduler on exiting ++ * the critical section. However, this would result in recursion with ++ * KMSAN. Therefore, disable preemption here, and re-enable preemption ++ * below while suppressing reschedules to avoid recursion. ++ * ++ * Note, this sacrifices occasionally breaking scheduling guarantees. ++ * Although, a kernel compiled with KMSAN has already given up on any ++ * performance guarantees due to being heavily instrumented. ++ */ ++ preempt_disable(); ++ ret = pfn_valid(x >> PAGE_SHIFT); ++ preempt_enable_no_resched(); ++ ++ return ret; + } + + #endif /* !MODULE */ +diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h +index e3054e3e46d52d..9b419f0de713cc 100644 +--- a/arch/x86/include/asm/kvm-x86-ops.h ++++ b/arch/x86/include/asm/kvm-x86-ops.h +@@ -108,6 +108,7 @@ KVM_X86_OP_OPTIONAL(vcpu_blocking) + KVM_X86_OP_OPTIONAL(vcpu_unblocking) + KVM_X86_OP_OPTIONAL(pi_update_irte) + KVM_X86_OP_OPTIONAL(pi_start_assignment) ++KVM_X86_OP_OPTIONAL(apicv_pre_state_restore) + KVM_X86_OP_OPTIONAL(apicv_post_state_restore) + KVM_X86_OP_OPTIONAL_RET0(dy_apicv_has_pending_interrupt) + KVM_X86_OP_OPTIONAL(set_hv_timer) +diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/kvm-x86-pmu-ops.h +index 6c98f4bb4228ba..058bc636356a11 100644 +--- a/arch/x86/include/asm/kvm-x86-pmu-ops.h ++++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h +@@ -22,7 +22,7 @@ KVM_X86_PMU_OP(get_msr) + KVM_X86_PMU_OP(set_msr) + KVM_X86_PMU_OP(refresh) + KVM_X86_PMU_OP(init) +-KVM_X86_PMU_OP(reset) ++KVM_X86_PMU_OP_OPTIONAL(reset) + KVM_X86_PMU_OP_OPTIONAL(deliver_pmi) + KVM_X86_PMU_OP_OPTIONAL(cleanup) + +diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h +index 70d139406bc80d..257bf2e71d0605 100644 +--- a/arch/x86/include/asm/kvm_host.h ++++ b/arch/x86/include/asm/kvm_host.h +@@ -828,6 +828,7 @@ struct kvm_vcpu_arch { + int cpuid_nent; + struct kvm_cpuid_entry2 *cpuid_entries; + struct kvm_hypervisor_cpuid kvm_cpuid; ++ bool is_amd_compatible; + + /* + * FIXME: Drop this macro and use KVM_NR_GOVERNED_FEATURES directly +@@ -1708,6 +1709,7 @@ struct kvm_x86_ops { + int (*pi_update_irte)(struct kvm *kvm, unsigned int host_irq, + uint32_t guest_irq, bool set); + void (*pi_start_assignment)(struct kvm *kvm); ++ void (*apicv_pre_state_restore)(struct kvm_vcpu *vcpu); + void (*apicv_post_state_restore)(struct kvm_vcpu *vcpu); + bool (*dy_apicv_has_pending_interrupt)(struct kvm_vcpu *vcpu); + +@@ -1756,7 +1758,7 @@ struct kvm_x86_nested_ops { + bool (*is_exception_vmexit)(struct kvm_vcpu *vcpu, u8 vector, + u32 error_code); + int (*check_events)(struct kvm_vcpu *vcpu); +- bool (*has_events)(struct kvm_vcpu *vcpu); ++ bool (*has_events)(struct kvm_vcpu *vcpu, bool for_injection); + void (*triple_fault)(struct kvm_vcpu *vcpu); + int (*get_state)(struct kvm_vcpu *vcpu, + struct kvm_nested_state __user *user_kvm_nested_state, +diff --git a/arch/x86/include/asm/mem_encrypt.h b/arch/x86/include/asm/mem_encrypt.h +index 473b16d73b4710..76081a34fc231b 100644 +--- a/arch/x86/include/asm/mem_encrypt.h ++++ b/arch/x86/include/asm/mem_encrypt.h +@@ -15,7 +15,8 @@ + #include + #include + +-#include ++#include ++struct boot_params; + + #ifdef CONFIG_X86_MEM_ENCRYPT + void __init mem_encrypt_init(void); +@@ -45,8 +46,8 @@ void __init sme_unmap_bootdata(char *real_mode_data); + void __init sme_early_init(void); + void __init sev_setup_arch(void); + +-void __init sme_encrypt_kernel(struct boot_params *bp); +-void __init sme_enable(struct boot_params *bp); ++void sme_encrypt_kernel(struct boot_params *bp); ++void 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); +@@ -57,6 +58,11 @@ void __init mem_encrypt_free_decrypted_mem(void); + + void __init sev_es_init_vc_handling(void); + ++static inline u64 sme_get_me_mask(void) ++{ ++ return RIP_REL_REF(sme_me_mask); ++} ++ + #define __bss_decrypted __section(".bss..decrypted") + + #else /* !CONFIG_AMD_MEM_ENCRYPT */ +@@ -75,8 +81,8 @@ static inline void __init sme_unmap_bootdata(char *real_mode_data) { } + static inline void __init sme_early_init(void) { } + static inline void __init sev_setup_arch(void) { } + +-static inline void __init sme_encrypt_kernel(struct boot_params *bp) { } +-static inline void __init sme_enable(struct boot_params *bp) { } ++static inline void sme_encrypt_kernel(struct boot_params *bp) { } ++static inline void sme_enable(struct boot_params *bp) { } + + static inline void sev_es_init_vc_handling(void) { } + +@@ -89,6 +95,8 @@ early_set_mem_enc_dec_hypercall(unsigned long vaddr, unsigned long size, bool en + + static inline void mem_encrypt_free_decrypted_mem(void) { } + ++static inline u64 sme_get_me_mask(void) { return 0; } ++ + #define __bss_decrypted + + #endif /* CONFIG_AMD_MEM_ENCRYPT */ +@@ -106,11 +114,6 @@ void add_encrypt_protection_map(void); + + extern char __start_bss_decrypted[], __end_bss_decrypted[], __start_bss_decrypted_unused[]; + +-static inline u64 sme_get_me_mask(void) +-{ +- return sme_me_mask; +-} +- + #endif /* __ASSEMBLY__ */ + + #endif /* __X86_MEM_ENCRYPT_H__ */ +diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h +index 896445edc6a8e9..ec95d6e9f1682c 100644 +--- a/arch/x86/include/asm/mshyperv.h ++++ b/arch/x86/include/asm/mshyperv.h +@@ -40,7 +40,6 @@ static inline unsigned char hv_get_nmi_reason(void) + } + + #if IS_ENABLED(CONFIG_HYPERV) +-extern int hyperv_init_cpuhp; + extern bool hyperv_paravisor_present; + + extern void *hv_hypercall_pg; +diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h +index b37abb55e948b7..24b7bd255e9830 100644 +--- a/arch/x86/include/asm/msr-index.h ++++ b/arch/x86/include/asm/msr-index.h +@@ -50,10 +50,13 @@ + #define SPEC_CTRL_SSBD BIT(SPEC_CTRL_SSBD_SHIFT) /* Speculative Store Bypass Disable */ + #define SPEC_CTRL_RRSBA_DIS_S_SHIFT 6 /* Disable RRSBA behavior */ + #define SPEC_CTRL_RRSBA_DIS_S BIT(SPEC_CTRL_RRSBA_DIS_S_SHIFT) ++#define SPEC_CTRL_BHI_DIS_S_SHIFT 10 /* Disable Branch History Injection behavior */ ++#define SPEC_CTRL_BHI_DIS_S BIT(SPEC_CTRL_BHI_DIS_S_SHIFT) + + /* A mask for bits which the kernel toggles when controlling mitigations */ + #define SPEC_CTRL_MITIGATIONS_MASK (SPEC_CTRL_IBRS | SPEC_CTRL_STIBP | SPEC_CTRL_SSBD \ +- | SPEC_CTRL_RRSBA_DIS_S) ++ | SPEC_CTRL_RRSBA_DIS_S \ ++ | SPEC_CTRL_BHI_DIS_S) + + #define MSR_IA32_PRED_CMD 0x00000049 /* Prediction Command */ + #define PRED_CMD_IBPB BIT(0) /* Indirect Branch Prediction Barrier */ +@@ -152,6 +155,10 @@ + * are restricted to targets in + * kernel. + */ ++#define ARCH_CAP_BHI_NO BIT(20) /* ++ * CPU is not affected by Branch ++ * History Injection. ++ */ + #define ARCH_CAP_PBRSB_NO BIT(24) /* + * Not susceptible to Post-Barrier + * Return Stack Buffer Predictions. +@@ -165,6 +172,14 @@ + * CPU is not vulnerable to Gather + * Data Sampling (GDS). + */ ++#define ARCH_CAP_RFDS_NO BIT(27) /* ++ * Not susceptible to Register ++ * File Data Sampling. ++ */ ++#define ARCH_CAP_RFDS_CLEAR BIT(28) /* ++ * VERW clears CPU Register ++ * File. ++ */ + + #define ARCH_CAP_XAPIC_DISABLE BIT(21) /* + * IA32_XAPIC_DISABLE_STATUS MSR +@@ -222,6 +237,7 @@ + #define MSR_INTEGRITY_CAPS_ARRAY_BIST BIT(MSR_INTEGRITY_CAPS_ARRAY_BIST_BIT) + #define MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT 4 + #define MSR_INTEGRITY_CAPS_PERIODIC_BIST BIT(MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT) ++#define MSR_INTEGRITY_CAPS_SAF_GEN_MASK GENMASK_ULL(10, 9) + + #define MSR_LBR_NHM_FROM 0x00000680 + #define MSR_LBR_NHM_TO 0x000006c0 +@@ -553,6 +569,7 @@ + #define MSR_AMD64_CPUID_FN_1 0xc0011004 + #define MSR_AMD64_LS_CFG 0xc0011020 + #define MSR_AMD64_DC_CFG 0xc0011022 ++#define MSR_AMD64_TW_CFG 0xc0011023 + + #define MSR_AMD64_DE_CFG 0xc0011029 + #define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT 1 +diff --git a/arch/x86/include/asm/mwait.h b/arch/x86/include/asm/mwait.h +index 778df05f853918..bae83810505bf5 100644 +--- a/arch/x86/include/asm/mwait.h ++++ b/arch/x86/include/asm/mwait.h +@@ -115,8 +115,15 @@ static __always_inline void mwait_idle_with_hints(unsigned long eax, unsigned lo + } + + __monitor((void *)¤t_thread_info()->flags, 0, 0); +- if (!need_resched()) +- __mwait(eax, ecx); ++ ++ if (!need_resched()) { ++ if (ecx & 1) { ++ __mwait(eax, ecx); ++ } else { ++ __sti_mwait(eax, ecx); ++ raw_local_irq_disable(); ++ } ++ } + } + current_clr_polling(); + } +diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h +index c55cc243592e94..ee642d26e30457 100644 +--- a/arch/x86/include/asm/nospec-branch.h ++++ b/arch/x86/include/asm/nospec-branch.h +@@ -196,7 +196,7 @@ + .macro ANNOTATE_RETPOLINE_SAFE + .Lhere_\@: + .pushsection .discard.retpoline_safe +- .long .Lhere_\@ - . ++ .long .Lhere_\@ + .popsection + .endm + +@@ -271,11 +271,20 @@ + .Lskip_rsb_\@: + .endm + +-#ifdef CONFIG_CPU_UNRET_ENTRY +-#define CALL_UNTRAIN_RET "call entry_untrain_ret" +-#else +-#define CALL_UNTRAIN_RET "" ++/* ++ * The CALL to srso_alias_untrain_ret() must be patched in directly at ++ * the spot where untraining must be done, ie., srso_alias_untrain_ret() ++ * must be the target of a CALL instruction instead of indirectly ++ * jumping to a wrapper which then calls it. Therefore, this macro is ++ * called outside of __UNTRAIN_RET below, for the time being, before the ++ * kernel can support nested alternatives with arbitrary nesting. ++ */ ++.macro CALL_UNTRAIN_RET ++#if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_SRSO) ++ ALTERNATIVE_2 "", "call entry_untrain_ret", X86_FEATURE_UNRET, \ ++ "call srso_alias_untrain_ret", X86_FEATURE_SRSO_ALIAS + #endif ++.endm + + /* + * Mitigate RETBleed for AMD/Hygon Zen uarch. Requires KERNEL CR3 because the +@@ -288,38 +297,24 @@ + * As such, this must be placed after every *SWITCH_TO_KERNEL_CR3 at a point + * where we have a stack but before any RET instruction. + */ +-.macro UNTRAIN_RET +-#if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_IBPB_ENTRY) || \ +- defined(CONFIG_CALL_DEPTH_TRACKING) || defined(CONFIG_CPU_SRSO) ++.macro __UNTRAIN_RET ibpb_feature, call_depth_insns ++#if defined(CONFIG_RETHUNK) || defined(CONFIG_CPU_IBPB_ENTRY) + VALIDATE_UNRET_END +- ALTERNATIVE_3 "", \ +- CALL_UNTRAIN_RET, X86_FEATURE_UNRET, \ +- "call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \ +- __stringify(RESET_CALL_DEPTH), X86_FEATURE_CALL_DEPTH ++ CALL_UNTRAIN_RET ++ ALTERNATIVE_2 "", \ ++ "call entry_ibpb", \ibpb_feature, \ ++ __stringify(\call_depth_insns), X86_FEATURE_CALL_DEPTH + #endif + .endm + +-.macro UNTRAIN_RET_VM +-#if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_IBPB_ENTRY) || \ +- defined(CONFIG_CALL_DEPTH_TRACKING) || defined(CONFIG_CPU_SRSO) +- VALIDATE_UNRET_END +- ALTERNATIVE_3 "", \ +- CALL_UNTRAIN_RET, X86_FEATURE_UNRET, \ +- "call entry_ibpb", X86_FEATURE_IBPB_ON_VMEXIT, \ +- __stringify(RESET_CALL_DEPTH), X86_FEATURE_CALL_DEPTH +-#endif +-.endm ++#define UNTRAIN_RET \ ++ __UNTRAIN_RET X86_FEATURE_ENTRY_IBPB, __stringify(RESET_CALL_DEPTH) + +-.macro UNTRAIN_RET_FROM_CALL +-#if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_IBPB_ENTRY) || \ +- defined(CONFIG_CALL_DEPTH_TRACKING) +- VALIDATE_UNRET_END +- ALTERNATIVE_3 "", \ +- CALL_UNTRAIN_RET, X86_FEATURE_UNRET, \ +- "call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \ +- __stringify(RESET_CALL_DEPTH_FROM_CALL), X86_FEATURE_CALL_DEPTH +-#endif +-.endm ++#define UNTRAIN_RET_VM \ ++ __UNTRAIN_RET X86_FEATURE_IBPB_ON_VMEXIT, __stringify(RESET_CALL_DEPTH) ++ ++#define UNTRAIN_RET_FROM_CALL \ ++ __UNTRAIN_RET X86_FEATURE_ENTRY_IBPB, __stringify(RESET_CALL_DEPTH_FROM_CALL) + + + .macro CALL_DEPTH_ACCOUNT +@@ -329,12 +324,45 @@ + #endif + .endm + ++/* ++ * Macro to execute VERW instruction that mitigate transient data sampling ++ * attacks such as MDS. On affected systems a microcode update overloaded VERW ++ * instruction to also clear the CPU buffers. VERW clobbers CFLAGS.ZF. ++ * ++ * Note: Only the memory operand variant of VERW clears the CPU buffers. ++ */ ++.macro CLEAR_CPU_BUFFERS ++#ifdef CONFIG_X86_64 ++ ALTERNATIVE "", "verw mds_verw_sel(%rip)", X86_FEATURE_CLEAR_CPU_BUF ++#else ++ /* ++ * In 32bit mode, the memory operand must be a %cs reference. The data ++ * segments may not be usable (vm86 mode), and the stack segment may not ++ * be flat (ESPFIX32). ++ */ ++ ALTERNATIVE "", "verw %cs:mds_verw_sel", X86_FEATURE_CLEAR_CPU_BUF ++#endif ++.endm ++ ++#ifdef CONFIG_X86_64 ++.macro CLEAR_BRANCH_HISTORY ++ ALTERNATIVE "", "call clear_bhb_loop", X86_FEATURE_CLEAR_BHB_LOOP ++.endm ++ ++.macro CLEAR_BRANCH_HISTORY_VMEXIT ++ ALTERNATIVE "", "call clear_bhb_loop", X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT ++.endm ++#else ++#define CLEAR_BRANCH_HISTORY ++#define CLEAR_BRANCH_HISTORY_VMEXIT ++#endif ++ + #else /* __ASSEMBLY__ */ + + #define ANNOTATE_RETPOLINE_SAFE \ + "999:\n\t" \ + ".pushsection .discard.retpoline_safe\n\t" \ +- ".long 999b - .\n\t" \ ++ ".long 999b\n\t" \ + ".popsection\n\t" + + typedef u8 retpoline_thunk_t[RETPOLINE_THUNK_SIZE]; +@@ -348,6 +376,22 @@ extern void __x86_return_thunk(void); + static inline void __x86_return_thunk(void) {} + #endif + ++#ifdef CONFIG_CPU_UNRET_ENTRY ++extern void retbleed_return_thunk(void); ++#else ++static inline void retbleed_return_thunk(void) {} ++#endif ++ ++extern void srso_alias_untrain_ret(void); ++ ++#ifdef CONFIG_CPU_SRSO ++extern void srso_return_thunk(void); ++extern void srso_alias_return_thunk(void); ++#else ++static inline void srso_return_thunk(void) {} ++static inline void srso_alias_return_thunk(void) {} ++#endif ++ + extern void retbleed_return_thunk(void); + extern void srso_return_thunk(void); + extern void srso_alias_return_thunk(void); +@@ -359,6 +403,10 @@ extern void srso_alias_untrain_ret(void); + extern void entry_untrain_ret(void); + extern void entry_ibpb(void); + ++#ifdef CONFIG_X86_64 ++extern void clear_bhb_loop(void); ++#endif ++ + extern void (*x86_return_thunk)(void); + + #ifdef CONFIG_CALL_DEPTH_TRACKING +@@ -538,13 +586,14 @@ DECLARE_STATIC_KEY_FALSE(switch_to_cond_stibp); + DECLARE_STATIC_KEY_FALSE(switch_mm_cond_ibpb); + DECLARE_STATIC_KEY_FALSE(switch_mm_always_ibpb); + +-DECLARE_STATIC_KEY_FALSE(mds_user_clear); + DECLARE_STATIC_KEY_FALSE(mds_idle_clear); + + DECLARE_STATIC_KEY_FALSE(switch_mm_cond_l1d_flush); + + DECLARE_STATIC_KEY_FALSE(mmio_stale_data_clear); + ++extern u16 mds_verw_sel; ++ + #include + + /** +@@ -570,17 +619,6 @@ static __always_inline void mds_clear_cpu_buffers(void) + asm volatile("verw %[ds]" : : [ds] "m" (ds) : "cc"); + } + +-/** +- * mds_user_clear_cpu_buffers - Mitigation for MDS and TAA vulnerability +- * +- * Clear CPU buffers if the corresponding static key is enabled +- */ +-static __always_inline void mds_user_clear_cpu_buffers(void) +-{ +- if (static_branch_likely(&mds_user_clear)) +- mds_clear_cpu_buffers(); +-} +- + /** + * mds_idle_clear_cpu_buffers - Mitigation for MDS vulnerability + * +diff --git a/arch/x86/include/asm/numa.h b/arch/x86/include/asm/numa.h +index e3bae2b60a0db9..ef2844d691735d 100644 +--- a/arch/x86/include/asm/numa.h ++++ b/arch/x86/include/asm/numa.h +@@ -12,13 +12,6 @@ + + #define NR_NODE_MEMBLKS (MAX_NUMNODES*2) + +-/* +- * Too small node sizes may confuse the VM badly. Usually they +- * result from BIOS bugs. So dont recognize nodes as standalone +- * NUMA entities that have less than this amount of RAM listed: +- */ +-#define NODE_MIN_SIZE (4*1024*1024) +- + extern int numa_off; + + /* +diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h +index d18e5c332cb9f4..1b93ff80b43bcc 100644 +--- a/arch/x86/include/asm/page.h ++++ b/arch/x86/include/asm/page.h +@@ -66,10 +66,14 @@ static inline void copy_user_page(void *to, void *from, unsigned long vaddr, + * virt_addr_valid(kaddr) returns true. + */ + #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) +-#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) + extern bool __virt_addr_valid(unsigned long kaddr); + #define virt_addr_valid(kaddr) __virt_addr_valid((unsigned long) (kaddr)) + ++static __always_inline void *pfn_to_kaddr(unsigned long pfn) ++{ ++ return __va(pfn << PAGE_SHIFT); ++} ++ + static __always_inline u64 __canonical_address(u64 vaddr, u8 vaddr_bits) + { + return ((s64)vaddr << (64 - vaddr_bits)) >> (64 - vaddr_bits); +diff --git a/arch/x86/include/asm/page_64.h b/arch/x86/include/asm/page_64.h +index cc6b8e087192e4..9dab85aba7afd9 100644 +--- a/arch/x86/include/asm/page_64.h ++++ b/arch/x86/include/asm/page_64.h +@@ -17,6 +17,7 @@ extern unsigned long phys_base; + extern unsigned long page_offset_base; + extern unsigned long vmalloc_base; + extern unsigned long vmemmap_base; ++extern unsigned long physmem_end; + + static __always_inline unsigned long __phys_addr_nodebug(unsigned long x) + { +diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h +index e02b179ec65989..d03fe4fb41f43c 100644 +--- a/arch/x86/include/asm/pgtable.h ++++ b/arch/x86/include/asm/pgtable.h +@@ -387,23 +387,7 @@ static inline pte_t pte_wrprotect(pte_t pte) + #ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP + static inline int pte_uffd_wp(pte_t pte) + { +- bool wp = pte_flags(pte) & _PAGE_UFFD_WP; +- +-#ifdef CONFIG_DEBUG_VM +- /* +- * Having write bit for wr-protect-marked present ptes is fatal, +- * because it means the uffd-wp bit will be ignored and write will +- * just go through. +- * +- * Use any chance of pgtable walking to verify this (e.g., when +- * page swapped out or being migrated for all purposes). It means +- * something is already wrong. Tell the admin even before the +- * process crashes. We also nail it with wrong pgtable setup. +- */ +- WARN_ON_ONCE(wp && pte_write(pte)); +-#endif +- +- return wp; ++ return pte_flags(pte) & _PAGE_UFFD_WP; + } + + static inline pte_t pte_mkuffd_wp(pte_t pte) +diff --git a/arch/x86/include/asm/pgtable_64_types.h b/arch/x86/include/asm/pgtable_64_types.h +index 38b54b992f32e3..35c416f061552b 100644 +--- a/arch/x86/include/asm/pgtable_64_types.h ++++ b/arch/x86/include/asm/pgtable_64_types.h +@@ -140,6 +140,10 @@ extern unsigned int ptrs_per_p4d; + # define VMEMMAP_START __VMEMMAP_BASE_L4 + #endif /* CONFIG_DYNAMIC_MEMORY_LAYOUT */ + ++#ifdef CONFIG_RANDOMIZE_MEMORY ++# define PHYSMEM_END physmem_end ++#endif ++ + /* + * End of the region for which vmalloc page tables are pre-allocated. + * For non-KMSAN builds, this is the same as VMALLOC_END. +diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h +index 0b748ee16b3d94..b786449626267e 100644 +--- a/arch/x86/include/asm/pgtable_types.h ++++ b/arch/x86/include/asm/pgtable_types.h +@@ -148,7 +148,7 @@ + #define _COMMON_PAGE_CHG_MASK (PTE_PFN_MASK | _PAGE_PCD | _PAGE_PWT | \ + _PAGE_SPECIAL | _PAGE_ACCESSED | \ + _PAGE_DIRTY_BITS | _PAGE_SOFT_DIRTY | \ +- _PAGE_DEVMAP | _PAGE_ENC | _PAGE_UFFD_WP) ++ _PAGE_DEVMAP | _PAGE_CC | _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) + +@@ -173,6 +173,7 @@ enum page_cache_mode { + }; + #endif + ++#define _PAGE_CC (_AT(pteval_t, cc_mask)) + #define _PAGE_ENC (_AT(pteval_t, sme_me_mask)) + + #define _PAGE_CACHE_MASK (_PAGE_PWT | _PAGE_PCD | _PAGE_PAT) +@@ -566,6 +567,8 @@ static inline void update_page_count(int level, unsigned long pages) { } + extern pte_t *lookup_address(unsigned long address, unsigned int *level); + extern pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address, + unsigned int *level); ++pte_t *lookup_address_in_pgd_attr(pgd_t *pgd, unsigned long address, ++ unsigned int *level, bool *nx, bool *rw); + extern pmd_t *lookup_pmd_address(unsigned long address); + extern phys_addr_t slow_virt_to_phys(void *__address); + extern int __init kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, +diff --git a/arch/x86/include/asm/posted_intr.h b/arch/x86/include/asm/posted_intr.h +new file mode 100644 +index 00000000000000..f0324c56f7af51 +--- /dev/null ++++ b/arch/x86/include/asm/posted_intr.h +@@ -0,0 +1,88 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _X86_POSTED_INTR_H ++#define _X86_POSTED_INTR_H ++ ++#define POSTED_INTR_ON 0 ++#define POSTED_INTR_SN 1 ++ ++#define PID_TABLE_ENTRY_VALID 1 ++ ++/* Posted-Interrupt Descriptor */ ++struct pi_desc { ++ u32 pir[8]; /* Posted interrupt requested */ ++ union { ++ struct { ++ /* bit 256 - Outstanding Notification */ ++ u16 on : 1, ++ /* bit 257 - Suppress Notification */ ++ sn : 1, ++ /* bit 271:258 - Reserved */ ++ rsvd_1 : 14; ++ /* bit 279:272 - Notification Vector */ ++ u8 nv; ++ /* bit 287:280 - Reserved */ ++ u8 rsvd_2; ++ /* bit 319:288 - Notification Destination */ ++ u32 ndst; ++ }; ++ u64 control; ++ }; ++ u32 rsvd[6]; ++} __aligned(64); ++ ++static inline bool pi_test_and_set_on(struct pi_desc *pi_desc) ++{ ++ return test_and_set_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control); ++} ++ ++static inline bool pi_test_and_clear_on(struct pi_desc *pi_desc) ++{ ++ return test_and_clear_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control); ++} ++ ++static inline bool pi_test_and_clear_sn(struct pi_desc *pi_desc) ++{ ++ return test_and_clear_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control); ++} ++ ++static inline bool pi_test_and_set_pir(int vector, struct pi_desc *pi_desc) ++{ ++ return test_and_set_bit(vector, (unsigned long *)pi_desc->pir); ++} ++ ++static inline bool pi_is_pir_empty(struct pi_desc *pi_desc) ++{ ++ return bitmap_empty((unsigned long *)pi_desc->pir, NR_VECTORS); ++} ++ ++static inline void pi_set_sn(struct pi_desc *pi_desc) ++{ ++ set_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control); ++} ++ ++static inline void pi_set_on(struct pi_desc *pi_desc) ++{ ++ set_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control); ++} ++ ++static inline void pi_clear_on(struct pi_desc *pi_desc) ++{ ++ clear_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control); ++} ++ ++static inline void pi_clear_sn(struct pi_desc *pi_desc) ++{ ++ clear_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control); ++} ++ ++static inline bool pi_test_on(struct pi_desc *pi_desc) ++{ ++ return test_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control); ++} ++ ++static inline bool pi_test_sn(struct pi_desc *pi_desc) ++{ ++ return test_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control); ++} ++ ++#endif /* _X86_POSTED_INTR_H */ +diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h +index a3669a7774edbb..67ad64efa9263f 100644 +--- a/arch/x86/include/asm/processor.h ++++ b/arch/x86/include/asm/processor.h +@@ -399,7 +399,7 @@ static inline unsigned long cpu_kernelmode_gs_base(int cpu) + return (unsigned long)per_cpu(fixed_percpu_data.gs_base, cpu); + } + +-extern asmlinkage void ignore_sysret(void); ++extern asmlinkage void entry_SYSCALL32_ignore(void); + + /* Save actual FS/GS selectors and bases to current->thread */ + void current_save_fsgs(void); +@@ -464,7 +464,6 @@ struct thread_struct { + unsigned long iopl_emul; + + unsigned int iopl_warn:1; +- unsigned int sig_on_uaccess_err:1; + + /* + * Protection Keys Register for Userspace. Loaded immediately on +@@ -734,4 +733,22 @@ bool arch_is_platform_page(u64 paddr); + + extern bool gds_ucode_mitigated(void); + ++/* ++ * Make previous memory operations globally visible before ++ * a WRMSR. ++ * ++ * MFENCE makes writes visible, but only affects load/store ++ * instructions. WRMSR is unfortunately not a load/store ++ * instruction and is unaffected by MFENCE. The LFENCE ensures ++ * that the WRMSR is not reordered. ++ * ++ * Most WRMSRs are full serializing instructions themselves and ++ * do not require this barrier. This is only required for the ++ * IA32_TSC_DEADLINE and X2APIC MSRs. ++ */ ++static inline void weak_wrmsr_fence(void) ++{ ++ alternative("mfence; lfence", "", ALT_NOT(X86_FEATURE_APIC_MSRS_FENCE)); ++} ++ + #endif /* _ASM_X86_PROCESSOR_H */ +diff --git a/arch/x86/include/asm/proto.h b/arch/x86/include/asm/proto.h +index 12ef86b19910d3..84294b66b91625 100644 +--- a/arch/x86/include/asm/proto.h ++++ b/arch/x86/include/asm/proto.h +@@ -32,10 +32,6 @@ void entry_SYSCALL_compat(void); + void entry_SYSCALL_compat_safe_stack(void); + void entry_SYSRETL_compat_unsafe_stack(void); + void entry_SYSRETL_compat_end(void); +-void entry_INT80_compat(void); +-#ifdef CONFIG_XEN_PV +-void xen_entry_INT80_compat(void); +-#endif + #endif + + void x86_configure_nx(void); +diff --git a/arch/x86/include/asm/qspinlock.h b/arch/x86/include/asm/qspinlock.h +index cde8357bb226d1..e897046c5d2c63 100644 +--- a/arch/x86/include/asm/qspinlock.h ++++ b/arch/x86/include/asm/qspinlock.h +@@ -66,13 +66,15 @@ static inline bool vcpu_is_preempted(long cpu) + + #ifdef CONFIG_PARAVIRT + /* +- * virt_spin_lock_key - enables (by default) the virt_spin_lock() hijack. ++ * virt_spin_lock_key - disables by default the virt_spin_lock() hijack. + * +- * Native (and PV wanting native due to vCPU pinning) should disable this key. +- * It is done in this backwards fashion to only have a single direction change, +- * which removes ordering between native_pv_spin_init() and HV setup. ++ * Native (and PV wanting native due to vCPU pinning) should keep this key ++ * disabled. Native does not touch the key. ++ * ++ * When in a guest then native_pv_lock_init() enables the key first and ++ * KVM/XEN might conditionally disable it later in the boot process again. + */ +-DECLARE_STATIC_KEY_TRUE(virt_spin_lock_key); ++DECLARE_STATIC_KEY_FALSE(virt_spin_lock_key); + + /* + * Shortcut for the queued_spin_lock_slowpath() function that allows +diff --git a/arch/x86/include/asm/required-features.h b/arch/x86/include/asm/required-features.h +index 7ba1726b71c7b8..e9187ddd3d1fdc 100644 +--- a/arch/x86/include/asm/required-features.h ++++ b/arch/x86/include/asm/required-features.h +@@ -99,6 +99,7 @@ + #define REQUIRED_MASK18 0 + #define REQUIRED_MASK19 0 + #define REQUIRED_MASK20 0 +-#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 21) ++#define REQUIRED_MASK21 0 ++#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 22) + + #endif /* _ASM_X86_REQUIRED_FEATURES_H */ +diff --git a/arch/x86/include/asm/rmwcc.h b/arch/x86/include/asm/rmwcc.h +index 4b081e0d3306b7..363266cbcadaf2 100644 +--- a/arch/x86/include/asm/rmwcc.h ++++ b/arch/x86/include/asm/rmwcc.h +@@ -13,7 +13,7 @@ + #define __GEN_RMWcc(fullop, _var, cc, clobbers, ...) \ + ({ \ + bool c = false; \ +- asm_volatile_goto (fullop "; j" #cc " %l[cc_label]" \ ++ asm goto (fullop "; j" #cc " %l[cc_label]" \ + : : [var] "m" (_var), ## __VA_ARGS__ \ + : clobbers : cc_label); \ + if (0) { \ +diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h +index 5b4a1ce3d36808..75a5388d40681e 100644 +--- a/arch/x86/include/asm/sev.h ++++ b/arch/x86/include/asm/sev.h +@@ -199,16 +199,16 @@ static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) + struct snp_guest_request_ioctl; + + void setup_ghcb(void); +-void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr, +- unsigned long npages); +-void __init early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr, +- unsigned long npages); +-void __init snp_prep_memory(unsigned long paddr, unsigned int sz, enum psc_op op); ++void early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr, ++ unsigned long npages); ++void early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr, ++ unsigned long npages); + void snp_set_memory_shared(unsigned long vaddr, unsigned long npages); + void snp_set_memory_private(unsigned long vaddr, unsigned long npages); + void snp_set_wakeup_secondary_cpu(void); + bool snp_init(struct boot_params *bp); +-void __init __noreturn snp_abort(void); ++void __noreturn snp_abort(void); ++void snp_dmi_setup(void); + int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio); + void snp_accept_memory(phys_addr_t start, phys_addr_t end); + u64 snp_get_unsupported_features(u64 status); +@@ -227,12 +227,12 @@ static inline void __init + early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr, unsigned long npages) { } + static inline void __init + early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr, unsigned long npages) { } +-static inline void __init snp_prep_memory(unsigned long paddr, unsigned int sz, enum psc_op op) { } + static inline void snp_set_memory_shared(unsigned long vaddr, unsigned long npages) { } + static inline void snp_set_memory_private(unsigned long vaddr, unsigned long npages) { } + static inline void snp_set_wakeup_secondary_cpu(void) { } + static inline bool snp_init(struct boot_params *bp) { return false; } + static inline void snp_abort(void) { } ++static inline void snp_dmi_setup(void) { } + static inline int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio) + { + return -ENOTTY; +diff --git a/arch/x86/include/asm/shstk.h b/arch/x86/include/asm/shstk.h +index 42fee8959df7be..896909f306e306 100644 +--- a/arch/x86/include/asm/shstk.h ++++ b/arch/x86/include/asm/shstk.h +@@ -21,6 +21,7 @@ unsigned long shstk_alloc_thread_stack(struct task_struct *p, unsigned long clon + void shstk_free(struct task_struct *p); + int setup_signal_shadow_stack(struct ksignal *ksig); + int restore_signal_shadow_stack(void); ++int shstk_update_last_frame(unsigned long val); + #else + static inline long shstk_prctl(struct task_struct *task, int option, + unsigned long arg2) { return -EINVAL; } +@@ -31,6 +32,7 @@ static inline unsigned long shstk_alloc_thread_stack(struct task_struct *p, + static inline void shstk_free(struct task_struct *p) {} + static inline int setup_signal_shadow_stack(struct ksignal *ksig) { return 0; } + static inline int restore_signal_shadow_stack(void) { return 0; } ++static inline int shstk_update_last_frame(unsigned long val) { return 0; } + #endif /* CONFIG_X86_USER_SHADOW_STACK */ + + #endif /* __ASSEMBLY__ */ +diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h +index d6cd9344f6c78e..48f8dd47cf6882 100644 +--- a/arch/x86/include/asm/special_insns.h ++++ b/arch/x86/include/asm/special_insns.h +@@ -205,7 +205,7 @@ static inline void clwb(volatile void *__p) + #ifdef CONFIG_X86_USER_SHADOW_STACK + static inline int write_user_shstk_64(u64 __user *addr, u64 val) + { +- asm_volatile_goto("1: wrussq %[val], (%[addr])\n" ++ asm goto("1: wrussq %[val], (%[addr])\n" + _ASM_EXTABLE(1b, %l[fail]) + :: [addr] "r" (addr), [val] "r" (val) + :: fail); +diff --git a/arch/x86/include/asm/suspend_32.h b/arch/x86/include/asm/suspend_32.h +index a800abb1a99255..d8416b3bf832e4 100644 +--- a/arch/x86/include/asm/suspend_32.h ++++ b/arch/x86/include/asm/suspend_32.h +@@ -12,11 +12,6 @@ + + /* image of the saved processor state */ + struct saved_context { +- /* +- * On x86_32, all segment registers except gs are saved at kernel +- * entry in pt_regs. +- */ +- u16 gs; + unsigned long cr0, cr2, cr3, cr4; + u64 misc_enable; + struct saved_msrs saved_msrs; +@@ -27,6 +22,11 @@ struct saved_context { + unsigned long tr; + unsigned long safety; + unsigned long return_address; ++ /* ++ * On x86_32, all segment registers except gs are saved at kernel ++ * entry in pt_regs. ++ */ ++ u16 gs; + bool misc_enable_saved; + } __attribute__((packed)); + +diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h +index 4fb36fba4b5a1f..228a42585d5c97 100644 +--- a/arch/x86/include/asm/syscall.h ++++ b/arch/x86/include/asm/syscall.h +@@ -16,19 +16,17 @@ + #include /* for TS_COMPAT */ + #include + ++/* This is used purely for kernel/trace/trace_syscalls.c */ + typedef long (*sys_call_ptr_t)(const struct pt_regs *); + extern const sys_call_ptr_t sys_call_table[]; + +-#if defined(CONFIG_X86_32) +-#define ia32_sys_call_table sys_call_table +-#else + /* + * These may not exist, but still put the prototypes in so we + * can use IS_ENABLED(). + */ +-extern const sys_call_ptr_t ia32_sys_call_table[]; +-extern const sys_call_ptr_t x32_sys_call_table[]; +-#endif ++extern long ia32_sys_call(const struct pt_regs *, unsigned int nr); ++extern long x32_sys_call(const struct pt_regs *, unsigned int nr); ++extern long x64_sys_call(const struct pt_regs *, unsigned int nr); + + /* + * Only the low 32 bits of orig_ax are meaningful, so we return int. +@@ -84,7 +82,12 @@ static inline void syscall_get_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned long *args) + { +- memcpy(args, ®s->bx, 6 * sizeof(args[0])); ++ args[0] = regs->bx; ++ args[1] = regs->cx; ++ args[2] = regs->dx; ++ args[3] = regs->si; ++ args[4] = regs->di; ++ args[5] = regs->bp; + } + + static inline int syscall_get_arch(struct task_struct *task) +@@ -127,6 +130,7 @@ static inline int syscall_get_arch(struct task_struct *task) + } + + void do_syscall_64(struct pt_regs *regs, int nr); ++void do_int80_emulation(struct pt_regs *regs); + + #endif /* CONFIG_X86_32 */ + +diff --git a/arch/x86/include/asm/syscall_wrapper.h b/arch/x86/include/asm/syscall_wrapper.h +index fd2669b1cb2d95..7e88705e907f41 100644 +--- a/arch/x86/include/asm/syscall_wrapper.h ++++ b/arch/x86/include/asm/syscall_wrapper.h +@@ -58,12 +58,29 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs); + ,,regs->di,,regs->si,,regs->dx \ + ,,regs->r10,,regs->r8,,regs->r9) \ + ++ ++/* SYSCALL_PT_ARGS is Adapted from s390x */ ++#define SYSCALL_PT_ARG6(m, t1, t2, t3, t4, t5, t6) \ ++ SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5), m(t6, (regs->bp)) ++#define SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5) \ ++ SYSCALL_PT_ARG4(m, t1, t2, t3, t4), m(t5, (regs->di)) ++#define SYSCALL_PT_ARG4(m, t1, t2, t3, t4) \ ++ SYSCALL_PT_ARG3(m, t1, t2, t3), m(t4, (regs->si)) ++#define SYSCALL_PT_ARG3(m, t1, t2, t3) \ ++ SYSCALL_PT_ARG2(m, t1, t2), m(t3, (regs->dx)) ++#define SYSCALL_PT_ARG2(m, t1, t2) \ ++ SYSCALL_PT_ARG1(m, t1), m(t2, (regs->cx)) ++#define SYSCALL_PT_ARG1(m, t1) m(t1, (regs->bx)) ++#define SYSCALL_PT_ARGS(x, ...) SYSCALL_PT_ARG##x(__VA_ARGS__) ++ ++#define __SC_COMPAT_CAST(t, a) \ ++ (__typeof(__builtin_choose_expr(__TYPE_IS_L(t), 0, 0U))) \ ++ (unsigned int)a ++ + /* Mapping of registers to parameters for syscalls on i386 */ + #define SC_IA32_REGS_TO_ARGS(x, ...) \ +- __MAP(x,__SC_ARGS \ +- ,,(unsigned int)regs->bx,,(unsigned int)regs->cx \ +- ,,(unsigned int)regs->dx,,(unsigned int)regs->si \ +- ,,(unsigned int)regs->di,,(unsigned int)regs->bp) ++ SYSCALL_PT_ARGS(x, __SC_COMPAT_CAST, \ ++ __MAP(x, __SC_TYPE, __VA_ARGS__)) \ + + #define __SYS_STUB0(abi, name) \ + long __##abi##_##name(const struct pt_regs *regs); \ +@@ -86,9 +103,6 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs); + return sys_ni_syscall(); \ + } + +-#define __SYS_NI(abi, name) \ +- SYSCALL_ALIAS(__##abi##_##name, sys_ni_posix_timers); +- + #ifdef CONFIG_X86_64 + #define __X64_SYS_STUB0(name) \ + __SYS_STUB0(x64, sys_##name) +@@ -100,13 +114,10 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs); + #define __X64_COND_SYSCALL(name) \ + __COND_SYSCALL(x64, sys_##name) + +-#define __X64_SYS_NI(name) \ +- __SYS_NI(x64, sys_##name) + #else /* CONFIG_X86_64 */ + #define __X64_SYS_STUB0(name) + #define __X64_SYS_STUBx(x, name, ...) + #define __X64_COND_SYSCALL(name) +-#define __X64_SYS_NI(name) + #endif /* CONFIG_X86_64 */ + + #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) +@@ -120,13 +131,10 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs); + #define __IA32_COND_SYSCALL(name) \ + __COND_SYSCALL(ia32, sys_##name) + +-#define __IA32_SYS_NI(name) \ +- __SYS_NI(ia32, sys_##name) + #else /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */ + #define __IA32_SYS_STUB0(name) + #define __IA32_SYS_STUBx(x, name, ...) + #define __IA32_COND_SYSCALL(name) +-#define __IA32_SYS_NI(name) + #endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */ + + #ifdef CONFIG_IA32_EMULATION +@@ -135,8 +143,7 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs); + * additional wrappers (aptly named __ia32_sys_xyzzy) which decode the + * ia32 regs in the proper order for shared or "common" syscalls. As some + * syscalls may not be implemented, we need to expand COND_SYSCALL in +- * kernel/sys_ni.c and SYS_NI in kernel/time/posix-stubs.c to cover this +- * case as well. ++ * kernel/sys_ni.c to cover this case as well. + */ + #define __IA32_COMPAT_SYS_STUB0(name) \ + __SYS_STUB0(ia32, compat_sys_##name) +@@ -148,14 +155,10 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs); + #define __IA32_COMPAT_COND_SYSCALL(name) \ + __COND_SYSCALL(ia32, compat_sys_##name) + +-#define __IA32_COMPAT_SYS_NI(name) \ +- __SYS_NI(ia32, compat_sys_##name) +- + #else /* CONFIG_IA32_EMULATION */ + #define __IA32_COMPAT_SYS_STUB0(name) + #define __IA32_COMPAT_SYS_STUBx(x, name, ...) + #define __IA32_COMPAT_COND_SYSCALL(name) +-#define __IA32_COMPAT_SYS_NI(name) + #endif /* CONFIG_IA32_EMULATION */ + + +@@ -175,13 +178,10 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs); + #define __X32_COMPAT_COND_SYSCALL(name) \ + __COND_SYSCALL(x64, compat_sys_##name) + +-#define __X32_COMPAT_SYS_NI(name) \ +- __SYS_NI(x64, compat_sys_##name) + #else /* CONFIG_X86_X32_ABI */ + #define __X32_COMPAT_SYS_STUB0(name) + #define __X32_COMPAT_SYS_STUBx(x, name, ...) + #define __X32_COMPAT_COND_SYSCALL(name) +-#define __X32_COMPAT_SYS_NI(name) + #endif /* CONFIG_X86_X32_ABI */ + + +@@ -212,17 +212,12 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs); + + /* + * As some compat syscalls may not be implemented, we need to expand +- * COND_SYSCALL_COMPAT in kernel/sys_ni.c and COMPAT_SYS_NI in +- * kernel/time/posix-stubs.c to cover this case as well. ++ * COND_SYSCALL_COMPAT in kernel/sys_ni.c to cover this case as well. + */ + #define COND_SYSCALL_COMPAT(name) \ + __IA32_COMPAT_COND_SYSCALL(name) \ + __X32_COMPAT_COND_SYSCALL(name) + +-#define COMPAT_SYS_NI(name) \ +- __IA32_COMPAT_SYS_NI(name) \ +- __X32_COMPAT_SYS_NI(name) +- + #endif /* CONFIG_COMPAT */ + + #define __SYSCALL_DEFINEx(x, name, ...) \ +@@ -243,8 +238,8 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs); + * As the generic SYSCALL_DEFINE0() macro does not decode any parameters for + * obvious reasons, and passing struct pt_regs *regs to it in %rdi does not + * hurt, we only need to re-define it here to keep the naming congruent to +- * SYSCALL_DEFINEx() -- which is essential for the COND_SYSCALL() and SYS_NI() +- * macros to work correctly. ++ * SYSCALL_DEFINEx() -- which is essential for the COND_SYSCALL() macro ++ * to work correctly. + */ + #define SYSCALL_DEFINE0(sname) \ + SYSCALL_METADATA(_##sname, 0); \ +@@ -257,10 +252,6 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs); + __X64_COND_SYSCALL(name) \ + __IA32_COND_SYSCALL(name) + +-#define SYS_NI(name) \ +- __X64_SYS_NI(name) \ +- __IA32_SYS_NI(name) +- + + /* + * For VSYSCALLS, we need to declare these three syscalls with the new +diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h +index 8bae40a662827d..3a7755c1a44102 100644 +--- a/arch/x86/include/asm/uaccess.h ++++ b/arch/x86/include/asm/uaccess.h +@@ -78,10 +78,10 @@ extern int __get_user_bad(void); + int __ret_gu; \ + register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX); \ + __chk_user_ptr(ptr); \ +- asm volatile("call __" #fn "_%P4" \ ++ asm volatile("call __" #fn "_%c[size]" \ + : "=a" (__ret_gu), "=r" (__val_gu), \ + ASM_CALL_CONSTRAINT \ +- : "0" (ptr), "i" (sizeof(*(ptr)))); \ ++ : "0" (ptr), [size] "i" (sizeof(*(ptr)))); \ + instrument_get_user(__val_gu); \ + (x) = (__force __typeof__(*(ptr))) __val_gu; \ + __builtin_expect(__ret_gu, 0); \ +@@ -133,7 +133,7 @@ extern int __get_user_bad(void); + + #ifdef CONFIG_X86_32 + #define __put_user_goto_u64(x, addr, label) \ +- asm_volatile_goto("\n" \ ++ asm goto("\n" \ + "1: movl %%eax,0(%1)\n" \ + "2: movl %%edx,4(%1)\n" \ + _ASM_EXTABLE_UA(1b, %l2) \ +@@ -177,7 +177,7 @@ extern void __put_user_nocheck_8(void); + __chk_user_ptr(__ptr); \ + __ptr_pu = __ptr; \ + __val_pu = __x; \ +- asm volatile("call __" #fn "_%P[size]" \ ++ asm volatile("call __" #fn "_%c[size]" \ + : "=c" (__ret_pu), \ + ASM_CALL_CONSTRAINT \ + : "0" (__ptr_pu), \ +@@ -295,7 +295,7 @@ do { \ + } while (0) + + #define __get_user_asm(x, addr, itype, ltype, label) \ +- asm_volatile_goto("\n" \ ++ asm_goto_output("\n" \ + "1: mov"itype" %[umem],%[output]\n" \ + _ASM_EXTABLE_UA(1b, %l2) \ + : [output] ltype(x) \ +@@ -375,7 +375,7 @@ do { \ + __typeof__(_ptr) _old = (__typeof__(_ptr))(_pold); \ + __typeof__(*(_ptr)) __old = *_old; \ + __typeof__(*(_ptr)) __new = (_new); \ +- asm_volatile_goto("\n" \ ++ asm_goto_output("\n" \ + "1: " LOCK_PREFIX "cmpxchg"itype" %[new], %[ptr]\n"\ + _ASM_EXTABLE_UA(1b, %l[label]) \ + : CC_OUT(z) (success), \ +@@ -394,7 +394,7 @@ do { \ + __typeof__(_ptr) _old = (__typeof__(_ptr))(_pold); \ + __typeof__(*(_ptr)) __old = *_old; \ + __typeof__(*(_ptr)) __new = (_new); \ +- asm_volatile_goto("\n" \ ++ asm_goto_output("\n" \ + "1: " LOCK_PREFIX "cmpxchg8b %[ptr]\n" \ + _ASM_EXTABLE_UA(1b, %l[label]) \ + : CC_OUT(z) (success), \ +@@ -477,7 +477,7 @@ struct __large_struct { unsigned long buf[100]; }; + * aliasing issues. + */ + #define __put_user_goto(x, addr, itype, ltype, label) \ +- asm_volatile_goto("\n" \ ++ asm goto("\n" \ + "1: mov"itype" %0,%1\n" \ + _ASM_EXTABLE_UA(1b, %l2) \ + : : ltype(x), "m" (__m(addr)) \ +@@ -496,7 +496,7 @@ copy_mc_to_kernel(void *to, const void *from, unsigned len); + #define copy_mc_to_kernel copy_mc_to_kernel + + unsigned long __must_check +-copy_mc_to_user(void *to, const void *from, unsigned len); ++copy_mc_to_user(void __user *to, const void *from, unsigned len); + #endif + + /* +diff --git a/arch/x86/include/asm/vsyscall.h b/arch/x86/include/asm/vsyscall.h +index ab60a71a8dcb98..472f0263dbc612 100644 +--- a/arch/x86/include/asm/vsyscall.h ++++ b/arch/x86/include/asm/vsyscall.h +@@ -4,6 +4,7 @@ + + #include + #include ++#include + + #ifdef CONFIG_X86_VSYSCALL_EMULATION + extern void map_vsyscall(void); +@@ -24,4 +25,13 @@ static inline bool emulate_vsyscall(unsigned long error_code, + } + #endif + ++/* ++ * The (legacy) vsyscall page is the long page in the kernel portion ++ * of the address space that has user-accessible permissions. ++ */ ++static inline bool is_vsyscall_vaddr(unsigned long vaddr) ++{ ++ return unlikely((vaddr & PAGE_MASK) == VSYSCALL_ADDR); ++} ++ + #endif /* _ASM_X86_VSYSCALL_H */ +diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h +index 5240d88db52a70..0fe4e482a97b17 100644 +--- a/arch/x86/include/asm/x86_init.h ++++ b/arch/x86/include/asm/x86_init.h +@@ -30,12 +30,13 @@ struct x86_init_mpparse { + * @reserve_resources: reserve the standard resources for the + * platform + * @memory_setup: platform specific memory setup +- * ++ * @dmi_setup: platform specific DMI setup + */ + struct x86_init_resources { + void (*probe_roms)(void); + void (*reserve_resources)(void); + char *(*memory_setup)(void); ++ void (*dmi_setup)(void); + }; + + /** +diff --git a/arch/x86/include/asm/xen/hypervisor.h b/arch/x86/include/asm/xen/hypervisor.h +index 7048dfacc04b24..64fbd2dbc5b761 100644 +--- a/arch/x86/include/asm/xen/hypervisor.h ++++ b/arch/x86/include/asm/xen/hypervisor.h +@@ -62,6 +62,11 @@ void xen_arch_unregister_cpu(int num); + #ifdef CONFIG_PVH + void __init xen_pvh_init(struct boot_params *boot_params); + void __init mem_map_via_hcall(struct boot_params *boot_params_p); ++#ifdef CONFIG_XEN_PVH ++void __init xen_reserve_extra_memory(struct boot_params *bootp); ++#else ++static inline void xen_reserve_extra_memory(struct boot_params *bootp) { } ++#endif + #endif + + /* Lazy mode for batching updates / context switch */ +@@ -100,4 +105,13 @@ static inline void leave_lazy(enum xen_lazy_mode mode) + + enum xen_lazy_mode xen_get_lazy_mode(void); + ++#if defined(CONFIG_XEN_DOM0) && defined(CONFIG_ACPI) ++void xen_sanitize_proc_cap_bits(uint32_t *buf); ++#else ++static inline void xen_sanitize_proc_cap_bits(uint32_t *buf) ++{ ++ BUG(); ++} ++#endif ++ + #endif /* _ASM_X86_XEN_HYPERVISOR_H */ +diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h +index 01d19fc223463d..eeea058cf6028e 100644 +--- a/arch/x86/include/uapi/asm/bootparam.h ++++ b/arch/x86/include/uapi/asm/bootparam.h +@@ -38,6 +38,7 @@ + #define XLF_EFI_KEXEC (1<<4) + #define XLF_5LEVEL (1<<5) + #define XLF_5LEVEL_ENABLED (1<<6) ++#define XLF_MEM_ENCRYPTION (1<<7) + + #ifndef __ASSEMBLY__ + +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index c55c0ef47a187e..49c39f5dc1c992 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1901,3 +1901,14 @@ u64 x86_default_get_root_pointer(void) + { + return boot_params.acpi_rsdp_addr; + } ++ ++#ifdef CONFIG_XEN_PV ++void __iomem *x86_acpi_os_ioremap(acpi_physical_address phys, acpi_size size) ++{ ++ return ioremap_cache(phys, size); ++} ++ ++void __iomem * (*acpi_os_ioremap)(acpi_physical_address phys, acpi_size size) = ++ x86_acpi_os_ioremap; ++EXPORT_SYMBOL_GPL(acpi_os_ioremap); ++#endif +diff --git a/arch/x86/kernel/acpi/cppc.c b/arch/x86/kernel/acpi/cppc.c +index 8d8752b44f1139..ff8f25faca3dd1 100644 +--- a/arch/x86/kernel/acpi/cppc.c ++++ b/arch/x86/kernel/acpi/cppc.c +@@ -20,7 +20,7 @@ bool cpc_supported_by_cpu(void) + (boot_cpu_data.x86_model >= 0x20 && boot_cpu_data.x86_model <= 0x2f))) + return true; + else if (boot_cpu_data.x86 == 0x17 && +- boot_cpu_data.x86_model >= 0x70 && boot_cpu_data.x86_model <= 0x7f) ++ boot_cpu_data.x86_model >= 0x30 && boot_cpu_data.x86_model <= 0x7f) + return true; + return boot_cpu_has(X86_FEATURE_CPPC); + } +diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c +index 73be3931e4f060..aae7456ece0700 100644 +--- a/arch/x86/kernel/alternative.c ++++ b/arch/x86/kernel/alternative.c +@@ -255,6 +255,16 @@ static void __init_or_module noinline optimize_nops(u8 *instr, size_t len) + } + } + ++static void __init_or_module noinline optimize_nops_inplace(u8 *instr, size_t len) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ optimize_nops(instr, len); ++ sync_core(); ++ local_irq_restore(flags); ++} ++ + /* + * In this context, "source" is where the instructions are placed in the + * section .altinstr_replacement, for example during kernel build by the +@@ -438,7 +448,7 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start, + * patch if feature is *NOT* present. + */ + if (!boot_cpu_has(a->cpuid) == !(a->flags & ALT_FLAG_NOT)) { +- optimize_nops(instr, a->instrlen); ++ optimize_nops_inplace(instr, a->instrlen); + continue; + } + +@@ -1685,8 +1695,8 @@ void __init_or_module text_poke_early(void *addr, const void *opcode, + } else { + local_irq_save(flags); + memcpy(addr, opcode, len); +- local_irq_restore(flags); + sync_core(); ++ local_irq_restore(flags); + + /* + * Could also do a CLFLUSH here to speed up CPU recovery; but +diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c +index 356de955e78ddc..6dabb53f58a445 100644 +--- a/arch/x86/kernel/amd_nb.c ++++ b/arch/x86/kernel/amd_nb.c +@@ -26,6 +26,7 @@ + #define PCI_DEVICE_ID_AMD_19H_M70H_ROOT 0x14e8 + #define PCI_DEVICE_ID_AMD_1AH_M00H_ROOT 0x153a + #define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507 ++#define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122 + #define PCI_DEVICE_ID_AMD_MI200_ROOT 0x14bb + + #define PCI_DEVICE_ID_AMD_17H_DF_F4 0x1464 +@@ -61,6 +62,7 @@ static const struct pci_device_id amd_root_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M70H_ROOT) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M00H_ROOT) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_ROOT) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_MI200_ROOT) }, + {} + }; +@@ -92,6 +94,8 @@ static const struct pci_device_id amd_nb_misc_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M78H_DF_F3) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M00H_DF_F3) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_DF_F3) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_DF_F3) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M70H_DF_F3) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_MI200_DF_F3) }, + {} + }; +@@ -112,6 +116,9 @@ static const struct pci_device_id amd_nb_link_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M10H_DF_F4) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M40H_DF_F4) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M50H_DF_F4) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M60H_DF_F4) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M70H_DF_F4) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M78H_DF_F4) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F4) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M00H_DF_F4) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_MI200_DF_F4) }, +@@ -206,7 +213,14 @@ static int __amd_smn_rw(u16 node, u32 address, u32 *value, bool write) + + int amd_smn_read(u16 node, u32 address, u32 *value) + { +- return __amd_smn_rw(node, address, value, false); ++ int err = __amd_smn_rw(node, address, value, false); ++ ++ if (PCI_POSSIBLE_ERROR(*value)) { ++ err = -ENODEV; ++ *value = 0; ++ } ++ ++ return err; + } + EXPORT_SYMBOL_GPL(amd_smn_read); + +diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c +index 760adac3d1a824..00ca9c3c1d8bf8 100644 +--- a/arch/x86/kernel/apic/apic.c ++++ b/arch/x86/kernel/apic/apic.c +@@ -36,6 +36,8 @@ + #include + #include + ++#include ++ + #include + #include + #include +@@ -471,7 +473,19 @@ static int lapic_timer_shutdown(struct clock_event_device *evt) + v = apic_read(APIC_LVTT); + v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR); + apic_write(APIC_LVTT, v); +- apic_write(APIC_TMICT, 0); ++ ++ /* ++ * Setting APIC_LVT_MASKED (above) should be enough to tell ++ * the hardware that this timer will never fire. But AMD ++ * erratum 411 and some Intel CPU behavior circa 2024 say ++ * otherwise. Time for belt and suspenders programming: mask ++ * the timer _and_ zero the counter registers: ++ */ ++ if (v & APIC_LVT_TIMER_TSCDEADLINE) ++ wrmsrl(MSR_IA32_TSC_DEADLINE, 0); ++ else ++ apic_write(APIC_TMICT, 0); ++ + return 0; + } + +@@ -1722,11 +1736,11 @@ static int x2apic_state; + + static bool x2apic_hw_locked(void) + { +- u64 ia32_cap; ++ u64 x86_arch_cap_msr; + u64 msr; + +- ia32_cap = x86_read_arch_cap_msr(); +- if (ia32_cap & ARCH_CAP_XAPIC_DISABLE) { ++ x86_arch_cap_msr = x86_read_arch_cap_msr(); ++ if (x86_arch_cap_msr & ARCH_CAP_XAPIC_DISABLE) { + rdmsrl(MSR_IA32_XAPIC_DISABLE_STATUS, msr); + return (msr & LEGACY_XAPIC_DISABLED); + } +@@ -1806,16 +1820,13 @@ void x2apic_setup(void) + __x2apic_enable(); + } + +-static __init void apic_set_fixmap(void); ++static __init void apic_set_fixmap(bool read_apic); + + static __init void x2apic_disable(void) + { +- u32 x2apic_id, state = x2apic_state; ++ u32 x2apic_id; + +- x2apic_mode = 0; +- x2apic_state = X2APIC_DISABLED; +- +- if (state != X2APIC_ON) ++ if (x2apic_state < X2APIC_ON) + return; + + x2apic_id = read_apic_id(); +@@ -1828,7 +1839,16 @@ static __init void x2apic_disable(void) + } + + __x2apic_disable(); +- apic_set_fixmap(); ++ ++ x2apic_mode = 0; ++ x2apic_state = X2APIC_DISABLED; ++ ++ /* ++ * Don't reread the APIC ID as it was already done from ++ * check_x2apic() and the APIC driver still is a x2APIC variant, ++ * which fails to do the read after x2APIC was disabled. ++ */ ++ apic_set_fixmap(false); + } + + static __init void x2apic_enable(void) +@@ -2093,13 +2113,14 @@ void __init init_apic_mappings(void) + } + } + +-static __init void apic_set_fixmap(void) ++static __init void apic_set_fixmap(bool read_apic) + { + set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr); + apic_mmio_base = APIC_BASE; + apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n", + apic_mmio_base, mp_lapic_addr); +- apic_read_boot_cpu_id(false); ++ if (read_apic) ++ apic_read_boot_cpu_id(false); + } + + void __init register_lapic_address(unsigned long address) +@@ -2109,7 +2130,7 @@ void __init register_lapic_address(unsigned long address) + mp_lapic_addr = address; + + if (!x2apic_mode) +- apic_set_fixmap(); ++ apic_set_fixmap(true); + } + + /* +@@ -2344,6 +2365,15 @@ static int __init smp_init_primary_thread_mask(void) + { + unsigned int cpu; + ++ /* ++ * XEN/PV provides either none or useless topology information. ++ * Pretend that all vCPUs are primary threads. ++ */ ++ if (xen_pv_domain()) { ++ cpumask_copy(&__cpu_primary_thread_mask, cpu_possible_mask); ++ return 0; ++ } ++ + for (cpu = 0; cpu < nr_logical_cpuids; cpu++) + cpu_mark_primary_thread(cpu, cpuid_to_apicid[cpu]); + return 0; +diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c +index 00da6cf6b07dcb..d0c5325d175102 100644 +--- a/arch/x86/kernel/apic/io_apic.c ++++ b/arch/x86/kernel/apic/io_apic.c +@@ -352,27 +352,26 @@ static void ioapic_mask_entry(int apic, int pin) + * shared ISA-space IRQs, so we have to support them. We are super + * fast in the common case, and fast for shared ISA-space IRQs. + */ +-static int __add_pin_to_irq_node(struct mp_chip_data *data, +- int node, int apic, int pin) ++static bool add_pin_to_irq_node(struct mp_chip_data *data, int node, int apic, int pin) + { + struct irq_pin_list *entry; + +- /* don't allow duplicates */ +- for_each_irq_pin(entry, data->irq_2_pin) ++ /* Don't allow duplicates */ ++ for_each_irq_pin(entry, data->irq_2_pin) { + if (entry->apic == apic && entry->pin == pin) +- return 0; ++ return true; ++ } + + entry = kzalloc_node(sizeof(struct irq_pin_list), GFP_ATOMIC, node); + if (!entry) { +- pr_err("can not alloc irq_pin_list (%d,%d,%d)\n", +- node, apic, pin); +- return -ENOMEM; ++ pr_err("Cannot allocate irq_pin_list (%d,%d,%d)\n", node, apic, pin); ++ return false; + } ++ + entry->apic = apic; + entry->pin = pin; + list_add_tail(&entry->list, &data->irq_2_pin); +- +- return 0; ++ return true; + } + + static void __remove_pin_from_irq(struct mp_chip_data *data, int apic, int pin) +@@ -387,13 +386,6 @@ static void __remove_pin_from_irq(struct mp_chip_data *data, int apic, int pin) + } + } + +-static void add_pin_to_irq_node(struct mp_chip_data *data, +- int node, int apic, int pin) +-{ +- if (__add_pin_to_irq_node(data, node, apic, pin)) +- panic("IO-APIC: failed to add irq-pin. Can not proceed\n"); +-} +- + /* + * Reroute an IRQ to a different pin. + */ +@@ -1002,8 +994,7 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain, + if (irq_data && irq_data->parent_data) { + if (!mp_check_pin_attr(irq, info)) + return -EBUSY; +- if (__add_pin_to_irq_node(irq_data->chip_data, node, ioapic, +- info->ioapic.pin)) ++ if (!add_pin_to_irq_node(irq_data->chip_data, node, ioapic, info->ioapic.pin)) + return -ENOMEM; + } else { + info->flags |= X86_IRQ_ALLOC_LEGACY; +@@ -3037,10 +3028,8 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, + return -ENOMEM; + + ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info); +- if (ret < 0) { +- kfree(data); +- return ret; +- } ++ if (ret < 0) ++ goto free_data; + + INIT_LIST_HEAD(&data->irq_2_pin); + irq_data->hwirq = info->ioapic.pin; +@@ -3049,7 +3038,10 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, + irq_data->chip_data = data; + mp_irqdomain_get_attr(mp_pin_to_gsi(ioapic, pin), data, info); + +- add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin); ++ if (!add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin)) { ++ ret = -ENOMEM; ++ goto free_irqs; ++ } + + mp_preconfigure_entry(data); + mp_register_handler(virq, data->is_level); +@@ -3064,6 +3056,12 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, + ioapic, mpc_ioapic_id(ioapic), pin, virq, + data->is_level, data->active_low); + return 0; ++ ++free_irqs: ++ irq_domain_free_irqs_parent(domain, virq, nr_irqs); ++free_data: ++ kfree(data); ++ return ret; + } + + void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq, +diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c +index 6b6b711678fe03..d9651f15ae4f70 100644 +--- a/arch/x86/kernel/apic/msi.c ++++ b/arch/x86/kernel/apic/msi.c +@@ -55,14 +55,14 @@ msi_set_affinity(struct irq_data *irqd, const struct cpumask *mask, bool force) + * caused by the non-atomic update of the address/data pair. + * + * Direct update is possible when: +- * - The MSI is maskable (remapped MSI does not use this code path)). +- * The quirk bit is not set in this case. ++ * - The MSI is maskable (remapped MSI does not use this code path). ++ * The reservation mode bit is set in this case. + * - The new vector is the same as the old vector + * - The old vector is MANAGED_IRQ_SHUTDOWN_VECTOR (interrupt starts up) + * - The interrupt is not yet started up + * - The new destination CPU is the same as the old destination CPU + */ +- if (!irqd_msi_nomask_quirk(irqd) || ++ if (!irqd_can_reserve(irqd) || + cfg->vector == old_cfg.vector || + old_cfg.vector == MANAGED_IRQ_SHUTDOWN_VECTOR || + !irqd_is_started(irqd) || +@@ -215,8 +215,6 @@ static bool x86_init_dev_msi_info(struct device *dev, struct irq_domain *domain, + if (WARN_ON_ONCE(domain != real_parent)) + return false; + info->chip->irq_set_affinity = msi_set_affinity; +- /* See msi_set_affinity() for the gory details */ +- info->flags |= MSI_FLAG_NOMASK_QUIRK; + break; + case DOMAIN_BUS_DMAR: + case DOMAIN_BUS_AMDVI: +diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c +index 319448d87b99a7..218ef9072c0c61 100644 +--- a/arch/x86/kernel/apic/vector.c ++++ b/arch/x86/kernel/apic/vector.c +@@ -1036,7 +1036,8 @@ static void __vector_schedule_cleanup(struct apic_chip_data *apicd) + add_timer_on(&cl->timer, cpu); + } + } else { +- apicd->prev_vector = 0; ++ pr_warn("IRQ %u schedule cleanup for offline CPU %u\n", apicd->irq, cpu); ++ free_moved_vector(apicd); + } + raw_spin_unlock(&vector_lock); + } +@@ -1073,6 +1074,7 @@ void irq_complete_move(struct irq_cfg *cfg) + */ + void irq_force_complete_move(struct irq_desc *desc) + { ++ unsigned int cpu = smp_processor_id(); + struct apic_chip_data *apicd; + struct irq_data *irqd; + unsigned int vector; +@@ -1097,10 +1099,11 @@ void irq_force_complete_move(struct irq_desc *desc) + goto unlock; + + /* +- * If prev_vector is empty, no action required. ++ * If prev_vector is empty or the descriptor is neither currently ++ * nor previously on the outgoing CPU no action required. + */ + vector = apicd->prev_vector; +- if (!vector) ++ if (!vector || (apicd->cpu != cpu && apicd->prev_cpu != cpu)) + goto unlock; + + /* +diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c +index ece2b5b7b0fe4e..145c81c68394be 100644 +--- a/arch/x86/kernel/cpu/amd.c ++++ b/arch/x86/kernel/cpu/amd.c +@@ -66,20 +66,6 @@ static const int amd_erratum_400[] = + static const int amd_erratum_383[] = + AMD_OSVW_ERRATUM(3, AMD_MODEL_RANGE(0x10, 0, 0, 0xff, 0xf)); + +-/* #1054: Instructions Retired Performance Counter May Be Inaccurate */ +-static const int amd_erratum_1054[] = +- AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0, 0, 0x2f, 0xf)); +- +-static const int amd_zenbleed[] = +- AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x30, 0x0, 0x4f, 0xf), +- AMD_MODEL_RANGE(0x17, 0x60, 0x0, 0x7f, 0xf), +- AMD_MODEL_RANGE(0x17, 0x90, 0x0, 0x91, 0xf), +- AMD_MODEL_RANGE(0x17, 0xa0, 0x0, 0xaf, 0xf)); +- +-static const int amd_div0[] = +- AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x00, 0x0, 0x2f, 0xf), +- AMD_MODEL_RANGE(0x17, 0x50, 0x0, 0x5f, 0xf)); +- + static const int amd_erratum_1485[] = + AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x19, 0x10, 0x0, 0x1f, 0xf), + AMD_MODEL_RANGE(0x19, 0x60, 0x0, 0xaf, 0xf)); +@@ -620,6 +606,49 @@ static void bsp_init_amd(struct cpuinfo_x86 *c) + } + + resctrl_cpu_detect(c); ++ ++ /* Figure out Zen generations: */ ++ switch (c->x86) { ++ case 0x17: { ++ switch (c->x86_model) { ++ case 0x00 ... 0x2f: ++ case 0x50 ... 0x5f: ++ setup_force_cpu_cap(X86_FEATURE_ZEN1); ++ break; ++ case 0x30 ... 0x4f: ++ case 0x60 ... 0x7f: ++ case 0x90 ... 0x91: ++ case 0xa0 ... 0xaf: ++ setup_force_cpu_cap(X86_FEATURE_ZEN2); ++ break; ++ default: ++ goto warn; ++ } ++ break; ++ } ++ case 0x19: { ++ switch (c->x86_model) { ++ case 0x00 ... 0x0f: ++ case 0x20 ... 0x5f: ++ setup_force_cpu_cap(X86_FEATURE_ZEN3); ++ break; ++ case 0x10 ... 0x1f: ++ case 0x60 ... 0xaf: ++ setup_force_cpu_cap(X86_FEATURE_ZEN4); ++ break; ++ default: ++ goto warn; ++ } ++ break; ++ } ++ default: ++ break; ++ } ++ ++ return; ++ ++warn: ++ WARN_ONCE(1, "Family 0x%x, model: 0x%x??\n", c->x86, c->x86_model); + } + + static void early_detect_mem_encrypt(struct cpuinfo_x86 *c) +@@ -945,6 +974,19 @@ static void init_amd_bd(struct cpuinfo_x86 *c) + clear_rdrand_cpuid_bit(c); + } + ++static void fix_erratum_1386(struct cpuinfo_x86 *c) ++{ ++ /* ++ * Work around Erratum 1386. The XSAVES instruction malfunctions in ++ * certain circumstances on Zen1/2 uarch, and not all parts have had ++ * updated microcode at the time of writing (March 2023). ++ * ++ * Affected parts all have no supervisor XSAVE states, meaning that ++ * the XSAVEC instruction (which works fine) is equivalent. ++ */ ++ clear_cpu_cap(c, X86_FEATURE_XSAVES); ++} ++ + void init_spectral_chicken(struct cpuinfo_x86 *c) + { + #ifdef CONFIG_CPU_UNRET_ENTRY +@@ -965,24 +1007,19 @@ void init_spectral_chicken(struct cpuinfo_x86 *c) + } + } + #endif +- /* +- * Work around Erratum 1386. The XSAVES instruction malfunctions in +- * certain circumstances on Zen1/2 uarch, and not all parts have had +- * updated microcode at the time of writing (March 2023). +- * +- * Affected parts all have no supervisor XSAVE states, meaning that +- * the XSAVEC instruction (which works fine) is equivalent. +- */ +- clear_cpu_cap(c, X86_FEATURE_XSAVES); + } + + static void init_amd_zn(struct cpuinfo_x86 *c) + { +- set_cpu_cap(c, X86_FEATURE_ZEN); +- ++ setup_force_cpu_cap(X86_FEATURE_ZEN); + #ifdef CONFIG_NUMA + node_reclaim_distance = 32; + #endif ++} ++ ++static void init_amd_zen1(struct cpuinfo_x86 *c) ++{ ++ fix_erratum_1386(c); + + /* Fix up CPUID bits, but only if not virtualised. */ + if (!cpu_has(c, X86_FEATURE_HYPERVISOR)) { +@@ -999,6 +1036,9 @@ static void init_amd_zn(struct cpuinfo_x86 *c) + if (c->x86 == 0x19 && !cpu_has(c, X86_FEATURE_BTC_NO)) + set_cpu_cap(c, X86_FEATURE_BTC_NO); + } ++ ++ pr_notice_once("AMD Zen1 DIV0 bug detected. Disable SMT for full protection.\n"); ++ setup_force_cpu_bug(X86_BUG_DIV0); + } + + static bool cpu_has_zenbleed_microcode(void) +@@ -1006,11 +1046,11 @@ static bool cpu_has_zenbleed_microcode(void) + u32 good_rev = 0; + + switch (boot_cpu_data.x86_model) { +- case 0x30 ... 0x3f: good_rev = 0x0830107a; break; +- case 0x60 ... 0x67: good_rev = 0x0860010b; break; +- case 0x68 ... 0x6f: good_rev = 0x08608105; break; +- case 0x70 ... 0x7f: good_rev = 0x08701032; break; +- case 0xa0 ... 0xaf: good_rev = 0x08a00008; break; ++ case 0x30 ... 0x3f: good_rev = 0x0830107b; break; ++ case 0x60 ... 0x67: good_rev = 0x0860010c; break; ++ case 0x68 ... 0x6f: good_rev = 0x08608107; break; ++ case 0x70 ... 0x7f: good_rev = 0x08701033; break; ++ case 0xa0 ... 0xaf: good_rev = 0x08a00009; break; + + default: + return false; +@@ -1023,11 +1063,8 @@ static bool cpu_has_zenbleed_microcode(void) + return true; + } + +-static void zenbleed_check(struct cpuinfo_x86 *c) ++static void zen2_zenbleed_check(struct cpuinfo_x86 *c) + { +- if (!cpu_has_amd_erratum(c, amd_zenbleed)) +- return; +- + if (cpu_has(c, X86_FEATURE_HYPERVISOR)) + return; + +@@ -1042,6 +1079,20 @@ static void zenbleed_check(struct cpuinfo_x86 *c) + } + } + ++static void init_amd_zen2(struct cpuinfo_x86 *c) ++{ ++ fix_erratum_1386(c); ++ zen2_zenbleed_check(c); ++} ++ ++static void init_amd_zen3(struct cpuinfo_x86 *c) ++{ ++} ++ ++static void init_amd_zen4(struct cpuinfo_x86 *c) ++{ ++} ++ + static void init_amd(struct cpuinfo_x86 *c) + { + early_init_amd(c); +@@ -1080,6 +1131,15 @@ static void init_amd(struct cpuinfo_x86 *c) + case 0x19: init_amd_zn(c); break; + } + ++ if (boot_cpu_has(X86_FEATURE_ZEN1)) ++ init_amd_zen1(c); ++ else if (boot_cpu_has(X86_FEATURE_ZEN2)) ++ init_amd_zen2(c); ++ else if (boot_cpu_has(X86_FEATURE_ZEN3)) ++ init_amd_zen3(c); ++ else if (boot_cpu_has(X86_FEATURE_ZEN4)) ++ init_amd_zen4(c); ++ + /* + * Enable workaround for FXSAVE leak on CPUs + * without a XSaveErPtr feature +@@ -1131,7 +1191,7 @@ static void init_amd(struct cpuinfo_x86 *c) + * Counter May Be Inaccurate". + */ + if (cpu_has(c, X86_FEATURE_IRPERF) && +- !cpu_has_amd_erratum(c, amd_erratum_1054)) ++ (boot_cpu_has(X86_FEATURE_ZEN1) && c->x86_model > 0x2f)) + msr_set_bit(MSR_K7_HWCR, MSR_K7_HWCR_IRPERF_EN_BIT); + + check_null_seg_clears_base(c); +@@ -1147,16 +1207,12 @@ static void init_amd(struct cpuinfo_x86 *c) + cpu_has(c, X86_FEATURE_AUTOIBRS)) + WARN_ON_ONCE(msr_set_bit(MSR_EFER, _EFER_AUTOIBRS)); + +- zenbleed_check(c); +- +- if (cpu_has_amd_erratum(c, amd_div0)) { +- pr_notice_once("AMD Zen1 DIV0 bug detected. Disable SMT for full protection.\n"); +- setup_force_cpu_bug(X86_BUG_DIV0); +- } +- + if (!cpu_has(c, X86_FEATURE_HYPERVISOR) && + cpu_has_amd_erratum(c, amd_erratum_1485)) + msr_set_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT); ++ ++ /* AMD CPUs don't need fencing after x2APIC/TSC_DEADLINE MSR writes. */ ++ clear_cpu_cap(c, X86_FEATURE_APIC_MSRS_FENCE); + } + + #ifdef CONFIG_X86_32 +@@ -1310,12 +1366,16 @@ static void zenbleed_check_cpu(void *unused) + { + struct cpuinfo_x86 *c = &cpu_data(smp_processor_id()); + +- zenbleed_check(c); ++ zen2_zenbleed_check(c); + } + + void amd_check_microcode(void) + { +- on_each_cpu(zenbleed_check_cpu, NULL, 1); ++ if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) ++ return; ++ ++ if (cpu_feature_enabled(X86_FEATURE_ZEN2)) ++ on_each_cpu(zenbleed_check_cpu, NULL, 1); + } + + /* +diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c +index 10499bcd4e3962..7b5ba5b8592a25 100644 +--- a/arch/x86/kernel/cpu/bugs.c ++++ b/arch/x86/kernel/cpu/bugs.c +@@ -61,9 +61,11 @@ EXPORT_SYMBOL_GPL(x86_spec_ctrl_current); + u64 x86_pred_cmd __ro_after_init = PRED_CMD_IBPB; + EXPORT_SYMBOL_GPL(x86_pred_cmd); + ++static u64 __ro_after_init x86_arch_cap_msr; ++ + static DEFINE_MUTEX(spec_ctrl_mutex); + +-void (*x86_return_thunk)(void) __ro_after_init = &__x86_return_thunk; ++void (*x86_return_thunk)(void) __ro_after_init = __x86_return_thunk; + + /* Update SPEC_CTRL MSR and its cached copy unconditionally */ + static void update_spec_ctrl(u64 val) +@@ -111,9 +113,6 @@ DEFINE_STATIC_KEY_FALSE(switch_mm_cond_ibpb); + /* Control unconditional IBPB in switch_mm() */ + DEFINE_STATIC_KEY_FALSE(switch_mm_always_ibpb); + +-/* Control MDS CPU buffer clear before returning to user space */ +-DEFINE_STATIC_KEY_FALSE(mds_user_clear); +-EXPORT_SYMBOL_GPL(mds_user_clear); + /* Control MDS CPU buffer clear before idling (halt, mwait) */ + DEFINE_STATIC_KEY_FALSE(mds_idle_clear); + EXPORT_SYMBOL_GPL(mds_idle_clear); +@@ -147,6 +146,8 @@ void __init cpu_select_mitigations(void) + x86_spec_ctrl_base &= ~SPEC_CTRL_MITIGATIONS_MASK; + } + ++ x86_arch_cap_msr = x86_read_arch_cap_msr(); ++ + /* Select the proper CPU mitigations before patching alternatives: */ + spectre_v1_select_mitigation(); + spectre_v2_select_mitigation(); +@@ -252,7 +253,7 @@ static void __init mds_select_mitigation(void) + if (!boot_cpu_has(X86_FEATURE_MD_CLEAR)) + mds_mitigation = MDS_MITIGATION_VMWERV; + +- static_branch_enable(&mds_user_clear); ++ setup_force_cpu_cap(X86_FEATURE_CLEAR_CPU_BUF); + + if (!boot_cpu_has(X86_BUG_MSBDS_ONLY) && + (mds_nosmt || cpu_mitigations_auto_nosmt())) +@@ -304,8 +305,6 @@ static const char * const taa_strings[] = { + + static void __init taa_select_mitigation(void) + { +- u64 ia32_cap; +- + if (!boot_cpu_has_bug(X86_BUG_TAA)) { + taa_mitigation = TAA_MITIGATION_OFF; + return; +@@ -344,9 +343,8 @@ static void __init taa_select_mitigation(void) + * On MDS_NO=1 CPUs if ARCH_CAP_TSX_CTRL_MSR is not set, microcode + * update is required. + */ +- ia32_cap = x86_read_arch_cap_msr(); +- if ( (ia32_cap & ARCH_CAP_MDS_NO) && +- !(ia32_cap & ARCH_CAP_TSX_CTRL_MSR)) ++ if ( (x86_arch_cap_msr & ARCH_CAP_MDS_NO) && ++ !(x86_arch_cap_msr & ARCH_CAP_TSX_CTRL_MSR)) + taa_mitigation = TAA_MITIGATION_UCODE_NEEDED; + + /* +@@ -356,7 +354,7 @@ static void __init taa_select_mitigation(void) + * For guests that can't determine whether the correct microcode is + * present on host, enable the mitigation for UCODE_NEEDED as well. + */ +- static_branch_enable(&mds_user_clear); ++ setup_force_cpu_cap(X86_FEATURE_CLEAR_CPU_BUF); + + if (taa_nosmt || cpu_mitigations_auto_nosmt()) + cpu_smt_disable(false); +@@ -404,8 +402,6 @@ static const char * const mmio_strings[] = { + + static void __init mmio_select_mitigation(void) + { +- u64 ia32_cap; +- + if (!boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA) || + boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN) || + cpu_mitigations_off()) { +@@ -416,15 +412,20 @@ static void __init mmio_select_mitigation(void) + if (mmio_mitigation == MMIO_MITIGATION_OFF) + return; + +- ia32_cap = x86_read_arch_cap_msr(); +- + /* + * Enable CPU buffer clear mitigation for host and VMM, if also affected + * by MDS or TAA. Otherwise, enable mitigation for VMM only. + */ + if (boot_cpu_has_bug(X86_BUG_MDS) || (boot_cpu_has_bug(X86_BUG_TAA) && + boot_cpu_has(X86_FEATURE_RTM))) +- static_branch_enable(&mds_user_clear); ++ setup_force_cpu_cap(X86_FEATURE_CLEAR_CPU_BUF); ++ ++ /* ++ * X86_FEATURE_CLEAR_CPU_BUF could be enabled by other VERW based ++ * mitigations, disable KVM-only mitigation in that case. ++ */ ++ if (boot_cpu_has(X86_FEATURE_CLEAR_CPU_BUF)) ++ static_branch_disable(&mmio_stale_data_clear); + else + static_branch_enable(&mmio_stale_data_clear); + +@@ -433,7 +434,7 @@ static void __init mmio_select_mitigation(void) + * be propagated to uncore buffers, clearing the Fill buffers on idle + * is required irrespective of SMT state. + */ +- if (!(ia32_cap & ARCH_CAP_FBSDP_NO)) ++ if (!(x86_arch_cap_msr & ARCH_CAP_FBSDP_NO)) + static_branch_enable(&mds_idle_clear); + + /* +@@ -443,10 +444,10 @@ static void __init mmio_select_mitigation(void) + * FB_CLEAR or by the presence of both MD_CLEAR and L1D_FLUSH on MDS + * affected systems. + */ +- if ((ia32_cap & ARCH_CAP_FB_CLEAR) || ++ if ((x86_arch_cap_msr & ARCH_CAP_FB_CLEAR) || + (boot_cpu_has(X86_FEATURE_MD_CLEAR) && + boot_cpu_has(X86_FEATURE_FLUSH_L1D) && +- !(ia32_cap & ARCH_CAP_MDS_NO))) ++ !(x86_arch_cap_msr & ARCH_CAP_MDS_NO))) + mmio_mitigation = MMIO_MITIGATION_VERW; + else + mmio_mitigation = MMIO_MITIGATION_UCODE_NEEDED; +@@ -476,6 +477,57 @@ static int __init mmio_stale_data_parse_cmdline(char *str) + } + early_param("mmio_stale_data", mmio_stale_data_parse_cmdline); + ++#undef pr_fmt ++#define pr_fmt(fmt) "Register File Data Sampling: " fmt ++ ++enum rfds_mitigations { ++ RFDS_MITIGATION_OFF, ++ RFDS_MITIGATION_VERW, ++ RFDS_MITIGATION_UCODE_NEEDED, ++}; ++ ++/* Default mitigation for Register File Data Sampling */ ++static enum rfds_mitigations rfds_mitigation __ro_after_init = ++ IS_ENABLED(CONFIG_MITIGATION_RFDS) ? RFDS_MITIGATION_VERW : RFDS_MITIGATION_OFF; ++ ++static const char * const rfds_strings[] = { ++ [RFDS_MITIGATION_OFF] = "Vulnerable", ++ [RFDS_MITIGATION_VERW] = "Mitigation: Clear Register File", ++ [RFDS_MITIGATION_UCODE_NEEDED] = "Vulnerable: No microcode", ++}; ++ ++static void __init rfds_select_mitigation(void) ++{ ++ if (!boot_cpu_has_bug(X86_BUG_RFDS) || cpu_mitigations_off()) { ++ rfds_mitigation = RFDS_MITIGATION_OFF; ++ return; ++ } ++ if (rfds_mitigation == RFDS_MITIGATION_OFF) ++ return; ++ ++ if (x86_arch_cap_msr & ARCH_CAP_RFDS_CLEAR) ++ setup_force_cpu_cap(X86_FEATURE_CLEAR_CPU_BUF); ++ else ++ rfds_mitigation = RFDS_MITIGATION_UCODE_NEEDED; ++} ++ ++static __init int rfds_parse_cmdline(char *str) ++{ ++ if (!str) ++ return -EINVAL; ++ ++ if (!boot_cpu_has_bug(X86_BUG_RFDS)) ++ return 0; ++ ++ if (!strcmp(str, "off")) ++ rfds_mitigation = RFDS_MITIGATION_OFF; ++ else if (!strcmp(str, "on")) ++ rfds_mitigation = RFDS_MITIGATION_VERW; ++ ++ return 0; ++} ++early_param("reg_file_data_sampling", rfds_parse_cmdline); ++ + #undef pr_fmt + #define pr_fmt(fmt) "" fmt + +@@ -484,12 +536,12 @@ static void __init md_clear_update_mitigation(void) + if (cpu_mitigations_off()) + return; + +- if (!static_key_enabled(&mds_user_clear)) ++ if (!boot_cpu_has(X86_FEATURE_CLEAR_CPU_BUF)) + goto out; + + /* +- * mds_user_clear is now enabled. Update MDS, TAA and MMIO Stale Data +- * mitigation, if necessary. ++ * X86_FEATURE_CLEAR_CPU_BUF is now enabled. Update MDS, TAA and MMIO ++ * Stale Data mitigation, if necessary. + */ + if (mds_mitigation == MDS_MITIGATION_OFF && + boot_cpu_has_bug(X86_BUG_MDS)) { +@@ -501,11 +553,19 @@ static void __init md_clear_update_mitigation(void) + taa_mitigation = TAA_MITIGATION_VERW; + taa_select_mitigation(); + } +- if (mmio_mitigation == MMIO_MITIGATION_OFF && +- boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA)) { ++ /* ++ * MMIO_MITIGATION_OFF is not checked here so that mmio_stale_data_clear ++ * gets updated correctly as per X86_FEATURE_CLEAR_CPU_BUF state. ++ */ ++ if (boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA)) { + mmio_mitigation = MMIO_MITIGATION_VERW; + mmio_select_mitigation(); + } ++ if (rfds_mitigation == RFDS_MITIGATION_OFF && ++ boot_cpu_has_bug(X86_BUG_RFDS)) { ++ rfds_mitigation = RFDS_MITIGATION_VERW; ++ rfds_select_mitigation(); ++ } + out: + if (boot_cpu_has_bug(X86_BUG_MDS)) + pr_info("MDS: %s\n", mds_strings[mds_mitigation]); +@@ -515,6 +575,8 @@ static void __init md_clear_update_mitigation(void) + pr_info("MMIO Stale Data: %s\n", mmio_strings[mmio_mitigation]); + else if (boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN)) + pr_info("MMIO Stale Data: Unknown: No mitigations\n"); ++ if (boot_cpu_has_bug(X86_BUG_RFDS)) ++ pr_info("Register File Data Sampling: %s\n", rfds_strings[rfds_mitigation]); + } + + static void __init md_clear_select_mitigation(void) +@@ -522,11 +584,12 @@ static void __init md_clear_select_mitigation(void) + mds_select_mitigation(); + taa_select_mitigation(); + mmio_select_mitigation(); ++ rfds_select_mitigation(); + + /* +- * As MDS, TAA and MMIO Stale Data mitigations are inter-related, update +- * and print their mitigation after MDS, TAA and MMIO Stale Data +- * mitigation selection is done. ++ * As these mitigations are inter-related and rely on VERW instruction ++ * to clear the microarchitural buffers, update and print their status ++ * after mitigation selection is done for each of these vulnerabilities. + */ + md_clear_update_mitigation(); + } +@@ -593,8 +656,6 @@ void update_srbds_msr(void) + + static void __init srbds_select_mitigation(void) + { +- u64 ia32_cap; +- + if (!boot_cpu_has_bug(X86_BUG_SRBDS)) + return; + +@@ -603,8 +664,7 @@ static void __init srbds_select_mitigation(void) + * are only exposed to SRBDS when TSX is enabled or when CPU is affected + * by Processor MMIO Stale Data vulnerability. + */ +- ia32_cap = x86_read_arch_cap_msr(); +- if ((ia32_cap & ARCH_CAP_MDS_NO) && !boot_cpu_has(X86_FEATURE_RTM) && ++ if ((x86_arch_cap_msr & ARCH_CAP_MDS_NO) && !boot_cpu_has(X86_FEATURE_RTM) && + !boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA)) + srbds_mitigation = SRBDS_MITIGATION_TSX_OFF; + else if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) +@@ -747,7 +807,7 @@ static void __init gds_select_mitigation(void) + /* Will verify below that mitigation _can_ be disabled */ + + /* No microcode */ +- if (!(x86_read_arch_cap_msr() & ARCH_CAP_GDS_CTRL)) { ++ if (!(x86_arch_cap_msr & ARCH_CAP_GDS_CTRL)) { + if (gds_mitigation == GDS_MITIGATION_FORCE) { + /* + * This only needs to be done on the boot CPU so do it +@@ -1042,8 +1102,7 @@ static void __init retbleed_select_mitigation(void) + setup_force_cpu_cap(X86_FEATURE_RETHUNK); + setup_force_cpu_cap(X86_FEATURE_UNRET); + +- if (IS_ENABLED(CONFIG_RETHUNK)) +- x86_return_thunk = retbleed_return_thunk; ++ x86_return_thunk = retbleed_return_thunk; + + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD && + boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) +@@ -1054,8 +1113,25 @@ static void __init retbleed_select_mitigation(void) + + case RETBLEED_MITIGATION_IBPB: + setup_force_cpu_cap(X86_FEATURE_ENTRY_IBPB); ++ ++ /* ++ * IBPB on entry already obviates the need for ++ * software-based untraining so clear those in case some ++ * other mitigation like SRSO has selected them. ++ */ ++ setup_clear_cpu_cap(X86_FEATURE_UNRET); ++ setup_clear_cpu_cap(X86_FEATURE_RETHUNK); ++ + setup_force_cpu_cap(X86_FEATURE_IBPB_ON_VMEXIT); + mitigate_smt = true; ++ ++ /* ++ * There is no need for RSB filling: entry_ibpb() ensures ++ * all predictions, including the RSB, are invalidated, ++ * regardless of IBPB implementation. ++ */ ++ setup_clear_cpu_cap(X86_FEATURE_RSB_VMEXIT); ++ + break; + + case RETBLEED_MITIGATION_STUFF: +@@ -1478,20 +1554,25 @@ static enum spectre_v2_mitigation __init spectre_v2_select_retpoline(void) + return SPECTRE_V2_RETPOLINE; + } + ++static bool __ro_after_init rrsba_disabled; ++ + /* Disable in-kernel use of non-RSB RET predictors */ + static void __init spec_ctrl_disable_kernel_rrsba(void) + { +- u64 ia32_cap; ++ if (rrsba_disabled) ++ return; + +- if (!boot_cpu_has(X86_FEATURE_RRSBA_CTRL)) ++ if (!(x86_arch_cap_msr & ARCH_CAP_RRSBA)) { ++ rrsba_disabled = true; + return; ++ } + +- ia32_cap = x86_read_arch_cap_msr(); ++ if (!boot_cpu_has(X86_FEATURE_RRSBA_CTRL)) ++ return; + +- if (ia32_cap & ARCH_CAP_RRSBA) { +- x86_spec_ctrl_base |= SPEC_CTRL_RRSBA_DIS_S; +- update_spec_ctrl(x86_spec_ctrl_base); +- } ++ x86_spec_ctrl_base |= SPEC_CTRL_RRSBA_DIS_S; ++ update_spec_ctrl(x86_spec_ctrl_base); ++ rrsba_disabled = true; + } + + static void __init spectre_v2_determine_rsb_fill_type_at_vmexit(enum spectre_v2_mitigation mode) +@@ -1541,6 +1622,74 @@ static void __init spectre_v2_determine_rsb_fill_type_at_vmexit(enum spectre_v2_ + dump_stack(); + } + ++/* ++ * Set BHI_DIS_S to prevent indirect branches in kernel to be influenced by ++ * branch history in userspace. Not needed if BHI_NO is set. ++ */ ++static bool __init spec_ctrl_bhi_dis(void) ++{ ++ if (!boot_cpu_has(X86_FEATURE_BHI_CTRL)) ++ return false; ++ ++ x86_spec_ctrl_base |= SPEC_CTRL_BHI_DIS_S; ++ update_spec_ctrl(x86_spec_ctrl_base); ++ setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_HW); ++ ++ return true; ++} ++ ++enum bhi_mitigations { ++ BHI_MITIGATION_OFF, ++ BHI_MITIGATION_ON, ++}; ++ ++static enum bhi_mitigations bhi_mitigation __ro_after_init = ++ IS_ENABLED(CONFIG_MITIGATION_SPECTRE_BHI) ? BHI_MITIGATION_ON : BHI_MITIGATION_OFF; ++ ++static int __init spectre_bhi_parse_cmdline(char *str) ++{ ++ if (!str) ++ return -EINVAL; ++ ++ if (!strcmp(str, "off")) ++ bhi_mitigation = BHI_MITIGATION_OFF; ++ else if (!strcmp(str, "on")) ++ bhi_mitigation = BHI_MITIGATION_ON; ++ else ++ pr_err("Ignoring unknown spectre_bhi option (%s)", str); ++ ++ return 0; ++} ++early_param("spectre_bhi", spectre_bhi_parse_cmdline); ++ ++static void __init bhi_select_mitigation(void) ++{ ++ if (bhi_mitigation == BHI_MITIGATION_OFF) ++ return; ++ ++ /* Retpoline mitigates against BHI unless the CPU has RRSBA behavior */ ++ if (boot_cpu_has(X86_FEATURE_RETPOLINE) && ++ !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE)) { ++ spec_ctrl_disable_kernel_rrsba(); ++ if (rrsba_disabled) ++ return; ++ } ++ ++ if (spec_ctrl_bhi_dis()) ++ return; ++ ++ if (!IS_ENABLED(CONFIG_X86_64)) ++ return; ++ ++ /* Mitigate KVM by default */ ++ setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT); ++ pr_info("Spectre BHI mitigation: SW BHB clearing on vm exit\n"); ++ ++ /* Mitigate syscalls when the mitigation is forced =on */ ++ setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_LOOP); ++ pr_info("Spectre BHI mitigation: SW BHB clearing on syscall\n"); ++} ++ + static void __init spectre_v2_select_mitigation(void) + { + enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline(); +@@ -1652,6 +1801,9 @@ static void __init spectre_v2_select_mitigation(void) + mode == SPECTRE_V2_RETPOLINE) + spec_ctrl_disable_kernel_rrsba(); + ++ if (boot_cpu_has(X86_BUG_BHI)) ++ bhi_select_mitigation(); ++ + spectre_v2_enabled = mode; + pr_info("%s\n", spectre_v2_strings[mode]); + +@@ -1766,8 +1918,6 @@ static void update_indir_branch_cond(void) + /* Update the static key controlling the MDS CPU buffer clear in idle */ + static void update_mds_branch_idle(void) + { +- u64 ia32_cap = x86_read_arch_cap_msr(); +- + /* + * Enable the idle clearing if SMT is active on CPUs which are + * affected only by MSBDS and not any other MDS variant. +@@ -1782,7 +1932,7 @@ static void update_mds_branch_idle(void) + if (sched_smt_active()) { + static_branch_enable(&mds_idle_clear); + } else if (mmio_mitigation == MMIO_MITIGATION_OFF || +- (ia32_cap & ARCH_CAP_FBSDP_NO)) { ++ (x86_arch_cap_msr & ARCH_CAP_FBSDP_NO)) { + static_branch_disable(&mds_idle_clear); + } + } +@@ -2353,6 +2503,8 @@ early_param("l1tf", l1tf_cmdline); + + enum srso_mitigation { + SRSO_MITIGATION_NONE, ++ SRSO_MITIGATION_UCODE_NEEDED, ++ SRSO_MITIGATION_SAFE_RET_UCODE_NEEDED, + SRSO_MITIGATION_MICROCODE, + SRSO_MITIGATION_SAFE_RET, + SRSO_MITIGATION_IBPB, +@@ -2368,11 +2520,13 @@ enum srso_mitigation_cmd { + }; + + static const char * const srso_strings[] = { +- [SRSO_MITIGATION_NONE] = "Vulnerable", +- [SRSO_MITIGATION_MICROCODE] = "Mitigation: microcode", +- [SRSO_MITIGATION_SAFE_RET] = "Mitigation: safe RET", +- [SRSO_MITIGATION_IBPB] = "Mitigation: IBPB", +- [SRSO_MITIGATION_IBPB_ON_VMEXIT] = "Mitigation: IBPB on VMEXIT only" ++ [SRSO_MITIGATION_NONE] = "Vulnerable", ++ [SRSO_MITIGATION_UCODE_NEEDED] = "Vulnerable: No microcode", ++ [SRSO_MITIGATION_SAFE_RET_UCODE_NEEDED] = "Vulnerable: Safe RET, no microcode", ++ [SRSO_MITIGATION_MICROCODE] = "Vulnerable: Microcode, no safe RET", ++ [SRSO_MITIGATION_SAFE_RET] = "Mitigation: Safe RET", ++ [SRSO_MITIGATION_IBPB] = "Mitigation: IBPB", ++ [SRSO_MITIGATION_IBPB_ON_VMEXIT] = "Mitigation: IBPB on VMEXIT only" + }; + + static enum srso_mitigation srso_mitigation __ro_after_init = SRSO_MITIGATION_NONE; +@@ -2409,10 +2563,7 @@ static void __init srso_select_mitigation(void) + if (!boot_cpu_has_bug(X86_BUG_SRSO) || cpu_mitigations_off()) + goto pred_cmd; + +- if (!has_microcode) { +- pr_warn("IBPB-extending microcode not applied!\n"); +- pr_warn(SRSO_NOTICE); +- } else { ++ if (has_microcode) { + /* + * Zen1/2 with SMT off aren't vulnerable after the right + * IBPB microcode has been applied. +@@ -2421,14 +2572,17 @@ static void __init srso_select_mitigation(void) + setup_force_cpu_cap(X86_FEATURE_SRSO_NO); + return; + } +- } + +- if (retbleed_mitigation == RETBLEED_MITIGATION_IBPB) { +- if (has_microcode) { +- pr_err("Retbleed IBPB mitigation enabled, using same for SRSO\n"); ++ if (retbleed_mitigation == RETBLEED_MITIGATION_IBPB) { + srso_mitigation = SRSO_MITIGATION_IBPB; +- goto pred_cmd; ++ goto out; + } ++ } else { ++ pr_warn("IBPB-extending microcode not applied!\n"); ++ pr_warn(SRSO_NOTICE); ++ ++ /* may be overwritten by SRSO_CMD_SAFE_RET below */ ++ srso_mitigation = SRSO_MITIGATION_UCODE_NEEDED; + } + + switch (srso_cmd) { +@@ -2458,7 +2612,10 @@ static void __init srso_select_mitigation(void) + setup_force_cpu_cap(X86_FEATURE_SRSO); + x86_return_thunk = srso_return_thunk; + } +- srso_mitigation = SRSO_MITIGATION_SAFE_RET; ++ if (has_microcode) ++ srso_mitigation = SRSO_MITIGATION_SAFE_RET; ++ else ++ srso_mitigation = SRSO_MITIGATION_SAFE_RET_UCODE_NEEDED; + } else { + pr_err("WARNING: kernel not compiled with CPU_SRSO.\n"); + goto pred_cmd; +@@ -2470,6 +2627,14 @@ static void __init srso_select_mitigation(void) + if (has_microcode) { + setup_force_cpu_cap(X86_FEATURE_ENTRY_IBPB); + srso_mitigation = SRSO_MITIGATION_IBPB; ++ ++ /* ++ * IBPB on entry already obviates the need for ++ * software-based untraining so clear those in case some ++ * other mitigation like Retbleed has selected them. ++ */ ++ setup_clear_cpu_cap(X86_FEATURE_UNRET); ++ setup_clear_cpu_cap(X86_FEATURE_RETHUNK); + } + } else { + pr_err("WARNING: kernel not compiled with CPU_IBPB_ENTRY.\n"); +@@ -2482,6 +2647,13 @@ static void __init srso_select_mitigation(void) + if (!boot_cpu_has(X86_FEATURE_ENTRY_IBPB) && has_microcode) { + setup_force_cpu_cap(X86_FEATURE_IBPB_ON_VMEXIT); + srso_mitigation = SRSO_MITIGATION_IBPB_ON_VMEXIT; ++ ++ /* ++ * There is no need for RSB filling: entry_ibpb() ensures ++ * all predictions, including the RSB, are invalidated, ++ * regardless of IBPB implementation. ++ */ ++ setup_clear_cpu_cap(X86_FEATURE_RSB_VMEXIT); + } + } else { + pr_err("WARNING: kernel not compiled with CPU_SRSO.\n"); +@@ -2493,10 +2665,11 @@ static void __init srso_select_mitigation(void) + break; + } + +- pr_info("%s%s\n", srso_strings[srso_mitigation], (has_microcode ? "" : ", no microcode")); ++out: ++ pr_info("%s\n", srso_strings[srso_mitigation]); + + pred_cmd: +- if ((boot_cpu_has(X86_FEATURE_SRSO_NO) || srso_cmd == SRSO_CMD_OFF) && ++ if ((!boot_cpu_has_bug(X86_BUG_SRSO) || srso_cmd == SRSO_CMD_OFF) && + boot_cpu_has(X86_FEATURE_SBPB)) + x86_pred_cmd = PRED_CMD_SBPB; + } +@@ -2608,6 +2781,11 @@ static ssize_t mmio_stale_data_show_state(char *buf) + sched_smt_active() ? "vulnerable" : "disabled"); + } + ++static ssize_t rfds_show_state(char *buf) ++{ ++ return sysfs_emit(buf, "%s\n", rfds_strings[rfds_mitigation]); ++} ++ + static char *stibp_state(void) + { + if (spectre_v2_in_eibrs_mode(spectre_v2_enabled) && +@@ -2616,15 +2794,15 @@ static char *stibp_state(void) + + switch (spectre_v2_user_stibp) { + case SPECTRE_V2_USER_NONE: +- return ", STIBP: disabled"; ++ return "; STIBP: disabled"; + case SPECTRE_V2_USER_STRICT: +- return ", STIBP: forced"; ++ return "; STIBP: forced"; + case SPECTRE_V2_USER_STRICT_PREFERRED: +- return ", STIBP: always-on"; ++ return "; STIBP: always-on"; + case SPECTRE_V2_USER_PRCTL: + case SPECTRE_V2_USER_SECCOMP: + if (static_key_enabled(&switch_to_cond_stibp)) +- return ", STIBP: conditional"; ++ return "; STIBP: conditional"; + } + return ""; + } +@@ -2633,10 +2811,10 @@ static char *ibpb_state(void) + { + if (boot_cpu_has(X86_FEATURE_IBPB)) { + if (static_key_enabled(&switch_mm_always_ibpb)) +- return ", IBPB: always-on"; ++ return "; IBPB: always-on"; + if (static_key_enabled(&switch_mm_cond_ibpb)) +- return ", IBPB: conditional"; +- return ", IBPB: disabled"; ++ return "; IBPB: conditional"; ++ return "; IBPB: disabled"; + } + return ""; + } +@@ -2646,14 +2824,32 @@ static char *pbrsb_eibrs_state(void) + if (boot_cpu_has_bug(X86_BUG_EIBRS_PBRSB)) { + if (boot_cpu_has(X86_FEATURE_RSB_VMEXIT_LITE) || + boot_cpu_has(X86_FEATURE_RSB_VMEXIT)) +- return ", PBRSB-eIBRS: SW sequence"; ++ return "; PBRSB-eIBRS: SW sequence"; + else +- return ", PBRSB-eIBRS: Vulnerable"; ++ return "; PBRSB-eIBRS: Vulnerable"; + } else { +- return ", PBRSB-eIBRS: Not affected"; ++ return "; PBRSB-eIBRS: Not affected"; + } + } + ++static const char *spectre_bhi_state(void) ++{ ++ if (!boot_cpu_has_bug(X86_BUG_BHI)) ++ return "; BHI: Not affected"; ++ else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_HW)) ++ return "; BHI: BHI_DIS_S"; ++ else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_LOOP)) ++ return "; BHI: SW loop, KVM: SW loop"; ++ else if (boot_cpu_has(X86_FEATURE_RETPOLINE) && ++ !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE) && ++ rrsba_disabled) ++ return "; BHI: Retpoline"; ++ else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT)) ++ return "; BHI: Vulnerable, KVM: SW loop"; ++ ++ return "; BHI: Vulnerable"; ++} ++ + static ssize_t spectre_v2_show_state(char *buf) + { + if (spectre_v2_enabled == SPECTRE_V2_LFENCE) +@@ -2666,13 +2862,15 @@ static ssize_t spectre_v2_show_state(char *buf) + spectre_v2_enabled == SPECTRE_V2_EIBRS_LFENCE) + return sysfs_emit(buf, "Vulnerable: eIBRS+LFENCE with unprivileged eBPF and SMT\n"); + +- return sysfs_emit(buf, "%s%s%s%s%s%s%s\n", ++ return sysfs_emit(buf, "%s%s%s%s%s%s%s%s\n", + spectre_v2_strings[spectre_v2_enabled], + ibpb_state(), +- boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "", ++ boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? "; IBRS_FW" : "", + stibp_state(), +- boot_cpu_has(X86_FEATURE_RSB_CTXSW) ? ", RSB filling" : "", ++ boot_cpu_has(X86_FEATURE_RSB_CTXSW) ? "; RSB filling" : "", + pbrsb_eibrs_state(), ++ spectre_bhi_state(), ++ /* this should always be at the end */ + spectre_v2_module_string()); + } + +@@ -2704,9 +2902,7 @@ static ssize_t srso_show_state(char *buf) + if (boot_cpu_has(X86_FEATURE_SRSO_NO)) + return sysfs_emit(buf, "Mitigation: SMT disabled\n"); + +- return sysfs_emit(buf, "%s%s\n", +- srso_strings[srso_mitigation], +- boot_cpu_has(X86_FEATURE_IBPB_BRTYPE) ? "" : ", no microcode"); ++ return sysfs_emit(buf, "%s\n", srso_strings[srso_mitigation]); + } + + static ssize_t gds_show_state(char *buf) +@@ -2769,6 +2965,9 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr + case X86_BUG_GDS: + return gds_show_state(buf); + ++ case X86_BUG_RFDS: ++ return rfds_show_state(buf); ++ + default: + break; + } +@@ -2843,4 +3042,9 @@ ssize_t cpu_show_gds(struct device *dev, struct device_attribute *attr, char *bu + { + return cpu_show_common(dev, attr, buf, X86_BUG_GDS); + } ++ ++ssize_t cpu_show_reg_file_data_sampling(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ return cpu_show_common(dev, attr, buf, X86_BUG_RFDS); ++} + #endif +diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c +index 4e5ffc8b0e469d..7a1e58fb43a033 100644 +--- a/arch/x86/kernel/cpu/common.c ++++ b/arch/x86/kernel/cpu/common.c +@@ -1165,6 +1165,7 @@ static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c) + #define NO_SPECTRE_V2 BIT(8) + #define NO_MMIO BIT(9) + #define NO_EIBRS_PBRSB BIT(10) ++#define NO_BHI BIT(11) + + #define VULNWL(vendor, family, model, whitelist) \ + X86_MATCH_VENDOR_FAM_MODEL(vendor, family, model, whitelist) +@@ -1227,18 +1228,18 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = { + VULNWL_INTEL(ATOM_TREMONT_D, NO_ITLB_MULTIHIT | NO_EIBRS_PBRSB), + + /* AMD Family 0xf - 0x12 */ +- VULNWL_AMD(0x0f, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO), +- VULNWL_AMD(0x10, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO), +- VULNWL_AMD(0x11, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO), +- VULNWL_AMD(0x12, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO), ++ VULNWL_AMD(0x0f, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_BHI), ++ VULNWL_AMD(0x10, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_BHI), ++ VULNWL_AMD(0x11, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_BHI), ++ VULNWL_AMD(0x12, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_BHI), + + /* FAMILY_ANY must be last, otherwise 0x0f - 0x12 matches won't work */ +- VULNWL_AMD(X86_FAMILY_ANY, NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_EIBRS_PBRSB), +- VULNWL_HYGON(X86_FAMILY_ANY, NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_EIBRS_PBRSB), ++ VULNWL_AMD(X86_FAMILY_ANY, NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_EIBRS_PBRSB | NO_BHI), ++ VULNWL_HYGON(X86_FAMILY_ANY, NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO | NO_EIBRS_PBRSB | NO_BHI), + + /* Zhaoxin Family 7 */ +- VULNWL(CENTAUR, 7, X86_MODEL_ANY, NO_SPECTRE_V2 | NO_SWAPGS | NO_MMIO), +- VULNWL(ZHAOXIN, 7, X86_MODEL_ANY, NO_SPECTRE_V2 | NO_SWAPGS | NO_MMIO), ++ VULNWL(CENTAUR, 7, X86_MODEL_ANY, NO_SPECTRE_V2 | NO_SWAPGS | NO_MMIO | NO_BHI), ++ VULNWL(ZHAOXIN, 7, X86_MODEL_ANY, NO_SPECTRE_V2 | NO_SWAPGS | NO_MMIO | NO_BHI), + {} + }; + +@@ -1269,6 +1270,8 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = { + #define SRSO BIT(5) + /* CPU is affected by GDS */ + #define GDS BIT(6) ++/* CPU is affected by Register File Data Sampling */ ++#define RFDS BIT(7) + + static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = { + VULNBL_INTEL_STEPPINGS(IVYBRIDGE, X86_STEPPING_ANY, SRBDS), +@@ -1296,9 +1299,18 @@ static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = { + VULNBL_INTEL_STEPPINGS(TIGERLAKE, X86_STEPPING_ANY, GDS), + VULNBL_INTEL_STEPPINGS(LAKEFIELD, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED), + VULNBL_INTEL_STEPPINGS(ROCKETLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS), +- VULNBL_INTEL_STEPPINGS(ATOM_TREMONT, X86_STEPPING_ANY, MMIO | MMIO_SBDS), +- VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_D, X86_STEPPING_ANY, MMIO), +- VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS), ++ VULNBL_INTEL_STEPPINGS(ALDERLAKE, X86_STEPPING_ANY, RFDS), ++ VULNBL_INTEL_STEPPINGS(ALDERLAKE_L, X86_STEPPING_ANY, RFDS), ++ VULNBL_INTEL_STEPPINGS(RAPTORLAKE, X86_STEPPING_ANY, RFDS), ++ VULNBL_INTEL_STEPPINGS(RAPTORLAKE_P, X86_STEPPING_ANY, RFDS), ++ VULNBL_INTEL_STEPPINGS(RAPTORLAKE_S, X86_STEPPING_ANY, RFDS), ++ VULNBL_INTEL_STEPPINGS(ATOM_GRACEMONT, X86_STEPPING_ANY, RFDS), ++ VULNBL_INTEL_STEPPINGS(ATOM_TREMONT, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RFDS), ++ VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_D, X86_STEPPING_ANY, MMIO | RFDS), ++ VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RFDS), ++ VULNBL_INTEL_STEPPINGS(ATOM_GOLDMONT, X86_STEPPING_ANY, RFDS), ++ VULNBL_INTEL_STEPPINGS(ATOM_GOLDMONT_D, X86_STEPPING_ANY, RFDS), ++ VULNBL_INTEL_STEPPINGS(ATOM_GOLDMONT_PLUS, X86_STEPPING_ANY, RFDS), + + VULNBL_AMD(0x15, RETBLEED), + VULNBL_AMD(0x16, RETBLEED), +@@ -1317,28 +1329,46 @@ static bool __init cpu_matches(const struct x86_cpu_id *table, unsigned long whi + + u64 x86_read_arch_cap_msr(void) + { +- u64 ia32_cap = 0; ++ u64 x86_arch_cap_msr = 0; + + if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) +- rdmsrl(MSR_IA32_ARCH_CAPABILITIES, ia32_cap); ++ rdmsrl(MSR_IA32_ARCH_CAPABILITIES, x86_arch_cap_msr); + +- return ia32_cap; ++ return x86_arch_cap_msr; + } + +-static bool arch_cap_mmio_immune(u64 ia32_cap) ++static bool arch_cap_mmio_immune(u64 x86_arch_cap_msr) + { +- return (ia32_cap & ARCH_CAP_FBSDP_NO && +- ia32_cap & ARCH_CAP_PSDP_NO && +- ia32_cap & ARCH_CAP_SBDR_SSDP_NO); ++ return (x86_arch_cap_msr & ARCH_CAP_FBSDP_NO && ++ x86_arch_cap_msr & ARCH_CAP_PSDP_NO && ++ x86_arch_cap_msr & ARCH_CAP_SBDR_SSDP_NO); ++} ++ ++static bool __init vulnerable_to_rfds(u64 x86_arch_cap_msr) ++{ ++ /* The "immunity" bit trumps everything else: */ ++ if (x86_arch_cap_msr & ARCH_CAP_RFDS_NO) ++ return false; ++ ++ /* ++ * VMMs set ARCH_CAP_RFDS_CLEAR for processors not in the blacklist to ++ * indicate that mitigation is needed because guest is running on a ++ * vulnerable hardware or may migrate to such hardware: ++ */ ++ if (x86_arch_cap_msr & ARCH_CAP_RFDS_CLEAR) ++ return true; ++ ++ /* Only consult the blacklist when there is no enumeration: */ ++ return cpu_matches(cpu_vuln_blacklist, RFDS); + } + + static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) + { +- u64 ia32_cap = x86_read_arch_cap_msr(); ++ u64 x86_arch_cap_msr = x86_read_arch_cap_msr(); + + /* Set ITLB_MULTIHIT bug if cpu is not in the whitelist and not mitigated */ + if (!cpu_matches(cpu_vuln_whitelist, NO_ITLB_MULTIHIT) && +- !(ia32_cap & ARCH_CAP_PSCHANGE_MC_NO)) ++ !(x86_arch_cap_msr & ARCH_CAP_PSCHANGE_MC_NO)) + setup_force_cpu_bug(X86_BUG_ITLB_MULTIHIT); + + if (cpu_matches(cpu_vuln_whitelist, NO_SPECULATION)) +@@ -1350,7 +1380,7 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) + setup_force_cpu_bug(X86_BUG_SPECTRE_V2); + + if (!cpu_matches(cpu_vuln_whitelist, NO_SSB) && +- !(ia32_cap & ARCH_CAP_SSB_NO) && ++ !(x86_arch_cap_msr & ARCH_CAP_SSB_NO) && + !cpu_has(c, X86_FEATURE_AMD_SSB_NO)) + setup_force_cpu_bug(X86_BUG_SPEC_STORE_BYPASS); + +@@ -1358,15 +1388,15 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) + * AMD's AutoIBRS is equivalent to Intel's eIBRS - use the Intel feature + * flag and protect from vendor-specific bugs via the whitelist. + */ +- if ((ia32_cap & ARCH_CAP_IBRS_ALL) || cpu_has(c, X86_FEATURE_AUTOIBRS)) { ++ if ((x86_arch_cap_msr & ARCH_CAP_IBRS_ALL) || cpu_has(c, X86_FEATURE_AUTOIBRS)) { + setup_force_cpu_cap(X86_FEATURE_IBRS_ENHANCED); + if (!cpu_matches(cpu_vuln_whitelist, NO_EIBRS_PBRSB) && +- !(ia32_cap & ARCH_CAP_PBRSB_NO)) ++ !(x86_arch_cap_msr & ARCH_CAP_PBRSB_NO)) + setup_force_cpu_bug(X86_BUG_EIBRS_PBRSB); + } + + if (!cpu_matches(cpu_vuln_whitelist, NO_MDS) && +- !(ia32_cap & ARCH_CAP_MDS_NO)) { ++ !(x86_arch_cap_msr & ARCH_CAP_MDS_NO)) { + setup_force_cpu_bug(X86_BUG_MDS); + if (cpu_matches(cpu_vuln_whitelist, MSBDS_ONLY)) + setup_force_cpu_bug(X86_BUG_MSBDS_ONLY); +@@ -1385,9 +1415,9 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) + * TSX_CTRL check alone is not sufficient for cases when the microcode + * update is not present or running as guest that don't get TSX_CTRL. + */ +- if (!(ia32_cap & ARCH_CAP_TAA_NO) && ++ if (!(x86_arch_cap_msr & ARCH_CAP_TAA_NO) && + (cpu_has(c, X86_FEATURE_RTM) || +- (ia32_cap & ARCH_CAP_TSX_CTRL_MSR))) ++ (x86_arch_cap_msr & ARCH_CAP_TSX_CTRL_MSR))) + setup_force_cpu_bug(X86_BUG_TAA); + + /* +@@ -1413,7 +1443,7 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) + * Set X86_BUG_MMIO_UNKNOWN for CPUs that are neither in the blacklist, + * nor in the whitelist and also don't enumerate MSR ARCH_CAP MMIO bits. + */ +- if (!arch_cap_mmio_immune(ia32_cap)) { ++ if (!arch_cap_mmio_immune(x86_arch_cap_msr)) { + if (cpu_matches(cpu_vuln_blacklist, MMIO)) + setup_force_cpu_bug(X86_BUG_MMIO_STALE_DATA); + else if (!cpu_matches(cpu_vuln_whitelist, NO_MMIO)) +@@ -1421,7 +1451,7 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) + } + + if (!cpu_has(c, X86_FEATURE_BTC_NO)) { +- if (cpu_matches(cpu_vuln_blacklist, RETBLEED) || (ia32_cap & ARCH_CAP_RSBA)) ++ if (cpu_matches(cpu_vuln_blacklist, RETBLEED) || (x86_arch_cap_msr & ARCH_CAP_RSBA)) + setup_force_cpu_bug(X86_BUG_RETBLEED); + } + +@@ -1439,15 +1469,28 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) + * disabling AVX2. The only way to do this in HW is to clear XCR0[2], + * which means that AVX will be disabled. + */ +- if (cpu_matches(cpu_vuln_blacklist, GDS) && !(ia32_cap & ARCH_CAP_GDS_NO) && ++ if (cpu_matches(cpu_vuln_blacklist, GDS) && !(x86_arch_cap_msr & ARCH_CAP_GDS_NO) && + boot_cpu_has(X86_FEATURE_AVX)) + setup_force_cpu_bug(X86_BUG_GDS); + ++ if (vulnerable_to_rfds(x86_arch_cap_msr)) ++ setup_force_cpu_bug(X86_BUG_RFDS); ++ ++ /* When virtualized, eIBRS could be hidden, assume vulnerable */ ++ if (!(x86_arch_cap_msr & ARCH_CAP_BHI_NO) && ++ !cpu_matches(cpu_vuln_whitelist, NO_BHI) && ++ (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED) || ++ boot_cpu_has(X86_FEATURE_HYPERVISOR))) ++ setup_force_cpu_bug(X86_BUG_BHI); ++ ++ if (cpu_has(c, X86_FEATURE_AMD_IBPB) && !cpu_has(c, X86_FEATURE_AMD_IBPB_RET)) ++ setup_force_cpu_bug(X86_BUG_IBPB_NO_RET); ++ + if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN)) + return; + + /* Rogue Data Cache Load? No! */ +- if (ia32_cap & ARCH_CAP_RDCL_NO) ++ if (x86_arch_cap_msr & ARCH_CAP_RDCL_NO) + return; + + setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN); +@@ -1858,6 +1901,13 @@ static void identify_cpu(struct cpuinfo_x86 *c) + c->apicid = apic->phys_pkg_id(c->initial_apicid, 0); + #endif + ++ ++ /* ++ * Set default APIC and TSC_DEADLINE MSR fencing flag. AMD and ++ * Hygon will clear it in ->c_init() below. ++ */ ++ set_cpu_cap(c, X86_FEATURE_APIC_MSRS_FENCE); ++ + /* + * Vendor-specific initialization. In this section we + * canonicalize the feature flags, meaning if there are +@@ -2087,7 +2137,7 @@ void syscall_init(void) + (unsigned long)(cpu_entry_stack(smp_processor_id()) + 1)); + wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)entry_SYSENTER_compat); + #else +- wrmsrl_cstar((unsigned long)ignore_sysret); ++ wrmsrl_cstar((unsigned long)entry_SYSCALL32_ignore); + wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)GDT_ENTRY_INVALID_SEG); + wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL); + wrmsrl_safe(MSR_IA32_SYSENTER_EIP, 0ULL); +diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c +index e462c1d3800a6c..6fb6d8a57cecaf 100644 +--- a/arch/x86/kernel/cpu/cpuid-deps.c ++++ b/arch/x86/kernel/cpu/cpuid-deps.c +@@ -44,7 +44,10 @@ static const struct cpuid_dep cpuid_deps[] = { + { X86_FEATURE_F16C, X86_FEATURE_XMM2, }, + { X86_FEATURE_AES, X86_FEATURE_XMM2 }, + { X86_FEATURE_SHA_NI, X86_FEATURE_XMM2 }, ++ { X86_FEATURE_GFNI, X86_FEATURE_XMM2 }, + { X86_FEATURE_FMA, X86_FEATURE_AVX }, ++ { X86_FEATURE_VAES, X86_FEATURE_AVX }, ++ { X86_FEATURE_VPCLMULQDQ, X86_FEATURE_AVX }, + { X86_FEATURE_AVX2, X86_FEATURE_AVX, }, + { X86_FEATURE_AVX512F, X86_FEATURE_AVX, }, + { X86_FEATURE_AVX512IFMA, X86_FEATURE_AVX512F }, +@@ -56,9 +59,6 @@ static const struct cpuid_dep cpuid_deps[] = { + { X86_FEATURE_AVX512VL, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512VBMI, X86_FEATURE_AVX512F }, + { X86_FEATURE_AVX512_VBMI2, X86_FEATURE_AVX512VL }, +- { X86_FEATURE_GFNI, X86_FEATURE_AVX512VL }, +- { X86_FEATURE_VAES, X86_FEATURE_AVX512VL }, +- { X86_FEATURE_VPCLMULQDQ, X86_FEATURE_AVX512VL }, + { X86_FEATURE_AVX512_VNNI, X86_FEATURE_AVX512VL }, + { X86_FEATURE_AVX512_BITALG, X86_FEATURE_AVX512VL }, + { X86_FEATURE_AVX512_4VNNIW, X86_FEATURE_AVX512F }, +diff --git a/arch/x86/kernel/cpu/hygon.c b/arch/x86/kernel/cpu/hygon.c +index defdc594be14df..6e738759779e81 100644 +--- a/arch/x86/kernel/cpu/hygon.c ++++ b/arch/x86/kernel/cpu/hygon.c +@@ -87,8 +87,12 @@ static void hygon_get_topology(struct cpuinfo_x86 *c) + if (!err) + c->x86_coreid_bits = get_count_order(c->x86_max_cores); + +- /* Socket ID is ApicId[6] for these processors. */ +- c->phys_proc_id = c->apicid >> APICID_SOCKET_ID_BIT; ++ /* ++ * Socket ID is ApicId[6] for the processors with model <= 0x3 ++ * when running on host. ++ */ ++ if (!boot_cpu_has(X86_FEATURE_HYPERVISOR) && c->x86_model <= 0x3) ++ c->phys_proc_id = c->apicid >> APICID_SOCKET_ID_BIT; + + cacheinfo_hygon_init_llc_id(c, cpu); + } else if (cpu_has(c, X86_FEATURE_NODEID_MSR)) { +@@ -344,6 +348,9 @@ static void init_hygon(struct cpuinfo_x86 *c) + set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); + + check_null_seg_clears_base(c); ++ ++ /* Hygon CPUs don't need fencing after x2APIC/TSC_DEADLINE MSR writes. */ ++ clear_cpu_cap(c, X86_FEATURE_APIC_MSRS_FENCE); + } + + static void cpu_detect_tlb_hygon(struct cpuinfo_x86 *c) +diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c +index be4045628fd33b..aa3e7ed0eb3d7f 100644 +--- a/arch/x86/kernel/cpu/intel.c ++++ b/arch/x86/kernel/cpu/intel.c +@@ -184,6 +184,90 @@ static bool bad_spectre_microcode(struct cpuinfo_x86 *c) + return false; + } + ++#define MSR_IA32_TME_ACTIVATE 0x982 ++ ++/* Helpers to access TME_ACTIVATE MSR */ ++#define TME_ACTIVATE_LOCKED(x) (x & 0x1) ++#define TME_ACTIVATE_ENABLED(x) (x & 0x2) ++ ++#define TME_ACTIVATE_POLICY(x) ((x >> 4) & 0xf) /* Bits 7:4 */ ++#define TME_ACTIVATE_POLICY_AES_XTS_128 0 ++ ++#define TME_ACTIVATE_KEYID_BITS(x) ((x >> 32) & 0xf) /* Bits 35:32 */ ++ ++#define TME_ACTIVATE_CRYPTO_ALGS(x) ((x >> 48) & 0xffff) /* Bits 63:48 */ ++#define TME_ACTIVATE_CRYPTO_AES_XTS_128 1 ++ ++/* Values for mktme_status (SW only construct) */ ++#define MKTME_ENABLED 0 ++#define MKTME_DISABLED 1 ++#define MKTME_UNINITIALIZED 2 ++static int mktme_status = MKTME_UNINITIALIZED; ++ ++static void detect_tme_early(struct cpuinfo_x86 *c) ++{ ++ u64 tme_activate, tme_policy, tme_crypto_algs; ++ int keyid_bits = 0, nr_keyids = 0; ++ static u64 tme_activate_cpu0 = 0; ++ ++ rdmsrl(MSR_IA32_TME_ACTIVATE, tme_activate); ++ ++ if (mktme_status != MKTME_UNINITIALIZED) { ++ if (tme_activate != tme_activate_cpu0) { ++ /* Broken BIOS? */ ++ pr_err_once("x86/tme: configuration is inconsistent between CPUs\n"); ++ pr_err_once("x86/tme: MKTME is not usable\n"); ++ mktme_status = MKTME_DISABLED; ++ ++ /* Proceed. We may need to exclude bits from x86_phys_bits. */ ++ } ++ } else { ++ tme_activate_cpu0 = tme_activate; ++ } ++ ++ if (!TME_ACTIVATE_LOCKED(tme_activate) || !TME_ACTIVATE_ENABLED(tme_activate)) { ++ pr_info_once("x86/tme: not enabled by BIOS\n"); ++ mktme_status = MKTME_DISABLED; ++ return; ++ } ++ ++ if (mktme_status != MKTME_UNINITIALIZED) ++ goto detect_keyid_bits; ++ ++ pr_info("x86/tme: enabled by BIOS\n"); ++ ++ tme_policy = TME_ACTIVATE_POLICY(tme_activate); ++ if (tme_policy != TME_ACTIVATE_POLICY_AES_XTS_128) ++ pr_warn("x86/tme: Unknown policy is active: %#llx\n", tme_policy); ++ ++ tme_crypto_algs = TME_ACTIVATE_CRYPTO_ALGS(tme_activate); ++ if (!(tme_crypto_algs & TME_ACTIVATE_CRYPTO_AES_XTS_128)) { ++ pr_err("x86/mktme: No known encryption algorithm is supported: %#llx\n", ++ tme_crypto_algs); ++ mktme_status = MKTME_DISABLED; ++ } ++detect_keyid_bits: ++ keyid_bits = TME_ACTIVATE_KEYID_BITS(tme_activate); ++ nr_keyids = (1UL << keyid_bits) - 1; ++ if (nr_keyids) { ++ pr_info_once("x86/mktme: enabled by BIOS\n"); ++ pr_info_once("x86/mktme: %d KeyIDs available\n", nr_keyids); ++ } else { ++ pr_info_once("x86/mktme: disabled by BIOS\n"); ++ } ++ ++ if (mktme_status == MKTME_UNINITIALIZED) { ++ /* MKTME is usable */ ++ mktme_status = MKTME_ENABLED; ++ } ++ ++ /* ++ * KeyID bits effectively lower the number of physical address ++ * bits. Update cpuinfo_x86::x86_phys_bits accordingly. ++ */ ++ c->x86_phys_bits -= keyid_bits; ++} ++ + static void early_init_intel(struct cpuinfo_x86 *c) + { + u64 misc_enable; +@@ -335,6 +419,13 @@ static void early_init_intel(struct cpuinfo_x86 *c) + */ + if (detect_extended_topology_early(c) < 0) + detect_ht_early(c); ++ ++ /* ++ * Adjust the number of physical bits early because it affects the ++ * valid bits of the MTRR mask registers. ++ */ ++ if (cpu_has(c, X86_FEATURE_TME)) ++ detect_tme_early(c); + } + + static void bsp_init_intel(struct cpuinfo_x86 *c) +@@ -495,90 +586,6 @@ static void srat_detect_node(struct cpuinfo_x86 *c) + #endif + } + +-#define MSR_IA32_TME_ACTIVATE 0x982 +- +-/* Helpers to access TME_ACTIVATE MSR */ +-#define TME_ACTIVATE_LOCKED(x) (x & 0x1) +-#define TME_ACTIVATE_ENABLED(x) (x & 0x2) +- +-#define TME_ACTIVATE_POLICY(x) ((x >> 4) & 0xf) /* Bits 7:4 */ +-#define TME_ACTIVATE_POLICY_AES_XTS_128 0 +- +-#define TME_ACTIVATE_KEYID_BITS(x) ((x >> 32) & 0xf) /* Bits 35:32 */ +- +-#define TME_ACTIVATE_CRYPTO_ALGS(x) ((x >> 48) & 0xffff) /* Bits 63:48 */ +-#define TME_ACTIVATE_CRYPTO_AES_XTS_128 1 +- +-/* Values for mktme_status (SW only construct) */ +-#define MKTME_ENABLED 0 +-#define MKTME_DISABLED 1 +-#define MKTME_UNINITIALIZED 2 +-static int mktme_status = MKTME_UNINITIALIZED; +- +-static void detect_tme(struct cpuinfo_x86 *c) +-{ +- u64 tme_activate, tme_policy, tme_crypto_algs; +- int keyid_bits = 0, nr_keyids = 0; +- static u64 tme_activate_cpu0 = 0; +- +- rdmsrl(MSR_IA32_TME_ACTIVATE, tme_activate); +- +- if (mktme_status != MKTME_UNINITIALIZED) { +- if (tme_activate != tme_activate_cpu0) { +- /* Broken BIOS? */ +- pr_err_once("x86/tme: configuration is inconsistent between CPUs\n"); +- pr_err_once("x86/tme: MKTME is not usable\n"); +- mktme_status = MKTME_DISABLED; +- +- /* Proceed. We may need to exclude bits from x86_phys_bits. */ +- } +- } else { +- tme_activate_cpu0 = tme_activate; +- } +- +- if (!TME_ACTIVATE_LOCKED(tme_activate) || !TME_ACTIVATE_ENABLED(tme_activate)) { +- pr_info_once("x86/tme: not enabled by BIOS\n"); +- mktme_status = MKTME_DISABLED; +- return; +- } +- +- if (mktme_status != MKTME_UNINITIALIZED) +- goto detect_keyid_bits; +- +- pr_info("x86/tme: enabled by BIOS\n"); +- +- tme_policy = TME_ACTIVATE_POLICY(tme_activate); +- if (tme_policy != TME_ACTIVATE_POLICY_AES_XTS_128) +- pr_warn("x86/tme: Unknown policy is active: %#llx\n", tme_policy); +- +- tme_crypto_algs = TME_ACTIVATE_CRYPTO_ALGS(tme_activate); +- if (!(tme_crypto_algs & TME_ACTIVATE_CRYPTO_AES_XTS_128)) { +- pr_err("x86/mktme: No known encryption algorithm is supported: %#llx\n", +- tme_crypto_algs); +- mktme_status = MKTME_DISABLED; +- } +-detect_keyid_bits: +- keyid_bits = TME_ACTIVATE_KEYID_BITS(tme_activate); +- nr_keyids = (1UL << keyid_bits) - 1; +- if (nr_keyids) { +- pr_info_once("x86/mktme: enabled by BIOS\n"); +- pr_info_once("x86/mktme: %d KeyIDs available\n", nr_keyids); +- } else { +- pr_info_once("x86/mktme: disabled by BIOS\n"); +- } +- +- if (mktme_status == MKTME_UNINITIALIZED) { +- /* MKTME is usable */ +- mktme_status = MKTME_ENABLED; +- } +- +- /* +- * KeyID bits effectively lower the number of physical address +- * bits. Update cpuinfo_x86::x86_phys_bits accordingly. +- */ +- c->x86_phys_bits -= keyid_bits; +-} +- + static void init_cpuid_fault(struct cpuinfo_x86 *c) + { + u64 msr; +@@ -715,9 +722,6 @@ static void init_intel(struct cpuinfo_x86 *c) + + init_ia32_feat_ctl(c); + +- if (cpu_has(c, X86_FEATURE_TME)) +- detect_tme(c); +- + init_intel_misc_features(c); + + split_lock_init(); +diff --git a/arch/x86/kernel/cpu/match.c b/arch/x86/kernel/cpu/match.c +index ad6776081e60da..ae71b8ef909c9a 100644 +--- a/arch/x86/kernel/cpu/match.c ++++ b/arch/x86/kernel/cpu/match.c +@@ -39,9 +39,7 @@ const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match) + const struct x86_cpu_id *m; + struct cpuinfo_x86 *c = &boot_cpu_data; + +- for (m = match; +- m->vendor | m->family | m->model | m->steppings | m->feature; +- m++) { ++ for (m = match; m->flags & X86_CPU_ID_FLAG_ENTRY_VALID; m++) { + if (m->vendor != X86_VENDOR_ANY && c->x86_vendor != m->vendor) + continue; + if (m->family != X86_FAMILY_ANY && c->x86 != m->family) +diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c +index 6f35f724cc142e..e103c227acd3ae 100644 +--- a/arch/x86/kernel/cpu/mce/core.c ++++ b/arch/x86/kernel/cpu/mce/core.c +@@ -44,6 +44,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -233,6 +234,7 @@ static noinstr void mce_panic(const char *msg, struct mce *final, char *exp) + struct llist_node *pending; + struct mce_evt_llist *l; + int apei_err = 0; ++ struct page *p; + + /* + * Allow instrumentation around external facilities usage. Not that it +@@ -286,6 +288,20 @@ static noinstr void mce_panic(const char *msg, struct mce *final, char *exp) + if (!fake_panic) { + if (panic_timeout == 0) + panic_timeout = mca_cfg.panic_timeout; ++ ++ /* ++ * Kdump skips the poisoned page in order to avoid ++ * touching the error bits again. Poison the page even ++ * if the error is fatal and the machine is about to ++ * panic. ++ */ ++ if (kexec_crash_loaded()) { ++ if (final && (final->status & MCI_STATUS_ADDRV)) { ++ p = pfn_to_online_page(final->addr >> PAGE_SHIFT); ++ if (p) ++ SetPageHWPoison(p); ++ } ++ } + panic(msg); + } else + pr_emerg(HW_ERR "Fake kernel panic: %s\n", msg); +@@ -2452,12 +2468,14 @@ static ssize_t set_bank(struct device *s, struct device_attribute *attr, + return -EINVAL; + + b = &per_cpu(mce_banks_array, s->id)[bank]; +- + if (!b->init) + return -ENODEV; + + b->ctl = new; ++ ++ mutex_lock(&mce_sysfs_mutex); + mce_restart(); ++ mutex_unlock(&mce_sysfs_mutex); + + return size; + } +diff --git a/arch/x86/kernel/cpu/mce/inject.c b/arch/x86/kernel/cpu/mce/inject.c +index 4d8d4bcf915ddd..72f0695c3dc1dd 100644 +--- a/arch/x86/kernel/cpu/mce/inject.c ++++ b/arch/x86/kernel/cpu/mce/inject.c +@@ -746,6 +746,7 @@ static void check_hw_inj_possible(void) + + wrmsrl_safe(mca_msr_reg(bank, MCA_STATUS), status); + rdmsrl_safe(mca_msr_reg(bank, MCA_STATUS), &status); ++ wrmsrl_safe(mca_msr_reg(bank, MCA_STATUS), 0); + + if (!status) { + hw_injection_possible = false; +diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c +index 6cc7a2c181da5f..a4ebd5e0ae8287 100644 +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -208,6 +208,11 @@ static int __init save_microcode_in_initrd(void) + struct cpuinfo_x86 *c = &boot_cpu_data; + int ret = -EINVAL; + ++ if (dis_ucode_ldr) { ++ ret = 0; ++ goto out; ++ } ++ + switch (c->x86_vendor) { + case X86_VENDOR_INTEL: + if (c->x86 >= 6) +@@ -221,6 +226,7 @@ static int __init save_microcode_in_initrd(void) + break; + } + ++out: + initrd_gone = true; + + return ret; +diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c +index e6bba12c759cb7..bcb2d640a0cd85 100644 +--- a/arch/x86/kernel/cpu/mshyperv.c ++++ b/arch/x86/kernel/cpu/mshyperv.c +@@ -199,8 +199,8 @@ static void hv_machine_shutdown(void) + * Call hv_cpu_die() on all the CPUs, otherwise later the hypervisor + * corrupts the old VP Assist Pages and can crash the kexec kernel. + */ +- if (kexec_in_progress && hyperv_init_cpuhp > 0) +- cpuhp_remove_state(hyperv_init_cpuhp); ++ if (kexec_in_progress) ++ cpuhp_remove_state(CPUHP_AP_HYPERV_ONLINE); + + /* The function calls stop_other_cpus(). */ + native_machine_shutdown(); +@@ -423,6 +423,7 @@ static void __init ms_hyperv_init_platform(void) + ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) { + x86_platform.calibrate_tsc = hv_get_tsc_khz; + x86_platform.calibrate_cpu = hv_get_tsc_khz; ++ setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ); + } + + if (ms_hyperv.priv_high & HV_ISOLATION) { +diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.c b/arch/x86/kernel/cpu/mtrr/mtrr.c +index 767bf1c71aadda..2a2fc14955cd3b 100644 +--- a/arch/x86/kernel/cpu/mtrr/mtrr.c ++++ b/arch/x86/kernel/cpu/mtrr/mtrr.c +@@ -609,7 +609,7 @@ void mtrr_save_state(void) + { + int first_cpu; + +- if (!mtrr_enabled()) ++ if (!mtrr_enabled() || !mtrr_state.have_fixed) + return; + + first_cpu = cpumask_first(cpu_online_mask); +diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c +index 030d3b409768de..10830995eadab6 100644 +--- a/arch/x86/kernel/cpu/resctrl/core.c ++++ b/arch/x86/kernel/cpu/resctrl/core.c +@@ -193,7 +193,7 @@ static inline bool rdt_get_mb_table(struct rdt_resource *r) + return false; + } + +-static bool __get_mem_config_intel(struct rdt_resource *r) ++static __init bool __get_mem_config_intel(struct rdt_resource *r) + { + struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); + union cpuid_0x10_3_eax eax; +@@ -227,12 +227,10 @@ static bool __get_mem_config_intel(struct rdt_resource *r) + return true; + } + +-static bool __rdt_get_mem_config_amd(struct rdt_resource *r) ++static __init bool __rdt_get_mem_config_amd(struct rdt_resource *r) + { + struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); +- union cpuid_0x10_3_eax eax; +- union cpuid_0x10_x_edx edx; +- u32 ebx, ecx, subleaf; ++ u32 eax, ebx, ecx, edx, subleaf; + + /* + * Query CPUID_Fn80000020_EDX_x01 for MBA and +@@ -240,9 +238,9 @@ static bool __rdt_get_mem_config_amd(struct rdt_resource *r) + */ + subleaf = (r->rid == RDT_RESOURCE_SMBA) ? 2 : 1; + +- cpuid_count(0x80000020, subleaf, &eax.full, &ebx, &ecx, &edx.full); +- hw_res->num_closid = edx.split.cos_max + 1; +- r->default_ctrl = MAX_MBA_BW_AMD; ++ cpuid_count(0x80000020, subleaf, &eax, &ebx, &ecx, &edx); ++ hw_res->num_closid = edx + 1; ++ r->default_ctrl = 1 << eax; + + /* AMD does not use delay */ + r->membw.delay_linear = false; +diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h +index 85ceaf9a31ac20..566386abb877f9 100644 +--- a/arch/x86/kernel/cpu/resctrl/internal.h ++++ b/arch/x86/kernel/cpu/resctrl/internal.h +@@ -18,7 +18,6 @@ + #define MBM_OVERFLOW_INTERVAL 1000 + #define MAX_MBA_BW 100u + #define MBA_IS_LINEAR 0x4 +-#define MAX_MBA_BW_AMD 0x800 + #define MBM_CNTR_WIDTH_OFFSET_AMD 20 + + #define RMID_VAL_ERROR BIT_ULL(63) +@@ -296,14 +295,10 @@ struct rftype { + * struct mbm_state - status for each MBM counter in each domain + * @prev_bw_bytes: Previous bytes value read for bandwidth calculation + * @prev_bw: The most recent bandwidth in MBps +- * @delta_bw: Difference between the current and previous bandwidth +- * @delta_comp: Indicates whether to compute the delta_bw + */ + struct mbm_state { + u64 prev_bw_bytes; + u32 prev_bw; +- u32 delta_bw; +- bool delta_comp; + }; + + /** +@@ -395,6 +390,8 @@ struct rdt_parse_data { + * @msr_update: Function pointer to update QOS MSRs + * @mon_scale: cqm counter * mon_scale = occupancy in bytes + * @mbm_width: Monitor width, to detect and correct for overflow. ++ * @mbm_cfg_mask: Bandwidth sources that can be tracked when Bandwidth ++ * Monitoring Event Configuration (BMEC) is supported. + * @cdp_enabled: CDP state of this resource + * + * Members of this structure are either private to the architecture +@@ -409,6 +406,7 @@ struct rdt_hw_resource { + struct rdt_resource *r); + unsigned int mon_scale; + unsigned int mbm_width; ++ unsigned int mbm_cfg_mask; + bool cdp_enabled; + }; + +diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c +index f136ac046851c8..3a6c069614eb84 100644 +--- a/arch/x86/kernel/cpu/resctrl/monitor.c ++++ b/arch/x86/kernel/cpu/resctrl/monitor.c +@@ -440,9 +440,6 @@ static void mbm_bw_count(u32 rmid, struct rmid_read *rr) + + cur_bw = bytes / SZ_1M; + +- if (m->delta_comp) +- m->delta_bw = abs(cur_bw - m->prev_bw); +- m->delta_comp = false; + m->prev_bw = cur_bw; + } + +@@ -520,11 +517,11 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) + { + u32 closid, rmid, cur_msr_val, new_msr_val; + struct mbm_state *pmbm_data, *cmbm_data; +- u32 cur_bw, delta_bw, user_bw; + struct rdt_resource *r_mba; + struct rdt_domain *dom_mba; + struct list_head *head; + struct rdtgroup *entry; ++ u32 cur_bw, user_bw; + + if (!is_mbm_local_enabled()) + return; +@@ -543,7 +540,6 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) + + cur_bw = pmbm_data->prev_bw; + user_bw = dom_mba->mbps_val[closid]; +- delta_bw = pmbm_data->delta_bw; + + /* MBA resource doesn't support CDP */ + cur_msr_val = resctrl_arch_get_config(r_mba, dom_mba, closid, CDP_NONE); +@@ -555,49 +551,31 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) + list_for_each_entry(entry, head, mon.crdtgrp_list) { + cmbm_data = &dom_mbm->mbm_local[entry->mon.rmid]; + cur_bw += cmbm_data->prev_bw; +- delta_bw += cmbm_data->delta_bw; + } + + /* + * Scale up/down the bandwidth linearly for the ctrl group. The + * bandwidth step is the bandwidth granularity specified by the + * hardware. +- * +- * The delta_bw is used when increasing the bandwidth so that we +- * dont alternately increase and decrease the control values +- * continuously. +- * +- * For ex: consider cur_bw = 90MBps, user_bw = 100MBps and if +- * bandwidth step is 20MBps(> user_bw - cur_bw), we would keep +- * switching between 90 and 110 continuously if we only check +- * cur_bw < user_bw. ++ * Always increase throttling if current bandwidth is above the ++ * target set by user. ++ * But avoid thrashing up and down on every poll by checking ++ * whether a decrease in throttling is likely to push the group ++ * back over target. E.g. if currently throttling to 30% of bandwidth ++ * on a system with 10% granularity steps, check whether moving to ++ * 40% would go past the limit by multiplying current bandwidth by ++ * "(30 + 10) / 30". + */ + if (cur_msr_val > r_mba->membw.min_bw && user_bw < cur_bw) { + new_msr_val = cur_msr_val - r_mba->membw.bw_gran; + } else if (cur_msr_val < MAX_MBA_BW && +- (user_bw > (cur_bw + delta_bw))) { ++ (user_bw > (cur_bw * (cur_msr_val + r_mba->membw.min_bw) / cur_msr_val))) { + new_msr_val = cur_msr_val + r_mba->membw.bw_gran; + } else { + return; + } + + resctrl_arch_update_one(r_mba, dom_mba, closid, CDP_NONE, new_msr_val); +- +- /* +- * Delta values are updated dynamically package wise for each +- * rdtgrp every time the throttle MSR changes value. +- * +- * This is because (1)the increase in bandwidth is not perfectly +- * linear and only "approximately" linear even when the hardware +- * says it is linear.(2)Also since MBA is a core specific +- * mechanism, the delta values vary based on number of cores used +- * by the rdtgrp. +- */ +- pmbm_data->delta_comp = true; +- list_for_each_entry(entry, head, mon.crdtgrp_list) { +- cmbm_data = &dom_mbm->mbm_local[entry->mon.rmid]; +- cmbm_data->delta_comp = true; +- } + } + + static void mbm_update(struct rdt_resource *r, struct rdt_domain *d, int rmid) +@@ -813,6 +791,12 @@ int __init rdt_get_mon_l3_config(struct rdt_resource *r) + return ret; + + if (rdt_cpu_has(X86_FEATURE_BMEC)) { ++ u32 eax, ebx, ecx, edx; ++ ++ /* Detect list of bandwidth sources that can be tracked */ ++ cpuid_count(0x80000020, 3, &eax, &ebx, &ecx, &edx); ++ hw_res->mbm_cfg_mask = ecx & MAX_EVT_CONFIG_BITS; ++ + if (rdt_cpu_has(X86_FEATURE_CQM_MBM_TOTAL)) { + mbm_total_event.configurable = true; + mbm_config_rftype_init("mbm_total_bytes_config"); +diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c +index 725344048f85da..d82d5de183b107 100644 +--- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c ++++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c +@@ -1553,12 +1553,6 @@ static int mbm_config_write_domain(struct rdt_resource *r, + struct mon_config_info mon_info = {0}; + int ret = 0; + +- /* mon_config cannot be more than the supported set of events */ +- if (val > MAX_EVT_CONFIG_BITS) { +- rdt_last_cmd_puts("Invalid event configuration\n"); +- return -EINVAL; +- } +- + /* + * Read the current config value first. If both are the same then + * no need to write it again. +@@ -1596,6 +1590,7 @@ static int mbm_config_write_domain(struct rdt_resource *r, + + static int mon_config_write(struct rdt_resource *r, char *tok, u32 evtid) + { ++ struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); + char *dom_str = NULL, *id_str; + unsigned long dom_id, val; + struct rdt_domain *d; +@@ -1619,6 +1614,13 @@ static int mon_config_write(struct rdt_resource *r, char *tok, u32 evtid) + return -EINVAL; + } + ++ /* Value from user cannot be more than the supported set of events */ ++ if ((val & hw_res->mbm_cfg_mask) != val) { ++ rdt_last_cmd_printf("Invalid event configuration: max valid mask is 0x%02x\n", ++ hw_res->mbm_cfg_mask); ++ return -EINVAL; ++ } ++ + list_for_each_entry(d, &r->domains, list) { + if (d->id == dom_id) { + ret = mbm_config_write_domain(r, d, evtid, val); +diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c +index 0dad49a09b7a9e..af5aa2c754c222 100644 +--- a/arch/x86/kernel/cpu/scattered.c ++++ b/arch/x86/kernel/cpu/scattered.c +@@ -28,6 +28,7 @@ static const struct cpuid_bit cpuid_bits[] = { + { X86_FEATURE_EPB, CPUID_ECX, 3, 0x00000006, 0 }, + { X86_FEATURE_INTEL_PPIN, CPUID_EBX, 0, 0x00000007, 1 }, + { X86_FEATURE_RRSBA_CTRL, CPUID_EDX, 2, 0x00000007, 2 }, ++ { X86_FEATURE_BHI_CTRL, CPUID_EDX, 4, 0x00000007, 2 }, + { X86_FEATURE_CQM_LLC, CPUID_EDX, 1, 0x0000000f, 0 }, + { X86_FEATURE_CQM_OCCUP_LLC, CPUID_EDX, 0, 0x0000000f, 1 }, + { X86_FEATURE_CQM_MBM_TOTAL, CPUID_EDX, 1, 0x0000000f, 1 }, +@@ -49,6 +50,7 @@ static const struct cpuid_bit cpuid_bits[] = { + { X86_FEATURE_BMEC, CPUID_EBX, 3, 0x80000020, 0 }, + { X86_FEATURE_PERFMON_V2, CPUID_EAX, 0, 0x80000022, 0 }, + { X86_FEATURE_AMD_LBR_V2, CPUID_EAX, 1, 0x80000022, 0 }, ++ { X86_FEATURE_AMD_LBR_PMC_FREEZE, CPUID_EAX, 2, 0x80000022, 0 }, + { 0, 0, 0, 0, 0 } + }; + +diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c +index 166692f2d50111..c7f8c3200e8d7f 100644 +--- a/arch/x86/kernel/cpu/sgx/main.c ++++ b/arch/x86/kernel/cpu/sgx/main.c +@@ -474,24 +474,25 @@ struct sgx_epc_page *__sgx_alloc_epc_page(void) + { + struct sgx_epc_page *page; + int nid_of_current = numa_node_id(); +- int nid = nid_of_current; ++ int nid_start, nid; + +- if (node_isset(nid_of_current, sgx_numa_mask)) { +- page = __sgx_alloc_epc_page_from_node(nid_of_current); +- if (page) +- return page; +- } +- +- /* Fall back to the non-local NUMA nodes: */ +- while (true) { +- nid = next_node_in(nid, sgx_numa_mask); +- if (nid == nid_of_current) +- break; ++ /* ++ * Try local node first. If it doesn't have an EPC section, ++ * fall back to the non-local NUMA nodes. ++ */ ++ if (node_isset(nid_of_current, sgx_numa_mask)) ++ nid_start = nid_of_current; ++ else ++ nid_start = next_node_in(nid_of_current, sgx_numa_mask); + ++ nid = nid_start; ++ do { + page = __sgx_alloc_epc_page_from_node(nid); + if (page) + return page; +- } ++ ++ nid = next_node_in(nid, sgx_numa_mask); ++ } while (nid != nid_start); + + return ERR_PTR(-ENOMEM); + } +diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c +index 87d38f17ff5c9c..c13c9cb40b9b46 100644 +--- a/arch/x86/kernel/devicetree.c ++++ b/arch/x86/kernel/devicetree.c +@@ -82,7 +82,7 @@ static int x86_of_pci_irq_enable(struct pci_dev *dev) + + ret = pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (ret) +- return ret; ++ return pcibios_err_to_errno(ret); + if (!pin) + return 0; + +diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c +index fb8cf953380dab..b66f540de054a7 100644 +--- a/arch/x86/kernel/e820.c ++++ b/arch/x86/kernel/e820.c +@@ -1017,10 +1017,12 @@ void __init e820__reserve_setup_data(void) + e820__range_update(pa_data, sizeof(*data)+data->len, E820_TYPE_RAM, E820_TYPE_RESERVED_KERN); + + /* +- * SETUP_EFI and SETUP_IMA are supplied by kexec and do not need +- * to be reserved. ++ * SETUP_EFI, SETUP_IMA and SETUP_RNG_SEED are supplied by ++ * kexec and do not need to be reserved. + */ +- if (data->type != SETUP_EFI && data->type != SETUP_IMA) ++ if (data->type != SETUP_EFI && ++ data->type != SETUP_IMA && ++ data->type != SETUP_RNG_SEED) + e820__range_update_kexec(pa_data, + sizeof(*data) + data->len, + E820_TYPE_RAM, E820_TYPE_RESERVED_KERN); +diff --git a/arch/x86/kernel/eisa.c b/arch/x86/kernel/eisa.c +index e963344b044902..53935b4d62e305 100644 +--- a/arch/x86/kernel/eisa.c ++++ b/arch/x86/kernel/eisa.c +@@ -2,6 +2,7 @@ + /* + * EISA specific code + */ ++#include + #include + #include + #include +@@ -12,7 +13,7 @@ static __init int eisa_bus_probe(void) + { + void __iomem *p; + +- if (xen_pv_domain() && !xen_initial_domain()) ++ if ((xen_pv_domain() && !xen_initial_domain()) || cc_platform_has(CC_ATTR_GUEST_SEV_SNP)) + return 0; + + p = ioremap(0x0FFFD9, 4); +diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c +index a21a4d0ecc345b..4b414b0ab0692a 100644 +--- a/arch/x86/kernel/fpu/core.c ++++ b/arch/x86/kernel/fpu/core.c +@@ -145,8 +145,8 @@ void restore_fpregs_from_fpstate(struct fpstate *fpstate, u64 mask) + asm volatile( + "fnclex\n\t" + "emms\n\t" +- "fildl %P[addr]" /* set F?P to defined value */ +- : : [addr] "m" (fpstate)); ++ "fildl %[addr]" /* set F?P to defined value */ ++ : : [addr] "m" (*fpstate)); + } + + if (use_xsave()) { +diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c +index 558076dbde5bfc..2b3b9e140dd41b 100644 +--- a/arch/x86/kernel/fpu/signal.c ++++ b/arch/x86/kernel/fpu/signal.c +@@ -156,7 +156,7 @@ static inline bool save_xstate_epilog(void __user *buf, int ia32_frame, + return !err; + } + +-static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf) ++static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf, u32 pkru) + { + if (use_xsave()) + return xsave_to_user_sigframe(buf); +@@ -185,7 +185,7 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf) + * For [f]xsave state, update the SW reserved fields in the [f]xsave frame + * indicating the absence/presence of the extended state to the user. + */ +-bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) ++bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size, u32 pkru) + { + struct task_struct *tsk = current; + struct fpstate *fpstate = tsk->thread.fpu.fpstate; +@@ -228,7 +228,7 @@ bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) + fpregs_restore_userregs(); + + pagefault_disable(); +- ret = copy_fpregs_to_sigframe(buf_fx); ++ ret = copy_fpregs_to_sigframe(buf_fx, pkru); + pagefault_enable(); + fpregs_unlock(); + +@@ -274,12 +274,13 @@ static int __restore_fpregs_from_user(void __user *buf, u64 ufeatures, + * Attempt to restore the FPU registers directly from user memory. + * Pagefaults are handled and any errors returned are fatal. + */ +-static bool restore_fpregs_from_user(void __user *buf, u64 xrestore, +- bool fx_only, unsigned int size) ++static bool restore_fpregs_from_user(void __user *buf, u64 xrestore, bool fx_only) + { + struct fpu *fpu = ¤t->thread.fpu; + int ret; + ++ /* Restore enabled features only. */ ++ xrestore &= fpu->fpstate->user_xfeatures; + retry: + fpregs_lock(); + /* Ensure that XFD is up to date */ +@@ -309,7 +310,7 @@ static bool restore_fpregs_from_user(void __user *buf, u64 xrestore, + if (ret != X86_TRAP_PF) + return false; + +- if (!fault_in_readable(buf, size)) ++ if (!fault_in_readable(buf, fpu->fpstate->user_size)) + goto retry; + return false; + } +@@ -339,7 +340,6 @@ static bool __fpu_restore_sig(void __user *buf, void __user *buf_fx, + struct user_i387_ia32_struct env; + bool success, fx_only = false; + union fpregs_state *fpregs; +- unsigned int state_size; + u64 user_xfeatures = 0; + + if (use_xsave()) { +@@ -349,17 +349,14 @@ static bool __fpu_restore_sig(void __user *buf, void __user *buf_fx, + return false; + + fx_only = !fx_sw_user.magic1; +- state_size = fx_sw_user.xstate_size; + user_xfeatures = fx_sw_user.xfeatures; + } else { + user_xfeatures = XFEATURE_MASK_FPSSE; +- state_size = fpu->fpstate->user_size; + } + + if (likely(!ia32_fxstate)) { + /* Restore the FPU registers directly from user memory. */ +- return restore_fpregs_from_user(buf_fx, user_xfeatures, fx_only, +- state_size); ++ return restore_fpregs_from_user(buf_fx, user_xfeatures, fx_only); + } + + /* +diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c +index ef6906107c541d..255ff8f6c52705 100644 +--- a/arch/x86/kernel/fpu/xstate.c ++++ b/arch/x86/kernel/fpu/xstate.c +@@ -178,10 +178,11 @@ void fpu__init_cpu_xstate(void) + * Must happen after CR4 setup and before xsetbv() to allow KVM + * lazy passthrough. Write independent of the dynamic state static + * key as that does not work on the boot CPU. This also ensures +- * that any stale state is wiped out from XFD. ++ * that any stale state is wiped out from XFD. Reset the per CPU ++ * xfd cache too. + */ + if (cpu_feature_enabled(X86_FEATURE_XFD)) +- wrmsrl(MSR_IA32_XFD, init_fpstate.xfd); ++ xfd_set_state(init_fpstate.xfd); + + /* + * XCR_XFEATURE_ENABLED_MASK (aka. XCR0) sets user features +@@ -787,6 +788,9 @@ void __init fpu__init_system_xstate(unsigned int legacy_size) + goto out_disable; + } + ++ fpu_kernel_cfg.independent_features = fpu_kernel_cfg.max_features & ++ XFEATURE_MASK_INDEPENDENT; ++ + /* + * Clear XSAVE features that are disabled in the normal CPUID. + */ +diff --git a/arch/x86/kernel/fpu/xstate.h b/arch/x86/kernel/fpu/xstate.h +index 3518fb26d06b02..544224611e23c5 100644 +--- a/arch/x86/kernel/fpu/xstate.h ++++ b/arch/x86/kernel/fpu/xstate.h +@@ -64,9 +64,9 @@ static inline u64 xfeatures_mask_supervisor(void) + static inline u64 xfeatures_mask_independent(void) + { + if (!cpu_feature_enabled(X86_FEATURE_ARCH_LBR)) +- return XFEATURE_MASK_INDEPENDENT & ~XFEATURE_MASK_LBR; ++ return fpu_kernel_cfg.independent_features & ~XFEATURE_MASK_LBR; + +- return XFEATURE_MASK_INDEPENDENT; ++ return fpu_kernel_cfg.independent_features; + } + + /* XSAVE/XRSTOR wrapper functions */ +@@ -148,20 +148,26 @@ static inline void xfd_validate_state(struct fpstate *fpstate, u64 mask, bool rs + #endif + + #ifdef CONFIG_X86_64 ++static inline void xfd_set_state(u64 xfd) ++{ ++ wrmsrl(MSR_IA32_XFD, xfd); ++ __this_cpu_write(xfd_state, xfd); ++} ++ + static inline void xfd_update_state(struct fpstate *fpstate) + { + if (fpu_state_size_dynamic()) { + u64 xfd = fpstate->xfd; + +- if (__this_cpu_read(xfd_state) != xfd) { +- wrmsrl(MSR_IA32_XFD, xfd); +- __this_cpu_write(xfd_state, xfd); +- } ++ if (__this_cpu_read(xfd_state) != xfd) ++ xfd_set_state(xfd); + } + } + + extern int __xfd_enable_feature(u64 which, struct fpu_guest *guest_fpu); + #else ++static inline void xfd_set_state(u64 xfd) { } ++ + static inline void xfd_update_state(struct fpstate *fpstate) { } + + static inline int __xfd_enable_feature(u64 which, struct fpu_guest *guest_fpu) { +diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c +index 49f7629b17f734..c58213bce294e9 100644 +--- a/arch/x86/kernel/head64.c ++++ b/arch/x86/kernel/head64.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + + /* + * Manage page tables very early on. +@@ -80,12 +81,10 @@ static struct desc_struct startup_gdt[GDT_ENTRIES] = { + * while the kernel still uses a direct mapping. + */ + static struct desc_ptr startup_gdt_descr = { +- .size = sizeof(startup_gdt), ++ .size = sizeof(startup_gdt)-1, + .address = 0, + }; + +-#define __head __section(".head.text") +- + static void __head *fixup_pointer(void *ptr, unsigned long physaddr) + { + return ptr - (void *)_text + (void *)physaddr; +diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S +index ea6995920b7aa9..e6eaee8509ceed 100644 +--- a/arch/x86/kernel/head_64.S ++++ b/arch/x86/kernel/head_64.S +@@ -256,6 +256,22 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL) + testl $X2APIC_ENABLE, %eax + jnz .Lread_apicid_msr + ++#ifdef CONFIG_X86_X2APIC ++ /* ++ * If system is in X2APIC mode then MMIO base might not be ++ * mapped causing the MMIO read below to fault. Faults can't ++ * be handled at that point. ++ */ ++ cmpl $0, x2apic_mode(%rip) ++ jz .Lread_apicid_mmio ++ ++ /* Force the AP into X2APIC mode. */ ++ orl $X2APIC_ENABLE, %eax ++ wrmsr ++ jmp .Lread_apicid_msr ++#endif ++ ++.Lread_apicid_mmio: + /* Read the APIC ID from the fix-mapped MMIO space. */ + movq apic_mmio_base(%rip), %rcx + addq $APIC_ID, %rcx +diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c +index 1648aa0204d97d..046bc9d57e9966 100644 +--- a/arch/x86/kernel/hpet.c ++++ b/arch/x86/kernel/hpet.c +@@ -1438,7 +1438,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) + memset(&curr_time, 0, sizeof(struct rtc_time)); + + if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) { +- if (unlikely(mc146818_get_time(&curr_time) < 0)) { ++ if (unlikely(mc146818_get_time(&curr_time, 10) < 0)) { + pr_err_ratelimited("unable to read current time from RTC\n"); + return IRQ_HANDLED; + } +diff --git a/arch/x86/kernel/idt.c b/arch/x86/kernel/idt.c +index b786d48f5a0faf..fc77a96040b7ea 100644 +--- a/arch/x86/kernel/idt.c ++++ b/arch/x86/kernel/idt.c +@@ -117,7 +117,7 @@ static const __initconst struct idt_data def_idts[] = { + + SYSG(X86_TRAP_OF, asm_exc_overflow), + #if defined(CONFIG_IA32_EMULATION) +- SYSG(IA32_SYSCALL_VECTOR, entry_INT80_compat), ++ SYSG(IA32_SYSCALL_VECTOR, asm_int80_emulation), + #elif defined(CONFIG_X86_32) + SYSG(IA32_SYSCALL_VECTOR, entry_INT80_32), + #endif +diff --git a/arch/x86/kernel/jailhouse.c b/arch/x86/kernel/jailhouse.c +index 578d16fc040fa1..5481c7c5db301b 100644 +--- a/arch/x86/kernel/jailhouse.c ++++ b/arch/x86/kernel/jailhouse.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c +index e8babebad7b888..a6a3475e1d6097 100644 +--- a/arch/x86/kernel/kprobes/core.c ++++ b/arch/x86/kernel/kprobes/core.c +@@ -335,7 +335,16 @@ static int can_probe(unsigned long paddr) + kprobe_opcode_t *arch_adjust_kprobe_addr(unsigned long addr, unsigned long offset, + bool *on_func_entry) + { +- if (is_endbr(*(u32 *)addr)) { ++ u32 insn; ++ ++ /* ++ * Since 'addr' is not guaranteed to be safe to access, use ++ * copy_from_kernel_nofault() to read the instruction: ++ */ ++ if (copy_from_kernel_nofault(&insn, (void *)addr, sizeof(u32))) ++ return NULL; ++ ++ if (is_endbr(insn)) { + *on_func_entry = !offset || offset == 4; + if (*on_func_entry) + offset = 4; +@@ -576,7 +585,8 @@ static void kprobe_emulate_call_indirect(struct kprobe *p, struct pt_regs *regs) + { + unsigned long offs = addrmode_regoffs[p->ainsn.indirect.reg]; + +- int3_emulate_call(regs, regs_get_register(regs, offs)); ++ int3_emulate_push(regs, regs->ip - INT3_INSN_SIZE + p->ainsn.size); ++ int3_emulate_jmp(regs, regs_get_register(regs, offs)); + } + NOKPROBE_SYMBOL(kprobe_emulate_call_indirect); + +diff --git a/arch/x86/kernel/kprobes/ftrace.c b/arch/x86/kernel/kprobes/ftrace.c +index dd2ec14adb77ba..15af7e98e161a4 100644 +--- a/arch/x86/kernel/kprobes/ftrace.c ++++ b/arch/x86/kernel/kprobes/ftrace.c +@@ -21,6 +21,9 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, + struct kprobe_ctlblk *kcb; + int bit; + ++ if (unlikely(kprobe_ftrace_disabled)) ++ return; ++ + bit = ftrace_test_recursion_trylock(ip, parent_ip); + if (bit < 0) + return; +diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c +index fb8f52149be9ad..f2fff625576d56 100644 +--- a/arch/x86/kernel/kvmclock.c ++++ b/arch/x86/kernel/kvmclock.c +@@ -24,8 +24,8 @@ + + static int kvmclock __initdata = 1; + static int kvmclock_vsyscall __initdata = 1; +-static int msr_kvm_system_time __ro_after_init = MSR_KVM_SYSTEM_TIME; +-static int msr_kvm_wall_clock __ro_after_init = MSR_KVM_WALL_CLOCK; ++static int msr_kvm_system_time __ro_after_init; ++static int msr_kvm_wall_clock __ro_after_init; + static u64 kvm_sched_clock_offset __ro_after_init; + + static int __init parse_no_kvmclock(char *arg) +@@ -195,7 +195,8 @@ static void kvm_setup_secondary_clock(void) + + void kvmclock_disable(void) + { +- native_write_msr(msr_kvm_system_time, 0, 0); ++ if (msr_kvm_system_time) ++ native_write_msr(msr_kvm_system_time, 0, 0); + } + + static void __init kvmclock_init_mem(void) +@@ -294,7 +295,10 @@ void __init kvmclock_init(void) + if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE2)) { + msr_kvm_system_time = MSR_KVM_SYSTEM_TIME_NEW; + msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK_NEW; +- } else if (!kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) { ++ } else if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) { ++ msr_kvm_system_time = MSR_KVM_SYSTEM_TIME; ++ msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK; ++ } else { + return; + } + +diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c +index 1a3e2c05a8a5b6..2fa12d1dc67602 100644 +--- a/arch/x86/kernel/machine_kexec_64.c ++++ b/arch/x86/kernel/machine_kexec_64.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #ifdef CONFIG_ACPI + /* +@@ -90,6 +91,8 @@ map_efi_systab(struct x86_mapping_info *info, pgd_t *level4p) + { + #ifdef CONFIG_EFI + unsigned long mstart, mend; ++ void *kaddr; ++ int ret; + + if (!efi_enabled(EFI_BOOT)) + return 0; +@@ -105,6 +108,30 @@ map_efi_systab(struct x86_mapping_info *info, pgd_t *level4p) + if (!mstart) + return 0; + ++ ret = kernel_ident_mapping_init(info, level4p, mstart, mend); ++ if (ret) ++ return ret; ++ ++ kaddr = memremap(mstart, mend - mstart, MEMREMAP_WB); ++ if (!kaddr) { ++ pr_err("Could not map UEFI system table\n"); ++ return -ENOMEM; ++ } ++ ++ mstart = efi_config_table; ++ ++ if (efi_enabled(EFI_64BIT)) { ++ efi_system_table_64_t *stbl = (efi_system_table_64_t *)kaddr; ++ ++ mend = mstart + sizeof(efi_config_table_64_t) * stbl->nr_tables; ++ } else { ++ efi_system_table_32_t *stbl = (efi_system_table_32_t *)kaddr; ++ ++ mend = mstart + sizeof(efi_config_table_32_t) * stbl->nr_tables; ++ } ++ ++ memunmap(kaddr); ++ + return kernel_ident_mapping_init(info, level4p, mstart, mend); + #endif + return 0; +@@ -298,8 +325,15 @@ void machine_kexec_cleanup(struct kimage *image) + void machine_kexec(struct kimage *image) + { + unsigned long page_list[PAGES_NR]; +- void *control_page; ++ unsigned int host_mem_enc_active; + int save_ftrace_enabled; ++ void *control_page; ++ ++ /* ++ * This must be done before load_segments() since if call depth tracking ++ * is used then GS must be valid to make any function calls. ++ */ ++ host_mem_enc_active = cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT); + + #ifdef CONFIG_KEXEC_JUMP + if (image->preserve_context) +@@ -361,7 +395,7 @@ void machine_kexec(struct kimage *image) + (unsigned long)page_list, + image->start, + image->preserve_context, +- cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT)); ++ host_mem_enc_active); + + #ifdef CONFIG_KEXEC_JUMP + if (image->preserve_context) +diff --git a/arch/x86/kernel/mmconf-fam10h_64.c b/arch/x86/kernel/mmconf-fam10h_64.c +index c94dec6a18345a..1f54eedc3015e9 100644 +--- a/arch/x86/kernel/mmconf-fam10h_64.c ++++ b/arch/x86/kernel/mmconf-fam10h_64.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + + #include + #include +diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c +index a0c551846b35f1..87aee638e1a5d8 100644 +--- a/arch/x86/kernel/nmi.c ++++ b/arch/x86/kernel/nmi.c +@@ -507,12 +507,13 @@ DEFINE_IDTENTRY_RAW(exc_nmi) + } + this_cpu_write(nmi_state, NMI_EXECUTING); + this_cpu_write(nmi_cr2, read_cr2()); ++ ++nmi_restart: + if (IS_ENABLED(CONFIG_NMI_CHECK_CPU)) { + WRITE_ONCE(nsp->idt_seq, nsp->idt_seq + 1); + WARN_ON_ONCE(!(nsp->idt_seq & 0x1)); + WRITE_ONCE(nsp->recv_jiffies, jiffies); + } +-nmi_restart: + + /* + * Needs to happen before DR7 is accessed, because the hypervisor can +@@ -548,16 +549,13 @@ DEFINE_IDTENTRY_RAW(exc_nmi) + + if (unlikely(this_cpu_read(nmi_cr2) != read_cr2())) + write_cr2(this_cpu_read(nmi_cr2)); +- if (this_cpu_dec_return(nmi_state)) +- goto nmi_restart; +- +- if (user_mode(regs)) +- mds_user_clear_cpu_buffers(); + if (IS_ENABLED(CONFIG_NMI_CHECK_CPU)) { + WRITE_ONCE(nsp->idt_seq, nsp->idt_seq + 1); + WARN_ON_ONCE(nsp->idt_seq & 0x1); + WRITE_ONCE(nsp->recv_jiffies, jiffies); + } ++ if (this_cpu_dec_return(nmi_state)) ++ goto nmi_restart; + } + + #if IS_ENABLED(CONFIG_KVM_INTEL) +@@ -631,7 +629,7 @@ void nmi_backtrace_stall_check(const struct cpumask *btp) + msgp = nmi_check_stall_msg[idx]; + if (nsp->idt_ignored_snap != READ_ONCE(nsp->idt_ignored) && (idx & 0x1)) + modp = ", but OK because ignore_nmis was set"; +- if (nmi_seq & ~0x1) ++ if (nmi_seq & 0x1) + msghp = " (CPU currently in NMI handler function)"; + else if (nsp->idt_nmi_seq_snap + 1 == nmi_seq) + msghp = " (CPU exited one NMI handler function)"; +diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c +index 97f1436c1a2034..8d51c86caa415f 100644 +--- a/arch/x86/kernel/paravirt.c ++++ b/arch/x86/kernel/paravirt.c +@@ -71,13 +71,12 @@ DEFINE_PARAVIRT_ASM(pv_native_irq_enable, "sti", .noinstr.text); + DEFINE_PARAVIRT_ASM(pv_native_read_cr2, "mov %cr2, %rax", .noinstr.text); + #endif + +-DEFINE_STATIC_KEY_TRUE(virt_spin_lock_key); ++DEFINE_STATIC_KEY_FALSE(virt_spin_lock_key); + + void __init native_pv_lock_init(void) + { +- if (IS_ENABLED(CONFIG_PARAVIRT_SPINLOCKS) && +- !boot_cpu_has(X86_FEATURE_HYPERVISOR)) +- static_branch_disable(&virt_spin_lock_key); ++ if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) ++ static_branch_enable(&virt_spin_lock_key); + } + + static void native_tlb_remove_table(struct mmu_gather *tlb, void *table) +diff --git a/arch/x86/kernel/probe_roms.c b/arch/x86/kernel/probe_roms.c +index 319fef37d9dce4..cc2c34ba7228ac 100644 +--- a/arch/x86/kernel/probe_roms.c ++++ b/arch/x86/kernel/probe_roms.c +@@ -203,16 +203,6 @@ void __init probe_roms(void) + unsigned char c; + int i; + +- /* +- * The ROM memory range is not part of the e820 table and is therefore not +- * pre-validated by BIOS. The kernel page table maps the ROM region as encrypted +- * memory, and SNP requires encrypted memory to be validated before access. +- * Do that here. +- */ +- snp_prep_memory(video_rom_resource.start, +- ((system_rom_resource.end + 1) - video_rom_resource.start), +- SNP_PAGE_STATE_PRIVATE); +- + /* video rom */ + upper = adapter_rom_resources[0].start; + for (start = video_rom_resource.start; start < upper; start += 2048) { +diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c +index b6f4e8399fca20..5351f293f770b5 100644 +--- a/arch/x86/kernel/process.c ++++ b/arch/x86/kernel/process.c +@@ -1030,7 +1030,10 @@ unsigned long arch_align_stack(unsigned long sp) + + unsigned long arch_randomize_brk(struct mm_struct *mm) + { +- return randomize_page(mm->brk, 0x02000000); ++ if (mmap_is_ia32()) ++ return randomize_page(mm->brk, SZ_32M); ++ ++ return randomize_page(mm->brk, SZ_1G); + } + + /* +diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c +index 33b268747bb7bb..d595ef7c1de05e 100644 +--- a/arch/x86/kernel/process_64.c ++++ b/arch/x86/kernel/process_64.c +@@ -138,7 +138,7 @@ void __show_regs(struct pt_regs *regs, enum show_regs_mode mode, + log_lvl, d3, d6, d7); + } + +- if (cpu_feature_enabled(X86_FEATURE_OSPKE)) ++ if (cr4 & X86_CR4_PKE) + printk("%sPKRU: %08x\n", log_lvl, read_pkru()); + } + +@@ -750,6 +750,27 @@ static long prctl_map_vdso(const struct vdso_image *image, unsigned long addr) + + #define LAM_U57_BITS 6 + ++static void enable_lam_func(void *__mm) ++{ ++ struct mm_struct *mm = __mm; ++ ++ if (this_cpu_read(cpu_tlbstate.loaded_mm) == mm) { ++ write_cr3(__read_cr3() | mm->context.lam_cr3_mask); ++ set_tlbstate_lam_mode(mm); ++ } ++} ++ ++static void mm_enable_lam(struct mm_struct *mm) ++{ ++ /* ++ * Even though the process must still be single-threaded at this ++ * point, kernel threads may be using the mm. IPI those kernel ++ * threads if they exist. ++ */ ++ on_each_cpu_mask(mm_cpumask(mm), enable_lam_func, mm, true); ++ set_bit(MM_CONTEXT_LOCK_LAM, &mm->context.flags); ++} ++ + static int prctl_enable_tagged_addr(struct mm_struct *mm, unsigned long nr_bits) + { + if (!cpu_feature_enabled(X86_FEATURE_LAM)) +@@ -766,6 +787,10 @@ static int prctl_enable_tagged_addr(struct mm_struct *mm, unsigned long nr_bits) + if (mmap_write_lock_killable(mm)) + return -EINTR; + ++ /* ++ * MM_CONTEXT_LOCK_LAM is set on clone. Prevent LAM from ++ * being enabled unless the process is single threaded: ++ */ + if (test_bit(MM_CONTEXT_LOCK_LAM, &mm->context.flags)) { + mmap_write_unlock(mm); + return -EBUSY; +@@ -782,9 +807,7 @@ static int prctl_enable_tagged_addr(struct mm_struct *mm, unsigned long nr_bits) + return -EINVAL; + } + +- write_cr3(__read_cr3() | mm->context.lam_cr3_mask); +- set_tlbstate_lam_mode(mm); +- set_bit(MM_CONTEXT_LOCK_LAM, &mm->context.flags); ++ mm_enable_lam(mm); + + mmap_write_unlock(mm); + +diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c +index 1309b9b053386b..2e7066980f3e8b 100644 +--- a/arch/x86/kernel/rtc.c ++++ b/arch/x86/kernel/rtc.c +@@ -67,7 +67,7 @@ void mach_get_cmos_time(struct timespec64 *now) + return; + } + +- if (mc146818_get_time(&tm)) { ++ if (mc146818_get_time(&tm, 1000)) { + pr_err("Unable to read current time from RTC\n"); + now->tv_sec = now->tv_nsec = 0; + return; +diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c +index b098b1fa247081..eb129277dcdd64 100644 +--- a/arch/x86/kernel/setup.c ++++ b/arch/x86/kernel/setup.c +@@ -9,7 +9,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -36,6 +35,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1029,7 +1029,7 @@ void __init setup_arch(char **cmdline_p) + efi_init(); + + reserve_ibft_region(); +- dmi_setup(); ++ x86_init.resources.dmi_setup(); + + /* + * VMware detection requires dmi to be available, so this +@@ -1121,6 +1121,7 @@ void __init setup_arch(char **cmdline_p) + * memory size. + */ + sev_setup_arch(); ++ cc_random_init(); + + efi_fake_memmap(); + efi_find_mirror(); +diff --git a/arch/x86/kernel/sev-shared.c b/arch/x86/kernel/sev-shared.c +index ccb0915e84e10c..acbec4de3ec31a 100644 +--- a/arch/x86/kernel/sev-shared.c ++++ b/arch/x86/kernel/sev-shared.c +@@ -89,7 +89,8 @@ static bool __init sev_es_check_cpu_features(void) + return true; + } + +-static void __noreturn sev_es_terminate(unsigned int set, unsigned int reason) ++static void __head __noreturn ++sev_es_terminate(unsigned int set, unsigned int reason) + { + u64 val = GHCB_MSR_TERM_REQ; + +@@ -326,13 +327,7 @@ static int sev_cpuid_hv(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid + */ + static const struct snp_cpuid_table *snp_cpuid_get_table(void) + { +- void *ptr; +- +- asm ("lea cpuid_table_copy(%%rip), %0" +- : "=r" (ptr) +- : "p" (&cpuid_table_copy)); +- +- return ptr; ++ return &RIP_REL_REF(cpuid_table_copy); + } + + /* +@@ -391,7 +386,7 @@ static u32 snp_cpuid_calc_xsave_size(u64 xfeatures_en, bool compacted) + return xsave_size; + } + +-static bool ++static bool __head + snp_cpuid_get_validated_func(struct cpuid_leaf *leaf) + { + const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table(); +@@ -528,7 +523,8 @@ static int snp_cpuid_postprocess(struct ghcb *ghcb, struct es_em_ctxt *ctxt, + * Returns -EOPNOTSUPP if feature not enabled. Any other non-zero return value + * should be treated as fatal by caller. + */ +-static int snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf) ++static int __head ++snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_leaf *leaf) + { + const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table(); + +@@ -556,9 +552,9 @@ static int snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_le + leaf->eax = leaf->ebx = leaf->ecx = leaf->edx = 0; + + /* Skip post-processing for out-of-range zero leafs. */ +- if (!(leaf->fn <= cpuid_std_range_max || +- (leaf->fn >= 0x40000000 && leaf->fn <= cpuid_hyp_range_max) || +- (leaf->fn >= 0x80000000 && leaf->fn <= cpuid_ext_range_max))) ++ if (!(leaf->fn <= RIP_REL_REF(cpuid_std_range_max) || ++ (leaf->fn >= 0x40000000 && leaf->fn <= RIP_REL_REF(cpuid_hyp_range_max)) || ++ (leaf->fn >= 0x80000000 && leaf->fn <= RIP_REL_REF(cpuid_ext_range_max)))) + return 0; + } + +@@ -570,7 +566,7 @@ static int snp_cpuid(struct ghcb *ghcb, struct es_em_ctxt *ctxt, struct cpuid_le + * page yet, so it only supports the MSR based communication with the + * hypervisor and only the CPUID exit-code. + */ +-void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code) ++void __head do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code) + { + unsigned int subfn = lower_bits(regs->cx, 32); + unsigned int fn = lower_bits(regs->ax, 32); +@@ -1016,7 +1012,8 @@ struct cc_setup_data { + * Search for a Confidential Computing blob passed in as a setup_data entry + * via the Linux Boot Protocol. + */ +-static struct cc_blob_sev_info *find_cc_blob_setup_data(struct boot_params *bp) ++static __head ++struct cc_blob_sev_info *find_cc_blob_setup_data(struct boot_params *bp) + { + struct cc_setup_data *sd = NULL; + struct setup_data *hdr; +@@ -1043,7 +1040,7 @@ static struct cc_blob_sev_info *find_cc_blob_setup_data(struct boot_params *bp) + * mapping needs to be updated in sync with all the changes to virtual memory + * layout and related mapping facilities throughout the boot process. + */ +-static void __init setup_cpuid_table(const struct cc_blob_sev_info *cc_info) ++static void __head setup_cpuid_table(const struct cc_blob_sev_info *cc_info) + { + const struct snp_cpuid_table *cpuid_table_fw, *cpuid_table; + int i; +@@ -1063,11 +1060,11 @@ static void __init setup_cpuid_table(const struct cc_blob_sev_info *cc_info) + const struct snp_cpuid_fn *fn = &cpuid_table->fn[i]; + + if (fn->eax_in == 0x0) +- cpuid_std_range_max = fn->eax; ++ RIP_REL_REF(cpuid_std_range_max) = fn->eax; + else if (fn->eax_in == 0x40000000) +- cpuid_hyp_range_max = fn->eax; ++ RIP_REL_REF(cpuid_hyp_range_max) = fn->eax; + else if (fn->eax_in == 0x80000000) +- cpuid_ext_range_max = fn->eax; ++ RIP_REL_REF(cpuid_ext_range_max) = fn->eax; + } + } + +diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c +index 6395bfd87b68b5..9905dc0e0b0960 100644 +--- a/arch/x86/kernel/sev.c ++++ b/arch/x86/kernel/sev.c +@@ -23,8 +23,10 @@ + #include + #include + #include ++#include + #include + ++#include + #include + #include + #include +@@ -682,8 +684,9 @@ static u64 __init get_jump_table_addr(void) + return ret; + } + +-static void early_set_pages_state(unsigned long vaddr, unsigned long paddr, +- unsigned long npages, enum psc_op op) ++static void __head ++early_set_pages_state(unsigned long vaddr, unsigned long paddr, ++ unsigned long npages, enum psc_op op) + { + unsigned long paddr_end; + u64 val; +@@ -739,7 +742,7 @@ static void early_set_pages_state(unsigned long vaddr, unsigned long paddr, + sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC); + } + +-void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr, ++void __head early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr, + unsigned long npages) + { + /* +@@ -748,7 +751,7 @@ void __init early_snp_set_memory_private(unsigned long vaddr, unsigned long padd + * This eliminates worries about jump tables or checking boot_cpu_data + * in the cc_platform_has() function. + */ +- if (!(sev_status & MSR_AMD64_SEV_SNP_ENABLED)) ++ if (!(RIP_REL_REF(sev_status) & MSR_AMD64_SEV_SNP_ENABLED)) + return; + + /* +@@ -767,28 +770,13 @@ void __init early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr + * This eliminates worries about jump tables or checking boot_cpu_data + * in the cc_platform_has() function. + */ +- if (!(sev_status & MSR_AMD64_SEV_SNP_ENABLED)) ++ if (!(RIP_REL_REF(sev_status) & MSR_AMD64_SEV_SNP_ENABLED)) + return; + + /* Ask hypervisor to mark the memory pages shared in the RMP table. */ + early_set_pages_state(vaddr, paddr, npages, SNP_PAGE_STATE_SHARED); + } + +-void __init snp_prep_memory(unsigned long paddr, unsigned int sz, enum psc_op op) +-{ +- unsigned long vaddr, npages; +- +- vaddr = (unsigned long)__va(paddr); +- npages = PAGE_ALIGN(sz) >> PAGE_SHIFT; +- +- if (op == SNP_PAGE_STATE_PRIVATE) +- early_snp_set_memory_private(vaddr, paddr, npages); +- else if (op == SNP_PAGE_STATE_SHARED) +- early_snp_set_memory_shared(vaddr, paddr, npages); +- else +- WARN(1, "invalid memory op %d\n", op); +-} +- + static unsigned long __set_pages_state(struct snp_psc_desc *data, unsigned long vaddr, + unsigned long vaddr_end, int op) + { +@@ -1234,10 +1222,6 @@ void setup_ghcb(void) + if (!cc_platform_has(CC_ATTR_GUEST_STATE_ENCRYPT)) + return; + +- /* First make sure the hypervisor talks a supported protocol. */ +- if (!sev_es_negotiate_protocol()) +- sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ); +- + /* + * Check whether the runtime #VC exception handler is active. It uses + * the per-CPU GHCB page which is set up by sev_es_init_vc_handling(). +@@ -1254,6 +1238,13 @@ void setup_ghcb(void) + return; + } + ++ /* ++ * Make sure the hypervisor talks a supported protocol. ++ * This gets called only in the BSP boot phase. ++ */ ++ if (!sev_es_negotiate_protocol()) ++ sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ); ++ + /* + * Clear the boot_ghcb. The first exception comes in before the bss + * section is cleared. +@@ -2056,7 +2047,7 @@ bool __init handle_vc_boot_ghcb(struct pt_regs *regs) + * + * Scan for the blob in that order. + */ +-static __init struct cc_blob_sev_info *find_cc_blob(struct boot_params *bp) ++static __head struct cc_blob_sev_info *find_cc_blob(struct boot_params *bp) + { + struct cc_blob_sev_info *cc_info; + +@@ -2082,7 +2073,7 @@ static __init struct cc_blob_sev_info *find_cc_blob(struct boot_params *bp) + return cc_info; + } + +-bool __init snp_init(struct boot_params *bp) ++bool __head snp_init(struct boot_params *bp) + { + struct cc_blob_sev_info *cc_info; + +@@ -2104,11 +2095,22 @@ bool __init snp_init(struct boot_params *bp) + return true; + } + +-void __init __noreturn snp_abort(void) ++void __head __noreturn snp_abort(void) + { + sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED); + } + ++/* ++ * SEV-SNP guests should only execute dmi_setup() if EFI_CONFIG_TABLES are ++ * enabled, as the alternative (fallback) logic for DMI probing in the legacy ++ * ROM region can cause a crash since this region is not pre-validated. ++ */ ++void __init snp_dmi_setup(void) ++{ ++ if (efi_enabled(EFI_CONFIG_TABLES)) ++ dmi_setup(); ++} ++ + static void dump_cpuid_table(void) + { + const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table(); +diff --git a/arch/x86/kernel/shstk.c b/arch/x86/kernel/shstk.c +index 59e15dd8d0f866..19e4db582fb69a 100644 +--- a/arch/x86/kernel/shstk.c ++++ b/arch/x86/kernel/shstk.c +@@ -577,3 +577,14 @@ long shstk_prctl(struct task_struct *task, int option, unsigned long arg2) + return wrss_control(true); + return -EINVAL; + } ++ ++int shstk_update_last_frame(unsigned long val) ++{ ++ unsigned long ssp; ++ ++ if (!features_enabled(ARCH_SHSTK_SHSTK)) ++ return 0; ++ ++ ssp = get_user_shstk_addr(); ++ return write_user_shstk_64((u64 __user *)ssp, (u64)val); ++} +diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c +index 65fe2094da59b8..876d3b30c2c774 100644 +--- a/arch/x86/kernel/signal.c ++++ b/arch/x86/kernel/signal.c +@@ -83,6 +83,7 @@ get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size, + unsigned long math_size = 0; + unsigned long sp = regs->sp; + unsigned long buf_fx = 0; ++ u32 pkru = read_pkru(); + + /* redzone */ + if (!ia32_frame) +@@ -138,7 +139,7 @@ get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size, + } + + /* save i387 and extended state */ +- if (!copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size)) ++ if (!copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size, pkru)) + return (void __user *)-1L; + + return (void __user *)sp; +diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c +index cacf2ede62175d..449a6ed0b8c982 100644 +--- a/arch/x86/kernel/signal_64.c ++++ b/arch/x86/kernel/signal_64.c +@@ -175,9 +175,6 @@ int x64_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs) + frame = get_sigframe(ksig, regs, sizeof(struct rt_sigframe), &fp); + uc_flags = frame_uc_flags(regs); + +- if (setup_signal_shadow_stack(ksig)) +- return -EFAULT; +- + if (!user_access_begin(frame, sizeof(*frame))) + return -EFAULT; + +@@ -198,6 +195,9 @@ int x64_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs) + return -EFAULT; + } + ++ if (setup_signal_shadow_stack(ksig)) ++ return -EFAULT; ++ + /* Set up registers for signal handler */ + regs->di = ksig->sig; + /* In case the signal handler was declared without prototypes */ +@@ -260,13 +260,13 @@ SYSCALL_DEFINE0(rt_sigreturn) + + set_current_blocked(&set); + +- if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags)) ++ if (restore_altstack(&frame->uc.uc_stack)) + goto badframe; + +- if (restore_signal_shadow_stack()) ++ if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags)) + goto badframe; + +- if (restore_altstack(&frame->uc.uc_stack)) ++ if (restore_signal_shadow_stack()) + goto badframe; + + return regs->ax; +diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c +index 2a187c0cbd5b11..ce77dac9a0202a 100644 +--- a/arch/x86/kernel/smpboot.c ++++ b/arch/x86/kernel/smpboot.c +@@ -60,6 +60,7 @@ + #include + #include + #include ++#include + + #include + #include +diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c +index e42faa792c0793..52e1f3f0b361ce 100644 +--- a/arch/x86/kernel/time.c ++++ b/arch/x86/kernel/time.c +@@ -27,25 +27,7 @@ + + unsigned long profile_pc(struct pt_regs *regs) + { +- unsigned long pc = instruction_pointer(regs); +- +- if (!user_mode(regs) && in_lock_functions(pc)) { +-#ifdef CONFIG_FRAME_POINTER +- return *(unsigned long *)(regs->bp + sizeof(long)); +-#else +- unsigned long *sp = (unsigned long *)regs->sp; +- /* +- * Return address is either directly at stack pointer +- * or above a saved flags. Eflags has bits 22-31 zero, +- * kernel addresses don't. +- */ +- if (sp[0] >> 22) +- return sp[0]; +- if (sp[1] >> 22) +- return sp[1]; +-#endif +- } +- return pc; ++ return instruction_pointer(regs); + } + EXPORT_SYMBOL(profile_pc); + +diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c +index 1123ef3ccf9011..4334033658edfb 100644 +--- a/arch/x86/kernel/tsc_sync.c ++++ b/arch/x86/kernel/tsc_sync.c +@@ -193,11 +193,9 @@ bool tsc_store_and_check_tsc_adjust(bool bootcpu) + cur->warned = false; + + /* +- * If a non-zero TSC value for socket 0 may be valid then the default +- * adjusted value cannot assumed to be zero either. ++ * The default adjust value cannot be assumed to be zero on any socket. + */ +- if (tsc_async_resets) +- cur->adjusted = bootval; ++ cur->adjusted = bootval; + + /* + * Check whether this CPU is the first in a package to come up. In +diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c +index 6c07f6daaa227a..6402fb3089d262 100644 +--- a/arch/x86/kernel/uprobes.c ++++ b/arch/x86/kernel/uprobes.c +@@ -1076,8 +1076,13 @@ arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs + return orig_ret_vaddr; + + nleft = copy_to_user((void __user *)regs->sp, &trampoline_vaddr, rasize); +- if (likely(!nleft)) ++ if (likely(!nleft)) { ++ if (shstk_update_last_frame(trampoline_vaddr)) { ++ force_sig(SIGSEGV); ++ return -1; ++ } + return orig_ret_vaddr; ++ } + + if (nleft != rasize) { + pr_err("return address clobbered: pid=%d, %%sp=%#lx, %%ip=%#lx\n", +diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S +index f15fb71f280e24..54a5596adaa61e 100644 +--- a/arch/x86/kernel/vmlinux.lds.S ++++ b/arch/x86/kernel/vmlinux.lds.S +@@ -139,10 +139,7 @@ SECTIONS + STATIC_CALL_TEXT + + ALIGN_ENTRY_TEXT_BEGIN +-#ifdef CONFIG_CPU_SRSO + *(.text..__x86.rethunk_untrain) +-#endif +- + ENTRY_TEXT + + #ifdef CONFIG_CPU_SRSO +@@ -520,12 +517,12 @@ INIT_PER_CPU(irq_stack_backing_store); + "fixed_percpu_data is not at start of per-cpu area"); + #endif + +-#ifdef CONFIG_RETHUNK ++#ifdef CONFIG_CPU_UNRET_ENTRY + . = ASSERT((retbleed_return_thunk & 0x3f) == 0, "retbleed_return_thunk not cacheline-aligned"); +-. = ASSERT((srso_safe_ret & 0x3f) == 0, "srso_safe_ret not cacheline-aligned"); + #endif + + #ifdef CONFIG_CPU_SRSO ++. = ASSERT((srso_safe_ret & 0x3f) == 0, "srso_safe_ret not cacheline-aligned"); + /* + * GNU ld cannot do XOR until 2.41. + * https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=f6f78318fca803c4907fb8d7f6ded8295f1947b1 +diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c +index a37ebd3b47736d..268627a17cf0d8 100644 +--- a/arch/x86/kernel/x86_init.c ++++ b/arch/x86/kernel/x86_init.c +@@ -3,10 +3,12 @@ + * + * For licencing details see kernel-base/COPYING + */ ++#include + #include + #include + #include + #include ++#include + + #include + #include +@@ -66,6 +68,7 @@ struct x86_init_ops x86_init __initdata = { + .probe_roms = probe_roms, + .reserve_resources = reserve_standard_io_resources, + .memory_setup = e820__memory_setup_default, ++ .dmi_setup = dmi_setup, + }, + + .mpparse = { +diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile +index 80e3fe184d17e6..a99ffc3f3a3fdb 100644 +--- a/arch/x86/kvm/Makefile ++++ b/arch/x86/kvm/Makefile +@@ -26,6 +26,10 @@ kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \ + vmx/hyperv.o vmx/nested.o vmx/posted_intr.o + kvm-intel-$(CONFIG_X86_SGX_KVM) += vmx/sgx.o + ++ifdef CONFIG_HYPERV ++kvm-intel-y += vmx/vmx_onhyperv.o ++endif ++ + kvm-amd-y += svm/svm.o svm/vmenter.o svm/pmu.o svm/nested.o svm/avic.o \ + svm/sev.o svm/hyperv.o + +diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c +index 773132c3bf5af7..ac042a9a61f576 100644 +--- a/arch/x86/kvm/cpuid.c ++++ b/arch/x86/kvm/cpuid.c +@@ -362,6 +362,7 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) + + kvm_update_pv_runtime(vcpu); + ++ vcpu->arch.is_amd_compatible = guest_cpuid_is_amd_or_hygon(vcpu); + vcpu->arch.maxphyaddr = cpuid_query_maxphyaddr(vcpu); + vcpu->arch.reserved_gpa_bits = kvm_vcpu_reserved_gpa_bits_raw(vcpu); + +@@ -677,6 +678,11 @@ void kvm_set_cpu_caps(void) + F(AMX_COMPLEX) + ); + ++ kvm_cpu_cap_init_kvm_defined(CPUID_7_2_EDX, ++ F(INTEL_PSFD) | F(IPRED_CTRL) | F(RRSBA_CTRL) | F(DDPD_U) | ++ F(BHI_CTRL) | F(MCDT_NO) ++ ); ++ + kvm_cpu_cap_mask(CPUID_D_1_EAX, + F(XSAVEOPT) | F(XSAVEC) | F(XGETBV1) | F(XSAVES) | f_xfd + ); +@@ -956,13 +962,13 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) + break; + /* function 7 has additional index. */ + case 7: +- entry->eax = min(entry->eax, 1u); ++ max_idx = entry->eax = min(entry->eax, 2u); + cpuid_entry_override(entry, CPUID_7_0_EBX); + cpuid_entry_override(entry, CPUID_7_ECX); + cpuid_entry_override(entry, CPUID_7_EDX); + +- /* KVM only supports 0x7.0 and 0x7.1, capped above via min(). */ +- if (entry->eax == 1) { ++ /* KVM only supports up to 0x7.2, capped above via min(). */ ++ if (max_idx >= 1) { + entry = do_host_cpuid(array, function, 1); + if (!entry) + goto out; +@@ -972,6 +978,16 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) + entry->ebx = 0; + entry->ecx = 0; + } ++ if (max_idx >= 2) { ++ entry = do_host_cpuid(array, function, 2); ++ if (!entry) ++ goto out; ++ ++ cpuid_entry_override(entry, CPUID_7_2_EDX); ++ entry->ecx = 0; ++ entry->ebx = 0; ++ entry->eax = 0; ++ } + break; + case 0xa: { /* Architectural Performance Monitoring */ + union cpuid10_eax eax; +@@ -1196,9 +1212,8 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) + entry->eax = entry->ebx = entry->ecx = 0; + break; + case 0x80000008: { +- unsigned g_phys_as = (entry->eax >> 16) & 0xff; +- unsigned virt_as = max((entry->eax >> 8) & 0xff, 48U); +- unsigned phys_as = entry->eax & 0xff; ++ unsigned int virt_as = max((entry->eax >> 8) & 0xff, 48U); ++ unsigned int phys_as; + + /* + * If TDP (NPT) is disabled use the adjusted host MAXPHYADDR as +@@ -1206,16 +1221,16 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) + * reductions in MAXPHYADDR for memory encryption affect shadow + * paging, too. + * +- * If TDP is enabled but an explicit guest MAXPHYADDR is not +- * provided, use the raw bare metal MAXPHYADDR as reductions to +- * the HPAs do not affect GPAs. ++ * If TDP is enabled, use the raw bare metal MAXPHYADDR as ++ * reductions to the HPAs do not affect GPAs. + */ +- if (!tdp_enabled) +- g_phys_as = boot_cpu_data.x86_phys_bits; +- else if (!g_phys_as) +- g_phys_as = phys_as; ++ if (!tdp_enabled) { ++ phys_as = boot_cpu_data.x86_phys_bits; ++ } else { ++ phys_as = entry->eax & 0xff; ++ } + +- entry->eax = g_phys_as | (virt_as << 8); ++ entry->eax = phys_as | (virt_as << 8); + entry->ecx &= ~(GENMASK(31, 16) | GENMASK(11, 8)); + entry->edx = 0; + cpuid_entry_override(entry, CPUID_8000_0008_EBX); +diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h +index 284fa4704553da..57ee789ada1411 100644 +--- a/arch/x86/kvm/cpuid.h ++++ b/arch/x86/kvm/cpuid.h +@@ -125,6 +125,16 @@ static inline bool guest_cpuid_is_intel(struct kvm_vcpu *vcpu) + return best && is_guest_vendor_intel(best->ebx, best->ecx, best->edx); + } + ++static inline bool guest_cpuid_is_amd_compatible(struct kvm_vcpu *vcpu) ++{ ++ return vcpu->arch.is_amd_compatible; ++} ++ ++static inline bool guest_cpuid_is_intel_compatible(struct kvm_vcpu *vcpu) ++{ ++ return !guest_cpuid_is_amd_compatible(vcpu); ++} ++ + static inline int guest_cpuid_family(struct kvm_vcpu *vcpu) + { + struct kvm_cpuid_entry2 *best; +diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c +index 7c2dac6824e262..238afd7335e46d 100644 +--- a/arch/x86/kvm/hyperv.c ++++ b/arch/x86/kvm/hyperv.c +@@ -727,10 +727,12 @@ static int stimer_set_count(struct kvm_vcpu_hv_stimer *stimer, u64 count, + + stimer_cleanup(stimer); + stimer->count = count; +- if (stimer->count == 0) +- stimer->config.enable = 0; +- else if (stimer->config.auto_enable) +- stimer->config.enable = 1; ++ if (!host) { ++ if (stimer->count == 0) ++ stimer->config.enable = 0; ++ else if (stimer->config.auto_enable) ++ stimer->config.enable = 1; ++ } + + if (stimer->config.enable) + stimer_mark_pending(stimer, false); +diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c +index 3e977dbbf9933d..1380f34897770d 100644 +--- a/arch/x86/kvm/lapic.c ++++ b/arch/x86/kvm/lapic.c +@@ -41,6 +41,7 @@ + #include "ioapic.h" + #include "trace.h" + #include "x86.h" ++#include "xen.h" + #include "cpuid.h" + #include "hyperv.h" + #include "smm.h" +@@ -499,8 +500,10 @@ static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val) + } + + /* Check if there are APF page ready requests pending */ +- if (enabled) ++ if (enabled) { + kvm_make_request(KVM_REQ_APF_READY, apic->vcpu); ++ kvm_xen_sw_enable_lapic(apic->vcpu); ++ } + } + + static inline void kvm_apic_set_xapic_id(struct kvm_lapic *apic, u8 id) +@@ -2440,26 +2443,49 @@ void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu) + } + EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi); + ++#define X2APIC_ICR_RESERVED_BITS (GENMASK_ULL(31, 20) | GENMASK_ULL(17, 16) | BIT(13)) ++ ++int kvm_x2apic_icr_write(struct kvm_lapic *apic, u64 data) ++{ ++ if (data & X2APIC_ICR_RESERVED_BITS) ++ return 1; ++ ++ /* ++ * The BUSY bit is reserved on both Intel and AMD in x2APIC mode, but ++ * only AMD requires it to be zero, Intel essentially just ignores the ++ * bit. And if IPI virtualization (Intel) or x2AVIC (AMD) is enabled, ++ * the CPU performs the reserved bits checks, i.e. the underlying CPU ++ * behavior will "win". Arbitrarily clear the BUSY bit, as there is no ++ * sane way to provide consistent behavior with respect to hardware. ++ */ ++ data &= ~APIC_ICR_BUSY; ++ ++ kvm_apic_send_ipi(apic, (u32)data, (u32)(data >> 32)); ++ kvm_lapic_set_reg64(apic, APIC_ICR, data); ++ trace_kvm_apic_write(APIC_ICR, data); ++ return 0; ++} ++ + /* emulate APIC access in a trap manner */ + void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset) + { + struct kvm_lapic *apic = vcpu->arch.apic; +- u64 val; + + /* +- * ICR is a single 64-bit register when x2APIC is enabled. For legacy +- * xAPIC, ICR writes need to go down the common (slightly slower) path +- * to get the upper half from ICR2. ++ * ICR is a single 64-bit register when x2APIC is enabled, all others ++ * registers hold 32-bit values. For legacy xAPIC, ICR writes need to ++ * go down the common path to get the upper half from ICR2. ++ * ++ * Note, using the write helpers may incur an unnecessary write to the ++ * virtual APIC state, but KVM needs to conditionally modify the value ++ * in certain cases, e.g. to clear the ICR busy bit. The cost of extra ++ * conditional branches is likely a wash relative to the cost of the ++ * maybe-unecessary write, and both are in the noise anyways. + */ +- if (apic_x2apic_mode(apic) && offset == APIC_ICR) { +- val = kvm_lapic_get_reg64(apic, APIC_ICR); +- kvm_apic_send_ipi(apic, (u32)val, (u32)(val >> 32)); +- trace_kvm_apic_write(APIC_ICR, val); +- } else { +- /* TODO: optimize to just emulate side effect w/o one more write */ +- val = kvm_lapic_get_reg(apic, offset); +- kvm_lapic_reg_write(apic, offset, (u32)val); +- } ++ if (apic_x2apic_mode(apic) && offset == APIC_ICR) ++ WARN_ON_ONCE(kvm_x2apic_icr_write(apic, kvm_lapic_get_reg64(apic, APIC_ICR))); ++ else ++ kvm_lapic_reg_write(apic, offset, kvm_lapic_get_reg(apic, offset)); + } + EXPORT_SYMBOL_GPL(kvm_apic_write_nodecode); + +@@ -2670,6 +2696,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event) + u64 msr_val; + int i; + ++ static_call_cond(kvm_x86_apicv_pre_state_restore)(vcpu); ++ + if (!init_event) { + msr_val = APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE; + if (kvm_vcpu_is_reset_bsp(vcpu)) +@@ -2767,7 +2795,8 @@ int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type) + trig_mode = reg & APIC_LVT_LEVEL_TRIGGER; + + r = __apic_accept_irq(apic, mode, vector, 1, trig_mode, NULL); +- if (r && lvt_type == APIC_LVTPC) ++ if (r && lvt_type == APIC_LVTPC && ++ guest_cpuid_is_intel_compatible(apic->vcpu)) + kvm_lapic_set_reg(apic, APIC_LVTPC, reg | APIC_LVT_MASKED); + return r; + } +@@ -2981,6 +3010,8 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s) + struct kvm_lapic *apic = vcpu->arch.apic; + int r; + ++ static_call_cond(kvm_x86_apicv_pre_state_restore)(vcpu); ++ + kvm_lapic_set_base(vcpu, vcpu->arch.apic_base); + /* set SPIV separately to get count of SW disabled APICs right */ + apic_set_spiv(apic, *((u32 *)(s->regs + APIC_SPIV))); +@@ -3145,16 +3176,6 @@ int kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr) + return 0; + } + +-int kvm_x2apic_icr_write(struct kvm_lapic *apic, u64 data) +-{ +- data &= ~APIC_ICR_BUSY; +- +- kvm_apic_send_ipi(apic, (u32)data, (u32)(data >> 32)); +- kvm_lapic_set_reg64(apic, APIC_ICR, data); +- trace_kvm_apic_write(APIC_ICR, data); +- return 0; +-} +- + static int kvm_lapic_msr_read(struct kvm_lapic *apic, u32 reg, u64 *data) + { + u32 low; +diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c +index f7901cb4d2fa4b..294775b7383b42 100644 +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -3120,7 +3120,7 @@ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn, + if (pud_none(pud) || !pud_present(pud)) + goto out; + +- if (pud_large(pud)) { ++ if (pud_leaf(pud)) { + level = PG_LEVEL_1G; + goto out; + } +@@ -4788,7 +4788,7 @@ static void reset_guest_rsvds_bits_mask(struct kvm_vcpu *vcpu, + context->cpu_role.base.level, is_efer_nx(context), + guest_can_use(vcpu, X86_FEATURE_GBPAGES), + is_cr4_pse(context), +- guest_cpuid_is_amd_or_hygon(vcpu)); ++ guest_cpuid_is_amd_compatible(vcpu)); + } + + static void __reset_rsvds_bits_mask_ept(struct rsvd_bits_validate *rsvd_check, +diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c +index 6cd4dd631a2fac..8eef3ed5fe04e2 100644 +--- a/arch/x86/kvm/mmu/tdp_mmu.c ++++ b/arch/x86/kvm/mmu/tdp_mmu.c +@@ -1506,6 +1506,16 @@ void kvm_tdp_mmu_try_split_huge_pages(struct kvm *kvm, + } + } + ++static bool tdp_mmu_need_write_protect(struct kvm_mmu_page *sp) ++{ ++ /* ++ * All TDP MMU shadow pages share the same role as their root, aside ++ * from level, so it is valid to key off any shadow page to determine if ++ * write protection is needed for an entire tree. ++ */ ++ return kvm_mmu_page_ad_need_write_protect(sp) || !kvm_ad_enabled(); ++} ++ + /* + * Clear the dirty status of all the SPTEs mapping GFNs in the memslot. If + * AD bits are enabled, this will involve clearing the dirty bit on each SPTE. +@@ -1516,7 +1526,8 @@ void kvm_tdp_mmu_try_split_huge_pages(struct kvm *kvm, + static bool clear_dirty_gfn_range(struct kvm *kvm, struct kvm_mmu_page *root, + gfn_t start, gfn_t end) + { +- u64 dbit = kvm_ad_enabled() ? shadow_dirty_mask : PT_WRITABLE_MASK; ++ const u64 dbit = tdp_mmu_need_write_protect(root) ? PT_WRITABLE_MASK : ++ shadow_dirty_mask; + struct tdp_iter iter; + bool spte_set = false; + +@@ -1530,7 +1541,7 @@ static bool clear_dirty_gfn_range(struct kvm *kvm, struct kvm_mmu_page *root, + if (!is_shadow_present_pte(iter.old_spte)) + continue; + +- KVM_MMU_WARN_ON(kvm_ad_enabled() && ++ KVM_MMU_WARN_ON(dbit == shadow_dirty_mask && + spte_ad_need_write_protect(iter.old_spte)); + + if (!(iter.old_spte & dbit)) +@@ -1578,8 +1589,8 @@ bool kvm_tdp_mmu_clear_dirty_slot(struct kvm *kvm, + static void clear_dirty_pt_masked(struct kvm *kvm, struct kvm_mmu_page *root, + gfn_t gfn, unsigned long mask, bool wrprot) + { +- u64 dbit = (wrprot || !kvm_ad_enabled()) ? PT_WRITABLE_MASK : +- shadow_dirty_mask; ++ const u64 dbit = (wrprot || tdp_mmu_need_write_protect(root)) ? PT_WRITABLE_MASK : ++ shadow_dirty_mask; + struct tdp_iter iter; + + lockdep_assert_held_write(&kvm->mmu_lock); +@@ -1591,7 +1602,7 @@ static void clear_dirty_pt_masked(struct kvm *kvm, struct kvm_mmu_page *root, + if (!mask) + break; + +- KVM_MMU_WARN_ON(kvm_ad_enabled() && ++ KVM_MMU_WARN_ON(dbit == shadow_dirty_mask && + spte_ad_need_write_protect(iter.old_spte)); + + if (iter.level > PG_LEVEL_4K || +diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c +index 9ae07db6f0f648..da2d82e3a8735e 100644 +--- a/arch/x86/kvm/pmu.c ++++ b/arch/x86/kvm/pmu.c +@@ -250,6 +250,24 @@ static bool pmc_resume_counter(struct kvm_pmc *pmc) + return true; + } + ++static void pmc_release_perf_event(struct kvm_pmc *pmc) ++{ ++ if (pmc->perf_event) { ++ perf_event_release_kernel(pmc->perf_event); ++ pmc->perf_event = NULL; ++ pmc->current_config = 0; ++ pmc_to_pmu(pmc)->event_count--; ++ } ++} ++ ++static void pmc_stop_counter(struct kvm_pmc *pmc) ++{ ++ if (pmc->perf_event) { ++ pmc->counter = pmc_read_counter(pmc); ++ pmc_release_perf_event(pmc); ++ } ++} ++ + static int filter_cmp(const void *pa, const void *pb, u64 mask) + { + u64 a = *(u64 *)pa & mask; +@@ -639,22 +657,79 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + return 0; + } + +-/* refresh PMU settings. This function generally is called when underlying +- * settings are changed (such as changes of PMU CPUID by guest VMs), which +- * should rarely happen. ++void kvm_pmu_reset(struct kvm_vcpu *vcpu) ++{ ++ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); ++ struct kvm_pmc *pmc; ++ int i; ++ ++ pmu->need_cleanup = false; ++ ++ bitmap_zero(pmu->reprogram_pmi, X86_PMC_IDX_MAX); ++ ++ for_each_set_bit(i, pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX) { ++ pmc = static_call(kvm_x86_pmu_pmc_idx_to_pmc)(pmu, i); ++ if (!pmc) ++ continue; ++ ++ pmc_stop_counter(pmc); ++ pmc->counter = 0; ++ ++ if (pmc_is_gp(pmc)) ++ pmc->eventsel = 0; ++ } ++ ++ pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status = 0; ++ ++ static_call_cond(kvm_x86_pmu_reset)(vcpu); ++} ++ ++ ++/* ++ * Refresh the PMU configuration for the vCPU, e.g. if userspace changes CPUID ++ * and/or PERF_CAPABILITIES. + */ + void kvm_pmu_refresh(struct kvm_vcpu *vcpu) + { ++ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); ++ + if (KVM_BUG_ON(kvm_vcpu_has_run(vcpu), vcpu->kvm)) + return; + +- bitmap_zero(vcpu_to_pmu(vcpu)->all_valid_pmc_idx, X86_PMC_IDX_MAX); ++ /* ++ * Stop/release all existing counters/events before realizing the new ++ * vPMU model. ++ */ ++ kvm_pmu_reset(vcpu); ++ ++ pmu->version = 0; ++ pmu->nr_arch_gp_counters = 0; ++ pmu->nr_arch_fixed_counters = 0; ++ pmu->counter_bitmask[KVM_PMC_GP] = 0; ++ pmu->counter_bitmask[KVM_PMC_FIXED] = 0; ++ pmu->reserved_bits = 0xffffffff00200000ull; ++ pmu->raw_event_mask = X86_RAW_EVENT_MASK; ++ pmu->global_ctrl_mask = ~0ull; ++ pmu->global_status_mask = ~0ull; ++ pmu->fixed_ctr_ctrl_mask = ~0ull; ++ pmu->pebs_enable_mask = ~0ull; ++ pmu->pebs_data_cfg_mask = ~0ull; ++ bitmap_zero(pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX); ++ ++ if (!vcpu->kvm->arch.enable_pmu) ++ return; ++ + static_call(kvm_x86_pmu_refresh)(vcpu); +-} + +-void kvm_pmu_reset(struct kvm_vcpu *vcpu) +-{ +- static_call(kvm_x86_pmu_reset)(vcpu); ++ /* ++ * At RESET, both Intel and AMD CPUs set all enable bits for general ++ * purpose counters in IA32_PERF_GLOBAL_CTRL (so that software that ++ * was written for v1 PMUs don't unknowingly leave GP counters disabled ++ * in the global controls). Emulate that behavior when refreshing the ++ * PMU so that userspace doesn't need to manually set PERF_GLOBAL_CTRL. ++ */ ++ if (kvm_pmu_has_perf_global_ctrl(pmu) && pmu->nr_arch_gp_counters) ++ pmu->global_ctrl = GENMASK_ULL(pmu->nr_arch_gp_counters - 1, 0); + } + + void kvm_pmu_init(struct kvm_vcpu *vcpu) +diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h +index 1d64113de4883e..a46aa9b25150f5 100644 +--- a/arch/x86/kvm/pmu.h ++++ b/arch/x86/kvm/pmu.h +@@ -80,24 +80,6 @@ static inline void pmc_write_counter(struct kvm_pmc *pmc, u64 val) + pmc->counter &= pmc_bitmask(pmc); + } + +-static inline void pmc_release_perf_event(struct kvm_pmc *pmc) +-{ +- if (pmc->perf_event) { +- perf_event_release_kernel(pmc->perf_event); +- pmc->perf_event = NULL; +- pmc->current_config = 0; +- pmc_to_pmu(pmc)->event_count--; +- } +-} +- +-static inline void pmc_stop_counter(struct kvm_pmc *pmc) +-{ +- if (pmc->perf_event) { +- pmc->counter = pmc_read_counter(pmc); +- pmc_release_perf_event(pmc); +- } +-} +- + static inline bool pmc_is_gp(struct kvm_pmc *pmc) + { + return pmc->type == KVM_PMC_GP; +diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h +index b816506783755a..2f4e155080badc 100644 +--- a/arch/x86/kvm/reverse_cpuid.h ++++ b/arch/x86/kvm/reverse_cpuid.h +@@ -16,6 +16,7 @@ enum kvm_only_cpuid_leafs { + CPUID_7_1_EDX, + CPUID_8000_0007_EDX, + CPUID_8000_0022_EAX, ++ CPUID_7_2_EDX, + NR_KVM_CPU_CAPS, + + NKVMCAPINTS = NR_KVM_CPU_CAPS - NCAPINTS, +@@ -46,6 +47,14 @@ enum kvm_only_cpuid_leafs { + #define X86_FEATURE_AMX_COMPLEX KVM_X86_FEATURE(CPUID_7_1_EDX, 8) + #define X86_FEATURE_PREFETCHITI KVM_X86_FEATURE(CPUID_7_1_EDX, 14) + ++/* Intel-defined sub-features, CPUID level 0x00000007:2 (EDX) */ ++#define X86_FEATURE_INTEL_PSFD KVM_X86_FEATURE(CPUID_7_2_EDX, 0) ++#define X86_FEATURE_IPRED_CTRL KVM_X86_FEATURE(CPUID_7_2_EDX, 1) ++#define KVM_X86_FEATURE_RRSBA_CTRL KVM_X86_FEATURE(CPUID_7_2_EDX, 2) ++#define X86_FEATURE_DDPD_U KVM_X86_FEATURE(CPUID_7_2_EDX, 3) ++#define KVM_X86_FEATURE_BHI_CTRL KVM_X86_FEATURE(CPUID_7_2_EDX, 4) ++#define X86_FEATURE_MCDT_NO KVM_X86_FEATURE(CPUID_7_2_EDX, 5) ++ + /* CPUID level 0x80000007 (EDX). */ + #define KVM_X86_FEATURE_CONSTANT_TSC KVM_X86_FEATURE(CPUID_8000_0007_EDX, 8) + +@@ -80,6 +89,7 @@ static const struct cpuid_reg reverse_cpuid[] = { + [CPUID_8000_0007_EDX] = {0x80000007, 0, CPUID_EDX}, + [CPUID_8000_0021_EAX] = {0x80000021, 0, CPUID_EAX}, + [CPUID_8000_0022_EAX] = {0x80000022, 0, CPUID_EAX}, ++ [CPUID_7_2_EDX] = { 7, 2, CPUID_EDX}, + }; + + /* +@@ -92,10 +102,12 @@ static const struct cpuid_reg reverse_cpuid[] = { + */ + static __always_inline void reverse_cpuid_check(unsigned int x86_leaf) + { ++ BUILD_BUG_ON(NR_CPUID_WORDS != NCAPINTS); + BUILD_BUG_ON(x86_leaf == CPUID_LNX_1); + BUILD_BUG_ON(x86_leaf == CPUID_LNX_2); + BUILD_BUG_ON(x86_leaf == CPUID_LNX_3); + BUILD_BUG_ON(x86_leaf == CPUID_LNX_4); ++ BUILD_BUG_ON(x86_leaf == CPUID_LNX_5); + BUILD_BUG_ON(x86_leaf >= ARRAY_SIZE(reverse_cpuid)); + BUILD_BUG_ON(reverse_cpuid[x86_leaf].function == 0); + } +@@ -106,18 +118,20 @@ static __always_inline void reverse_cpuid_check(unsigned int x86_leaf) + */ + static __always_inline u32 __feature_translate(int x86_feature) + { +- if (x86_feature == X86_FEATURE_SGX1) +- return KVM_X86_FEATURE_SGX1; +- else if (x86_feature == X86_FEATURE_SGX2) +- return KVM_X86_FEATURE_SGX2; +- else if (x86_feature == X86_FEATURE_SGX_EDECCSSA) +- return KVM_X86_FEATURE_SGX_EDECCSSA; +- else if (x86_feature == X86_FEATURE_CONSTANT_TSC) +- return KVM_X86_FEATURE_CONSTANT_TSC; +- else if (x86_feature == X86_FEATURE_PERFMON_V2) +- return KVM_X86_FEATURE_PERFMON_V2; +- +- return x86_feature; ++#define KVM_X86_TRANSLATE_FEATURE(f) \ ++ case X86_FEATURE_##f: return KVM_X86_FEATURE_##f ++ ++ switch (x86_feature) { ++ KVM_X86_TRANSLATE_FEATURE(SGX1); ++ KVM_X86_TRANSLATE_FEATURE(SGX2); ++ KVM_X86_TRANSLATE_FEATURE(SGX_EDECCSSA); ++ KVM_X86_TRANSLATE_FEATURE(CONSTANT_TSC); ++ KVM_X86_TRANSLATE_FEATURE(PERFMON_V2); ++ KVM_X86_TRANSLATE_FEATURE(RRSBA_CTRL); ++ KVM_X86_TRANSLATE_FEATURE(BHI_CTRL); ++ default: ++ return x86_feature; ++ } + } + + static __always_inline u32 __feature_leaf(int x86_feature) +diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c +index 3fea8c47679e68..60891b9ce25f61 100644 +--- a/arch/x86/kvm/svm/nested.c ++++ b/arch/x86/kvm/svm/nested.c +@@ -247,18 +247,6 @@ static bool nested_svm_check_bitmap_pa(struct kvm_vcpu *vcpu, u64 pa, u32 size) + kvm_vcpu_is_legal_gpa(vcpu, addr + size - 1); + } + +-static bool nested_svm_check_tlb_ctl(struct kvm_vcpu *vcpu, u8 tlb_ctl) +-{ +- /* Nested FLUSHBYASID is not supported yet. */ +- switch(tlb_ctl) { +- case TLB_CONTROL_DO_NOTHING: +- case TLB_CONTROL_FLUSH_ALL_ASID: +- return true; +- default: +- return false; +- } +-} +- + static bool __nested_vmcb_check_controls(struct kvm_vcpu *vcpu, + struct vmcb_ctrl_area_cached *control) + { +@@ -278,9 +266,6 @@ static bool __nested_vmcb_check_controls(struct kvm_vcpu *vcpu, + IOPM_SIZE))) + return false; + +- if (CC(!nested_svm_check_tlb_ctl(vcpu, control->tlb_ctl))) +- return false; +- + if (CC((control->int_ctl & V_NMI_ENABLE_MASK) && + !vmcb12_is_intercept(control, INTERCEPT_NMI))) { + return false; +diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c +index 373ff6a6687b3a..3fd47de14b38a3 100644 +--- a/arch/x86/kvm/svm/pmu.c ++++ b/arch/x86/kvm/svm/pmu.c +@@ -233,21 +233,6 @@ static void amd_pmu_init(struct kvm_vcpu *vcpu) + } + } + +-static void amd_pmu_reset(struct kvm_vcpu *vcpu) +-{ +- struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); +- int i; +- +- for (i = 0; i < KVM_AMD_PMC_MAX_GENERIC; i++) { +- struct kvm_pmc *pmc = &pmu->gp_counters[i]; +- +- pmc_stop_counter(pmc); +- pmc->counter = pmc->prev_counter = pmc->eventsel = 0; +- } +- +- pmu->global_ctrl = pmu->global_status = 0; +-} +- + struct kvm_pmu_ops amd_pmu_ops __initdata = { + .hw_event_available = amd_hw_event_available, + .pmc_idx_to_pmc = amd_pmc_idx_to_pmc, +@@ -259,7 +244,6 @@ struct kvm_pmu_ops amd_pmu_ops __initdata = { + .set_msr = amd_pmu_set_msr, + .refresh = amd_pmu_refresh, + .init = amd_pmu_init, +- .reset = amd_pmu_reset, + .EVENTSEL_EVENT = AMD64_EVENTSEL_EVENT, + .MAX_NR_GP_COUNTERS = KVM_AMD_PMC_MAX_GENERIC, + .MIN_NR_GP_COUNTERS = AMD64_NUM_COUNTERS, +diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c +index 4900c078045acc..99e72b8a96ac0b 100644 +--- a/arch/x86/kvm/svm/sev.c ++++ b/arch/x86/kvm/svm/sev.c +@@ -57,7 +57,7 @@ static bool sev_es_enabled = true; + module_param_named(sev_es, sev_es_enabled, bool, 0444); + + /* enable/disable SEV-ES DebugSwap support */ +-static bool sev_es_debug_swap_enabled = true; ++static bool sev_es_debug_swap_enabled = false; + module_param_named(debug_swap, sev_es_debug_swap_enabled, bool, 0444); + #else + #define sev_enabled false +@@ -84,9 +84,10 @@ struct enc_region { + }; + + /* Called with the sev_bitmap_lock held, or on shutdown */ +-static int sev_flush_asids(int min_asid, int max_asid) ++static int sev_flush_asids(unsigned int min_asid, unsigned int max_asid) + { +- int ret, asid, error = 0; ++ int ret, error = 0; ++ unsigned int asid; + + /* Check if there are any ASIDs to reclaim before performing a flush */ + asid = find_next_bit(sev_reclaim_asid_bitmap, nr_asids, min_asid); +@@ -116,7 +117,7 @@ static inline bool is_mirroring_enc_context(struct kvm *kvm) + } + + /* Must be called with the sev_bitmap_lock held */ +-static bool __sev_recycle_asids(int min_asid, int max_asid) ++static bool __sev_recycle_asids(unsigned int min_asid, unsigned int max_asid) + { + if (sev_flush_asids(min_asid, max_asid)) + return false; +@@ -143,8 +144,20 @@ static void sev_misc_cg_uncharge(struct kvm_sev_info *sev) + + static int sev_asid_new(struct kvm_sev_info *sev) + { +- int asid, min_asid, max_asid, ret; ++ /* ++ * SEV-enabled guests must use asid from min_sev_asid to max_sev_asid. ++ * SEV-ES-enabled guest can use from 1 to min_sev_asid - 1. ++ * Note: min ASID can end up larger than the max if basic SEV support is ++ * effectively disabled by disallowing use of ASIDs for SEV guests. ++ */ ++ unsigned int min_asid = sev->es_active ? 1 : min_sev_asid; ++ unsigned int max_asid = sev->es_active ? min_sev_asid - 1 : max_sev_asid; ++ unsigned int asid; + bool retry = true; ++ int ret; ++ ++ if (min_asid > max_asid) ++ return -ENOTTY; + + WARN_ON(sev->misc_cg); + sev->misc_cg = get_current_misc_cg(); +@@ -157,12 +170,6 @@ static int sev_asid_new(struct kvm_sev_info *sev) + + mutex_lock(&sev_bitmap_lock); + +- /* +- * SEV-enabled guests must use asid from min_sev_asid to max_sev_asid. +- * SEV-ES-enabled guest can use from 1 to min_sev_asid - 1. +- */ +- min_asid = sev->es_active ? 1 : min_sev_asid; +- max_asid = sev->es_active ? min_sev_asid - 1 : max_sev_asid; + again: + asid = find_next_zero_bit(sev_asid_bitmap, max_asid + 1, min_asid); + if (asid > max_asid) { +@@ -187,7 +194,7 @@ static int sev_asid_new(struct kvm_sev_info *sev) + return ret; + } + +-static int sev_get_asid(struct kvm *kvm) ++static unsigned int sev_get_asid(struct kvm *kvm) + { + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; + +@@ -284,8 +291,8 @@ static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp) + + static int sev_bind_asid(struct kvm *kvm, unsigned int handle, int *error) + { ++ unsigned int asid = sev_get_asid(kvm); + struct sev_data_activate activate; +- int asid = sev_get_asid(kvm); + int ret; + + /* activate ASID on the given handle */ +@@ -612,8 +619,11 @@ static int sev_es_sync_vmsa(struct vcpu_svm *svm) + save->xss = svm->vcpu.arch.ia32_xss; + save->dr6 = svm->vcpu.arch.dr6; + +- if (sev_es_debug_swap_enabled) ++ if (sev_es_debug_swap_enabled) { + save->sev_features |= SVM_SEV_FEAT_DEBUG_SWAP; ++ pr_warn_once("Enabling DebugSwap with KVM_SEV_ES_INIT. " ++ "This will not work starting with Linux 6.10\n"); ++ } + + pr_debug("Virtual Machine Save Area (VMSA):\n"); + print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, save, sizeof(*save), false); +@@ -654,6 +664,14 @@ static int __sev_launch_update_vmsa(struct kvm *kvm, struct kvm_vcpu *vcpu, + return ret; + + vcpu->arch.guest_state_protected = true; ++ ++ /* ++ * SEV-ES guest mandates LBR Virtualization to be _always_ ON. Enable it ++ * only after setting guest_state_protected because KVM_SET_MSRS allows ++ * dynamic toggling of LBRV (for performance reason) on write access to ++ * MSR_IA32_DEBUGCTLMSR when guest_state_protected is not set. ++ */ ++ svm_enable_lbrv(vcpu); + return 0; + } + +@@ -1975,20 +1993,22 @@ int sev_mem_enc_register_region(struct kvm *kvm, + goto e_free; + } + +- region->uaddr = range->addr; +- region->size = range->size; +- +- list_add_tail(®ion->list, &sev->regions_list); +- mutex_unlock(&kvm->lock); +- + /* + * The guest may change the memory encryption attribute from C=0 -> C=1 + * or vice versa for this memory range. Lets make sure caches are + * flushed to ensure that guest data gets written into memory with +- * correct C-bit. ++ * correct C-bit. Note, this must be done before dropping kvm->lock, ++ * as region and its array of pages can be freed by a different task ++ * once kvm->lock is released. + */ + sev_clflush_pages(region->pages, region->npages); + ++ region->uaddr = range->addr; ++ region->size = range->size; ++ ++ list_add_tail(®ion->list, &sev->regions_list); ++ mutex_unlock(&kvm->lock); ++ + return ret; + + e_free: +@@ -2229,8 +2249,10 @@ void __init sev_hardware_setup(void) + goto out; + } + +- sev_asid_count = max_sev_asid - min_sev_asid + 1; +- WARN_ON_ONCE(misc_cg_set_capacity(MISC_CG_RES_SEV, sev_asid_count)); ++ if (min_sev_asid <= max_sev_asid) { ++ sev_asid_count = max_sev_asid - min_sev_asid + 1; ++ WARN_ON_ONCE(misc_cg_set_capacity(MISC_CG_RES_SEV, sev_asid_count)); ++ } + sev_supported = true; + + /* SEV-ES support requested? */ +@@ -2250,6 +2272,12 @@ void __init sev_hardware_setup(void) + if (!boot_cpu_has(X86_FEATURE_SEV_ES)) + goto out; + ++ if (!lbrv) { ++ WARN_ONCE(!boot_cpu_has(X86_FEATURE_LBRV), ++ "LBRV must be present for SEV-ES support"); ++ goto out; ++ } ++ + /* Has the system been allocated ASIDs for SEV-ES? */ + if (min_sev_asid == 1) + goto out; +@@ -2261,7 +2289,9 @@ void __init sev_hardware_setup(void) + out: + if (boot_cpu_has(X86_FEATURE_SEV)) + pr_info("SEV %s (ASIDs %u - %u)\n", +- sev_supported ? "enabled" : "disabled", ++ sev_supported ? min_sev_asid <= max_sev_asid ? "enabled" : ++ "unusable" : ++ "disabled", + min_sev_asid, max_sev_asid); + if (boot_cpu_has(X86_FEATURE_SEV_ES)) + pr_info("SEV-ES %s (ASIDs %u - %u)\n", +@@ -2309,7 +2339,7 @@ int sev_cpu_init(struct svm_cpu_data *sd) + */ + static void sev_flush_encrypted_page(struct kvm_vcpu *vcpu, void *va) + { +- int asid = to_kvm_svm(vcpu->kvm)->sev_info.asid; ++ unsigned int asid = sev_get_asid(vcpu->kvm); + + /* + * Note! The address must be a kernel address, as regular page walk +@@ -2627,7 +2657,7 @@ void sev_es_unmap_ghcb(struct vcpu_svm *svm) + void pre_sev_run(struct vcpu_svm *svm, int cpu) + { + struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, cpu); +- int asid = sev_get_asid(svm->vcpu.kvm); ++ unsigned int asid = sev_get_asid(svm->vcpu.kvm); + + /* Assign the asid allocated with this SEV guest */ + svm->asid = asid; +@@ -2972,6 +3002,25 @@ static void sev_es_vcpu_after_set_cpuid(struct vcpu_svm *svm) + + set_msr_interception(vcpu, svm->msrpm, MSR_TSC_AUX, v_tsc_aux, v_tsc_aux); + } ++ ++ /* ++ * For SEV-ES, accesses to MSR_IA32_XSS should not be intercepted if ++ * the host/guest supports its use. ++ * ++ * guest_can_use() checks a number of requirements on the host/guest to ++ * ensure that MSR_IA32_XSS is available, but it might report true even ++ * if X86_FEATURE_XSAVES isn't configured in the guest to ensure host ++ * MSR_IA32_XSS is always properly restored. For SEV-ES, it is better ++ * to further check that the guest CPUID actually supports ++ * X86_FEATURE_XSAVES so that accesses to MSR_IA32_XSS by misbehaved ++ * guests will still get intercepted and caught in the normal ++ * kvm_emulate_rdmsr()/kvm_emulated_wrmsr() paths. ++ */ ++ if (guest_can_use(vcpu, X86_FEATURE_XSAVES) && ++ guest_cpuid_has(vcpu, X86_FEATURE_XSAVES)) ++ set_msr_interception(vcpu, svm->msrpm, MSR_IA32_XSS, 1, 1); ++ else ++ set_msr_interception(vcpu, svm->msrpm, MSR_IA32_XSS, 0, 0); + } + + void sev_vcpu_after_set_cpuid(struct vcpu_svm *svm) +@@ -2994,7 +3043,6 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm) + struct kvm_vcpu *vcpu = &svm->vcpu; + + svm->vmcb->control.nested_ctl |= SVM_NESTED_CTL_SEV_ES_ENABLE; +- svm->vmcb->control.virt_ext |= LBR_CTL_ENABLE_MASK; + + /* + * An SEV-ES guest requires a VMSA area that is a separate from the +@@ -3046,10 +3094,6 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm) + /* Clear intercepts on selected MSRs */ + set_msr_interception(vcpu, svm->msrpm, MSR_EFER, 1, 1); + set_msr_interception(vcpu, svm->msrpm, MSR_IA32_CR_PAT, 1, 1); +- set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHFROMIP, 1, 1); +- set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHTOIP, 1, 1); +- set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTFROMIP, 1, 1); +- set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTTOIP, 1, 1); + } + + void sev_init_vmcb(struct vcpu_svm *svm) +diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c +index beea99c8e8e05e..413f1f2aadd1a3 100644 +--- a/arch/x86/kvm/svm/svm.c ++++ b/arch/x86/kvm/svm/svm.c +@@ -99,10 +99,12 @@ static const struct svm_direct_access_msrs { + { .index = MSR_IA32_SPEC_CTRL, .always = false }, + { .index = MSR_IA32_PRED_CMD, .always = false }, + { .index = MSR_IA32_FLUSH_CMD, .always = false }, ++ { .index = MSR_IA32_DEBUGCTLMSR, .always = false }, + { .index = MSR_IA32_LASTBRANCHFROMIP, .always = false }, + { .index = MSR_IA32_LASTBRANCHTOIP, .always = false }, + { .index = MSR_IA32_LASTINTFROMIP, .always = false }, + { .index = MSR_IA32_LASTINTTOIP, .always = false }, ++ { .index = MSR_IA32_XSS, .always = false }, + { .index = MSR_EFER, .always = false }, + { .index = MSR_IA32_CR_PAT, .always = false }, + { .index = MSR_AMD64_SEV_ES_GHCB, .always = true }, +@@ -214,7 +216,7 @@ int vgif = true; + module_param(vgif, int, 0444); + + /* enable/disable LBR virtualization */ +-static int lbrv = true; ++int lbrv = true; + module_param(lbrv, int, 0444); + + static int tsc_scaling = true; +@@ -1007,7 +1009,7 @@ void svm_copy_lbrs(struct vmcb *to_vmcb, struct vmcb *from_vmcb) + vmcb_mark_dirty(to_vmcb, VMCB_LBR); + } + +-static void svm_enable_lbrv(struct kvm_vcpu *vcpu) ++void svm_enable_lbrv(struct kvm_vcpu *vcpu) + { + struct vcpu_svm *svm = to_svm(vcpu); + +@@ -1017,6 +1019,9 @@ static void svm_enable_lbrv(struct kvm_vcpu *vcpu) + set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTFROMIP, 1, 1); + set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTTOIP, 1, 1); + ++ if (sev_es_guest(vcpu->kvm)) ++ set_msr_interception(vcpu, svm->msrpm, MSR_IA32_DEBUGCTLMSR, 1, 1); ++ + /* Move the LBR msrs to the vmcb02 so that the guest can see them. */ + if (is_guest_mode(vcpu)) + svm_copy_lbrs(svm->vmcb, svm->vmcb01.ptr); +@@ -1026,6 +1031,8 @@ static void svm_disable_lbrv(struct kvm_vcpu *vcpu) + { + struct vcpu_svm *svm = to_svm(vcpu); + ++ KVM_BUG_ON(sev_es_guest(vcpu->kvm), vcpu->kvm); ++ + svm->vmcb->control.virt_ext &= ~LBR_CTL_ENABLE_MASK; + set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHFROMIP, 0, 0); + set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHTOIP, 0, 0); +@@ -1873,15 +1880,17 @@ void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) + bool old_paging = is_paging(vcpu); + + #ifdef CONFIG_X86_64 +- if (vcpu->arch.efer & EFER_LME && !vcpu->arch.guest_state_protected) { ++ if (vcpu->arch.efer & EFER_LME) { + if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) { + vcpu->arch.efer |= EFER_LMA; +- svm->vmcb->save.efer |= EFER_LMA | EFER_LME; ++ if (!vcpu->arch.guest_state_protected) ++ svm->vmcb->save.efer |= EFER_LMA | EFER_LME; + } + + if (is_paging(vcpu) && !(cr0 & X86_CR0_PG)) { + vcpu->arch.efer &= ~EFER_LMA; +- svm->vmcb->save.efer &= ~(EFER_LMA | EFER_LME); ++ if (!vcpu->arch.guest_state_protected) ++ svm->vmcb->save.efer &= ~(EFER_LMA | EFER_LME); + } + } + #endif +@@ -2860,6 +2869,12 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + case MSR_CSTAR: + msr_info->data = svm->vmcb01.ptr->save.cstar; + break; ++ case MSR_GS_BASE: ++ msr_info->data = svm->vmcb01.ptr->save.gs.base; ++ break; ++ case MSR_FS_BASE: ++ msr_info->data = svm->vmcb01.ptr->save.fs.base; ++ break; + case MSR_KERNEL_GS_BASE: + msr_info->data = svm->vmcb01.ptr->save.kernel_gs_base; + break; +@@ -3081,6 +3096,12 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) + case MSR_CSTAR: + svm->vmcb01.ptr->save.cstar = data; + break; ++ case MSR_GS_BASE: ++ svm->vmcb01.ptr->save.gs.base = data; ++ break; ++ case MSR_FS_BASE: ++ svm->vmcb01.ptr->save.fs.base = data; ++ break; + case MSR_KERNEL_GS_BASE: + svm->vmcb01.ptr->save.kernel_gs_base = data; + break; +@@ -3854,16 +3875,27 @@ static void svm_enable_nmi_window(struct kvm_vcpu *vcpu) + struct vcpu_svm *svm = to_svm(vcpu); + + /* +- * KVM should never request an NMI window when vNMI is enabled, as KVM +- * allows at most one to-be-injected NMI and one pending NMI, i.e. if +- * two NMIs arrive simultaneously, KVM will inject one and set +- * V_NMI_PENDING for the other. WARN, but continue with the standard +- * single-step approach to try and salvage the pending NMI. ++ * If NMIs are outright masked, i.e. the vCPU is already handling an ++ * NMI, and KVM has not yet intercepted an IRET, then there is nothing ++ * more to do at this time as KVM has already enabled IRET intercepts. ++ * If KVM has already intercepted IRET, then single-step over the IRET, ++ * as NMIs aren't architecturally unmasked until the IRET completes. ++ * ++ * If vNMI is enabled, KVM should never request an NMI window if NMIs ++ * are masked, as KVM allows at most one to-be-injected NMI and one ++ * pending NMI. If two NMIs arrive simultaneously, KVM will inject one ++ * NMI and set V_NMI_PENDING for the other, but if and only if NMIs are ++ * unmasked. KVM _will_ request an NMI window in some situations, e.g. ++ * if the vCPU is in an STI shadow or if GIF=0, KVM can't immediately ++ * inject the NMI. In those situations, KVM needs to single-step over ++ * the STI shadow or intercept STGI. + */ +- WARN_ON_ONCE(is_vnmi_enabled(svm)); ++ if (svm_get_nmi_mask(vcpu)) { ++ WARN_ON_ONCE(is_vnmi_enabled(svm)); + +- if (svm_get_nmi_mask(vcpu) && !svm->awaiting_iret_completion) +- return; /* IRET will cause a vm exit */ ++ if (!svm->awaiting_iret_completion) ++ return; /* IRET will cause a vm exit */ ++ } + + /* + * SEV-ES guests are responsible for signaling when a vCPU is ready to +@@ -5146,6 +5178,9 @@ static __init void svm_set_cpu_caps(void) + + /* CPUID 0x8000001F (SME/SEV features) */ + sev_set_cpu_caps(); ++ ++ /* Don't advertise Bus Lock Detect to guest if SVM support is absent */ ++ kvm_cpu_cap_clear(X86_FEATURE_BUS_LOCK_DETECT); + } + + static __init int svm_hardware_setup(void) +@@ -5235,6 +5270,12 @@ static __init int svm_hardware_setup(void) + + nrips = nrips && boot_cpu_has(X86_FEATURE_NRIPS); + ++ if (lbrv) { ++ if (!boot_cpu_has(X86_FEATURE_LBRV)) ++ lbrv = false; ++ else ++ pr_info("LBR virtualization supported\n"); ++ } + /* + * Note, SEV setup consumes npt_enabled and enable_mmio_caching (which + * may be modified by svm_adjust_mmio_mask()), as well as nrips. +@@ -5288,14 +5329,6 @@ static __init int svm_hardware_setup(void) + svm_x86_ops.set_vnmi_pending = NULL; + } + +- +- if (lbrv) { +- if (!boot_cpu_has(X86_FEATURE_LBRV)) +- lbrv = false; +- else +- pr_info("LBR virtualization supported\n"); +- } +- + if (!enable_pmu) + pr_info("PMU virtualization is disabled\n"); + +diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h +index be67ab7fdd104e..37ada9808d9b57 100644 +--- a/arch/x86/kvm/svm/svm.h ++++ b/arch/x86/kvm/svm/svm.h +@@ -30,7 +30,7 @@ + #define IOPM_SIZE PAGE_SIZE * 3 + #define MSRPM_SIZE PAGE_SIZE * 2 + +-#define MAX_DIRECT_ACCESS_MSRS 46 ++#define MAX_DIRECT_ACCESS_MSRS 48 + #define MSRPM_OFFSETS 32 + extern u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly; + extern bool npt_enabled; +@@ -39,6 +39,7 @@ extern int vgif; + extern bool intercept_smi; + extern bool x2avic_enabled; + extern bool vnmi; ++extern int lbrv; + + /* + * Clean bits in VMCB. +@@ -541,6 +542,7 @@ u32 *svm_vcpu_alloc_msrpm(void); + void svm_vcpu_init_msrpm(struct kvm_vcpu *vcpu, u32 *msrpm); + void svm_vcpu_free_msrpm(u32 *msrpm); + void svm_copy_lbrs(struct vmcb *to_vmcb, struct vmcb *from_vmcb); ++void svm_enable_lbrv(struct kvm_vcpu *vcpu); + void svm_update_lbrv(struct kvm_vcpu *vcpu); + + int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer); +diff --git a/arch/x86/kvm/svm/svm_ops.h b/arch/x86/kvm/svm/svm_ops.h +index 36c8af87a707ac..4e725854c63a10 100644 +--- a/arch/x86/kvm/svm/svm_ops.h ++++ b/arch/x86/kvm/svm/svm_ops.h +@@ -8,7 +8,7 @@ + + #define svm_asm(insn, clobber...) \ + do { \ +- asm_volatile_goto("1: " __stringify(insn) "\n\t" \ ++ asm goto("1: " __stringify(insn) "\n\t" \ + _ASM_EXTABLE(1b, %l[fault]) \ + ::: clobber : fault); \ + return; \ +@@ -18,7 +18,7 @@ fault: \ + + #define svm_asm1(insn, op1, clobber...) \ + do { \ +- asm_volatile_goto("1: " __stringify(insn) " %0\n\t" \ ++ asm goto("1: " __stringify(insn) " %0\n\t" \ + _ASM_EXTABLE(1b, %l[fault]) \ + :: op1 : clobber : fault); \ + return; \ +@@ -28,7 +28,7 @@ fault: \ + + #define svm_asm2(insn, op1, op2, clobber...) \ + do { \ +- asm_volatile_goto("1: " __stringify(insn) " %1, %0\n\t" \ ++ asm goto("1: " __stringify(insn) " %1, %0\n\t" \ + _ASM_EXTABLE(1b, %l[fault]) \ + :: op1, op2 : clobber : fault); \ + return; \ +diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h +index 83843379813ee3..b82e6ed4f02417 100644 +--- a/arch/x86/kvm/trace.h ++++ b/arch/x86/kvm/trace.h +@@ -732,13 +732,13 @@ TRACE_EVENT(kvm_nested_intr_vmexit, + * Tracepoint for nested #vmexit because of interrupt pending + */ + TRACE_EVENT(kvm_invlpga, +- TP_PROTO(__u64 rip, int asid, u64 address), ++ TP_PROTO(__u64 rip, unsigned int asid, u64 address), + TP_ARGS(rip, asid, address), + + TP_STRUCT__entry( +- __field( __u64, rip ) +- __field( int, asid ) +- __field( __u64, address ) ++ __field( __u64, rip ) ++ __field( unsigned int, asid ) ++ __field( __u64, address ) + ), + + TP_fast_assign( +@@ -747,7 +747,7 @@ TRACE_EVENT(kvm_invlpga, + __entry->address = address; + ), + +- TP_printk("rip: 0x%016llx asid: %d address: 0x%016llx", ++ TP_printk("rip: 0x%016llx asid: %u address: 0x%016llx", + __entry->rip, __entry->asid, __entry->address) + ); + +diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c +index 313b8bb5b8a7cb..de13dc14fe1d2f 100644 +--- a/arch/x86/kvm/vmx/hyperv.c ++++ b/arch/x86/kvm/vmx/hyperv.c +@@ -13,111 +13,6 @@ + + #define CC KVM_NESTED_VMENTER_CONSISTENCY_CHECK + +-/* +- * Enlightened VMCSv1 doesn't support these: +- * +- * POSTED_INTR_NV = 0x00000002, +- * GUEST_INTR_STATUS = 0x00000810, +- * APIC_ACCESS_ADDR = 0x00002014, +- * POSTED_INTR_DESC_ADDR = 0x00002016, +- * EOI_EXIT_BITMAP0 = 0x0000201c, +- * EOI_EXIT_BITMAP1 = 0x0000201e, +- * EOI_EXIT_BITMAP2 = 0x00002020, +- * EOI_EXIT_BITMAP3 = 0x00002022, +- * GUEST_PML_INDEX = 0x00000812, +- * PML_ADDRESS = 0x0000200e, +- * VM_FUNCTION_CONTROL = 0x00002018, +- * EPTP_LIST_ADDRESS = 0x00002024, +- * VMREAD_BITMAP = 0x00002026, +- * VMWRITE_BITMAP = 0x00002028, +- * +- * TSC_MULTIPLIER = 0x00002032, +- * PLE_GAP = 0x00004020, +- * PLE_WINDOW = 0x00004022, +- * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E, +- * +- * Currently unsupported in KVM: +- * GUEST_IA32_RTIT_CTL = 0x00002814, +- */ +-#define EVMCS1_SUPPORTED_PINCTRL \ +- (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ +- PIN_BASED_EXT_INTR_MASK | \ +- PIN_BASED_NMI_EXITING | \ +- PIN_BASED_VIRTUAL_NMIS) +- +-#define EVMCS1_SUPPORTED_EXEC_CTRL \ +- (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ +- CPU_BASED_HLT_EXITING | \ +- CPU_BASED_CR3_LOAD_EXITING | \ +- CPU_BASED_CR3_STORE_EXITING | \ +- CPU_BASED_UNCOND_IO_EXITING | \ +- CPU_BASED_MOV_DR_EXITING | \ +- CPU_BASED_USE_TSC_OFFSETTING | \ +- CPU_BASED_MWAIT_EXITING | \ +- CPU_BASED_MONITOR_EXITING | \ +- CPU_BASED_INVLPG_EXITING | \ +- CPU_BASED_RDPMC_EXITING | \ +- CPU_BASED_INTR_WINDOW_EXITING | \ +- CPU_BASED_CR8_LOAD_EXITING | \ +- CPU_BASED_CR8_STORE_EXITING | \ +- CPU_BASED_RDTSC_EXITING | \ +- CPU_BASED_TPR_SHADOW | \ +- CPU_BASED_USE_IO_BITMAPS | \ +- CPU_BASED_MONITOR_TRAP_FLAG | \ +- CPU_BASED_USE_MSR_BITMAPS | \ +- CPU_BASED_NMI_WINDOW_EXITING | \ +- CPU_BASED_PAUSE_EXITING | \ +- CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) +- +-#define EVMCS1_SUPPORTED_2NDEXEC \ +- (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \ +- SECONDARY_EXEC_WBINVD_EXITING | \ +- SECONDARY_EXEC_ENABLE_VPID | \ +- SECONDARY_EXEC_ENABLE_EPT | \ +- SECONDARY_EXEC_UNRESTRICTED_GUEST | \ +- SECONDARY_EXEC_DESC | \ +- SECONDARY_EXEC_ENABLE_RDTSCP | \ +- SECONDARY_EXEC_ENABLE_INVPCID | \ +- SECONDARY_EXEC_ENABLE_XSAVES | \ +- SECONDARY_EXEC_RDSEED_EXITING | \ +- SECONDARY_EXEC_RDRAND_EXITING | \ +- SECONDARY_EXEC_TSC_SCALING | \ +- SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \ +- SECONDARY_EXEC_PT_USE_GPA | \ +- SECONDARY_EXEC_PT_CONCEAL_VMX | \ +- SECONDARY_EXEC_BUS_LOCK_DETECTION | \ +- SECONDARY_EXEC_NOTIFY_VM_EXITING | \ +- SECONDARY_EXEC_ENCLS_EXITING) +- +-#define EVMCS1_SUPPORTED_3RDEXEC (0ULL) +- +-#define EVMCS1_SUPPORTED_VMEXIT_CTRL \ +- (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \ +- VM_EXIT_SAVE_DEBUG_CONTROLS | \ +- VM_EXIT_ACK_INTR_ON_EXIT | \ +- VM_EXIT_HOST_ADDR_SPACE_SIZE | \ +- VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \ +- VM_EXIT_SAVE_IA32_PAT | \ +- VM_EXIT_LOAD_IA32_PAT | \ +- VM_EXIT_SAVE_IA32_EFER | \ +- VM_EXIT_LOAD_IA32_EFER | \ +- VM_EXIT_CLEAR_BNDCFGS | \ +- VM_EXIT_PT_CONCEAL_PIP | \ +- VM_EXIT_CLEAR_IA32_RTIT_CTL) +- +-#define EVMCS1_SUPPORTED_VMENTRY_CTRL \ +- (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \ +- VM_ENTRY_LOAD_DEBUG_CONTROLS | \ +- VM_ENTRY_IA32E_MODE | \ +- VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \ +- VM_ENTRY_LOAD_IA32_PAT | \ +- VM_ENTRY_LOAD_IA32_EFER | \ +- VM_ENTRY_LOAD_BNDCFGS | \ +- VM_ENTRY_PT_CONCEAL_PIP | \ +- VM_ENTRY_LOAD_IA32_RTIT_CTL) +- +-#define EVMCS1_SUPPORTED_VMFUNC (0) +- + #define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x) + #define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \ + {EVMCS1_OFFSET(name), clean_field} +@@ -608,40 +503,6 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12) + return 0; + } + +-#if IS_ENABLED(CONFIG_HYPERV) +-DEFINE_STATIC_KEY_FALSE(__kvm_is_using_evmcs); +- +-/* +- * KVM on Hyper-V always uses the latest known eVMCSv1 revision, the assumption +- * is: in case a feature has corresponding fields in eVMCS described and it was +- * exposed in VMX feature MSRs, KVM is free to use it. Warn if KVM meets a +- * feature which has no corresponding eVMCS field, this likely means that KVM +- * needs to be updated. +- */ +-#define evmcs_check_vmcs_conf(field, ctrl) \ +- do { \ +- typeof(vmcs_conf->field) unsupported; \ +- \ +- unsupported = vmcs_conf->field & ~EVMCS1_SUPPORTED_ ## ctrl; \ +- if (unsupported) { \ +- pr_warn_once(#field " unsupported with eVMCS: 0x%llx\n",\ +- (u64)unsupported); \ +- vmcs_conf->field &= EVMCS1_SUPPORTED_ ## ctrl; \ +- } \ +- } \ +- while (0) +- +-void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf) +-{ +- evmcs_check_vmcs_conf(cpu_based_exec_ctrl, EXEC_CTRL); +- evmcs_check_vmcs_conf(pin_based_exec_ctrl, PINCTRL); +- evmcs_check_vmcs_conf(cpu_based_2nd_exec_ctrl, 2NDEXEC); +- evmcs_check_vmcs_conf(cpu_based_3rd_exec_ctrl, 3RDEXEC); +- evmcs_check_vmcs_conf(vmentry_ctrl, VMENTRY_CTRL); +- evmcs_check_vmcs_conf(vmexit_ctrl, VMEXIT_CTRL); +-} +-#endif +- + int nested_enable_evmcs(struct kvm_vcpu *vcpu, + uint16_t *vmcs_version) + { +diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h +index 9623fe1651c48b..9401dbfaea7cef 100644 +--- a/arch/x86/kvm/vmx/hyperv.h ++++ b/arch/x86/kvm/vmx/hyperv.h +@@ -14,12 +14,113 @@ + #include "vmcs.h" + #include "vmcs12.h" + +-struct vmcs_config; +- +-#define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs)) +- + #define KVM_EVMCS_VERSION 1 + ++/* ++ * Enlightened VMCSv1 doesn't support these: ++ * ++ * POSTED_INTR_NV = 0x00000002, ++ * GUEST_INTR_STATUS = 0x00000810, ++ * APIC_ACCESS_ADDR = 0x00002014, ++ * POSTED_INTR_DESC_ADDR = 0x00002016, ++ * EOI_EXIT_BITMAP0 = 0x0000201c, ++ * EOI_EXIT_BITMAP1 = 0x0000201e, ++ * EOI_EXIT_BITMAP2 = 0x00002020, ++ * EOI_EXIT_BITMAP3 = 0x00002022, ++ * GUEST_PML_INDEX = 0x00000812, ++ * PML_ADDRESS = 0x0000200e, ++ * VM_FUNCTION_CONTROL = 0x00002018, ++ * EPTP_LIST_ADDRESS = 0x00002024, ++ * VMREAD_BITMAP = 0x00002026, ++ * VMWRITE_BITMAP = 0x00002028, ++ * ++ * TSC_MULTIPLIER = 0x00002032, ++ * PLE_GAP = 0x00004020, ++ * PLE_WINDOW = 0x00004022, ++ * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E, ++ * ++ * Currently unsupported in KVM: ++ * GUEST_IA32_RTIT_CTL = 0x00002814, ++ */ ++#define EVMCS1_SUPPORTED_PINCTRL \ ++ (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ ++ PIN_BASED_EXT_INTR_MASK | \ ++ PIN_BASED_NMI_EXITING | \ ++ PIN_BASED_VIRTUAL_NMIS) ++ ++#define EVMCS1_SUPPORTED_EXEC_CTRL \ ++ (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ ++ CPU_BASED_HLT_EXITING | \ ++ CPU_BASED_CR3_LOAD_EXITING | \ ++ CPU_BASED_CR3_STORE_EXITING | \ ++ CPU_BASED_UNCOND_IO_EXITING | \ ++ CPU_BASED_MOV_DR_EXITING | \ ++ CPU_BASED_USE_TSC_OFFSETTING | \ ++ CPU_BASED_MWAIT_EXITING | \ ++ CPU_BASED_MONITOR_EXITING | \ ++ CPU_BASED_INVLPG_EXITING | \ ++ CPU_BASED_RDPMC_EXITING | \ ++ CPU_BASED_INTR_WINDOW_EXITING | \ ++ CPU_BASED_CR8_LOAD_EXITING | \ ++ CPU_BASED_CR8_STORE_EXITING | \ ++ CPU_BASED_RDTSC_EXITING | \ ++ CPU_BASED_TPR_SHADOW | \ ++ CPU_BASED_USE_IO_BITMAPS | \ ++ CPU_BASED_MONITOR_TRAP_FLAG | \ ++ CPU_BASED_USE_MSR_BITMAPS | \ ++ CPU_BASED_NMI_WINDOW_EXITING | \ ++ CPU_BASED_PAUSE_EXITING | \ ++ CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) ++ ++#define EVMCS1_SUPPORTED_2NDEXEC \ ++ (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \ ++ SECONDARY_EXEC_WBINVD_EXITING | \ ++ SECONDARY_EXEC_ENABLE_VPID | \ ++ SECONDARY_EXEC_ENABLE_EPT | \ ++ SECONDARY_EXEC_UNRESTRICTED_GUEST | \ ++ SECONDARY_EXEC_DESC | \ ++ SECONDARY_EXEC_ENABLE_RDTSCP | \ ++ SECONDARY_EXEC_ENABLE_INVPCID | \ ++ SECONDARY_EXEC_ENABLE_XSAVES | \ ++ SECONDARY_EXEC_RDSEED_EXITING | \ ++ SECONDARY_EXEC_RDRAND_EXITING | \ ++ SECONDARY_EXEC_TSC_SCALING | \ ++ SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \ ++ SECONDARY_EXEC_PT_USE_GPA | \ ++ SECONDARY_EXEC_PT_CONCEAL_VMX | \ ++ SECONDARY_EXEC_BUS_LOCK_DETECTION | \ ++ SECONDARY_EXEC_NOTIFY_VM_EXITING | \ ++ SECONDARY_EXEC_ENCLS_EXITING) ++ ++#define EVMCS1_SUPPORTED_3RDEXEC (0ULL) ++ ++#define EVMCS1_SUPPORTED_VMEXIT_CTRL \ ++ (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \ ++ VM_EXIT_SAVE_DEBUG_CONTROLS | \ ++ VM_EXIT_ACK_INTR_ON_EXIT | \ ++ VM_EXIT_HOST_ADDR_SPACE_SIZE | \ ++ VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \ ++ VM_EXIT_SAVE_IA32_PAT | \ ++ VM_EXIT_LOAD_IA32_PAT | \ ++ VM_EXIT_SAVE_IA32_EFER | \ ++ VM_EXIT_LOAD_IA32_EFER | \ ++ VM_EXIT_CLEAR_BNDCFGS | \ ++ VM_EXIT_PT_CONCEAL_PIP | \ ++ VM_EXIT_CLEAR_IA32_RTIT_CTL) ++ ++#define EVMCS1_SUPPORTED_VMENTRY_CTRL \ ++ (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \ ++ VM_ENTRY_LOAD_DEBUG_CONTROLS | \ ++ VM_ENTRY_IA32E_MODE | \ ++ VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \ ++ VM_ENTRY_LOAD_IA32_PAT | \ ++ VM_ENTRY_LOAD_IA32_EFER | \ ++ VM_ENTRY_LOAD_BNDCFGS | \ ++ VM_ENTRY_PT_CONCEAL_PIP | \ ++ VM_ENTRY_LOAD_IA32_RTIT_CTL) ++ ++#define EVMCS1_SUPPORTED_VMFUNC (0) ++ + struct evmcs_field { + u16 offset; + u16 clean_field; +@@ -65,114 +166,6 @@ static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs, + return vmcs12_read_any((void *)evmcs, field, offset); + } + +-#if IS_ENABLED(CONFIG_HYPERV) +- +-DECLARE_STATIC_KEY_FALSE(__kvm_is_using_evmcs); +- +-static __always_inline bool kvm_is_using_evmcs(void) +-{ +- return static_branch_unlikely(&__kvm_is_using_evmcs); +-} +- +-static __always_inline int get_evmcs_offset(unsigned long field, +- u16 *clean_field) +-{ +- int offset = evmcs_field_offset(field, clean_field); +- +- WARN_ONCE(offset < 0, "accessing unsupported EVMCS field %lx\n", field); +- return offset; +-} +- +-static __always_inline void evmcs_write64(unsigned long field, u64 value) +-{ +- u16 clean_field; +- int offset = get_evmcs_offset(field, &clean_field); +- +- if (offset < 0) +- return; +- +- *(u64 *)((char *)current_evmcs + offset) = value; +- +- current_evmcs->hv_clean_fields &= ~clean_field; +-} +- +-static __always_inline void evmcs_write32(unsigned long field, u32 value) +-{ +- u16 clean_field; +- int offset = get_evmcs_offset(field, &clean_field); +- +- if (offset < 0) +- return; +- +- *(u32 *)((char *)current_evmcs + offset) = value; +- current_evmcs->hv_clean_fields &= ~clean_field; +-} +- +-static __always_inline void evmcs_write16(unsigned long field, u16 value) +-{ +- u16 clean_field; +- int offset = get_evmcs_offset(field, &clean_field); +- +- if (offset < 0) +- return; +- +- *(u16 *)((char *)current_evmcs + offset) = value; +- current_evmcs->hv_clean_fields &= ~clean_field; +-} +- +-static __always_inline u64 evmcs_read64(unsigned long field) +-{ +- int offset = get_evmcs_offset(field, NULL); +- +- if (offset < 0) +- return 0; +- +- return *(u64 *)((char *)current_evmcs + offset); +-} +- +-static __always_inline u32 evmcs_read32(unsigned long field) +-{ +- int offset = get_evmcs_offset(field, NULL); +- +- if (offset < 0) +- return 0; +- +- return *(u32 *)((char *)current_evmcs + offset); +-} +- +-static __always_inline u16 evmcs_read16(unsigned long field) +-{ +- int offset = get_evmcs_offset(field, NULL); +- +- if (offset < 0) +- return 0; +- +- return *(u16 *)((char *)current_evmcs + offset); +-} +- +-static inline void evmcs_load(u64 phys_addr) +-{ +- struct hv_vp_assist_page *vp_ap = +- hv_get_vp_assist_page(smp_processor_id()); +- +- if (current_evmcs->hv_enlightenments_control.nested_flush_hypercall) +- vp_ap->nested_control.features.directhypercall = 1; +- vp_ap->current_nested_vmcs = phys_addr; +- vp_ap->enlighten_vmentry = 1; +-} +- +-void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf); +-#else /* !IS_ENABLED(CONFIG_HYPERV) */ +-static __always_inline bool kvm_is_using_evmcs(void) { return false; } +-static __always_inline void evmcs_write64(unsigned long field, u64 value) {} +-static __always_inline void evmcs_write32(unsigned long field, u32 value) {} +-static __always_inline void evmcs_write16(unsigned long field, u16 value) {} +-static __always_inline u64 evmcs_read64(unsigned long field) { return 0; } +-static __always_inline u32 evmcs_read32(unsigned long field) { return 0; } +-static __always_inline u16 evmcs_read16(unsigned long field) { return 0; } +-static inline void evmcs_load(u64 phys_addr) {} +-#endif /* IS_ENABLED(CONFIG_HYPERV) */ +- + #define EVMPTR_INVALID (-1ULL) + #define EVMPTR_MAP_PENDING (-2ULL) + +diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c +index c5ec0ef51ff78f..0ad66b9207e85f 100644 +--- a/arch/x86/kvm/vmx/nested.c ++++ b/arch/x86/kvm/vmx/nested.c +@@ -12,6 +12,7 @@ + #include "mmu.h" + #include "nested.h" + #include "pmu.h" ++#include "posted_intr.h" + #include "sgx.h" + #include "trace.h" + #include "vmx.h" +@@ -3830,8 +3831,8 @@ static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu) + if (!pi_test_and_clear_on(vmx->nested.pi_desc)) + return 0; + +- max_irr = find_last_bit((unsigned long *)vmx->nested.pi_desc->pir, 256); +- if (max_irr != 256) { ++ max_irr = pi_find_highest_vector(vmx->nested.pi_desc); ++ if (max_irr > 0) { + vapic_page = vmx->nested.virtual_apic_map.hva; + if (!vapic_page) + goto mmio_needed; +@@ -3962,10 +3963,42 @@ static bool nested_vmx_preemption_timer_pending(struct kvm_vcpu *vcpu) + to_vmx(vcpu)->nested.preemption_timer_expired; + } + +-static bool vmx_has_nested_events(struct kvm_vcpu *vcpu) ++static bool vmx_has_nested_events(struct kvm_vcpu *vcpu, bool for_injection) + { +- return nested_vmx_preemption_timer_pending(vcpu) || +- to_vmx(vcpu)->nested.mtf_pending; ++ struct vcpu_vmx *vmx = to_vmx(vcpu); ++ void *vapic = vmx->nested.virtual_apic_map.hva; ++ int max_irr, vppr; ++ ++ if (nested_vmx_preemption_timer_pending(vcpu) || ++ vmx->nested.mtf_pending) ++ return true; ++ ++ /* ++ * Virtual Interrupt Delivery doesn't require manual injection. Either ++ * the interrupt is already in GUEST_RVI and will be recognized by CPU ++ * at VM-Entry, or there is a KVM_REQ_EVENT pending and KVM will move ++ * the interrupt from the PIR to RVI prior to entering the guest. ++ */ ++ if (for_injection) ++ return false; ++ ++ if (!nested_cpu_has_vid(get_vmcs12(vcpu)) || ++ __vmx_interrupt_blocked(vcpu)) ++ return false; ++ ++ if (!vapic) ++ return false; ++ ++ vppr = *((u32 *)(vapic + APIC_PROCPRI)); ++ ++ if (vmx->nested.pi_pending && vmx->nested.pi_desc && ++ pi_test_on(vmx->nested.pi_desc)) { ++ max_irr = pi_find_highest_vector(vmx->nested.pi_desc); ++ if (max_irr > 0 && (max_irr & 0xf0) > (vppr & 0xf0)) ++ return true; ++ } ++ ++ return false; + } + + /* +diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c +index 820d3e1f6b4f82..48a2f77f62ef35 100644 +--- a/arch/x86/kvm/vmx/pmu_intel.c ++++ b/arch/x86/kvm/vmx/pmu_intel.c +@@ -71,7 +71,7 @@ static int fixed_pmc_events[] = { + static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data) + { + struct kvm_pmc *pmc; +- u8 old_fixed_ctr_ctrl = pmu->fixed_ctr_ctrl; ++ u64 old_fixed_ctr_ctrl = pmu->fixed_ctr_ctrl; + int i; + + pmu->fixed_ctr_ctrl = data; +@@ -493,19 +493,6 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) + u64 counter_mask; + int i; + +- pmu->nr_arch_gp_counters = 0; +- pmu->nr_arch_fixed_counters = 0; +- pmu->counter_bitmask[KVM_PMC_GP] = 0; +- pmu->counter_bitmask[KVM_PMC_FIXED] = 0; +- pmu->version = 0; +- pmu->reserved_bits = 0xffffffff00200000ull; +- pmu->raw_event_mask = X86_RAW_EVENT_MASK; +- pmu->global_ctrl_mask = ~0ull; +- pmu->global_status_mask = ~0ull; +- pmu->fixed_ctr_ctrl_mask = ~0ull; +- pmu->pebs_enable_mask = ~0ull; +- pmu->pebs_data_cfg_mask = ~0ull; +- + memset(&lbr_desc->records, 0, sizeof(lbr_desc->records)); + + /* +@@ -517,8 +504,9 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) + return; + + entry = kvm_find_cpuid_entry(vcpu, 0xa); +- if (!entry || !vcpu->kvm->arch.enable_pmu) ++ if (!entry) + return; ++ + eax.full = entry->eax; + edx.full = entry->edx; + +@@ -632,26 +620,6 @@ static void intel_pmu_init(struct kvm_vcpu *vcpu) + + static void intel_pmu_reset(struct kvm_vcpu *vcpu) + { +- struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); +- struct kvm_pmc *pmc = NULL; +- int i; +- +- for (i = 0; i < KVM_INTEL_PMC_MAX_GENERIC; i++) { +- pmc = &pmu->gp_counters[i]; +- +- pmc_stop_counter(pmc); +- pmc->counter = pmc->prev_counter = pmc->eventsel = 0; +- } +- +- for (i = 0; i < KVM_PMC_MAX_FIXED; i++) { +- pmc = &pmu->fixed_counters[i]; +- +- pmc_stop_counter(pmc); +- pmc->counter = pmc->prev_counter = 0; +- } +- +- pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status = 0; +- + intel_pmu_release_guest_lbr_event(vcpu); + } + +diff --git a/arch/x86/kvm/vmx/posted_intr.h b/arch/x86/kvm/vmx/posted_intr.h +index 26992076552ef1..1715d2ab07be5d 100644 +--- a/arch/x86/kvm/vmx/posted_intr.h ++++ b/arch/x86/kvm/vmx/posted_intr.h +@@ -2,97 +2,8 @@ + #ifndef __KVM_X86_VMX_POSTED_INTR_H + #define __KVM_X86_VMX_POSTED_INTR_H + +-#define POSTED_INTR_ON 0 +-#define POSTED_INTR_SN 1 +- +-#define PID_TABLE_ENTRY_VALID 1 +- +-/* Posted-Interrupt Descriptor */ +-struct pi_desc { +- u32 pir[8]; /* Posted interrupt requested */ +- union { +- struct { +- /* bit 256 - Outstanding Notification */ +- u16 on : 1, +- /* bit 257 - Suppress Notification */ +- sn : 1, +- /* bit 271:258 - Reserved */ +- rsvd_1 : 14; +- /* bit 279:272 - Notification Vector */ +- u8 nv; +- /* bit 287:280 - Reserved */ +- u8 rsvd_2; +- /* bit 319:288 - Notification Destination */ +- u32 ndst; +- }; +- u64 control; +- }; +- u32 rsvd[6]; +-} __aligned(64); +- +-static inline bool pi_test_and_set_on(struct pi_desc *pi_desc) +-{ +- return test_and_set_bit(POSTED_INTR_ON, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline bool pi_test_and_clear_on(struct pi_desc *pi_desc) +-{ +- return test_and_clear_bit(POSTED_INTR_ON, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline bool pi_test_and_clear_sn(struct pi_desc *pi_desc) +-{ +- return test_and_clear_bit(POSTED_INTR_SN, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline bool pi_test_and_set_pir(int vector, struct pi_desc *pi_desc) +-{ +- return test_and_set_bit(vector, (unsigned long *)pi_desc->pir); +-} +- +-static inline bool pi_is_pir_empty(struct pi_desc *pi_desc) +-{ +- return bitmap_empty((unsigned long *)pi_desc->pir, NR_VECTORS); +-} +- +-static inline void pi_set_sn(struct pi_desc *pi_desc) +-{ +- set_bit(POSTED_INTR_SN, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline void pi_set_on(struct pi_desc *pi_desc) +-{ +- set_bit(POSTED_INTR_ON, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline void pi_clear_on(struct pi_desc *pi_desc) +-{ +- clear_bit(POSTED_INTR_ON, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline void pi_clear_sn(struct pi_desc *pi_desc) +-{ +- clear_bit(POSTED_INTR_SN, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline bool pi_test_on(struct pi_desc *pi_desc) +-{ +- return test_bit(POSTED_INTR_ON, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline bool pi_test_sn(struct pi_desc *pi_desc) +-{ +- return test_bit(POSTED_INTR_SN, +- (unsigned long *)&pi_desc->control); +-} ++#include ++#include + + void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu); + void vmx_vcpu_pi_put(struct kvm_vcpu *vcpu); +@@ -103,4 +14,12 @@ int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + uint32_t guest_irq, bool set); + void vmx_pi_start_assignment(struct kvm *kvm); + ++static inline int pi_find_highest_vector(struct pi_desc *pi_desc) ++{ ++ int vec; ++ ++ vec = find_last_bit((unsigned long *)pi_desc->pir, 256); ++ return vec < 256 ? vec : -1; ++} ++ + #endif /* __KVM_X86_VMX_POSTED_INTR_H */ +diff --git a/arch/x86/kvm/vmx/run_flags.h b/arch/x86/kvm/vmx/run_flags.h +index edc3f16cc1896f..6a9bfdfbb6e59b 100644 +--- a/arch/x86/kvm/vmx/run_flags.h ++++ b/arch/x86/kvm/vmx/run_flags.h +@@ -2,7 +2,10 @@ + #ifndef __KVM_X86_VMX_RUN_FLAGS_H + #define __KVM_X86_VMX_RUN_FLAGS_H + +-#define VMX_RUN_VMRESUME (1 << 0) +-#define VMX_RUN_SAVE_SPEC_CTRL (1 << 1) ++#define VMX_RUN_VMRESUME_SHIFT 0 ++#define VMX_RUN_SAVE_SPEC_CTRL_SHIFT 1 ++ ++#define VMX_RUN_VMRESUME BIT(VMX_RUN_VMRESUME_SHIFT) ++#define VMX_RUN_SAVE_SPEC_CTRL BIT(VMX_RUN_SAVE_SPEC_CTRL_SHIFT) + + #endif /* __KVM_X86_VMX_RUN_FLAGS_H */ +diff --git a/arch/x86/kvm/vmx/vmenter.S b/arch/x86/kvm/vmx/vmenter.S +index be275a0410a899..9522d46567f81b 100644 +--- a/arch/x86/kvm/vmx/vmenter.S ++++ b/arch/x86/kvm/vmx/vmenter.S +@@ -139,7 +139,7 @@ SYM_FUNC_START(__vmx_vcpu_run) + mov (%_ASM_SP), %_ASM_AX + + /* Check if vmlaunch or vmresume is needed */ +- test $VMX_RUN_VMRESUME, %ebx ++ bt $VMX_RUN_VMRESUME_SHIFT, %ebx + + /* Load guest registers. Don't clobber flags. */ + mov VCPU_RCX(%_ASM_AX), %_ASM_CX +@@ -161,8 +161,11 @@ SYM_FUNC_START(__vmx_vcpu_run) + /* Load guest RAX. This kills the @regs pointer! */ + mov VCPU_RAX(%_ASM_AX), %_ASM_AX + +- /* Check EFLAGS.ZF from 'test VMX_RUN_VMRESUME' above */ +- jz .Lvmlaunch ++ /* Clobbers EFLAGS.ZF */ ++ CLEAR_CPU_BUFFERS ++ ++ /* Check EFLAGS.CF from the VMX_RUN_VMRESUME bit test above. */ ++ jnc .Lvmlaunch + + /* + * After a successful VMRESUME/VMLAUNCH, control flow "magically" +@@ -272,6 +275,8 @@ SYM_INNER_LABEL_ALIGN(vmx_vmexit, SYM_L_GLOBAL) + + call vmx_spec_ctrl_restore_host + ++ CLEAR_BRANCH_HISTORY_VMEXIT ++ + /* Put return value in AX */ + mov %_ASM_BX, %_ASM_AX + +diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c +index 72e3943f36935c..2e0106d9d371cf 100644 +--- a/arch/x86/kvm/vmx/vmx.c ++++ b/arch/x86/kvm/vmx/vmx.c +@@ -66,6 +66,8 @@ + #include "vmx.h" + #include "x86.h" + #include "smm.h" ++#include "vmx_onhyperv.h" ++#include "posted_intr.h" + + MODULE_AUTHOR("Qumranet"); + MODULE_LICENSE("GPL"); +@@ -387,7 +389,16 @@ static __always_inline void vmx_enable_fb_clear(struct vcpu_vmx *vmx) + + static void vmx_update_fb_clear_dis(struct kvm_vcpu *vcpu, struct vcpu_vmx *vmx) + { +- vmx->disable_fb_clear = (host_arch_capabilities & ARCH_CAP_FB_CLEAR_CTRL) && ++ /* ++ * Disable VERW's behavior of clearing CPU buffers for the guest if the ++ * CPU isn't affected by MDS/TAA, and the host hasn't forcefully enabled ++ * the mitigation. Disabling the clearing behavior provides a ++ * performance boost for guests that aren't aware that manually clearing ++ * CPU buffers is unnecessary, at the cost of MSR accesses on VM-Entry ++ * and VM-Exit. ++ */ ++ vmx->disable_fb_clear = !cpu_feature_enabled(X86_FEATURE_CLEAR_CPU_BUF) && ++ (host_arch_capabilities & ARCH_CAP_FB_CLEAR_CTRL) && + !boot_cpu_has_bug(X86_BUG_MDS) && + !boot_cpu_has_bug(X86_BUG_TAA); + +@@ -745,7 +756,7 @@ static int vmx_set_guest_uret_msr(struct vcpu_vmx *vmx, + */ + static int kvm_cpu_vmxoff(void) + { +- asm_volatile_goto("1: vmxoff\n\t" ++ asm goto("1: vmxoff\n\t" + _ASM_EXTABLE(1b, %l[fault]) + ::: "cc", "memory" : fault); + +@@ -2789,7 +2800,7 @@ static int kvm_cpu_vmxon(u64 vmxon_pointer) + + cr4_set_bits(X86_CR4_VMXE); + +- asm_volatile_goto("1: vmxon %[vmxon_pointer]\n\t" ++ asm goto("1: vmxon %[vmxon_pointer]\n\t" + _ASM_EXTABLE(1b, %l[fault]) + : : [vmxon_pointer] "m"(vmxon_pointer) + : : fault); +@@ -5039,14 +5050,19 @@ static int vmx_nmi_allowed(struct kvm_vcpu *vcpu, bool for_injection) + return !vmx_nmi_blocked(vcpu); + } + ++bool __vmx_interrupt_blocked(struct kvm_vcpu *vcpu) ++{ ++ return !(vmx_get_rflags(vcpu) & X86_EFLAGS_IF) || ++ (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & ++ (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)); ++} ++ + bool vmx_interrupt_blocked(struct kvm_vcpu *vcpu) + { + if (is_guest_mode(vcpu) && nested_exit_on_intr(vcpu)) + return false; + +- return !(vmx_get_rflags(vcpu) & X86_EFLAGS_IF) || +- (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & +- (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)); ++ return __vmx_interrupt_blocked(vcpu); + } + + static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection) +@@ -6912,7 +6928,7 @@ static void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap) + vmcs_write64(EOI_EXIT_BITMAP3, eoi_exit_bitmap[3]); + } + +-static void vmx_apicv_post_state_restore(struct kvm_vcpu *vcpu) ++static void vmx_apicv_pre_state_restore(struct kvm_vcpu *vcpu) + { + struct vcpu_vmx *vmx = to_vmx(vcpu); + +@@ -7226,11 +7242,14 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu, + + guest_state_enter_irqoff(); + +- /* L1D Flush includes CPU buffer clear to mitigate MDS */ ++ /* ++ * L1D Flush includes CPU buffer clear to mitigate MDS, but VERW ++ * mitigation for MDS is done late in VMentry and is still ++ * executed in spite of L1D Flush. This is because an extra VERW ++ * should not matter much after the big hammer L1D Flush. ++ */ + if (static_branch_unlikely(&vmx_l1d_should_flush)) + vmx_l1d_flush(vcpu); +- else if (static_branch_unlikely(&mds_user_clear)) +- mds_clear_cpu_buffers(); + else if (static_branch_unlikely(&mmio_stale_data_clear) && + kvm_arch_has_assigned_device(vcpu->kvm)) + mds_clear_cpu_buffers(); +@@ -7846,8 +7865,28 @@ static u64 vmx_get_perf_capabilities(void) + + if (vmx_pebs_supported()) { + perf_cap |= host_perf_cap & PERF_CAP_PEBS_MASK; +- if ((perf_cap & PERF_CAP_PEBS_FORMAT) < 4) +- perf_cap &= ~PERF_CAP_PEBS_BASELINE; ++ ++ /* ++ * Disallow adaptive PEBS as it is functionally broken, can be ++ * used by the guest to read *host* LBRs, and can be used to ++ * bypass userspace event filters. To correctly and safely ++ * support adaptive PEBS, KVM needs to: ++ * ++ * 1. Account for the ADAPTIVE flag when (re)programming fixed ++ * counters. ++ * ++ * 2. Gain support from perf (or take direct control of counter ++ * programming) to support events without adaptive PEBS ++ * enabled for the hardware counter. ++ * ++ * 3. Ensure LBR MSRs cannot hold host data on VM-Entry with ++ * adaptive PEBS enabled and MSR_PEBS_DATA_CFG.LBRS=1. ++ * ++ * 4. Document which PMU events are effectively exposed to the ++ * guest via adaptive PEBS, and make adaptive PEBS mutually ++ * exclusive with KVM_SET_PMU_EVENT_FILTER if necessary. ++ */ ++ perf_cap &= ~PERF_CAP_PEBS_BASELINE; + } + + return perf_cap; +@@ -8286,7 +8325,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = { + .set_apic_access_page_addr = vmx_set_apic_access_page_addr, + .refresh_apicv_exec_ctrl = vmx_refresh_apicv_exec_ctrl, + .load_eoi_exitmap = vmx_load_eoi_exitmap, +- .apicv_post_state_restore = vmx_apicv_post_state_restore, ++ .apicv_pre_state_restore = vmx_apicv_pre_state_restore, + .required_apicv_inhibits = VMX_REQUIRED_APICV_INHIBITS, + .hwapic_irr_update = vmx_hwapic_irr_update, + .hwapic_isr_update = vmx_hwapic_isr_update, +diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h +index c2130d2c8e24bb..6be1627d888e5a 100644 +--- a/arch/x86/kvm/vmx/vmx.h ++++ b/arch/x86/kvm/vmx/vmx.h +@@ -7,10 +7,10 @@ + #include + #include + #include ++#include + + #include "capabilities.h" + #include "../kvm_cache_regs.h" +-#include "posted_intr.h" + #include "vmcs.h" + #include "vmx_ops.h" + #include "../cpuid.h" +@@ -400,6 +400,7 @@ u64 construct_eptp(struct kvm_vcpu *vcpu, hpa_t root_hpa, int root_level); + bool vmx_guest_inject_ac(struct kvm_vcpu *vcpu); + void vmx_update_exception_bitmap(struct kvm_vcpu *vcpu); + bool vmx_nmi_blocked(struct kvm_vcpu *vcpu); ++bool __vmx_interrupt_blocked(struct kvm_vcpu *vcpu); + bool vmx_interrupt_blocked(struct kvm_vcpu *vcpu); + bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu); + void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked); +diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.c b/arch/x86/kvm/vmx/vmx_onhyperv.c +new file mode 100644 +index 00000000000000..b9a8b91166d020 +--- /dev/null ++++ b/arch/x86/kvm/vmx/vmx_onhyperv.c +@@ -0,0 +1,36 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include "capabilities.h" ++#include "vmx_onhyperv.h" ++ ++DEFINE_STATIC_KEY_FALSE(__kvm_is_using_evmcs); ++ ++/* ++ * KVM on Hyper-V always uses the latest known eVMCSv1 revision, the assumption ++ * is: in case a feature has corresponding fields in eVMCS described and it was ++ * exposed in VMX feature MSRs, KVM is free to use it. Warn if KVM meets a ++ * feature which has no corresponding eVMCS field, this likely means that KVM ++ * needs to be updated. ++ */ ++#define evmcs_check_vmcs_conf(field, ctrl) \ ++ do { \ ++ typeof(vmcs_conf->field) unsupported; \ ++ \ ++ unsupported = vmcs_conf->field & ~EVMCS1_SUPPORTED_ ## ctrl; \ ++ if (unsupported) { \ ++ pr_warn_once(#field " unsupported with eVMCS: 0x%llx\n",\ ++ (u64)unsupported); \ ++ vmcs_conf->field &= EVMCS1_SUPPORTED_ ## ctrl; \ ++ } \ ++ } \ ++ while (0) ++ ++void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf) ++{ ++ evmcs_check_vmcs_conf(cpu_based_exec_ctrl, EXEC_CTRL); ++ evmcs_check_vmcs_conf(pin_based_exec_ctrl, PINCTRL); ++ evmcs_check_vmcs_conf(cpu_based_2nd_exec_ctrl, 2NDEXEC); ++ evmcs_check_vmcs_conf(cpu_based_3rd_exec_ctrl, 3RDEXEC); ++ evmcs_check_vmcs_conf(vmentry_ctrl, VMENTRY_CTRL); ++ evmcs_check_vmcs_conf(vmexit_ctrl, VMEXIT_CTRL); ++} +diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.h b/arch/x86/kvm/vmx/vmx_onhyperv.h +new file mode 100644 +index 00000000000000..11541d272dbd8c +--- /dev/null ++++ b/arch/x86/kvm/vmx/vmx_onhyperv.h +@@ -0,0 +1,124 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++ ++#ifndef __ARCH_X86_KVM_VMX_ONHYPERV_H__ ++#define __ARCH_X86_KVM_VMX_ONHYPERV_H__ ++ ++#include ++ ++#include ++ ++#include "capabilities.h" ++#include "hyperv.h" ++#include "vmcs12.h" ++ ++#define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs)) ++ ++#if IS_ENABLED(CONFIG_HYPERV) ++ ++DECLARE_STATIC_KEY_FALSE(__kvm_is_using_evmcs); ++ ++static __always_inline bool kvm_is_using_evmcs(void) ++{ ++ return static_branch_unlikely(&__kvm_is_using_evmcs); ++} ++ ++static __always_inline int get_evmcs_offset(unsigned long field, ++ u16 *clean_field) ++{ ++ int offset = evmcs_field_offset(field, clean_field); ++ ++ WARN_ONCE(offset < 0, "accessing unsupported EVMCS field %lx\n", field); ++ return offset; ++} ++ ++static __always_inline void evmcs_write64(unsigned long field, u64 value) ++{ ++ u16 clean_field; ++ int offset = get_evmcs_offset(field, &clean_field); ++ ++ if (offset < 0) ++ return; ++ ++ *(u64 *)((char *)current_evmcs + offset) = value; ++ ++ current_evmcs->hv_clean_fields &= ~clean_field; ++} ++ ++static __always_inline void evmcs_write32(unsigned long field, u32 value) ++{ ++ u16 clean_field; ++ int offset = get_evmcs_offset(field, &clean_field); ++ ++ if (offset < 0) ++ return; ++ ++ *(u32 *)((char *)current_evmcs + offset) = value; ++ current_evmcs->hv_clean_fields &= ~clean_field; ++} ++ ++static __always_inline void evmcs_write16(unsigned long field, u16 value) ++{ ++ u16 clean_field; ++ int offset = get_evmcs_offset(field, &clean_field); ++ ++ if (offset < 0) ++ return; ++ ++ *(u16 *)((char *)current_evmcs + offset) = value; ++ current_evmcs->hv_clean_fields &= ~clean_field; ++} ++ ++static __always_inline u64 evmcs_read64(unsigned long field) ++{ ++ int offset = get_evmcs_offset(field, NULL); ++ ++ if (offset < 0) ++ return 0; ++ ++ return *(u64 *)((char *)current_evmcs + offset); ++} ++ ++static __always_inline u32 evmcs_read32(unsigned long field) ++{ ++ int offset = get_evmcs_offset(field, NULL); ++ ++ if (offset < 0) ++ return 0; ++ ++ return *(u32 *)((char *)current_evmcs + offset); ++} ++ ++static __always_inline u16 evmcs_read16(unsigned long field) ++{ ++ int offset = get_evmcs_offset(field, NULL); ++ ++ if (offset < 0) ++ return 0; ++ ++ return *(u16 *)((char *)current_evmcs + offset); ++} ++ ++static inline void evmcs_load(u64 phys_addr) ++{ ++ struct hv_vp_assist_page *vp_ap = ++ hv_get_vp_assist_page(smp_processor_id()); ++ ++ if (current_evmcs->hv_enlightenments_control.nested_flush_hypercall) ++ vp_ap->nested_control.features.directhypercall = 1; ++ vp_ap->current_nested_vmcs = phys_addr; ++ vp_ap->enlighten_vmentry = 1; ++} ++ ++void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf); ++#else /* !IS_ENABLED(CONFIG_HYPERV) */ ++static __always_inline bool kvm_is_using_evmcs(void) { return false; } ++static __always_inline void evmcs_write64(unsigned long field, u64 value) {} ++static __always_inline void evmcs_write32(unsigned long field, u32 value) {} ++static __always_inline void evmcs_write16(unsigned long field, u16 value) {} ++static __always_inline u64 evmcs_read64(unsigned long field) { return 0; } ++static __always_inline u32 evmcs_read32(unsigned long field) { return 0; } ++static __always_inline u16 evmcs_read16(unsigned long field) { return 0; } ++static inline void evmcs_load(u64 phys_addr) {} ++#endif /* IS_ENABLED(CONFIG_HYPERV) */ ++ ++#endif /* __ARCH_X86_KVM_VMX_ONHYPERV_H__ */ +diff --git a/arch/x86/kvm/vmx/vmx_ops.h b/arch/x86/kvm/vmx/vmx_ops.h +index 33af7b4c6eb4a6..8060e5fc6dbd83 100644 +--- a/arch/x86/kvm/vmx/vmx_ops.h ++++ b/arch/x86/kvm/vmx/vmx_ops.h +@@ -6,7 +6,7 @@ + + #include + +-#include "hyperv.h" ++#include "vmx_onhyperv.h" + #include "vmcs.h" + #include "../x86.h" + +@@ -94,7 +94,7 @@ static __always_inline unsigned long __vmcs_readl(unsigned long field) + + #ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT + +- asm_volatile_goto("1: vmread %[field], %[output]\n\t" ++ asm_goto_output("1: vmread %[field], %[output]\n\t" + "jna %l[do_fail]\n\t" + + _ASM_EXTABLE(1b, %l[do_exception]) +@@ -188,7 +188,7 @@ static __always_inline unsigned long vmcs_readl(unsigned long field) + + #define vmx_asm1(insn, op1, error_args...) \ + do { \ +- asm_volatile_goto("1: " __stringify(insn) " %0\n\t" \ ++ asm goto("1: " __stringify(insn) " %0\n\t" \ + ".byte 0x2e\n\t" /* branch not taken hint */ \ + "jna %l[error]\n\t" \ + _ASM_EXTABLE(1b, %l[fault]) \ +@@ -205,7 +205,7 @@ fault: \ + + #define vmx_asm2(insn, op1, op2, error_args...) \ + do { \ +- asm_volatile_goto("1: " __stringify(insn) " %1, %0\n\t" \ ++ asm goto("1: " __stringify(insn) " %1, %0\n\t" \ + ".byte 0x2e\n\t" /* branch not taken hint */ \ + "jna %l[error]\n\t" \ + _ASM_EXTABLE(1b, %l[fault]) \ +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index 41cce5031126a0..50cc822e129007 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -1620,7 +1620,8 @@ static bool kvm_is_immutable_feature_msr(u32 msr) + ARCH_CAP_SKIP_VMENTRY_L1DFLUSH | ARCH_CAP_SSB_NO | ARCH_CAP_MDS_NO | \ + ARCH_CAP_PSCHANGE_MC_NO | ARCH_CAP_TSX_CTRL_MSR | ARCH_CAP_TAA_NO | \ + ARCH_CAP_SBDR_SSDP_NO | ARCH_CAP_FBSDP_NO | ARCH_CAP_PSDP_NO | \ +- ARCH_CAP_FB_CLEAR | ARCH_CAP_RRSBA | ARCH_CAP_PBRSB_NO | ARCH_CAP_GDS_NO) ++ ARCH_CAP_FB_CLEAR | ARCH_CAP_RRSBA | ARCH_CAP_PBRSB_NO | ARCH_CAP_GDS_NO | \ ++ ARCH_CAP_RFDS_NO | ARCH_CAP_RFDS_CLEAR | ARCH_CAP_BHI_NO) + + static u64 kvm_get_arch_capabilities(void) + { +@@ -1652,6 +1653,8 @@ static u64 kvm_get_arch_capabilities(void) + data |= ARCH_CAP_SSB_NO; + if (!boot_cpu_has_bug(X86_BUG_MDS)) + data |= ARCH_CAP_MDS_NO; ++ if (!boot_cpu_has_bug(X86_BUG_RFDS)) ++ data |= ARCH_CAP_RFDS_NO; + + if (!boot_cpu_has(X86_FEATURE_RTM)) { + /* +@@ -3314,7 +3317,7 @@ static bool is_mci_status_msr(u32 msr) + static bool can_set_mci_status(struct kvm_vcpu *vcpu) + { + /* McStatusWrEn enabled? */ +- if (guest_cpuid_is_amd_or_hygon(vcpu)) ++ if (guest_cpuid_is_amd_compatible(vcpu)) + return !!(vcpu->arch.msr_hwcr & BIT_ULL(18)); + + return false; +@@ -3641,6 +3644,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + case MSR_AMD64_PATCH_LOADER: + case MSR_AMD64_BU_CFG2: + case MSR_AMD64_DC_CFG: ++ case MSR_AMD64_TW_CFG: + case MSR_F15H_EX_CFG: + break; + +@@ -4065,6 +4069,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + case MSR_AMD64_BU_CFG2: + case MSR_IA32_PERF_CTL: + case MSR_AMD64_DC_CFG: ++ case MSR_AMD64_TW_CFG: + case MSR_F15H_EX_CFG: + /* + * Intel Sandy Bridge CPUs must support the RAPL (running average power +@@ -5298,7 +5303,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, + if (events->flags & KVM_VCPUEVENT_VALID_NMI_PENDING) { + vcpu->arch.nmi_pending = 0; + atomic_set(&vcpu->arch.nmi_queued, events->nmi.pending); +- kvm_make_request(KVM_REQ_NMI, vcpu); ++ if (events->nmi.pending) ++ kvm_make_request(KVM_REQ_NMI, vcpu); + } + static_call(kvm_x86_set_nmi_mask)(vcpu, events->nmi.masked); + +@@ -5823,7 +5829,9 @@ long kvm_arch_vcpu_ioctl(struct file *filp, + if (copy_from_user(&events, argp, sizeof(struct kvm_vcpu_events))) + break; + ++ kvm_vcpu_srcu_read_lock(vcpu); + r = kvm_vcpu_ioctl_x86_set_vcpu_events(vcpu, &events); ++ kvm_vcpu_srcu_read_unlock(vcpu); + break; + } + case KVM_GET_DEBUGREGS: { +@@ -7834,6 +7842,16 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt, + + if (r < 0) + return X86EMUL_UNHANDLEABLE; ++ ++ /* ++ * Mark the page dirty _before_ checking whether or not the CMPXCHG was ++ * successful, as the old value is written back on failure. Note, for ++ * live migration, this is unnecessarily conservative as CMPXCHG writes ++ * back the original value and the access is atomic, but KVM's ABI is ++ * that all writes are dirty logged, regardless of the value written. ++ */ ++ kvm_vcpu_mark_page_dirty(vcpu, gpa_to_gfn(gpa)); ++ + if (r) + return X86EMUL_CMPXCHG_FAILED; + +@@ -10238,7 +10256,7 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu, + + if (is_guest_mode(vcpu) && + kvm_x86_ops.nested_ops->has_events && +- kvm_x86_ops.nested_ops->has_events(vcpu)) ++ kvm_x86_ops.nested_ops->has_events(vcpu, true)) + *req_immediate_exit = true; + + /* +@@ -10440,13 +10458,12 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu) + + bitmap_zero(vcpu->arch.ioapic_handled_vectors, 256); + ++ static_call_cond(kvm_x86_sync_pir_to_irr)(vcpu); ++ + if (irqchip_split(vcpu->kvm)) + kvm_scan_ioapic_routes(vcpu, vcpu->arch.ioapic_handled_vectors); +- else { +- static_call_cond(kvm_x86_sync_pir_to_irr)(vcpu); +- if (ioapic_in_kernel(vcpu->kvm)) +- kvm_ioapic_scan_entry(vcpu, vcpu->arch.ioapic_handled_vectors); +- } ++ else if (ioapic_in_kernel(vcpu->kvm)) ++ kvm_ioapic_scan_entry(vcpu, vcpu->arch.ioapic_handled_vectors); + + if (is_guest_mode(vcpu)) + vcpu->arch.load_eoi_exitmap_pending = true; +@@ -12867,7 +12884,7 @@ static inline bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu) + + if (is_guest_mode(vcpu) && + kvm_x86_ops.nested_ops->has_events && +- kvm_x86_ops.nested_ops->has_events(vcpu)) ++ kvm_x86_ops.nested_ops->has_events(vcpu, false)) + return true; + + if (kvm_xen_has_pending_events(vcpu)) +diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c +index 40edf4d1974c53..0ea6016ad132a2 100644 +--- a/arch/x86/kvm/xen.c ++++ b/arch/x86/kvm/xen.c +@@ -471,7 +471,7 @@ void kvm_xen_update_runstate(struct kvm_vcpu *v, int state) + kvm_xen_update_runstate_guest(v, state == RUNSTATE_runnable); + } + +-static void kvm_xen_inject_vcpu_vector(struct kvm_vcpu *v) ++void kvm_xen_inject_vcpu_vector(struct kvm_vcpu *v) + { + struct kvm_lapic_irq irq = { }; + int r; +diff --git a/arch/x86/kvm/xen.h b/arch/x86/kvm/xen.h +index f8f1fe22d09069..f5841d9000aebd 100644 +--- a/arch/x86/kvm/xen.h ++++ b/arch/x86/kvm/xen.h +@@ -18,6 +18,7 @@ extern struct static_key_false_deferred kvm_xen_enabled; + + int __kvm_xen_has_interrupt(struct kvm_vcpu *vcpu); + void kvm_xen_inject_pending_events(struct kvm_vcpu *vcpu); ++void kvm_xen_inject_vcpu_vector(struct kvm_vcpu *vcpu); + int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data); + int kvm_xen_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data); + int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data); +@@ -36,6 +37,19 @@ int kvm_xen_setup_evtchn(struct kvm *kvm, + const struct kvm_irq_routing_entry *ue); + void kvm_xen_update_tsc_info(struct kvm_vcpu *vcpu); + ++static inline void kvm_xen_sw_enable_lapic(struct kvm_vcpu *vcpu) ++{ ++ /* ++ * The local APIC is being enabled. If the per-vCPU upcall vector is ++ * set and the vCPU's evtchn_upcall_pending flag is set, inject the ++ * interrupt. ++ */ ++ if (static_branch_unlikely(&kvm_xen_enabled.key) && ++ vcpu->arch.xen.vcpu_info_cache.active && ++ vcpu->arch.xen.upcall_vector && __kvm_xen_has_interrupt(vcpu)) ++ kvm_xen_inject_vcpu_vector(vcpu); ++} ++ + static inline bool kvm_xen_msr_enabled(struct kvm *kvm) + { + return static_branch_unlikely(&kvm_xen_enabled.key) && +@@ -101,6 +115,10 @@ static inline void kvm_xen_destroy_vcpu(struct kvm_vcpu *vcpu) + { + } + ++static inline void kvm_xen_sw_enable_lapic(struct kvm_vcpu *vcpu) ++{ ++} ++ + static inline bool kvm_xen_msr_enabled(struct kvm *kvm) + { + return false; +diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile +index ea3a28e7b613cc..f0dae4fb6d0716 100644 +--- a/arch/x86/lib/Makefile ++++ b/arch/x86/lib/Makefile +@@ -14,19 +14,6 @@ ifdef CONFIG_KCSAN + CFLAGS_REMOVE_delay.o = $(CC_FLAGS_FTRACE) + endif + +-# Early boot use of cmdline; don't instrument it +-ifdef CONFIG_AMD_MEM_ENCRYPT +-KCOV_INSTRUMENT_cmdline.o := n +-KASAN_SANITIZE_cmdline.o := n +-KCSAN_SANITIZE_cmdline.o := n +- +-ifdef CONFIG_FUNCTION_TRACER +-CFLAGS_REMOVE_cmdline.o = -pg +-endif +- +-CFLAGS_cmdline.o := -fno-stack-protector -fno-jump-tables +-endif +- + inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk + inat_tables_maps = $(srctree)/arch/x86/lib/x86-opcode-map.txt + quiet_cmd_inat_tables = GEN $@ +diff --git a/arch/x86/lib/copy_mc.c b/arch/x86/lib/copy_mc.c +index 80efd45a776173..6e8b7e600def57 100644 +--- a/arch/x86/lib/copy_mc.c ++++ b/arch/x86/lib/copy_mc.c +@@ -70,23 +70,23 @@ unsigned long __must_check copy_mc_to_kernel(void *dst, const void *src, unsigne + } + EXPORT_SYMBOL_GPL(copy_mc_to_kernel); + +-unsigned long __must_check copy_mc_to_user(void *dst, const void *src, unsigned len) ++unsigned long __must_check copy_mc_to_user(void __user *dst, const void *src, unsigned len) + { + unsigned long ret; + + if (copy_mc_fragile_enabled) { + __uaccess_begin(); +- ret = copy_mc_fragile(dst, src, len); ++ ret = copy_mc_fragile((__force void *)dst, src, len); + __uaccess_end(); + return ret; + } + + if (static_cpu_has(X86_FEATURE_ERMS)) { + __uaccess_begin(); +- ret = copy_mc_enhanced_fast_string(dst, src, len); ++ ret = copy_mc_enhanced_fast_string((__force void *)dst, src, len); + __uaccess_end(); + return ret; + } + +- return copy_user_generic(dst, src, len); ++ return copy_user_generic((__force void *)dst, src, len); + } +diff --git a/arch/x86/lib/csum-partial_64.c b/arch/x86/lib/csum-partial_64.c +index cea25ca8b8cf69..c9dae65ac01b5a 100644 +--- a/arch/x86/lib/csum-partial_64.c ++++ b/arch/x86/lib/csum-partial_64.c +@@ -11,26 +11,23 @@ + #include + #include + +-static inline unsigned short from32to16(unsigned a) ++static inline __wsum csum_finalize_sum(u64 temp64) + { +- unsigned short b = a >> 16; +- asm("addw %w2,%w0\n\t" +- "adcw $0,%w0\n" +- : "=r" (b) +- : "0" (b), "r" (a)); +- return b; ++ return (__force __wsum)((temp64 + ror64(temp64, 32)) >> 32); + } + +-static inline __wsum csum_tail(u64 temp64, int odd) ++static inline unsigned long update_csum_40b(unsigned long sum, const unsigned long m[5]) + { +- unsigned int result; +- +- result = add32_with_carry(temp64 >> 32, temp64 & 0xffffffff); +- if (unlikely(odd)) { +- result = from32to16(result); +- result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); +- } +- return (__force __wsum)result; ++ asm("addq %1,%0\n\t" ++ "adcq %2,%0\n\t" ++ "adcq %3,%0\n\t" ++ "adcq %4,%0\n\t" ++ "adcq %5,%0\n\t" ++ "adcq $0,%0" ++ :"+r" (sum) ++ :"m" (m[0]), "m" (m[1]), "m" (m[2]), ++ "m" (m[3]), "m" (m[4])); ++ return sum; + } + + /* +@@ -47,64 +44,32 @@ static inline __wsum csum_tail(u64 temp64, int odd) + __wsum csum_partial(const void *buff, int len, __wsum sum) + { + u64 temp64 = (__force u64)sum; +- unsigned odd; + +- odd = 1 & (unsigned long) buff; +- if (unlikely(odd)) { +- if (unlikely(len == 0)) +- return sum; +- temp64 = ror32((__force u32)sum, 8); +- temp64 += (*(unsigned char *)buff << 8); +- len--; +- buff++; ++ /* Do two 40-byte chunks in parallel to get better ILP */ ++ if (likely(len >= 80)) { ++ u64 temp64_2 = 0; ++ do { ++ temp64 = update_csum_40b(temp64, buff); ++ temp64_2 = update_csum_40b(temp64_2, buff + 40); ++ buff += 80; ++ len -= 80; ++ } while (len >= 80); ++ ++ asm("addq %1,%0\n\t" ++ "adcq $0,%0" ++ :"+r" (temp64): "r" (temp64_2)); + } + + /* +- * len == 40 is the hot case due to IPv6 headers, but annotating it likely() +- * has noticeable negative affect on codegen for all other cases with +- * minimal performance benefit here. ++ * len == 40 is the hot case due to IPv6 headers, so return ++ * early for that exact case without checking the tail bytes. + */ +- if (len == 40) { +- asm("addq 0*8(%[src]),%[res]\n\t" +- "adcq 1*8(%[src]),%[res]\n\t" +- "adcq 2*8(%[src]),%[res]\n\t" +- "adcq 3*8(%[src]),%[res]\n\t" +- "adcq 4*8(%[src]),%[res]\n\t" +- "adcq $0,%[res]" +- : [res] "+r"(temp64) +- : [src] "r"(buff), "m"(*(const char(*)[40])buff)); +- return csum_tail(temp64, odd); +- } +- if (unlikely(len >= 64)) { +- /* +- * Extra accumulators for better ILP in the loop. +- */ +- u64 tmp_accum, tmp_carries; +- +- asm("xorl %k[tmp_accum],%k[tmp_accum]\n\t" +- "xorl %k[tmp_carries],%k[tmp_carries]\n\t" +- "subl $64, %[len]\n\t" +- "1:\n\t" +- "addq 0*8(%[src]),%[res]\n\t" +- "adcq 1*8(%[src]),%[res]\n\t" +- "adcq 2*8(%[src]),%[res]\n\t" +- "adcq 3*8(%[src]),%[res]\n\t" +- "adcl $0,%k[tmp_carries]\n\t" +- "addq 4*8(%[src]),%[tmp_accum]\n\t" +- "adcq 5*8(%[src]),%[tmp_accum]\n\t" +- "adcq 6*8(%[src]),%[tmp_accum]\n\t" +- "adcq 7*8(%[src]),%[tmp_accum]\n\t" +- "adcl $0,%k[tmp_carries]\n\t" +- "addq $64, %[src]\n\t" +- "subl $64, %[len]\n\t" +- "jge 1b\n\t" +- "addq %[tmp_accum],%[res]\n\t" +- "adcq %[tmp_carries],%[res]\n\t" +- "adcq $0,%[res]" +- : [tmp_accum] "=&r"(tmp_accum), +- [tmp_carries] "=&r"(tmp_carries), [res] "+r"(temp64), +- [len] "+r"(len), [src] "+r"(buff) +- : "m"(*(const char *)buff)); ++ if (len >= 40) { ++ temp64 = update_csum_40b(temp64, buff); ++ len -= 40; ++ if (!len) ++ return csum_finalize_sum(temp64); ++ buff += 40; + } + + if (len & 32) { +@@ -143,7 +108,7 @@ __wsum csum_partial(const void *buff, int len, __wsum sum) + : [res] "+r"(temp64) + : [trail] "r"(trail)); + } +- return csum_tail(temp64, odd); ++ return csum_finalize_sum(temp64); + } + EXPORT_SYMBOL(csum_partial); + +diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S +index 9c63713477bbb7..6913fbce6544fb 100644 +--- a/arch/x86/lib/getuser.S ++++ b/arch/x86/lib/getuser.S +@@ -44,7 +44,11 @@ + or %rdx, %rax + .else + cmp $TASK_SIZE_MAX-\size+1, %eax ++.if \size != 8 + jae .Lbad_get_user ++.else ++ jae .Lbad_get_user_8 ++.endif + sbb %edx, %edx /* array_index_mask_nospec() */ + and %edx, %eax + .endif +@@ -154,7 +158,7 @@ SYM_CODE_END(__get_user_handle_exception) + #ifdef CONFIG_X86_32 + SYM_CODE_START_LOCAL(__get_user_8_handle_exception) + ASM_CLAC +-bad_get_user_8: ++.Lbad_get_user_8: + xor %edx,%edx + xor %ecx,%ecx + mov $(-EFAULT),%_ASM_AX +@@ -163,23 +167,23 @@ SYM_CODE_END(__get_user_8_handle_exception) + #endif + + /* get_user */ +- _ASM_EXTABLE(1b, __get_user_handle_exception) +- _ASM_EXTABLE(2b, __get_user_handle_exception) +- _ASM_EXTABLE(3b, __get_user_handle_exception) ++ _ASM_EXTABLE_UA(1b, __get_user_handle_exception) ++ _ASM_EXTABLE_UA(2b, __get_user_handle_exception) ++ _ASM_EXTABLE_UA(3b, __get_user_handle_exception) + #ifdef CONFIG_X86_64 +- _ASM_EXTABLE(4b, __get_user_handle_exception) ++ _ASM_EXTABLE_UA(4b, __get_user_handle_exception) + #else +- _ASM_EXTABLE(4b, __get_user_8_handle_exception) +- _ASM_EXTABLE(5b, __get_user_8_handle_exception) ++ _ASM_EXTABLE_UA(4b, __get_user_8_handle_exception) ++ _ASM_EXTABLE_UA(5b, __get_user_8_handle_exception) + #endif + + /* __get_user */ +- _ASM_EXTABLE(6b, __get_user_handle_exception) +- _ASM_EXTABLE(7b, __get_user_handle_exception) +- _ASM_EXTABLE(8b, __get_user_handle_exception) ++ _ASM_EXTABLE_UA(6b, __get_user_handle_exception) ++ _ASM_EXTABLE_UA(7b, __get_user_handle_exception) ++ _ASM_EXTABLE_UA(8b, __get_user_handle_exception) + #ifdef CONFIG_X86_64 +- _ASM_EXTABLE(9b, __get_user_handle_exception) ++ _ASM_EXTABLE_UA(9b, __get_user_handle_exception) + #else +- _ASM_EXTABLE(9b, __get_user_8_handle_exception) +- _ASM_EXTABLE(10b, __get_user_8_handle_exception) ++ _ASM_EXTABLE_UA(9b, __get_user_8_handle_exception) ++ _ASM_EXTABLE_UA(10b, __get_user_8_handle_exception) + #endif +diff --git a/arch/x86/lib/iomem.c b/arch/x86/lib/iomem.c +index e0411a3774d495..5eecb45d05d5da 100644 +--- a/arch/x86/lib/iomem.c ++++ b/arch/x86/lib/iomem.c +@@ -25,6 +25,9 @@ static __always_inline void rep_movs(void *to, const void *from, size_t n) + + static void string_memcpy_fromio(void *to, const volatile void __iomem *from, size_t n) + { ++ const void *orig_to = to; ++ const size_t orig_n = n; ++ + if (unlikely(!n)) + return; + +@@ -39,7 +42,7 @@ static void string_memcpy_fromio(void *to, const volatile void __iomem *from, si + } + rep_movs(to, (const void *)from, n); + /* KMSAN must treat values read from devices as initialized. */ +- kmsan_unpoison_memory(to, n); ++ kmsan_unpoison_memory(orig_to, orig_n); + } + + static void string_memcpy_toio(volatile void __iomem *to, const void *from, size_t n) +diff --git a/arch/x86/lib/misc.c b/arch/x86/lib/misc.c +index 92cd8ecc3a2c8c..40b81c338ae5b9 100644 +--- a/arch/x86/lib/misc.c ++++ b/arch/x86/lib/misc.c +@@ -8,7 +8,7 @@ + */ + int num_digits(int val) + { +- int m = 10; ++ long long m = 10; + int d = 1; + + if (val < 0) { +diff --git a/arch/x86/lib/putuser.S b/arch/x86/lib/putuser.S +index 235bbda6fc8230..512dc58c938b81 100644 +--- a/arch/x86/lib/putuser.S ++++ b/arch/x86/lib/putuser.S +@@ -134,15 +134,15 @@ SYM_CODE_START_LOCAL(__put_user_handle_exception) + RET + SYM_CODE_END(__put_user_handle_exception) + +- _ASM_EXTABLE(1b, __put_user_handle_exception) +- _ASM_EXTABLE(2b, __put_user_handle_exception) +- _ASM_EXTABLE(3b, __put_user_handle_exception) +- _ASM_EXTABLE(4b, __put_user_handle_exception) +- _ASM_EXTABLE(5b, __put_user_handle_exception) +- _ASM_EXTABLE(6b, __put_user_handle_exception) +- _ASM_EXTABLE(7b, __put_user_handle_exception) +- _ASM_EXTABLE(9b, __put_user_handle_exception) ++ _ASM_EXTABLE_UA(1b, __put_user_handle_exception) ++ _ASM_EXTABLE_UA(2b, __put_user_handle_exception) ++ _ASM_EXTABLE_UA(3b, __put_user_handle_exception) ++ _ASM_EXTABLE_UA(4b, __put_user_handle_exception) ++ _ASM_EXTABLE_UA(5b, __put_user_handle_exception) ++ _ASM_EXTABLE_UA(6b, __put_user_handle_exception) ++ _ASM_EXTABLE_UA(7b, __put_user_handle_exception) ++ _ASM_EXTABLE_UA(9b, __put_user_handle_exception) + #ifdef CONFIG_X86_32 +- _ASM_EXTABLE(8b, __put_user_handle_exception) +- _ASM_EXTABLE(10b, __put_user_handle_exception) ++ _ASM_EXTABLE_UA(8b, __put_user_handle_exception) ++ _ASM_EXTABLE_UA(10b, __put_user_handle_exception) + #endif +diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S +index cd86aeb5fdd3ea..ffa51f392e17a3 100644 +--- a/arch/x86/lib/retpoline.S ++++ b/arch/x86/lib/retpoline.S +@@ -126,12 +126,13 @@ SYM_CODE_END(__x86_indirect_jump_thunk_array) + #include + #undef GEN + #endif +-/* +- * This function name is magical and is used by -mfunction-return=thunk-extern +- * for the compiler to generate JMPs to it. +- */ ++ + #ifdef CONFIG_RETHUNK + ++ .section .text..__x86.return_thunk ++ ++#ifdef CONFIG_CPU_SRSO ++ + /* + * srso_alias_untrain_ret() and srso_alias_safe_ret() are placed at + * special addresses: +@@ -147,9 +148,7 @@ SYM_CODE_END(__x86_indirect_jump_thunk_array) + * + * As a result, srso_alias_safe_ret() becomes a safe return. + */ +-#ifdef CONFIG_CPU_SRSO +- .section .text..__x86.rethunk_untrain +- ++ .pushsection .text..__x86.rethunk_untrain + SYM_START(srso_alias_untrain_ret, SYM_L_GLOBAL, SYM_A_NONE) + UNWIND_HINT_FUNC + ANNOTATE_NOENDBR +@@ -158,17 +157,9 @@ SYM_START(srso_alias_untrain_ret, SYM_L_GLOBAL, SYM_A_NONE) + jmp srso_alias_return_thunk + SYM_FUNC_END(srso_alias_untrain_ret) + __EXPORT_THUNK(srso_alias_untrain_ret) ++ .popsection + +- .section .text..__x86.rethunk_safe +-#else +-/* dummy definition for alternatives */ +-SYM_START(srso_alias_untrain_ret, SYM_L_GLOBAL, SYM_A_NONE) +- ANNOTATE_UNRET_SAFE +- ret +- int3 +-SYM_FUNC_END(srso_alias_untrain_ret) +-#endif +- ++ .pushsection .text..__x86.rethunk_safe + SYM_START(srso_alias_safe_ret, SYM_L_GLOBAL, SYM_A_NONE) + lea 8(%_ASM_SP), %_ASM_SP + UNWIND_HINT_FUNC +@@ -177,14 +168,69 @@ SYM_START(srso_alias_safe_ret, SYM_L_GLOBAL, SYM_A_NONE) + int3 + SYM_FUNC_END(srso_alias_safe_ret) + +- .section .text..__x86.return_thunk +- +-SYM_CODE_START(srso_alias_return_thunk) ++SYM_CODE_START_NOALIGN(srso_alias_return_thunk) + UNWIND_HINT_FUNC + ANNOTATE_NOENDBR + call srso_alias_safe_ret + ud2 + SYM_CODE_END(srso_alias_return_thunk) ++ .popsection ++ ++/* ++ * SRSO untraining sequence for Zen1/2, similar to retbleed_untrain_ret() ++ * above. On kernel entry, srso_untrain_ret() is executed which is a ++ * ++ * movabs $0xccccc30824648d48,%rax ++ * ++ * and when the return thunk executes the inner label srso_safe_ret() ++ * later, it is a stack manipulation and a RET which is mispredicted and ++ * thus a "safe" one to use. ++ */ ++ .align 64 ++ .skip 64 - (srso_safe_ret - srso_untrain_ret), 0xcc ++SYM_START(srso_untrain_ret, SYM_L_LOCAL, SYM_A_NONE) ++ ANNOTATE_NOENDBR ++ .byte 0x48, 0xb8 ++ ++/* ++ * This forces the function return instruction to speculate into a trap ++ * (UD2 in srso_return_thunk() below). This RET will then mispredict ++ * and execution will continue at the return site read from the top of ++ * the stack. ++ */ ++SYM_INNER_LABEL(srso_safe_ret, SYM_L_GLOBAL) ++ lea 8(%_ASM_SP), %_ASM_SP ++ ret ++ int3 ++ int3 ++ /* end of movabs */ ++ lfence ++ call srso_safe_ret ++ ud2 ++SYM_CODE_END(srso_safe_ret) ++SYM_FUNC_END(srso_untrain_ret) ++ ++SYM_CODE_START(srso_return_thunk) ++ UNWIND_HINT_FUNC ++ ANNOTATE_NOENDBR ++ call srso_safe_ret ++ ud2 ++SYM_CODE_END(srso_return_thunk) ++ ++#define JMP_SRSO_UNTRAIN_RET "jmp srso_untrain_ret" ++#else /* !CONFIG_CPU_SRSO */ ++#define JMP_SRSO_UNTRAIN_RET "ud2" ++/* Dummy for the alternative in CALL_UNTRAIN_RET. */ ++SYM_CODE_START(srso_alias_untrain_ret) ++ ANNOTATE_UNRET_SAFE ++ ANNOTATE_NOENDBR ++ ret ++ int3 ++SYM_FUNC_END(srso_alias_untrain_ret) ++__EXPORT_THUNK(srso_alias_untrain_ret) ++#endif /* CONFIG_CPU_SRSO */ ++ ++#ifdef CONFIG_CPU_UNRET_ENTRY + + /* + * Some generic notes on the untraining sequences: +@@ -266,65 +312,19 @@ SYM_CODE_END(retbleed_return_thunk) + SYM_FUNC_END(retbleed_untrain_ret) + __EXPORT_THUNK(retbleed_untrain_ret) + +-/* +- * SRSO untraining sequence for Zen1/2, similar to retbleed_untrain_ret() +- * above. On kernel entry, srso_untrain_ret() is executed which is a +- * +- * movabs $0xccccc30824648d48,%rax +- * +- * and when the return thunk executes the inner label srso_safe_ret() +- * later, it is a stack manipulation and a RET which is mispredicted and +- * thus a "safe" one to use. +- */ +- .align 64 +- .skip 64 - (srso_safe_ret - srso_untrain_ret), 0xcc +-SYM_START(srso_untrain_ret, SYM_L_GLOBAL, SYM_A_NONE) +- ANNOTATE_NOENDBR +- .byte 0x48, 0xb8 +- +-/* +- * This forces the function return instruction to speculate into a trap +- * (UD2 in srso_return_thunk() below). This RET will then mispredict +- * and execution will continue at the return site read from the top of +- * the stack. +- */ +-SYM_INNER_LABEL(srso_safe_ret, SYM_L_GLOBAL) +- lea 8(%_ASM_SP), %_ASM_SP +- ret +- int3 +- int3 +- /* end of movabs */ +- lfence +- call srso_safe_ret +- ud2 +-SYM_CODE_END(srso_safe_ret) +-SYM_FUNC_END(srso_untrain_ret) +-__EXPORT_THUNK(srso_untrain_ret) ++#define JMP_RETBLEED_UNTRAIN_RET "jmp retbleed_untrain_ret" ++#else /* !CONFIG_CPU_UNRET_ENTRY */ ++#define JMP_RETBLEED_UNTRAIN_RET "ud2" ++#endif /* CONFIG_CPU_UNRET_ENTRY */ + +-SYM_CODE_START(srso_return_thunk) +- UNWIND_HINT_FUNC +- ANNOTATE_NOENDBR +- call srso_safe_ret +- ud2 +-SYM_CODE_END(srso_return_thunk) ++#if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_SRSO) + + SYM_FUNC_START(entry_untrain_ret) +- ALTERNATIVE_2 "jmp retbleed_untrain_ret", \ +- "jmp srso_untrain_ret", X86_FEATURE_SRSO, \ +- "jmp srso_alias_untrain_ret", X86_FEATURE_SRSO_ALIAS ++ ALTERNATIVE JMP_RETBLEED_UNTRAIN_RET, JMP_SRSO_UNTRAIN_RET, X86_FEATURE_SRSO + SYM_FUNC_END(entry_untrain_ret) + __EXPORT_THUNK(entry_untrain_ret) + +-SYM_CODE_START(__x86_return_thunk) +- UNWIND_HINT_FUNC +- ANNOTATE_NOENDBR +- ANNOTATE_UNRET_SAFE +- ret +- int3 +-SYM_CODE_END(__x86_return_thunk) +-EXPORT_SYMBOL(__x86_return_thunk) +- +-#endif /* CONFIG_RETHUNK */ ++#endif /* CONFIG_CPU_UNRET_ENTRY || CONFIG_CPU_SRSO */ + + #ifdef CONFIG_CALL_DEPTH_TRACKING + +@@ -359,3 +359,22 @@ SYM_FUNC_START(__x86_return_skl) + SYM_FUNC_END(__x86_return_skl) + + #endif /* CONFIG_CALL_DEPTH_TRACKING */ ++ ++/* ++ * This function name is magical and is used by -mfunction-return=thunk-extern ++ * for the compiler to generate JMPs to it. ++ * ++ * This code is only used during kernel boot or module init. All ++ * 'JMP __x86_return_thunk' sites are changed to something else by ++ * apply_returns(). ++ */ ++SYM_CODE_START(__x86_return_thunk) ++ UNWIND_HINT_FUNC ++ ANNOTATE_NOENDBR ++ ANNOTATE_UNRET_SAFE ++ ret ++ int3 ++SYM_CODE_END(__x86_return_thunk) ++EXPORT_SYMBOL(__x86_return_thunk) ++ ++#endif /* CONFIG_RETHUNK */ +diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt +index 5168ee0360b246..d1ccd06c531278 100644 +--- a/arch/x86/lib/x86-opcode-map.txt ++++ b/arch/x86/lib/x86-opcode-map.txt +@@ -148,7 +148,7 @@ AVXcode: + 65: SEG=GS (Prefix) + 66: Operand-Size (Prefix) + 67: Address-Size (Prefix) +-68: PUSH Iz (d64) ++68: PUSH Iz + 69: IMUL Gv,Ev,Iz + 6a: PUSH Ib (d64) + 6b: IMUL Gv,Ev,Ib +@@ -698,10 +698,10 @@ AVXcode: 2 + 4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev) + 4e: vrsqrt14ps/d Vpd,Wpd (66),(ev) + 4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev) +-50: vpdpbusd Vx,Hx,Wx (66),(ev) +-51: vpdpbusds Vx,Hx,Wx (66),(ev) +-52: vdpbf16ps Vx,Hx,Wx (F3),(ev) | vpdpwssd Vx,Hx,Wx (66),(ev) | vp4dpwssd Vdqq,Hdqq,Wdq (F2),(ev) +-53: vpdpwssds Vx,Hx,Wx (66),(ev) | vp4dpwssds Vdqq,Hdqq,Wdq (F2),(ev) ++50: vpdpbusd Vx,Hx,Wx (66) ++51: vpdpbusds Vx,Hx,Wx (66) ++52: vdpbf16ps Vx,Hx,Wx (F3),(ev) | vpdpwssd Vx,Hx,Wx (66) | vp4dpwssd Vdqq,Hdqq,Wdq (F2),(ev) ++53: vpdpwssds Vx,Hx,Wx (66) | vp4dpwssds Vdqq,Hdqq,Wdq (F2),(ev) + 54: vpopcntb/w Vx,Wx (66),(ev) + 55: vpopcntd/q Vx,Wx (66),(ev) + 58: vpbroadcastd Vx,Wx (66),(v) +diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c +index ab778eac195205..6529b3e2cff3cc 100644 +--- a/arch/x86/mm/fault.c ++++ b/arch/x86/mm/fault.c +@@ -376,7 +376,7 @@ static void dump_pagetable(unsigned long address) + goto bad; + + pr_cont("PUD %lx ", pud_val(*pud)); +- if (!pud_present(*pud) || pud_large(*pud)) ++ if (!pud_present(*pud) || pud_leaf(*pud)) + goto out; + + pmd = pmd_offset(pud, address); +@@ -717,39 +717,8 @@ kernelmode_fixup_or_oops(struct pt_regs *regs, unsigned long error_code, + WARN_ON_ONCE(user_mode(regs)); + + /* Are we prepared to handle this kernel fault? */ +- if (fixup_exception(regs, X86_TRAP_PF, error_code, address)) { +- /* +- * Any interrupt that takes a fault gets the fixup. This makes +- * the below recursive fault logic only apply to a faults from +- * task context. +- */ +- if (in_interrupt()) +- return; +- +- /* +- * Per the above we're !in_interrupt(), aka. task context. +- * +- * In this case we need to make sure we're not recursively +- * faulting through the emulate_vsyscall() logic. +- */ +- if (current->thread.sig_on_uaccess_err && signal) { +- sanitize_error_code(address, &error_code); +- +- set_signal_archinfo(address, error_code); +- +- if (si_code == SEGV_PKUERR) { +- force_sig_pkuerr((void __user *)address, pkey); +- } else { +- /* XXX: hwpoison faults will set the wrong code. */ +- force_sig_fault(signal, si_code, (void __user *)address); +- } +- } +- +- /* +- * Barring that, we can do the fixup and be happy. +- */ ++ if (fixup_exception(regs, X86_TRAP_PF, error_code, address)) + return; +- } + + /* + * AMD erratum #91 manifests as a spurious page fault on a PREFETCH +@@ -798,15 +767,6 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code, + show_opcodes(regs, loglvl); + } + +-/* +- * The (legacy) vsyscall page is the long page in the kernel portion +- * of the address space that has user-accessible permissions. +- */ +-static bool is_vsyscall_vaddr(unsigned long vaddr) +-{ +- return unlikely((vaddr & PAGE_MASK) == VSYSCALL_ADDR); +-} +- + static void + __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, + unsigned long address, u32 pkey, int si_code) +@@ -1046,7 +1006,7 @@ spurious_kernel_fault(unsigned long error_code, unsigned long address) + if (!pud_present(*pud)) + return 0; + +- if (pud_large(*pud)) ++ if (pud_leaf(*pud)) + return spurious_kernel_fault_check(error_code, (pte_t *) pud); + + pmd = pmd_offset(pud, address); +diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c +index 679893ea5e6873..6215dfa23578da 100644 +--- a/arch/x86/mm/init.c ++++ b/arch/x86/mm/init.c +@@ -261,21 +261,17 @@ static void __init probe_page_size_mask(void) + } + } + +-#define INTEL_MATCH(_model) { .vendor = X86_VENDOR_INTEL, \ +- .family = 6, \ +- .model = _model, \ +- } + /* + * INVLPG may not properly flush Global entries + * on these CPUs when PCIDs are enabled. + */ + static const struct x86_cpu_id invlpg_miss_ids[] = { +- INTEL_MATCH(INTEL_FAM6_ALDERLAKE ), +- INTEL_MATCH(INTEL_FAM6_ALDERLAKE_L ), +- INTEL_MATCH(INTEL_FAM6_ATOM_GRACEMONT ), +- INTEL_MATCH(INTEL_FAM6_RAPTORLAKE ), +- INTEL_MATCH(INTEL_FAM6_RAPTORLAKE_P), +- INTEL_MATCH(INTEL_FAM6_RAPTORLAKE_S), ++ X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, 0), ++ X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, 0), ++ X86_MATCH_INTEL_FAM6_MODEL(ATOM_GRACEMONT, 0), ++ X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, 0), ++ X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, 0), ++ X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, 0), + {} + }; + +diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c +index a190aae8ceaf70..aa69353da49f24 100644 +--- a/arch/x86/mm/init_64.c ++++ b/arch/x86/mm/init_64.c +@@ -617,7 +617,7 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end, + } + + if (!pud_none(*pud)) { +- if (!pud_large(*pud)) { ++ if (!pud_leaf(*pud)) { + pmd = pmd_offset(pud, 0); + paddr_last = phys_pmd_init(pmd, paddr, + paddr_end, +@@ -950,8 +950,12 @@ static void update_end_of_memory_vars(u64 start, u64 size) + int add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages, + struct mhp_params *params) + { ++ unsigned long end = ((start_pfn + nr_pages) << PAGE_SHIFT) - 1; + int ret; + ++ if (WARN_ON_ONCE(end > PHYSMEM_END)) ++ return -ERANGE; ++ + ret = __add_pages(nid, start_pfn, nr_pages, params); + WARN_ON_ONCE(ret); + +@@ -1163,7 +1167,7 @@ remove_pud_table(pud_t *pud_start, unsigned long addr, unsigned long end, + if (!pud_present(*pud)) + continue; + +- if (pud_large(*pud) && ++ if (pud_leaf(*pud) && + IS_ALIGNED(addr, PUD_SIZE) && + IS_ALIGNED(next, PUD_SIZE)) { + spin_lock(&init_mm.page_table_lock); +diff --git a/arch/x86/mm/kasan_init_64.c b/arch/x86/mm/kasan_init_64.c +index 0302491d799d1b..fcf508c52bdc5c 100644 +--- a/arch/x86/mm/kasan_init_64.c ++++ b/arch/x86/mm/kasan_init_64.c +@@ -115,7 +115,7 @@ static void __init kasan_populate_p4d(p4d_t *p4d, unsigned long addr, + pud = pud_offset(p4d, addr); + do { + next = pud_addr_end(addr, end); +- if (!pud_large(*pud)) ++ if (!pud_leaf(*pud)) + kasan_populate_pud(pud, addr, next, nid); + } while (pud++, addr = next, addr != end); + } +diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c +index 37db264866b648..230f1dee4f0954 100644 +--- a/arch/x86/mm/kaslr.c ++++ b/arch/x86/mm/kaslr.c +@@ -47,13 +47,24 @@ static const unsigned long vaddr_end = CPU_ENTRY_AREA_BASE; + */ + static __initdata struct kaslr_memory_region { + unsigned long *base; ++ unsigned long *end; + unsigned long size_tb; + } kaslr_regions[] = { +- { &page_offset_base, 0 }, +- { &vmalloc_base, 0 }, +- { &vmemmap_base, 0 }, ++ { ++ .base = &page_offset_base, ++ .end = &physmem_end, ++ }, ++ { ++ .base = &vmalloc_base, ++ }, ++ { ++ .base = &vmemmap_base, ++ }, + }; + ++/* The end of the possible address space for physical memory */ ++unsigned long physmem_end __ro_after_init; ++ + /* Get size in bytes used by the memory region */ + static inline unsigned long get_padding(struct kaslr_memory_region *region) + { +@@ -82,6 +93,8 @@ void __init kernel_randomize_memory(void) + BUILD_BUG_ON(vaddr_end != CPU_ENTRY_AREA_BASE); + BUILD_BUG_ON(vaddr_end > __START_KERNEL_map); + ++ /* Preset the end of the possible address space for physical memory */ ++ physmem_end = ((1ULL << MAX_PHYSMEM_BITS) - 1); + if (!kaslr_memory_enabled()) + return; + +@@ -128,11 +141,18 @@ void __init kernel_randomize_memory(void) + vaddr += entropy; + *kaslr_regions[i].base = vaddr; + ++ /* Calculate the end of the region */ ++ vaddr += get_padding(&kaslr_regions[i]); + /* +- * Jump the region and add a minimum padding based on +- * randomization alignment. ++ * KASLR trims the maximum possible size of the ++ * direct-map. Update the physmem_end boundary. ++ * No rounding required as the region starts ++ * PUD aligned and size is in units of TB. + */ +- vaddr += get_padding(&kaslr_regions[i]); ++ if (kaslr_regions[i].end) ++ *kaslr_regions[i].end = __pa_nodebug(vaddr - 1); ++ ++ /* Add a minimum padding based on randomization alignment. */ + vaddr = round_up(vaddr + 1, PUD_SIZE); + remain_entropy -= entropy; + } +diff --git a/arch/x86/mm/maccess.c b/arch/x86/mm/maccess.c +index 5a53c2cc169cc9..42115ac079cfe6 100644 +--- a/arch/x86/mm/maccess.c ++++ b/arch/x86/mm/maccess.c +@@ -3,18 +3,37 @@ + #include + #include + ++#include ++ + #ifdef CONFIG_X86_64 + bool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size) + { + unsigned long vaddr = (unsigned long)unsafe_src; + + /* +- * Range covering the highest possible canonical userspace address +- * as well as non-canonical address range. For the canonical range +- * we also need to include the userspace guard page. ++ * Do not allow userspace addresses. This disallows ++ * normal userspace and the userspace guard page: ++ */ ++ if (vaddr < TASK_SIZE_MAX + PAGE_SIZE) ++ return false; ++ ++ /* ++ * Reading from the vsyscall page may cause an unhandled fault in ++ * certain cases. Though it is at an address above TASK_SIZE_MAX, it is ++ * usually considered as a user space address. + */ +- return vaddr >= TASK_SIZE_MAX + PAGE_SIZE && +- __is_canonical_address(vaddr, boot_cpu_data.x86_virt_bits); ++ if (is_vsyscall_vaddr(vaddr)) ++ return false; ++ ++ /* ++ * Allow everything during early boot before 'x86_virt_bits' ++ * is initialized. Needed for instruction decoding in early ++ * exception handlers. ++ */ ++ if (!boot_cpu_data.x86_virt_bits) ++ return true; ++ ++ return __is_canonical_address(vaddr, boot_cpu_data.x86_virt_bits); + } + #else + bool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size) +diff --git a/arch/x86/mm/mem_encrypt_amd.c b/arch/x86/mm/mem_encrypt_amd.c +index 6faea41e99b6bb..1873a65b565578 100644 +--- a/arch/x86/mm/mem_encrypt_amd.c ++++ b/arch/x86/mm/mem_encrypt_amd.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include "mm_internal.h" + +@@ -517,6 +518,34 @@ void __init sme_early_init(void) + */ + if (sev_status & MSR_AMD64_SEV_ES_ENABLED) + x86_cpuinit.parallel_bringup = false; ++ ++ /* ++ * The VMM is capable of injecting interrupt 0x80 and triggering the ++ * compatibility syscall path. ++ * ++ * By default, the 32-bit emulation is disabled in order to ensure ++ * the safety of the VM. ++ */ ++ if (sev_status & MSR_AMD64_SEV_ENABLED) ++ ia32_disable(); ++ ++ /* ++ * Override init functions that scan the ROM region in SEV-SNP guests, ++ * as this memory is not pre-validated and would thus cause a crash. ++ */ ++ if (sev_status & MSR_AMD64_SEV_SNP_ENABLED) { ++ x86_init.mpparse.find_smp_config = x86_init_noop; ++ x86_init.pci.init_irq = x86_init_noop; ++ x86_init.resources.probe_roms = x86_init_noop; ++ ++ /* ++ * DMI setup behavior for SEV-SNP guests depends on ++ * efi_enabled(EFI_CONFIG_TABLES), which hasn't been ++ * parsed yet. snp_dmi_setup() will run after that ++ * parsing has happened. ++ */ ++ x86_init.resources.dmi_setup = snp_dmi_setup; ++ } + } + + void __init mem_encrypt_free_decrypted_mem(void) +diff --git a/arch/x86/mm/mem_encrypt_identity.c b/arch/x86/mm/mem_encrypt_identity.c +index d73aeb16417fcf..cc47a818a640af 100644 +--- a/arch/x86/mm/mem_encrypt_identity.c ++++ b/arch/x86/mm/mem_encrypt_identity.c +@@ -41,9 +41,9 @@ + #include + #include + ++#include + #include + #include +-#include + #include + #include + +@@ -95,11 +95,7 @@ struct sme_populate_pgd_data { + */ + static char sme_workarea[2 * PMD_SIZE] __section(".init.scratch"); + +-static char sme_cmdline_arg[] __initdata = "mem_encrypt"; +-static char sme_cmdline_on[] __initdata = "on"; +-static char sme_cmdline_off[] __initdata = "off"; +- +-static void __init sme_clear_pgd(struct sme_populate_pgd_data *ppd) ++static void __head sme_clear_pgd(struct sme_populate_pgd_data *ppd) + { + unsigned long pgd_start, pgd_end, pgd_size; + pgd_t *pgd_p; +@@ -114,7 +110,7 @@ static void __init sme_clear_pgd(struct sme_populate_pgd_data *ppd) + memset(pgd_p, 0, pgd_size); + } + +-static pud_t __init *sme_prepare_pgd(struct sme_populate_pgd_data *ppd) ++static pud_t __head *sme_prepare_pgd(struct sme_populate_pgd_data *ppd) + { + pgd_t *pgd; + p4d_t *p4d; +@@ -145,13 +141,13 @@ static pud_t __init *sme_prepare_pgd(struct sme_populate_pgd_data *ppd) + set_pud(pud, __pud(PUD_FLAGS | __pa(pmd))); + } + +- if (pud_large(*pud)) ++ if (pud_leaf(*pud)) + return NULL; + + return pud; + } + +-static void __init sme_populate_pgd_large(struct sme_populate_pgd_data *ppd) ++static void __head sme_populate_pgd_large(struct sme_populate_pgd_data *ppd) + { + pud_t *pud; + pmd_t *pmd; +@@ -167,7 +163,7 @@ static void __init sme_populate_pgd_large(struct sme_populate_pgd_data *ppd) + set_pmd(pmd, __pmd(ppd->paddr | ppd->pmd_flags)); + } + +-static void __init sme_populate_pgd(struct sme_populate_pgd_data *ppd) ++static void __head sme_populate_pgd(struct sme_populate_pgd_data *ppd) + { + pud_t *pud; + pmd_t *pmd; +@@ -193,7 +189,7 @@ static void __init sme_populate_pgd(struct sme_populate_pgd_data *ppd) + set_pte(pte, __pte(ppd->paddr | ppd->pte_flags)); + } + +-static void __init __sme_map_range_pmd(struct sme_populate_pgd_data *ppd) ++static void __head __sme_map_range_pmd(struct sme_populate_pgd_data *ppd) + { + while (ppd->vaddr < ppd->vaddr_end) { + sme_populate_pgd_large(ppd); +@@ -203,7 +199,7 @@ static void __init __sme_map_range_pmd(struct sme_populate_pgd_data *ppd) + } + } + +-static void __init __sme_map_range_pte(struct sme_populate_pgd_data *ppd) ++static void __head __sme_map_range_pte(struct sme_populate_pgd_data *ppd) + { + while (ppd->vaddr < ppd->vaddr_end) { + sme_populate_pgd(ppd); +@@ -213,7 +209,7 @@ static void __init __sme_map_range_pte(struct sme_populate_pgd_data *ppd) + } + } + +-static void __init __sme_map_range(struct sme_populate_pgd_data *ppd, ++static void __head __sme_map_range(struct sme_populate_pgd_data *ppd, + pmdval_t pmd_flags, pteval_t pte_flags) + { + unsigned long vaddr_end; +@@ -237,22 +233,22 @@ static void __init __sme_map_range(struct sme_populate_pgd_data *ppd, + __sme_map_range_pte(ppd); + } + +-static void __init sme_map_range_encrypted(struct sme_populate_pgd_data *ppd) ++static void __head sme_map_range_encrypted(struct sme_populate_pgd_data *ppd) + { + __sme_map_range(ppd, PMD_FLAGS_ENC, PTE_FLAGS_ENC); + } + +-static void __init sme_map_range_decrypted(struct sme_populate_pgd_data *ppd) ++static void __head sme_map_range_decrypted(struct sme_populate_pgd_data *ppd) + { + __sme_map_range(ppd, PMD_FLAGS_DEC, PTE_FLAGS_DEC); + } + +-static void __init sme_map_range_decrypted_wp(struct sme_populate_pgd_data *ppd) ++static void __head sme_map_range_decrypted_wp(struct sme_populate_pgd_data *ppd) + { + __sme_map_range(ppd, PMD_FLAGS_DEC_WP, PTE_FLAGS_DEC_WP); + } + +-static unsigned long __init sme_pgtable_calc(unsigned long len) ++static unsigned long __head sme_pgtable_calc(unsigned long len) + { + unsigned long entries = 0, tables = 0; + +@@ -289,7 +285,7 @@ static unsigned long __init sme_pgtable_calc(unsigned long len) + return entries + tables; + } + +-void __init sme_encrypt_kernel(struct boot_params *bp) ++void __head sme_encrypt_kernel(struct boot_params *bp) + { + unsigned long workarea_start, workarea_end, workarea_len; + unsigned long execute_start, execute_end, execute_len; +@@ -305,7 +301,8 @@ void __init sme_encrypt_kernel(struct boot_params *bp) + * instrumentation or checking boot_cpu_data in the cc_platform_has() + * function. + */ +- if (!sme_get_me_mask() || sev_status & MSR_AMD64_SEV_ENABLED) ++ if (!sme_get_me_mask() || ++ RIP_REL_REF(sev_status) & MSR_AMD64_SEV_ENABLED) + return; + + /* +@@ -323,9 +320,8 @@ void __init sme_encrypt_kernel(struct boot_params *bp) + * memory from being cached. + */ + +- /* Physical addresses gives us the identity mapped virtual addresses */ +- kernel_start = __pa_symbol(_text); +- kernel_end = ALIGN(__pa_symbol(_end), PMD_SIZE); ++ kernel_start = (unsigned long)RIP_REL_REF(_text); ++ kernel_end = ALIGN((unsigned long)RIP_REL_REF(_end), PMD_SIZE); + kernel_len = kernel_end - kernel_start; + + initrd_start = 0; +@@ -342,14 +338,6 @@ void __init sme_encrypt_kernel(struct boot_params *bp) + } + #endif + +- /* +- * We're running identity mapped, so we must obtain the address to the +- * SME encryption workarea using rip-relative addressing. +- */ +- asm ("lea sme_workarea(%%rip), %0" +- : "=r" (workarea_start) +- : "p" (sme_workarea)); +- + /* + * Calculate required number of workarea bytes needed: + * executable encryption area size: +@@ -359,7 +347,7 @@ void __init sme_encrypt_kernel(struct boot_params *bp) + * pagetable structures for the encryption of the kernel + * pagetable structures for workarea (in case not currently mapped) + */ +- execute_start = workarea_start; ++ execute_start = workarea_start = (unsigned long)RIP_REL_REF(sme_workarea); + execute_end = execute_start + (PAGE_SIZE * 2) + PMD_SIZE; + execute_len = execute_end - execute_start; + +@@ -502,14 +490,11 @@ void __init sme_encrypt_kernel(struct boot_params *bp) + native_write_cr3(__native_read_cr3()); + } + +-void __init sme_enable(struct boot_params *bp) ++void __head sme_enable(struct boot_params *bp) + { +- const char *cmdline_ptr, *cmdline_arg, *cmdline_on, *cmdline_off; + unsigned int eax, ebx, ecx, edx; + unsigned long feature_mask; +- bool active_by_default; + unsigned long me_mask; +- char buffer[16]; + bool snp; + u64 msr; + +@@ -543,15 +528,18 @@ void __init sme_enable(struct boot_params *bp) + me_mask = 1UL << (ebx & 0x3f); + + /* Check the SEV MSR whether SEV or SME is enabled */ +- sev_status = __rdmsr(MSR_AMD64_SEV); +- feature_mask = (sev_status & MSR_AMD64_SEV_ENABLED) ? AMD_SEV_BIT : AMD_SME_BIT; ++ RIP_REL_REF(sev_status) = msr = __rdmsr(MSR_AMD64_SEV); ++ feature_mask = (msr & MSR_AMD64_SEV_ENABLED) ? AMD_SEV_BIT : AMD_SME_BIT; + + /* The SEV-SNP CC blob should never be present unless SEV-SNP is enabled. */ +- if (snp && !(sev_status & MSR_AMD64_SEV_SNP_ENABLED)) ++ if (snp && !(msr & MSR_AMD64_SEV_SNP_ENABLED)) + snp_abort(); + + /* Check if memory encryption is enabled */ + if (feature_mask == AMD_SME_BIT) { ++ if (!(bp->hdr.xloadflags & XLF_MEM_ENCRYPTION)) ++ return; ++ + /* + * No SME if Hypervisor bit is set. This check is here to + * prevent a guest from trying to enable SME. For running as a +@@ -571,48 +559,10 @@ void __init sme_enable(struct boot_params *bp) + msr = __rdmsr(MSR_AMD64_SYSCFG); + if (!(msr & MSR_AMD64_SYSCFG_MEM_ENCRYPT)) + return; +- } else { +- /* SEV state cannot be controlled by a command line option */ +- sme_me_mask = me_mask; +- goto out; + } + +- /* +- * Fixups have not been applied to phys_base yet and we're running +- * identity mapped, so we must obtain the address to the SME command +- * line argument data using rip-relative addressing. +- */ +- asm ("lea sme_cmdline_arg(%%rip), %0" +- : "=r" (cmdline_arg) +- : "p" (sme_cmdline_arg)); +- asm ("lea sme_cmdline_on(%%rip), %0" +- : "=r" (cmdline_on) +- : "p" (sme_cmdline_on)); +- asm ("lea sme_cmdline_off(%%rip), %0" +- : "=r" (cmdline_off) +- : "p" (sme_cmdline_off)); +- +- if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT)) +- active_by_default = true; +- else +- active_by_default = false; +- +- cmdline_ptr = (const char *)((u64)bp->hdr.cmd_line_ptr | +- ((u64)bp->ext_cmd_line_ptr << 32)); +- +- if (cmdline_find_option(cmdline_ptr, cmdline_arg, buffer, sizeof(buffer)) < 0) +- return; +- +- if (!strncmp(buffer, cmdline_on, sizeof(buffer))) +- sme_me_mask = me_mask; +- else if (!strncmp(buffer, cmdline_off, sizeof(buffer))) +- sme_me_mask = 0; +- else +- sme_me_mask = active_by_default ? me_mask : 0; +-out: +- if (sme_me_mask) { +- physical_mask &= ~sme_me_mask; +- cc_vendor = CC_VENDOR_AMD; +- cc_set_mask(sme_me_mask); +- } ++ RIP_REL_REF(sme_me_mask) = me_mask; ++ physical_mask &= ~me_mask; ++ cc_vendor = CC_VENDOR_AMD; ++ cc_set_mask(me_mask); + } +diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c +index 2aadb2019b4f23..c7fa5396c0f05c 100644 +--- a/arch/x86/mm/numa.c ++++ b/arch/x86/mm/numa.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -601,13 +602,6 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) + if (start >= end) + continue; + +- /* +- * Don't confuse VM with a node that doesn't have the +- * minimum amount of memory: +- */ +- if (end && (end - start) < NODE_MIN_SIZE) +- continue; +- + alloc_node_data(nid); + } + +@@ -961,4 +955,78 @@ int memory_add_physaddr_to_nid(u64 start) + return nid; + } + EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); ++ + #endif ++ ++static int __init cmp_memblk(const void *a, const void *b) ++{ ++ const struct numa_memblk *ma = *(const struct numa_memblk **)a; ++ const struct numa_memblk *mb = *(const struct numa_memblk **)b; ++ ++ return (ma->start > mb->start) - (ma->start < mb->start); ++} ++ ++static struct numa_memblk *numa_memblk_list[NR_NODE_MEMBLKS] __initdata; ++ ++/** ++ * numa_fill_memblks - Fill gaps in numa_meminfo memblks ++ * @start: address to begin fill ++ * @end: address to end fill ++ * ++ * Find and extend numa_meminfo memblks to cover the physical ++ * address range @start-@end ++ * ++ * RETURNS: ++ * 0 : Success ++ * NUMA_NO_MEMBLK : No memblks exist in address range @start-@end ++ */ ++ ++int __init numa_fill_memblks(u64 start, u64 end) ++{ ++ struct numa_memblk **blk = &numa_memblk_list[0]; ++ struct numa_meminfo *mi = &numa_meminfo; ++ int count = 0; ++ u64 prev_end; ++ ++ /* ++ * Create a list of pointers to numa_meminfo memblks that ++ * overlap start, end. The list is used to make in-place ++ * changes that fill out the numa_meminfo memblks. ++ */ ++ for (int i = 0; i < mi->nr_blks; i++) { ++ struct numa_memblk *bi = &mi->blk[i]; ++ ++ if (memblock_addrs_overlap(start, end - start, bi->start, ++ bi->end - bi->start)) { ++ blk[count] = &mi->blk[i]; ++ count++; ++ } ++ } ++ if (!count) ++ return NUMA_NO_MEMBLK; ++ ++ /* Sort the list of pointers in memblk->start order */ ++ sort(&blk[0], count, sizeof(blk[0]), cmp_memblk, NULL); ++ ++ /* Make sure the first/last memblks include start/end */ ++ blk[0]->start = min(blk[0]->start, start); ++ blk[count - 1]->end = max(blk[count - 1]->end, end); ++ ++ /* ++ * Fill any gaps by tracking the previous memblks ++ * end address and backfilling to it if needed. ++ */ ++ prev_end = blk[0]->end; ++ for (int i = 1; i < count; i++) { ++ struct numa_memblk *curr = blk[i]; ++ ++ if (prev_end >= curr->start) { ++ if (prev_end < curr->end) ++ prev_end = curr->end; ++ } else { ++ curr->start = prev_end; ++ prev_end = curr->end; ++ } ++ } ++ return 0; ++} +diff --git a/arch/x86/mm/pat/memtype.c b/arch/x86/mm/pat/memtype.c +index de10800cd4dd48..e7b9ac63bb02aa 100644 +--- a/arch/x86/mm/pat/memtype.c ++++ b/arch/x86/mm/pat/memtype.c +@@ -950,6 +950,38 @@ static void free_pfn_range(u64 paddr, unsigned long size) + memtype_free(paddr, paddr + size); + } + ++static int get_pat_info(struct vm_area_struct *vma, resource_size_t *paddr, ++ pgprot_t *pgprot) ++{ ++ unsigned long prot; ++ ++ VM_WARN_ON_ONCE(!(vma->vm_flags & VM_PAT)); ++ ++ /* ++ * We need the starting PFN and cachemode used for track_pfn_remap() ++ * that covered the whole VMA. For most mappings, we can obtain that ++ * information from the page tables. For COW mappings, we might now ++ * suddenly have anon folios mapped and follow_phys() will fail. ++ * ++ * Fallback to using vma->vm_pgoff, see remap_pfn_range_notrack(), to ++ * detect the PFN. If we need the cachemode as well, we're out of luck ++ * for now and have to fail fork(). ++ */ ++ if (!follow_phys(vma, vma->vm_start, 0, &prot, paddr)) { ++ if (pgprot) ++ *pgprot = __pgprot(prot); ++ return 0; ++ } ++ if (is_cow_mapping(vma->vm_flags)) { ++ if (pgprot) ++ return -EINVAL; ++ *paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT; ++ return 0; ++ } ++ WARN_ON_ONCE(1); ++ return -EINVAL; ++} ++ + /* + * track_pfn_copy is called when vma that is covering the pfnmap gets + * copied through copy_page_range(). +@@ -960,20 +992,13 @@ static void free_pfn_range(u64 paddr, unsigned long size) + int track_pfn_copy(struct vm_area_struct *vma) + { + resource_size_t paddr; +- unsigned long prot; + unsigned long vma_size = vma->vm_end - vma->vm_start; + pgprot_t pgprot; + + if (vma->vm_flags & VM_PAT) { +- /* +- * reserve the whole chunk covered by vma. We need the +- * starting address and protection from pte. +- */ +- if (follow_phys(vma, vma->vm_start, 0, &prot, &paddr)) { +- WARN_ON_ONCE(1); ++ if (get_pat_info(vma, &paddr, &pgprot)) + return -EINVAL; +- } +- pgprot = __pgprot(prot); ++ /* reserve the whole chunk covered by vma. */ + return reserve_pfn_range(paddr, vma_size, &pgprot, 1); + } + +@@ -1048,7 +1073,6 @@ void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn, + unsigned long size, bool mm_wr_locked) + { + resource_size_t paddr; +- unsigned long prot; + + if (vma && !(vma->vm_flags & VM_PAT)) + return; +@@ -1056,11 +1080,8 @@ void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn, + /* free the chunk starting from pfn or the whole chunk */ + paddr = (resource_size_t)pfn << PAGE_SHIFT; + if (!paddr && !size) { +- if (follow_phys(vma, vma->vm_start, 0, &prot, &paddr)) { +- WARN_ON_ONCE(1); ++ if (get_pat_info(vma, &paddr, NULL)) + return; +- } +- + size = vma->vm_end - vma->vm_start; + } + free_pfn_range(paddr, size); +diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c +index bda9f129835e95..2d850f6bae701c 100644 +--- a/arch/x86/mm/pat/set_memory.c ++++ b/arch/x86/mm/pat/set_memory.c +@@ -619,7 +619,8 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long start, + * Validate strict W^X semantics. + */ + static inline pgprot_t verify_rwx(pgprot_t old, pgprot_t new, unsigned long start, +- unsigned long pfn, unsigned long npg) ++ unsigned long pfn, unsigned long npg, ++ bool nx, bool rw) + { + unsigned long end; + +@@ -641,6 +642,10 @@ static inline pgprot_t verify_rwx(pgprot_t old, pgprot_t new, unsigned long star + if ((pgprot_val(new) & (_PAGE_RW | _PAGE_NX)) != _PAGE_RW) + return new; + ++ /* Non-leaf translation entries can disable writing or execution. */ ++ if (!rw || nx) ++ return new; ++ + end = start + npg * PAGE_SIZE - 1; + WARN_ONCE(1, "CPA detected W^X violation: %016llx -> %016llx range: 0x%016lx - 0x%016lx PFN %lx\n", + (unsigned long long)pgprot_val(old), +@@ -657,20 +662,26 @@ static inline pgprot_t verify_rwx(pgprot_t old, pgprot_t new, unsigned long star + + /* + * Lookup the page table entry for a virtual address in a specific pgd. +- * Return a pointer to the entry and the level of the mapping. ++ * Return a pointer to the entry, the level of the mapping, and the effective ++ * NX and RW bits of all page table levels. + */ +-pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address, +- unsigned int *level) ++pte_t *lookup_address_in_pgd_attr(pgd_t *pgd, unsigned long address, ++ unsigned int *level, bool *nx, bool *rw) + { + p4d_t *p4d; + pud_t *pud; + pmd_t *pmd; + + *level = PG_LEVEL_NONE; ++ *nx = false; ++ *rw = true; + + if (pgd_none(*pgd)) + return NULL; + ++ *nx |= pgd_flags(*pgd) & _PAGE_NX; ++ *rw &= pgd_flags(*pgd) & _PAGE_RW; ++ + p4d = p4d_offset(pgd, address); + if (p4d_none(*p4d)) + return NULL; +@@ -679,14 +690,20 @@ pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address, + if (p4d_large(*p4d) || !p4d_present(*p4d)) + return (pte_t *)p4d; + ++ *nx |= p4d_flags(*p4d) & _PAGE_NX; ++ *rw &= p4d_flags(*p4d) & _PAGE_RW; ++ + pud = pud_offset(p4d, address); + if (pud_none(*pud)) + return NULL; + + *level = PG_LEVEL_1G; +- if (pud_large(*pud) || !pud_present(*pud)) ++ if (pud_leaf(*pud) || !pud_present(*pud)) + return (pte_t *)pud; + ++ *nx |= pud_flags(*pud) & _PAGE_NX; ++ *rw &= pud_flags(*pud) & _PAGE_RW; ++ + pmd = pmd_offset(pud, address); + if (pmd_none(*pmd)) + return NULL; +@@ -695,11 +712,26 @@ pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address, + if (pmd_large(*pmd) || !pmd_present(*pmd)) + return (pte_t *)pmd; + ++ *nx |= pmd_flags(*pmd) & _PAGE_NX; ++ *rw &= pmd_flags(*pmd) & _PAGE_RW; ++ + *level = PG_LEVEL_4K; + + return pte_offset_kernel(pmd, address); + } + ++/* ++ * Lookup the page table entry for a virtual address in a specific pgd. ++ * Return a pointer to the entry and the level of the mapping. ++ */ ++pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address, ++ unsigned int *level) ++{ ++ bool nx, rw; ++ ++ return lookup_address_in_pgd_attr(pgd, address, level, &nx, &rw); ++} ++ + /* + * Lookup the page table entry for a virtual address. Return a pointer + * to the entry and the level of the mapping. +@@ -715,13 +747,16 @@ pte_t *lookup_address(unsigned long address, unsigned int *level) + EXPORT_SYMBOL_GPL(lookup_address); + + static pte_t *_lookup_address_cpa(struct cpa_data *cpa, unsigned long address, +- unsigned int *level) ++ unsigned int *level, bool *nx, bool *rw) + { +- if (cpa->pgd) +- return lookup_address_in_pgd(cpa->pgd + pgd_index(address), +- address, level); ++ pgd_t *pgd; ++ ++ if (!cpa->pgd) ++ pgd = pgd_offset_k(address); ++ else ++ pgd = cpa->pgd + pgd_index(address); + +- return lookup_address(address, level); ++ return lookup_address_in_pgd_attr(pgd, address, level, nx, rw); + } + + /* +@@ -743,7 +778,7 @@ pmd_t *lookup_pmd_address(unsigned long address) + return NULL; + + pud = pud_offset(p4d, address); +- if (pud_none(*pud) || pud_large(*pud) || !pud_present(*pud)) ++ if (pud_none(*pud) || pud_leaf(*pud) || !pud_present(*pud)) + return NULL; + + return pmd_offset(pud, address); +@@ -845,12 +880,13 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address, + pgprot_t old_prot, new_prot, req_prot, chk_prot; + pte_t new_pte, *tmp; + enum pg_level level; ++ bool nx, rw; + + /* + * Check for races, another CPU might have split this page + * up already: + */ +- tmp = _lookup_address_cpa(cpa, address, &level); ++ tmp = _lookup_address_cpa(cpa, address, &level, &nx, &rw); + if (tmp != kpte) + return 1; + +@@ -961,7 +997,8 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address, + new_prot = static_protections(req_prot, lpaddr, old_pfn, numpages, + psize, CPA_DETECT); + +- new_prot = verify_rwx(old_prot, new_prot, lpaddr, old_pfn, numpages); ++ new_prot = verify_rwx(old_prot, new_prot, lpaddr, old_pfn, numpages, ++ nx, rw); + + /* + * If there is a conflict, split the large page. +@@ -1042,6 +1079,7 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, + pte_t *pbase = (pte_t *)page_address(base); + unsigned int i, level; + pgprot_t ref_prot; ++ bool nx, rw; + pte_t *tmp; + + spin_lock(&pgd_lock); +@@ -1049,7 +1087,7 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, + * Check for races, another CPU might have split this page + * up for us already: + */ +- tmp = _lookup_address_cpa(cpa, address, &level); ++ tmp = _lookup_address_cpa(cpa, address, &level, &nx, &rw); + if (tmp != kpte) { + spin_unlock(&pgd_lock); + return 1; +@@ -1274,7 +1312,7 @@ static void unmap_pud_range(p4d_t *p4d, unsigned long start, unsigned long end) + */ + while (end - start >= PUD_SIZE) { + +- if (pud_large(*pud)) ++ if (pud_leaf(*pud)) + pud_clear(pud); + else + unmap_pmd_range(pud, start, start + PUD_SIZE); +@@ -1590,10 +1628,11 @@ static int __change_page_attr(struct cpa_data *cpa, int primary) + int do_split, err; + unsigned int level; + pte_t *kpte, old_pte; ++ bool nx, rw; + + address = __cpa_addr(cpa, cpa->curpage); + repeat: +- kpte = _lookup_address_cpa(cpa, address, &level); ++ kpte = _lookup_address_cpa(cpa, address, &level, &nx, &rw); + if (!kpte) + return __cpa_process_fault(cpa, address, primary); + +@@ -1615,7 +1654,8 @@ static int __change_page_attr(struct cpa_data *cpa, int primary) + new_prot = static_protections(new_prot, address, pfn, 1, 0, + CPA_PROTECT); + +- new_prot = verify_rwx(old_prot, new_prot, address, pfn, 1); ++ new_prot = verify_rwx(old_prot, new_prot, address, pfn, 1, ++ nx, rw); + + new_prot = pgprot_clear_protnone_bits(new_prot); + +diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c +index 9deadf517f14a9..b18f5a71e679e2 100644 +--- a/arch/x86/mm/pgtable.c ++++ b/arch/x86/mm/pgtable.c +@@ -628,6 +628,8 @@ int pmdp_clear_flush_young(struct vm_area_struct *vma, + pmd_t pmdp_invalidate_ad(struct vm_area_struct *vma, unsigned long address, + pmd_t *pmdp) + { ++ VM_WARN_ON_ONCE(!pmd_present(*pmdp)); ++ + /* + * No flush is necessary. Once an invalid PTE is established, the PTE's + * access and dirty bits cannot be updated. +@@ -774,7 +776,7 @@ int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot) + */ + int pud_clear_huge(pud_t *pud) + { +- if (pud_large(*pud)) { ++ if (pud_leaf(*pud)) { + pud_clear(pud); + return 1; + } +diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c +index 78414c6d1b5ed1..83a6bdf0b498ef 100644 +--- a/arch/x86/mm/pti.c ++++ b/arch/x86/mm/pti.c +@@ -217,7 +217,7 @@ static pmd_t *pti_user_pagetable_walk_pmd(unsigned long address) + + pud = pud_offset(p4d, address); + /* The user page tables do not use large mappings: */ +- if (pud_large(*pud)) { ++ if (pud_leaf(*pud)) { + WARN_ON(1); + return NULL; + } +@@ -241,7 +241,7 @@ static pmd_t *pti_user_pagetable_walk_pmd(unsigned long address) + * + * Returns a pointer to a PTE on success, or NULL on failure. + */ +-static pte_t *pti_user_pagetable_walk_pte(unsigned long address) ++static pte_t *pti_user_pagetable_walk_pte(unsigned long address, bool late_text) + { + gfp_t gfp = (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO); + pmd_t *pmd; +@@ -251,10 +251,15 @@ static pte_t *pti_user_pagetable_walk_pte(unsigned long address) + if (!pmd) + return NULL; + +- /* We can't do anything sensible if we hit a large mapping. */ ++ /* Large PMD mapping found */ + if (pmd_large(*pmd)) { +- WARN_ON(1); +- return NULL; ++ /* Clear the PMD if we hit a large mapping from the first round */ ++ if (late_text) { ++ set_pmd(pmd, __pmd(0)); ++ } else { ++ WARN_ON_ONCE(1); ++ return NULL; ++ } + } + + if (pmd_none(*pmd)) { +@@ -283,7 +288,7 @@ static void __init pti_setup_vsyscall(void) + if (!pte || WARN_ON(level != PG_LEVEL_4K) || pte_none(*pte)) + return; + +- target_pte = pti_user_pagetable_walk_pte(VSYSCALL_ADDR); ++ target_pte = pti_user_pagetable_walk_pte(VSYSCALL_ADDR, false); + if (WARN_ON(!target_pte)) + return; + +@@ -301,7 +306,7 @@ enum pti_clone_level { + + static void + pti_clone_pgtable(unsigned long start, unsigned long end, +- enum pti_clone_level level) ++ enum pti_clone_level level, bool late_text) + { + unsigned long addr; + +@@ -374,14 +379,14 @@ pti_clone_pgtable(unsigned long start, unsigned long end, + */ + *target_pmd = *pmd; + +- addr += PMD_SIZE; ++ addr = round_up(addr + 1, PMD_SIZE); + + } else if (level == PTI_CLONE_PTE) { + + /* Walk the page-table down to the pte level */ + pte = pte_offset_kernel(pmd, addr); + if (pte_none(*pte)) { +- addr += PAGE_SIZE; ++ addr = round_up(addr + 1, PAGE_SIZE); + continue; + } + +@@ -390,7 +395,7 @@ pti_clone_pgtable(unsigned long start, unsigned long end, + return; + + /* Allocate PTE in the user page-table */ +- target_pte = pti_user_pagetable_walk_pte(addr); ++ target_pte = pti_user_pagetable_walk_pte(addr, late_text); + if (WARN_ON(!target_pte)) + return; + +@@ -401,7 +406,7 @@ pti_clone_pgtable(unsigned long start, unsigned long end, + /* Clone the PTE */ + *target_pte = *pte; + +- addr += PAGE_SIZE; ++ addr = round_up(addr + 1, PAGE_SIZE); + + } else { + BUG(); +@@ -452,7 +457,7 @@ static void __init pti_clone_user_shared(void) + phys_addr_t pa = per_cpu_ptr_to_phys((void *)va); + pte_t *target_pte; + +- target_pte = pti_user_pagetable_walk_pte(va); ++ target_pte = pti_user_pagetable_walk_pte(va, false); + if (WARN_ON(!target_pte)) + return; + +@@ -475,7 +480,7 @@ static void __init pti_clone_user_shared(void) + start = CPU_ENTRY_AREA_BASE; + end = start + (PAGE_SIZE * CPU_ENTRY_AREA_PAGES); + +- pti_clone_pgtable(start, end, PTI_CLONE_PMD); ++ pti_clone_pgtable(start, end, PTI_CLONE_PMD, false); + } + #endif /* CONFIG_X86_64 */ + +@@ -492,11 +497,11 @@ static void __init pti_setup_espfix64(void) + /* + * Clone the populated PMDs of the entry text and force it RO. + */ +-static void pti_clone_entry_text(void) ++static void pti_clone_entry_text(bool late) + { + pti_clone_pgtable((unsigned long) __entry_text_start, + (unsigned long) __entry_text_end, +- PTI_CLONE_PMD); ++ PTI_LEVEL_KERNEL_IMAGE, late); + } + + /* +@@ -571,7 +576,7 @@ static void pti_clone_kernel_text(void) + * pti_set_kernel_image_nonglobal() did to clear the + * global bit. + */ +- pti_clone_pgtable(start, end_clone, PTI_LEVEL_KERNEL_IMAGE); ++ pti_clone_pgtable(start, end_clone, PTI_LEVEL_KERNEL_IMAGE, false); + + /* + * pti_clone_pgtable() will set the global bit in any PMDs +@@ -638,8 +643,15 @@ void __init pti_init(void) + + /* Undo all global bits from the init pagetables in head_64.S: */ + pti_set_kernel_image_nonglobal(); ++ + /* Replace some of the global bits just for shared entry text: */ +- pti_clone_entry_text(); ++ /* ++ * This is very early in boot. Device and Late initcalls can do ++ * modprobe before free_initmem() and mark_readonly(). This ++ * pti_clone_entry_text() allows those user-mode-helpers to function, ++ * but notably the text is still RW. ++ */ ++ pti_clone_entry_text(false); + pti_setup_espfix64(); + pti_setup_vsyscall(); + } +@@ -656,10 +668,11 @@ void pti_finalize(void) + if (!boot_cpu_has(X86_FEATURE_PTI)) + return; + /* +- * We need to clone everything (again) that maps parts of the +- * kernel image. ++ * This is after free_initmem() (all initcalls are done) and we've done ++ * mark_readonly(). Text is now NX which might've split some PMDs ++ * relative to the early clone. + */ +- pti_clone_entry_text(); ++ pti_clone_entry_text(true); + pti_clone_kernel_text(); + + debug_checkwx_user(); +diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c +index 453ea95b667dad..2fbae48f0b470a 100644 +--- a/arch/x86/mm/tlb.c ++++ b/arch/x86/mm/tlb.c +@@ -497,9 +497,9 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, + { + struct mm_struct *real_prev = this_cpu_read(cpu_tlbstate.loaded_mm); + u16 prev_asid = this_cpu_read(cpu_tlbstate.loaded_mm_asid); +- unsigned long new_lam = mm_lam_cr3_mask(next); + bool was_lazy = this_cpu_read(cpu_tlbstate_shared.is_lazy); + unsigned cpu = smp_processor_id(); ++ unsigned long new_lam; + u64 next_tlb_gen; + bool need_flush; + u16 new_asid; +@@ -622,9 +622,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, + cpumask_clear_cpu(cpu, mm_cpumask(real_prev)); + } + +- /* +- * Start remote flushes and then read tlb_gen. +- */ ++ /* Start receiving IPIs and then read tlb_gen (and LAM below) */ + if (next != &init_mm) + cpumask_set_cpu(cpu, mm_cpumask(next)); + next_tlb_gen = atomic64_read(&next->context.tlb_gen); +@@ -636,6 +634,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, + barrier(); + } + ++ new_lam = mm_lam_cr3_mask(next); + set_tlbstate_lam_mode(next); + if (need_flush) { + this_cpu_write(cpu_tlbstate.ctxs[new_asid].ctx_id, next->context.ctx_id); +diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c +index a5930042139d3b..a50c99e9b5c01f 100644 +--- a/arch/x86/net/bpf_jit_comp.c ++++ b/arch/x86/net/bpf_jit_comp.c +@@ -58,6 +58,56 @@ static bool is_imm8(int value) + return value <= 127 && value >= -128; + } + ++/* ++ * Let us limit the positive offset to be <= 123. ++ * This is to ensure eventual jit convergence For the following patterns: ++ * ... ++ * pass4, final_proglen=4391: ++ * ... ++ * 20e: 48 85 ff test rdi,rdi ++ * 211: 74 7d je 0x290 ++ * 213: 48 8b 77 00 mov rsi,QWORD PTR [rdi+0x0] ++ * ... ++ * 289: 48 85 ff test rdi,rdi ++ * 28c: 74 17 je 0x2a5 ++ * 28e: e9 7f ff ff ff jmp 0x212 ++ * 293: bf 03 00 00 00 mov edi,0x3 ++ * Note that insn at 0x211 is 2-byte cond jump insn for offset 0x7d (-125) ++ * and insn at 0x28e is 5-byte jmp insn with offset -129. ++ * ++ * pass5, final_proglen=4392: ++ * ... ++ * 20e: 48 85 ff test rdi,rdi ++ * 211: 0f 84 80 00 00 00 je 0x297 ++ * 217: 48 8b 77 00 mov rsi,QWORD PTR [rdi+0x0] ++ * ... ++ * 28d: 48 85 ff test rdi,rdi ++ * 290: 74 1a je 0x2ac ++ * 292: eb 84 jmp 0x218 ++ * 294: bf 03 00 00 00 mov edi,0x3 ++ * Note that insn at 0x211 is 6-byte cond jump insn now since its offset ++ * becomes 0x80 based on previous round (0x293 - 0x213 = 0x80). ++ * At the same time, insn at 0x292 is a 2-byte insn since its offset is ++ * -124. ++ * ++ * pass6 will repeat the same code as in pass4 and this will prevent ++ * eventual convergence. ++ * ++ * To fix this issue, we need to break je (2->6 bytes) <-> jmp (5->2 bytes) ++ * cycle in the above. In the above example je offset <= 0x7c should work. ++ * ++ * For other cases, je <-> je needs offset <= 0x7b to avoid no convergence ++ * issue. For jmp <-> je and jmp <-> jmp cases, jmp offset <= 0x7c should ++ * avoid no convergence issue. ++ * ++ * Overall, let us limit the positive offset for 8bit cond/uncond jmp insn ++ * to maximum 123 (0x7b). This way, the jit pass can eventually converge. ++ */ ++static bool is_imm8_jmp_offset(int value) ++{ ++ return value <= 123 && value >= -128; ++} ++ + static bool is_simm32(s64 value) + { + return value == (s64)(s32)value; +@@ -344,7 +394,7 @@ static int emit_call(u8 **pprog, void *func, void *ip) + static int emit_rsb_call(u8 **pprog, void *func, void *ip) + { + OPTIMIZER_HIDE_VAR(func); +- x86_call_depth_emit_accounting(pprog, func); ++ ip += x86_call_depth_emit_accounting(pprog, func); + return emit_patch(pprog, func, ip, 0xE8); + } + +@@ -1018,6 +1068,10 @@ static void emit_shiftx(u8 **pprog, u32 dst_reg, u8 src_reg, bool is64, u8 op) + + #define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp))) + ++/* mov rax, qword ptr [rbp - rounded_stack_depth - 8] */ ++#define RESTORE_TAIL_CALL_CNT(stack) \ ++ EMIT3_off32(0x48, 0x8B, 0x85, -round_up(stack, 8) - 8) ++ + static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image, + int oldproglen, struct jit_context *ctx, bool jmp_padding) + { +@@ -1454,36 +1508,41 @@ st: if (is_imm8(insn->off)) + if (BPF_MODE(insn->code) == BPF_PROBE_MEM || + BPF_MODE(insn->code) == BPF_PROBE_MEMSX) { + /* Conservatively check that src_reg + insn->off is a kernel address: +- * src_reg + insn->off >= TASK_SIZE_MAX + PAGE_SIZE +- * src_reg is used as scratch for src_reg += insn->off and restored +- * after emit_ldx if necessary ++ * src_reg + insn->off > TASK_SIZE_MAX + PAGE_SIZE ++ * and ++ * src_reg + insn->off < VSYSCALL_ADDR + */ + +- u64 limit = TASK_SIZE_MAX + PAGE_SIZE; ++ u64 limit = TASK_SIZE_MAX + PAGE_SIZE - VSYSCALL_ADDR; + u8 *end_of_jmp; + +- /* At end of these emitted checks, insn->off will have been added +- * to src_reg, so no need to do relative load with insn->off offset +- */ +- insn_off = 0; ++ /* movabsq r10, VSYSCALL_ADDR */ ++ emit_mov_imm64(&prog, BPF_REG_AX, (long)VSYSCALL_ADDR >> 32, ++ (u32)(long)VSYSCALL_ADDR); + +- /* movabsq r11, limit */ +- EMIT2(add_1mod(0x48, AUX_REG), add_1reg(0xB8, AUX_REG)); +- EMIT((u32)limit, 4); +- EMIT(limit >> 32, 4); ++ /* mov src_reg, r11 */ ++ EMIT_mov(AUX_REG, src_reg); + + if (insn->off) { +- /* add src_reg, insn->off */ +- maybe_emit_1mod(&prog, src_reg, true); +- EMIT2_off32(0x81, add_1reg(0xC0, src_reg), insn->off); ++ /* add r11, insn->off */ ++ maybe_emit_1mod(&prog, AUX_REG, true); ++ EMIT2_off32(0x81, add_1reg(0xC0, AUX_REG), insn->off); + } + +- /* cmp src_reg, r11 */ +- maybe_emit_mod(&prog, src_reg, AUX_REG, true); +- EMIT2(0x39, add_2reg(0xC0, src_reg, AUX_REG)); ++ /* sub r11, r10 */ ++ maybe_emit_mod(&prog, AUX_REG, BPF_REG_AX, true); ++ EMIT2(0x29, add_2reg(0xC0, AUX_REG, BPF_REG_AX)); ++ ++ /* movabsq r10, limit */ ++ emit_mov_imm64(&prog, BPF_REG_AX, (long)limit >> 32, ++ (u32)(long)limit); + +- /* if unsigned '>=', goto load */ +- EMIT2(X86_JAE, 0); ++ /* cmp r10, r11 */ ++ maybe_emit_mod(&prog, AUX_REG, BPF_REG_AX, true); ++ EMIT2(0x39, add_2reg(0xC0, AUX_REG, BPF_REG_AX)); ++ ++ /* if unsigned '>', goto load */ ++ EMIT2(X86_JA, 0); + end_of_jmp = prog; + + /* xor dst_reg, dst_reg */ +@@ -1509,18 +1568,6 @@ st: if (is_imm8(insn->off)) + /* populate jmp_offset for JMP above */ + start_of_ldx[-1] = prog - start_of_ldx; + +- if (insn->off && src_reg != dst_reg) { +- /* sub src_reg, insn->off +- * Restore src_reg after "add src_reg, insn->off" in prev +- * if statement. But if src_reg == dst_reg, emit_ldx +- * above already clobbered src_reg, so no need to restore. +- * If add src_reg, insn->off was unnecessary, no need to +- * restore either. +- */ +- maybe_emit_1mod(&prog, src_reg, true); +- EMIT2_off32(0x81, add_1reg(0xE8, src_reg), insn->off); +- } +- + if (!bpf_prog->aux->extable) + break; + +@@ -1623,9 +1670,7 @@ st: if (is_imm8(insn->off)) + + func = (u8 *) __bpf_call_base + imm32; + if (tail_call_reachable) { +- /* mov rax, qword ptr [rbp - rounded_stack_depth - 8] */ +- EMIT3_off32(0x48, 0x8B, 0x85, +- -round_up(bpf_prog->aux->stack_depth, 8) - 8); ++ RESTORE_TAIL_CALL_CNT(bpf_prog->aux->stack_depth); + if (!imm32) + return -EINVAL; + offs = 7 + x86_call_depth_emit_accounting(&prog, func); +@@ -1779,7 +1824,7 @@ st: if (is_imm8(insn->off)) + return -EFAULT; + } + jmp_offset = addrs[i + insn->off] - addrs[i]; +- if (is_imm8(jmp_offset)) { ++ if (is_imm8_jmp_offset(jmp_offset)) { + if (jmp_padding) { + /* To keep the jmp_offset valid, the extra bytes are + * padded before the jump insn, so we subtract the +@@ -1861,7 +1906,7 @@ st: if (is_imm8(insn->off)) + break; + } + emit_jmp: +- if (is_imm8(jmp_offset)) { ++ if (is_imm8_jmp_offset(jmp_offset)) { + if (jmp_padding) { + /* To avoid breaking jmp_offset, the extra bytes + * are padded before the actual jmp insn, so +@@ -2400,6 +2445,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i + * [ ... ] + * [ stack_arg2 ] + * RBP - arg_stack_off [ stack_arg1 ] ++ * RSP [ tail_call_cnt ] BPF_TRAMP_F_TAIL_CALL_CTX + */ + + /* room for return value of orig_call or fentry prog */ +@@ -2464,6 +2510,8 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i + else + /* sub rsp, stack_size */ + EMIT4(0x48, 0x83, 0xEC, stack_size); ++ if (flags & BPF_TRAMP_F_TAIL_CALL_CTX) ++ EMIT1(0x50); /* push rax */ + /* mov QWORD PTR [rbp - rbx_off], rbx */ + emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_6, -rbx_off); + +@@ -2516,9 +2564,15 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i + restore_regs(m, &prog, regs_off); + save_args(m, &prog, arg_stack_off, true); + ++ if (flags & BPF_TRAMP_F_TAIL_CALL_CTX) ++ /* Before calling the original function, restore the ++ * tail_call_cnt from stack to rax. ++ */ ++ RESTORE_TAIL_CALL_CNT(stack_size); ++ + if (flags & BPF_TRAMP_F_ORIG_STACK) { +- emit_ldx(&prog, BPF_DW, BPF_REG_0, BPF_REG_FP, 8); +- EMIT2(0xff, 0xd0); /* call *rax */ ++ emit_ldx(&prog, BPF_DW, BPF_REG_6, BPF_REG_FP, 8); ++ EMIT2(0xff, 0xd3); /* call *rbx */ + } else { + /* call original function */ + if (emit_rsb_call(&prog, orig_call, prog)) { +@@ -2569,7 +2623,12 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i + ret = -EINVAL; + goto cleanup; + } +- } ++ } else if (flags & BPF_TRAMP_F_TAIL_CALL_CTX) ++ /* Before running the original function, restore the ++ * tail_call_cnt from stack to rax. ++ */ ++ RESTORE_TAIL_CALL_CNT(stack_size); ++ + /* restore return value of orig_call or fentry prog back into RAX */ + if (save_ret) + emit_ldx(&prog, BPF_DW, BPF_REG_0, BPF_REG_FP, -8); +@@ -2913,3 +2972,49 @@ void bpf_jit_free(struct bpf_prog *prog) + + bpf_prog_unlock_free(prog); + } ++ ++void bpf_arch_poke_desc_update(struct bpf_jit_poke_descriptor *poke, ++ struct bpf_prog *new, struct bpf_prog *old) ++{ ++ u8 *old_addr, *new_addr, *old_bypass_addr; ++ int ret; ++ ++ old_bypass_addr = old ? NULL : poke->bypass_addr; ++ old_addr = old ? (u8 *)old->bpf_func + poke->adj_off : NULL; ++ new_addr = new ? (u8 *)new->bpf_func + poke->adj_off : NULL; ++ ++ /* ++ * On program loading or teardown, the program's kallsym entry ++ * might not be in place, so we use __bpf_arch_text_poke to skip ++ * the kallsyms check. ++ */ ++ if (new) { ++ ret = __bpf_arch_text_poke(poke->tailcall_target, ++ BPF_MOD_JUMP, ++ old_addr, new_addr); ++ BUG_ON(ret < 0); ++ if (!old) { ++ ret = __bpf_arch_text_poke(poke->tailcall_bypass, ++ BPF_MOD_JUMP, ++ poke->bypass_addr, ++ NULL); ++ BUG_ON(ret < 0); ++ } ++ } else { ++ ret = __bpf_arch_text_poke(poke->tailcall_bypass, ++ BPF_MOD_JUMP, ++ old_bypass_addr, ++ poke->bypass_addr); ++ BUG_ON(ret < 0); ++ /* let other CPUs finish the execution of program ++ * so that it will not possible to expose them ++ * to invalid nop, stack unwind, nop state ++ */ ++ if (!ret) ++ synchronize_rcu(); ++ ret = __bpf_arch_text_poke(poke->tailcall_target, ++ BPF_MOD_JUMP, ++ old_addr, NULL); ++ BUG_ON(ret < 0); ++ } ++} +diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c +index e3ec02e6ac9feb..98a9bb92d75c88 100644 +--- a/arch/x86/pci/fixup.c ++++ b/arch/x86/pci/fixup.c +@@ -3,9 +3,11 @@ + * Exceptions for specific devices. Usually work-arounds for fatal design flaws. + */ + ++#include + #include + #include + #include ++#include + #include + #include + #include +@@ -904,3 +906,108 @@ static void chromeos_fixup_apl_pci_l1ss_capability(struct pci_dev *dev) + } + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_save_apl_pci_l1ss_capability); + DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_fixup_apl_pci_l1ss_capability); ++ ++/* ++ * Disable D3cold on Asus B1400 PCI-NVMe bridge ++ * ++ * On this platform with VMD off, the NVMe device cannot successfully power ++ * back on from D3cold. This appears to be an untested transition by the ++ * vendor: Windows leaves the NVMe and parent bridge in D0 during suspend. ++ * ++ * We disable D3cold on the parent bridge for simplicity, and the fact that ++ * both parent bridge and NVMe device share the same power resource. ++ * ++ * This is only needed on BIOS versions before 308; the newer versions flip ++ * StorageD3Enable from 1 to 0. ++ */ ++static const struct dmi_system_id asus_nvme_broken_d3cold_table[] = { ++ { ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_BIOS_VERSION, "B1400CEAE.304"), ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_BIOS_VERSION, "B1400CEAE.305"), ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_BIOS_VERSION, "B1400CEAE.306"), ++ }, ++ }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_BIOS_VERSION, "B1400CEAE.307"), ++ }, ++ }, ++ {} ++}; ++ ++static void asus_disable_nvme_d3cold(struct pci_dev *pdev) ++{ ++ if (dmi_check_system(asus_nvme_broken_d3cold_table) > 0) ++ pci_d3cold_disable(pdev); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x9a09, asus_disable_nvme_d3cold); ++ ++#ifdef CONFIG_SUSPEND ++/* ++ * Root Ports on some AMD SoCs advertise PME_Support for D3hot and D3cold, but ++ * if the SoC is put into a hardware sleep state by the amd-pmc driver, the ++ * Root Ports don't generate wakeup interrupts for USB devices. ++ * ++ * When suspending, remove D3hot and D3cold from the PME_Support advertised ++ * by the Root Port so we don't use those states if we're expecting wakeup ++ * interrupts. Restore the advertised PME_Support when resuming. ++ */ ++static void amd_rp_pme_suspend(struct pci_dev *dev) ++{ ++ struct pci_dev *rp; ++ ++ /* ++ * PM_SUSPEND_ON means we're doing runtime suspend, which means ++ * amd-pmc will not be involved so PMEs during D3 work as advertised. ++ * ++ * The PMEs *do* work if amd-pmc doesn't put the SoC in the hardware ++ * sleep state, but we assume amd-pmc is always present. ++ */ ++ if (pm_suspend_target_state == PM_SUSPEND_ON) ++ return; ++ ++ rp = pcie_find_root_port(dev); ++ if (!rp || !rp->pm_cap) ++ return; ++ ++ rp->pme_support &= ~((PCI_PM_CAP_PME_D3hot|PCI_PM_CAP_PME_D3cold) >> ++ PCI_PM_CAP_PME_SHIFT); ++ dev_info_once(&rp->dev, "quirk: disabling D3cold for suspend\n"); ++} ++ ++static void amd_rp_pme_resume(struct pci_dev *dev) ++{ ++ struct pci_dev *rp; ++ u16 pmc; ++ ++ rp = pcie_find_root_port(dev); ++ if (!rp || !rp->pm_cap) ++ return; ++ ++ pci_read_config_word(rp, rp->pm_cap + PCI_PM_PMC, &pmc); ++ rp->pme_support = FIELD_GET(PCI_PM_CAP_PME_MASK, pmc); ++} ++/* Rembrandt (yellow_carp) */ ++DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x162e, amd_rp_pme_suspend); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x162e, amd_rp_pme_resume); ++DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x162f, amd_rp_pme_suspend); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x162f, amd_rp_pme_resume); ++/* Phoenix (pink_sardine) */ ++DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x1668, amd_rp_pme_suspend); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1668, amd_rp_pme_resume); ++DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x1669, amd_rp_pme_suspend); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1669, amd_rp_pme_resume); ++#endif /* CONFIG_SUSPEND */ +diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c +index 8edd6220660446..722a33be08a186 100644 +--- a/arch/x86/pci/intel_mid_pci.c ++++ b/arch/x86/pci/intel_mid_pci.c +@@ -233,9 +233,9 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev) + return 0; + + ret = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &gsi); +- if (ret < 0) { ++ if (ret) { + dev_warn(&dev->dev, "Failed to read interrupt line: %d\n", ret); +- return ret; ++ return pcibios_err_to_errno(ret); + } + + id = x86_match_cpu(intel_mid_cpu_ids); +diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c +index 4b3efaa82ab7c1..8447d1e2e1961e 100644 +--- a/arch/x86/pci/mmconfig-shared.c ++++ b/arch/x86/pci/mmconfig-shared.c +@@ -525,7 +525,36 @@ static bool __ref is_mmconf_reserved(check_reserved_t is_reserved, + static bool __ref + pci_mmcfg_check_reserved(struct device *dev, struct pci_mmcfg_region *cfg, int early) + { +- if (!early && !acpi_disabled) { ++ struct resource *conflict; ++ ++ if (early) { ++ ++ /* ++ * Don't try to do this check unless configuration type 1 ++ * is available. How about type 2? ++ */ ++ ++ /* ++ * 946f2ee5c731 ("Check that MCFG points to an e820 ++ * reserved area") added this E820 check in 2006 to work ++ * around BIOS defects. ++ * ++ * Per PCI Firmware r3.3, sec 4.1.2, ECAM space must be ++ * reserved by a PNP0C02 resource, but it need not be ++ * mentioned in E820. Before the ACPI interpreter is ++ * available, we can't check for PNP0C02 resources, so ++ * there's no reliable way to verify the region in this ++ * early check. Keep it only for the old machines that ++ * motivated 946f2ee5c731. ++ */ ++ if (dmi_get_bios_year() < 2016 && raw_pci_ops) ++ return is_mmconf_reserved(e820__mapped_all, cfg, dev, ++ "E820 entry"); ++ ++ return true; ++ } ++ ++ if (!acpi_disabled) { + if (is_mmconf_reserved(is_acpi_reserved, cfg, dev, + "ACPI motherboard resource")) + return true; +@@ -542,8 +571,17 @@ pci_mmcfg_check_reserved(struct device *dev, struct pci_mmcfg_region *cfg, int e + &cfg->res); + + if (is_mmconf_reserved(is_efi_mmio, cfg, dev, +- "EfiMemoryMappedIO")) ++ "EfiMemoryMappedIO")) { ++ conflict = insert_resource_conflict(&iomem_resource, ++ &cfg->res); ++ if (conflict) ++ pr_warn("MMCONFIG %pR conflicts with %s %pR\n", ++ &cfg->res, conflict->name, conflict); ++ else ++ pr_info("MMCONFIG %pR reserved to work around lack of ACPI motherboard _CRS\n", ++ &cfg->res); + return true; ++ } + } + + /* +@@ -552,16 +590,7 @@ pci_mmcfg_check_reserved(struct device *dev, struct pci_mmcfg_region *cfg, int e + * For MCFG information constructed from hotpluggable host bridge's + * _CBA method, just assume it's reserved. + */ +- if (pci_mmcfg_running_state) +- return true; +- +- /* Don't try to do this check unless configuration +- type 1 is available. how about type 2 ?*/ +- if (raw_pci_ops) +- return is_mmconf_reserved(e820__mapped_all, cfg, dev, +- "E820 entry"); +- +- return false; ++ return pci_mmcfg_running_state; + } + + static void __init pci_mmcfg_reject_broken(int early) +diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c +index 652cd53e77f641..0f2fe524f60dcd 100644 +--- a/arch/x86/pci/xen.c ++++ b/arch/x86/pci/xen.c +@@ -38,10 +38,10 @@ static int xen_pcifront_enable_irq(struct pci_dev *dev) + u8 gsi; + + rc = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &gsi); +- if (rc < 0) { ++ if (rc) { + dev_warn(&dev->dev, "Xen PCI: failed to read interrupt line: %d\n", + rc); +- return rc; ++ return pcibios_err_to_errno(rc); + } + /* In PV DomU the Xen PCI backend puts the PIRQ in the interrupt line.*/ + pirq = gsi; +diff --git a/arch/x86/platform/efi/memmap.c b/arch/x86/platform/efi/memmap.c +index 4ef20b49eb5e72..6ed1935504b96e 100644 +--- a/arch/x86/platform/efi/memmap.c ++++ b/arch/x86/platform/efi/memmap.c +@@ -92,12 +92,22 @@ int __init efi_memmap_alloc(unsigned int num_entries, + */ + int __init efi_memmap_install(struct efi_memory_map_data *data) + { ++ unsigned long size = efi.memmap.desc_size * efi.memmap.nr_map; ++ unsigned long flags = efi.memmap.flags; ++ u64 phys = efi.memmap.phys_map; ++ int ret; ++ + efi_memmap_unmap(); + + if (efi_enabled(EFI_PARAVIRT)) + return 0; + +- return __efi_memmap_init(data); ++ ret = __efi_memmap_init(data); ++ if (ret) ++ return ret; ++ ++ __efi_memmap_free(phys, size, flags); ++ return 0; + } + + /** +diff --git a/arch/x86/platform/intel/iosf_mbi.c b/arch/x86/platform/intel/iosf_mbi.c +index fdd49d70b43738..c81cea208c2c43 100644 +--- a/arch/x86/platform/intel/iosf_mbi.c ++++ b/arch/x86/platform/intel/iosf_mbi.c +@@ -62,7 +62,7 @@ static int iosf_mbi_pci_read_mdr(u32 mcrx, u32 mcr, u32 *mdr) + + fail_read: + dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result); +- return result; ++ return pcibios_err_to_errno(result); + } + + static int iosf_mbi_pci_write_mdr(u32 mcrx, u32 mcr, u32 mdr) +@@ -91,7 +91,7 @@ static int iosf_mbi_pci_write_mdr(u32 mcrx, u32 mcr, u32 mdr) + + fail_write: + dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result); +- return result; ++ return pcibios_err_to_errno(result); + } + + int iosf_mbi_read(u8 port, u8 opcode, u32 offset, u32 *mdr) +diff --git a/arch/x86/platform/pvh/enlighten.c b/arch/x86/platform/pvh/enlighten.c +index 00a92cb2c81474..a12117f3d4de72 100644 +--- a/arch/x86/platform/pvh/enlighten.c ++++ b/arch/x86/platform/pvh/enlighten.c +@@ -74,6 +74,9 @@ static void __init init_pvh_bootparams(bool xen_guest) + } else + xen_raw_printk("Warning: Can fit ISA range into e820\n"); + ++ if (xen_guest) ++ xen_reserve_extra_memory(&pvh_bootparams); ++ + pvh_bootparams.hdr.cmd_line_ptr = + pvh_start_info.cmdline_paddr; + +diff --git a/arch/x86/power/hibernate.c b/arch/x86/power/hibernate.c +index 6f955eb1e1631a..d8af46e6775034 100644 +--- a/arch/x86/power/hibernate.c ++++ b/arch/x86/power/hibernate.c +@@ -170,7 +170,7 @@ int relocate_restore_code(void) + goto out; + } + pud = pud_offset(p4d, relocated_restore_code); +- if (pud_large(*pud)) { ++ if (pud_leaf(*pud)) { + set_pud(pud, __pud(pud_val(*pud) & ~_PAGE_NX)); + goto out; + } +diff --git a/arch/x86/purgatory/Makefile b/arch/x86/purgatory/Makefile +index 08aa0f25f12a0f..8d1c82795ea1da 100644 +--- a/arch/x86/purgatory/Makefile ++++ b/arch/x86/purgatory/Makefile +@@ -42,7 +42,8 @@ KCOV_INSTRUMENT := n + # make up the standalone purgatory.ro + + PURGATORY_CFLAGS_REMOVE := -mcmodel=kernel +-PURGATORY_CFLAGS := -mcmodel=large -ffreestanding -fno-zero-initialized-in-bss -g0 ++PURGATORY_CFLAGS := -mcmodel=small -ffreestanding -fno-zero-initialized-in-bss -g0 ++PURGATORY_CFLAGS += -fpic -fvisibility=hidden + PURGATORY_CFLAGS += $(DISABLE_STACKLEAK_PLUGIN) -DDISABLE_BRANCH_PROFILING + PURGATORY_CFLAGS += -fno-stack-protector + +diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c +index d30949e25ebd9b..a2cfd19c11eea1 100644 +--- a/arch/x86/tools/relocs.c ++++ b/arch/x86/tools/relocs.c +@@ -653,6 +653,14 @@ static void print_absolute_relocs(void) + if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { + continue; + } ++ /* ++ * Do not perform relocations in .notes section; any ++ * values there are meant for pre-boot consumption (e.g. ++ * startup_xen). ++ */ ++ if (sec_applies->shdr.sh_type == SHT_NOTE) { ++ continue; ++ } + sh_symtab = sec_symtab->symtab; + sym_strtab = sec_symtab->link->strtab; + for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { +@@ -738,6 +746,15 @@ static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel, + if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { + continue; + } ++ ++ /* ++ * Do not perform relocations in .notes sections; any ++ * values there are meant for pre-boot consumption (e.g. ++ * startup_xen). ++ */ ++ if (sec_applies->shdr.sh_type == SHT_NOTE) ++ continue; ++ + sh_symtab = sec_symtab->symtab; + sym_strtab = sec_symtab->link->strtab; + for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { +diff --git a/arch/x86/um/shared/sysdep/archsetjmp.h b/arch/x86/um/shared/sysdep/archsetjmp.h +index 166cedbab9266f..8c81d1a604a942 100644 +--- a/arch/x86/um/shared/sysdep/archsetjmp.h ++++ b/arch/x86/um/shared/sysdep/archsetjmp.h +@@ -1,6 +1,13 @@ + /* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __X86_UM_SYSDEP_ARCHSETJMP_H ++#define __X86_UM_SYSDEP_ARCHSETJMP_H ++ + #ifdef __i386__ + #include "archsetjmp_32.h" + #else + #include "archsetjmp_64.h" + #endif ++ ++unsigned long get_thread_reg(int reg, jmp_buf *buf); ++ ++#endif /* __X86_UM_SYSDEP_ARCHSETJMP_H */ +diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig +index 9b1ec5d8c99c8d..a65fc2ae15b496 100644 +--- a/arch/x86/xen/Kconfig ++++ b/arch/x86/xen/Kconfig +@@ -9,6 +9,7 @@ config XEN + select PARAVIRT_CLOCK + select X86_HV_CALLBACK_VECTOR + depends on X86_64 || (X86_32 && X86_PAE) ++ depends on X86_64 || (X86_GENERIC || MPENTIUM4 || MCORE2 || MATOM || MK8) + depends on X86_LOCAL_APIC && X86_TSC + help + This is the Linux Xen port. Enabling this will allow the +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index 0337392a312141..b88722dfc4f867 100644 +--- a/arch/x86/xen/enlighten.c ++++ b/arch/x86/xen/enlighten.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -33,9 +34,12 @@ EXPORT_SYMBOL_GPL(hypercall_page); + * and xen_vcpu_setup for details. By default it points to share_info->vcpu_info + * but during boot it is switched to point to xen_vcpu_info. + * The pointer is used in xen_evtchn_do_upcall to acknowledge pending events. ++ * Make sure that xen_vcpu_info doesn't cross a page boundary by making it ++ * cache-line aligned (the struct is guaranteed to have a size of 64 bytes, ++ * which matches the cache line size of 64-bit x86 processors). + */ + DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu); +-DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info); ++DEFINE_PER_CPU_ALIGNED(struct vcpu_info, xen_vcpu_info); + + /* Linux <-> Xen vCPU id mapping */ + DEFINE_PER_CPU(uint32_t, xen_vcpu_id); +@@ -160,6 +164,7 @@ void xen_vcpu_setup(int cpu) + int err; + struct vcpu_info *vcpup; + ++ BUILD_BUG_ON(sizeof(*vcpup) > SMP_CACHE_BYTES); + BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); + + /* +@@ -346,3 +351,67 @@ void xen_arch_unregister_cpu(int num) + } + EXPORT_SYMBOL(xen_arch_unregister_cpu); + #endif ++ ++/* Amount of extra memory space we add to the e820 ranges */ ++struct xen_memory_region xen_extra_mem[XEN_EXTRA_MEM_MAX_REGIONS] __initdata; ++ ++void __init xen_add_extra_mem(unsigned long start_pfn, unsigned long n_pfns) ++{ ++ unsigned int i; ++ ++ /* ++ * No need to check for zero size, should happen rarely and will only ++ * write a new entry regarded to be unused due to zero size. ++ */ ++ for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) { ++ /* Add new region. */ ++ if (xen_extra_mem[i].n_pfns == 0) { ++ xen_extra_mem[i].start_pfn = start_pfn; ++ xen_extra_mem[i].n_pfns = n_pfns; ++ break; ++ } ++ /* Append to existing region. */ ++ if (xen_extra_mem[i].start_pfn + xen_extra_mem[i].n_pfns == ++ start_pfn) { ++ xen_extra_mem[i].n_pfns += n_pfns; ++ break; ++ } ++ } ++ if (i == XEN_EXTRA_MEM_MAX_REGIONS) ++ printk(KERN_WARNING "Warning: not enough extra memory regions\n"); ++ ++ memblock_reserve(PFN_PHYS(start_pfn), PFN_PHYS(n_pfns)); ++} ++ ++#ifdef CONFIG_XEN_UNPOPULATED_ALLOC ++int __init arch_xen_unpopulated_init(struct resource **res) ++{ ++ unsigned int i; ++ ++ if (!xen_domain()) ++ return -ENODEV; ++ ++ /* Must be set strictly before calling xen_free_unpopulated_pages(). */ ++ *res = &iomem_resource; ++ ++ /* ++ * Initialize with pages from the extra memory regions (see ++ * arch/x86/xen/setup.c). ++ */ ++ for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) { ++ unsigned int j; ++ ++ for (j = 0; j < xen_extra_mem[i].n_pfns; j++) { ++ struct page *pg = ++ pfn_to_page(xen_extra_mem[i].start_pfn + j); ++ ++ xen_free_unpopulated_pages(1, &pg); ++ } ++ ++ /* Zero so region is not also added to the balloon driver. */ ++ xen_extra_mem[i].n_pfns = 0; ++ } ++ ++ return 0; ++} ++#endif +diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c +index bbbfdd495ebd3a..aeb33e0a3f7633 100644 +--- a/arch/x86/xen/enlighten_pv.c ++++ b/arch/x86/xen/enlighten_pv.c +@@ -704,7 +704,7 @@ static struct trap_array_entry trap_array[] = { + TRAP_ENTRY(exc_int3, false ), + TRAP_ENTRY(exc_overflow, false ), + #ifdef CONFIG_IA32_EMULATION +- { entry_INT80_compat, xen_entry_INT80_compat, false }, ++ TRAP_ENTRY(int80_emulation, false ), + #endif + TRAP_ENTRY(exc_page_fault, false ), + TRAP_ENTRY(exc_divide_error, false ), +diff --git a/arch/x86/xen/enlighten_pvh.c b/arch/x86/xen/enlighten_pvh.c +index ada3868c02c231..c28f073c1df524 100644 +--- a/arch/x86/xen/enlighten_pvh.c ++++ b/arch/x86/xen/enlighten_pvh.c +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + #include + #include ++#include + + #include + +@@ -72,3 +73,70 @@ void __init mem_map_via_hcall(struct boot_params *boot_params_p) + } + boot_params_p->e820_entries = memmap.nr_entries; + } ++ ++/* ++ * Reserve e820 UNUSABLE regions to inflate the memory balloon. ++ * ++ * On PVH dom0 the host memory map is used, RAM regions available to dom0 are ++ * located as the same place as in the native memory map, but since dom0 gets ++ * less memory than the total amount of host RAM the ranges that can't be ++ * populated are converted from RAM -> UNUSABLE. Use such regions (up to the ++ * ratio signaled in EXTRA_MEM_RATIO) in order to inflate the balloon driver at ++ * boot. Doing so prevents the guest (even if just temporary) from using holes ++ * in the memory map in order to map grants or foreign addresses, and ++ * hopefully limits the risk of a clash with a device MMIO region. Ideally the ++ * hypervisor should notify us which memory ranges are suitable for creating ++ * foreign mappings, but that's not yet implemented. ++ */ ++void __init xen_reserve_extra_memory(struct boot_params *bootp) ++{ ++ unsigned int i, ram_pages = 0, extra_pages; ++ ++ for (i = 0; i < bootp->e820_entries; i++) { ++ struct boot_e820_entry *e = &bootp->e820_table[i]; ++ ++ if (e->type != E820_TYPE_RAM) ++ continue; ++ ram_pages += PFN_DOWN(e->addr + e->size) - PFN_UP(e->addr); ++ } ++ ++ /* Max amount of extra memory. */ ++ extra_pages = EXTRA_MEM_RATIO * ram_pages; ++ ++ /* ++ * Convert UNUSABLE ranges to RAM and reserve them for foreign mapping ++ * purposes. ++ */ ++ for (i = 0; i < bootp->e820_entries && extra_pages; i++) { ++ struct boot_e820_entry *e = &bootp->e820_table[i]; ++ unsigned long pages; ++ ++ if (e->type != E820_TYPE_UNUSABLE) ++ continue; ++ ++ pages = min(extra_pages, ++ PFN_DOWN(e->addr + e->size) - PFN_UP(e->addr)); ++ ++ if (pages != (PFN_DOWN(e->addr + e->size) - PFN_UP(e->addr))) { ++ struct boot_e820_entry *next; ++ ++ if (bootp->e820_entries == ++ ARRAY_SIZE(bootp->e820_table)) ++ /* No space left to split - skip region. */ ++ continue; ++ ++ /* Split entry. */ ++ next = e + 1; ++ memmove(next, e, ++ (bootp->e820_entries - i) * sizeof(*e)); ++ bootp->e820_entries++; ++ next->addr = PAGE_ALIGN(e->addr) + PFN_PHYS(pages); ++ e->size = next->addr - e->addr; ++ next->size -= e->size; ++ } ++ e->type = E820_TYPE_RAM; ++ extra_pages -= pages; ++ ++ xen_add_extra_mem(PFN_UP(e->addr), pages); ++ } ++} +diff --git a/arch/x86/xen/mmu_pv.c b/arch/x86/xen/mmu_pv.c +index b6830554ff6905..6b201e64d8abc8 100644 +--- a/arch/x86/xen/mmu_pv.c ++++ b/arch/x86/xen/mmu_pv.c +@@ -1082,7 +1082,7 @@ static void __init xen_cleanmfnmap_pud(pud_t *pud, bool unpin) + pmd_t *pmd_tbl; + int i; + +- if (pud_large(*pud)) { ++ if (pud_leaf(*pud)) { + pa = pud_val(*pud) & PHYSICAL_PAGE_MASK; + xen_free_ro_pages(pa, PUD_SIZE); + return; +@@ -1863,7 +1863,7 @@ static phys_addr_t __init xen_early_virt_to_phys(unsigned long vaddr) + if (!pud_present(pud)) + return 0; + pa = pud_val(pud) & PTE_PFN_MASK; +- if (pud_large(pud)) ++ if (pud_leaf(pud)) + return pa + (vaddr & ~PUD_MASK); + + pmd = native_make_pmd(xen_read_phys_ulong(pa + pmd_index(vaddr) * +@@ -2019,10 +2019,7 @@ void __init xen_reserve_special_pages(void) + + void __init xen_pt_check_e820(void) + { +- if (xen_is_e820_reserved(xen_pt_base, xen_pt_size)) { +- xen_raw_console_write("Xen hypervisor allocated page table memory conflicts with E820 map\n"); +- BUG(); +- } ++ xen_chk_is_e820_usable(xen_pt_base, xen_pt_size, "page table"); + } + + static unsigned char dummy_mapping[PAGE_SIZE] __page_aligned_bss; +diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c +index 9bdc3b656b2c49..11b5c042d4faef 100644 +--- a/arch/x86/xen/p2m.c ++++ b/arch/x86/xen/p2m.c +@@ -70,6 +70,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -80,6 +81,7 @@ + #include + #include + #include ++#include + + #include "multicalls.h" + #include "xen-ops.h" +@@ -731,7 +733,7 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, + * immediate unmapping. + */ + map_ops[i].status = GNTST_general_error; +- unmap[0].host_addr = map_ops[i].host_addr, ++ unmap[0].host_addr = map_ops[i].host_addr; + unmap[0].handle = map_ops[i].handle; + map_ops[i].handle = INVALID_GRANT_HANDLE; + if (map_ops[i].flags & GNTMAP_device_map) +@@ -741,7 +743,7 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, + + if (kmap_ops) { + kmap_ops[i].status = GNTST_general_error; +- unmap[1].host_addr = kmap_ops[i].host_addr, ++ unmap[1].host_addr = kmap_ops[i].host_addr; + unmap[1].handle = kmap_ops[i].handle; + kmap_ops[i].handle = INVALID_GRANT_HANDLE; + if (kmap_ops[i].flags & GNTMAP_device_map) +@@ -794,6 +796,102 @@ int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops, + return ret; + } + ++/* Remapped non-RAM areas */ ++#define NR_NONRAM_REMAP 4 ++static struct nonram_remap { ++ phys_addr_t maddr; ++ phys_addr_t paddr; ++ size_t size; ++} xen_nonram_remap[NR_NONRAM_REMAP] __ro_after_init; ++static unsigned int nr_nonram_remap __ro_after_init; ++ ++/* ++ * Do the real remapping of non-RAM regions as specified in the ++ * xen_nonram_remap[] array. ++ * In case of an error just crash the system. ++ */ ++void __init xen_do_remap_nonram(void) ++{ ++ unsigned int i; ++ unsigned int remapped = 0; ++ const struct nonram_remap *remap = xen_nonram_remap; ++ unsigned long pfn, mfn, end_pfn; ++ ++ for (i = 0; i < nr_nonram_remap; i++) { ++ end_pfn = PFN_UP(remap->paddr + remap->size); ++ pfn = PFN_DOWN(remap->paddr); ++ mfn = PFN_DOWN(remap->maddr); ++ while (pfn < end_pfn) { ++ if (!set_phys_to_machine(pfn, mfn)) ++ panic("Failed to set p2m mapping for pfn=%lx mfn=%lx\n", ++ pfn, mfn); ++ ++ pfn++; ++ mfn++; ++ remapped++; ++ } ++ ++ remap++; ++ } ++ ++ pr_info("Remapped %u non-RAM page(s)\n", remapped); ++} ++ ++#ifdef CONFIG_ACPI ++/* ++ * Xen variant of acpi_os_ioremap() taking potentially remapped non-RAM ++ * regions into account. ++ * Any attempt to map an area crossing a remap boundary will produce a ++ * WARN() splat. ++ * phys is related to remap->maddr on input and will be rebased to remap->paddr. ++ */ ++static void __iomem *xen_acpi_os_ioremap(acpi_physical_address phys, ++ acpi_size size) ++{ ++ unsigned int i; ++ const struct nonram_remap *remap = xen_nonram_remap; ++ ++ for (i = 0; i < nr_nonram_remap; i++) { ++ if (phys + size > remap->maddr && ++ phys < remap->maddr + remap->size) { ++ WARN_ON(phys < remap->maddr || ++ phys + size > remap->maddr + remap->size); ++ phys += remap->paddr - remap->maddr; ++ break; ++ } ++ } ++ ++ return x86_acpi_os_ioremap(phys, size); ++} ++#endif /* CONFIG_ACPI */ ++ ++/* ++ * Add a new non-RAM remap entry. ++ * In case of no free entry found, just crash the system. ++ */ ++void __init xen_add_remap_nonram(phys_addr_t maddr, phys_addr_t paddr, ++ unsigned long size) ++{ ++ BUG_ON((maddr & ~PAGE_MASK) != (paddr & ~PAGE_MASK)); ++ ++ if (nr_nonram_remap == NR_NONRAM_REMAP) { ++ xen_raw_console_write("Number of required E820 entry remapping actions exceed maximum value\n"); ++ BUG(); ++ } ++ ++#ifdef CONFIG_ACPI ++ /* Switch to the Xen acpi_os_ioremap() variant. */ ++ if (nr_nonram_remap == 0) ++ acpi_os_ioremap = xen_acpi_os_ioremap; ++#endif ++ ++ xen_nonram_remap[nr_nonram_remap].maddr = maddr; ++ xen_nonram_remap[nr_nonram_remap].paddr = paddr; ++ xen_nonram_remap[nr_nonram_remap].size = size; ++ ++ nr_nonram_remap++; ++} ++ + #ifdef CONFIG_XEN_DEBUG_FS + #include + #include "debugfs.h" +diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c +index b3e37961065a2c..dc822124cacb9c 100644 +--- a/arch/x86/xen/setup.c ++++ b/arch/x86/xen/setup.c +@@ -15,12 +15,12 @@ + #include + #include + #include ++#include + + #include + #include + #include + #include +-#include + #include + #include + #include +@@ -38,9 +38,6 @@ + + #define GB(x) ((uint64_t)(x) * 1024 * 1024 * 1024) + +-/* Amount of extra memory space we add to the e820 ranges */ +-struct xen_memory_region xen_extra_mem[XEN_EXTRA_MEM_MAX_REGIONS] __initdata; +- + /* Number of pages released from the initial allocation. */ + unsigned long xen_released_pages; + +@@ -50,6 +47,9 @@ bool xen_pv_pci_possible; + /* E820 map used during setting up memory. */ + static struct e820_table xen_e820_table __initdata; + ++/* Number of initially usable memory pages. */ ++static unsigned long ini_nr_pages __initdata; ++ + /* + * Buffer used to remap identity mapped pages. We only need the virtual space. + * The physical page behind this address is remapped as needed to different +@@ -64,18 +64,6 @@ static struct { + } xen_remap_buf __initdata __aligned(PAGE_SIZE); + static unsigned long xen_remap_mfn __initdata = INVALID_P2M_ENTRY; + +-/* +- * The maximum amount of extra memory compared to the base size. The +- * main scaling factor is the size of struct page. At extreme ratios +- * of base:extra, all the base memory can be filled with page +- * structures for the extra memory, leaving no space for anything +- * else. +- * +- * 10x seems like a reasonable balance between scaling flexibility and +- * leaving a practically usable system. +- */ +-#define EXTRA_MEM_RATIO (10) +- + static bool xen_512gb_limit __initdata = IS_ENABLED(CONFIG_XEN_512GB); + + static void __init xen_parse_512gb(void) +@@ -96,35 +84,6 @@ static void __init xen_parse_512gb(void) + xen_512gb_limit = val; + } + +-static void __init xen_add_extra_mem(unsigned long start_pfn, +- unsigned long n_pfns) +-{ +- int i; +- +- /* +- * No need to check for zero size, should happen rarely and will only +- * write a new entry regarded to be unused due to zero size. +- */ +- for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) { +- /* Add new region. */ +- if (xen_extra_mem[i].n_pfns == 0) { +- xen_extra_mem[i].start_pfn = start_pfn; +- xen_extra_mem[i].n_pfns = n_pfns; +- break; +- } +- /* Append to existing region. */ +- if (xen_extra_mem[i].start_pfn + xen_extra_mem[i].n_pfns == +- start_pfn) { +- xen_extra_mem[i].n_pfns += n_pfns; +- break; +- } +- } +- if (i == XEN_EXTRA_MEM_MAX_REGIONS) +- printk(KERN_WARNING "Warning: not enough extra memory regions\n"); +- +- memblock_reserve(PFN_PHYS(start_pfn), PFN_PHYS(n_pfns)); +-} +- + static void __init xen_del_extra_mem(unsigned long start_pfn, + unsigned long n_pfns) + { +@@ -257,7 +216,7 @@ static int __init xen_free_mfn(unsigned long mfn) + * as a fallback if the remapping fails. + */ + static void __init xen_set_identity_and_release_chunk(unsigned long start_pfn, +- unsigned long end_pfn, unsigned long nr_pages) ++ unsigned long end_pfn) + { + unsigned long pfn, end; + int ret; +@@ -265,7 +224,7 @@ static void __init xen_set_identity_and_release_chunk(unsigned long start_pfn, + WARN_ON(start_pfn > end_pfn); + + /* Release pages first. */ +- end = min(end_pfn, nr_pages); ++ end = min(end_pfn, ini_nr_pages); + for (pfn = start_pfn; pfn < end; pfn++) { + unsigned long mfn = pfn_to_mfn(pfn); + +@@ -386,15 +345,14 @@ static void __init xen_do_set_identity_and_remap_chunk( + * to Xen and not remapped. + */ + static unsigned long __init xen_set_identity_and_remap_chunk( +- unsigned long start_pfn, unsigned long end_pfn, unsigned long nr_pages, +- unsigned long remap_pfn) ++ unsigned long start_pfn, unsigned long end_pfn, unsigned long remap_pfn) + { + unsigned long pfn; + unsigned long i = 0; + unsigned long n = end_pfn - start_pfn; + + if (remap_pfn == 0) +- remap_pfn = nr_pages; ++ remap_pfn = ini_nr_pages; + + while (i < n) { + unsigned long cur_pfn = start_pfn + i; +@@ -403,19 +361,19 @@ static unsigned long __init xen_set_identity_and_remap_chunk( + unsigned long remap_range_size; + + /* Do not remap pages beyond the current allocation */ +- if (cur_pfn >= nr_pages) { ++ if (cur_pfn >= ini_nr_pages) { + /* Identity map remaining pages */ + set_phys_range_identity(cur_pfn, cur_pfn + size); + break; + } +- if (cur_pfn + size > nr_pages) +- size = nr_pages - cur_pfn; ++ if (cur_pfn + size > ini_nr_pages) ++ size = ini_nr_pages - cur_pfn; + + remap_range_size = xen_find_pfn_range(&remap_pfn); + if (!remap_range_size) { + pr_warn("Unable to find available pfn range, not remapping identity pages\n"); + xen_set_identity_and_release_chunk(cur_pfn, +- cur_pfn + left, nr_pages); ++ cur_pfn + left); + break; + } + /* Adjust size to fit in current e820 RAM region */ +@@ -442,18 +400,18 @@ static unsigned long __init xen_set_identity_and_remap_chunk( + } + + static unsigned long __init xen_count_remap_pages( +- unsigned long start_pfn, unsigned long end_pfn, unsigned long nr_pages, ++ unsigned long start_pfn, unsigned long end_pfn, + unsigned long remap_pages) + { +- if (start_pfn >= nr_pages) ++ if (start_pfn >= ini_nr_pages) + return remap_pages; + +- return remap_pages + min(end_pfn, nr_pages) - start_pfn; ++ return remap_pages + min(end_pfn, ini_nr_pages) - start_pfn; + } + +-static unsigned long __init xen_foreach_remap_area(unsigned long nr_pages, ++static unsigned long __init xen_foreach_remap_area( + unsigned long (*func)(unsigned long start_pfn, unsigned long end_pfn, +- unsigned long nr_pages, unsigned long last_val)) ++ unsigned long last_val)) + { + phys_addr_t start = 0; + unsigned long ret_val = 0; +@@ -481,8 +439,7 @@ static unsigned long __init xen_foreach_remap_area(unsigned long nr_pages, + end_pfn = PFN_UP(entry->addr); + + if (start_pfn < end_pfn) +- ret_val = func(start_pfn, end_pfn, nr_pages, +- ret_val); ++ ret_val = func(start_pfn, end_pfn, ret_val); + start = end; + } + } +@@ -539,6 +496,8 @@ void __init xen_remap_memory(void) + set_pte_mfn(buf, mfn_save, PAGE_KERNEL); + + pr_info("Remapped %ld page(s)\n", remapped); ++ ++ xen_do_remap_nonram(); + } + + static unsigned long __init xen_get_pages_limit(void) +@@ -612,7 +571,7 @@ static void __init xen_ignore_unusable(void) + } + } + +-bool __init xen_is_e820_reserved(phys_addr_t start, phys_addr_t size) ++static bool __init xen_is_e820_reserved(phys_addr_t start, phys_addr_t size) + { + struct e820_entry *entry; + unsigned mapcnt; +@@ -669,6 +628,111 @@ phys_addr_t __init xen_find_free_area(phys_addr_t size) + return 0; + } + ++/* ++ * Swap a non-RAM E820 map entry with RAM above ini_nr_pages. ++ * Note that the E820 map is modified accordingly, but the P2M map isn't yet. ++ * The adaption of the P2M must be deferred until page allocation is possible. ++ */ ++static void __init xen_e820_swap_entry_with_ram(struct e820_entry *swap_entry) ++{ ++ struct e820_entry *entry; ++ unsigned int mapcnt; ++ phys_addr_t mem_end = PFN_PHYS(ini_nr_pages); ++ phys_addr_t swap_addr, swap_size, entry_end; ++ ++ swap_addr = PAGE_ALIGN_DOWN(swap_entry->addr); ++ swap_size = PAGE_ALIGN(swap_entry->addr - swap_addr + swap_entry->size); ++ entry = xen_e820_table.entries; ++ ++ for (mapcnt = 0; mapcnt < xen_e820_table.nr_entries; mapcnt++) { ++ entry_end = entry->addr + entry->size; ++ if (entry->type == E820_TYPE_RAM && entry->size >= swap_size && ++ entry_end - swap_size >= mem_end) { ++ /* Reduce RAM entry by needed space (whole pages). */ ++ entry->size -= swap_size; ++ ++ /* Add new entry at the end of E820 map. */ ++ entry = xen_e820_table.entries + ++ xen_e820_table.nr_entries; ++ xen_e820_table.nr_entries++; ++ ++ /* Fill new entry (keep size and page offset). */ ++ entry->type = swap_entry->type; ++ entry->addr = entry_end - swap_size + ++ swap_addr - swap_entry->addr; ++ entry->size = swap_entry->size; ++ ++ /* Convert old entry to RAM, align to pages. */ ++ swap_entry->type = E820_TYPE_RAM; ++ swap_entry->addr = swap_addr; ++ swap_entry->size = swap_size; ++ ++ /* Remember PFN<->MFN relation for P2M update. */ ++ xen_add_remap_nonram(swap_addr, entry_end - swap_size, ++ swap_size); ++ ++ /* Order E820 table and merge entries. */ ++ e820__update_table(&xen_e820_table); ++ ++ return; ++ } ++ ++ entry++; ++ } ++ ++ xen_raw_console_write("No suitable area found for required E820 entry remapping action\n"); ++ BUG(); ++} ++ ++/* ++ * Look for non-RAM memory types in a specific guest physical area and move ++ * those away if possible (ACPI NVS only for now). ++ */ ++static void __init xen_e820_resolve_conflicts(phys_addr_t start, ++ phys_addr_t size) ++{ ++ struct e820_entry *entry; ++ unsigned int mapcnt; ++ phys_addr_t end; ++ ++ if (!size) ++ return; ++ ++ end = start + size; ++ entry = xen_e820_table.entries; ++ ++ for (mapcnt = 0; mapcnt < xen_e820_table.nr_entries; mapcnt++) { ++ if (entry->addr >= end) ++ return; ++ ++ if (entry->addr + entry->size > start && ++ entry->type == E820_TYPE_NVS) ++ xen_e820_swap_entry_with_ram(entry); ++ ++ entry++; ++ } ++} ++ ++/* ++ * Check for an area in physical memory to be usable for non-movable purposes. ++ * An area is considered to usable if the used E820 map lists it to be RAM or ++ * some other type which can be moved to higher PFNs while keeping the MFNs. ++ * In case the area is not usable, crash the system with an error message. ++ */ ++void __init xen_chk_is_e820_usable(phys_addr_t start, phys_addr_t size, ++ const char *component) ++{ ++ xen_e820_resolve_conflicts(start, size); ++ ++ if (!xen_is_e820_reserved(start, size)) ++ return; ++ ++ xen_raw_console_write("Xen hypervisor allocated "); ++ xen_raw_console_write(component); ++ xen_raw_console_write(" memory conflicts with E820 map\n"); ++ BUG(); ++} ++ + /* + * Like memcpy, but with physical addresses for dest and src. + */ +@@ -728,20 +792,20 @@ static void __init xen_reserve_xen_mfnlist(void) + **/ + char * __init xen_memory_setup(void) + { +- unsigned long max_pfn, pfn_s, n_pfns; ++ unsigned long pfn_s, n_pfns; + phys_addr_t mem_end, addr, size, chunk_size; + u32 type; + int rc; + struct xen_memory_map memmap; + unsigned long max_pages; + unsigned long extra_pages = 0; ++ unsigned long maxmem_pages; + int i; + int op; + + xen_parse_512gb(); +- max_pfn = xen_get_pages_limit(); +- max_pfn = min(max_pfn, xen_start_info->nr_pages); +- mem_end = PFN_PHYS(max_pfn); ++ ini_nr_pages = min(xen_get_pages_limit(), xen_start_info->nr_pages); ++ mem_end = PFN_PHYS(ini_nr_pages); + + memmap.nr_entries = ARRAY_SIZE(xen_e820_table.entries); + set_xen_guest_handle(memmap.buffer, xen_e820_table.entries); +@@ -791,13 +855,35 @@ char * __init xen_memory_setup(void) + /* Make sure the Xen-supplied memory map is well-ordered. */ + e820__update_table(&xen_e820_table); + ++ /* ++ * Check whether the kernel itself conflicts with the target E820 map. ++ * Failing now is better than running into weird problems later due ++ * to relocating (and even reusing) pages with kernel text or data. ++ */ ++ xen_chk_is_e820_usable(__pa_symbol(_text), ++ __pa_symbol(_end) - __pa_symbol(_text), ++ "kernel"); ++ ++ /* ++ * Check for a conflict of the xen_start_info memory with the target ++ * E820 map. ++ */ ++ xen_chk_is_e820_usable(__pa(xen_start_info), sizeof(*xen_start_info), ++ "xen_start_info"); ++ ++ /* ++ * Check for a conflict of the hypervisor supplied page tables with ++ * the target E820 map. ++ */ ++ xen_pt_check_e820(); ++ + max_pages = xen_get_max_pages(); + + /* How many extra pages do we need due to remapping? */ +- max_pages += xen_foreach_remap_area(max_pfn, xen_count_remap_pages); ++ max_pages += xen_foreach_remap_area(xen_count_remap_pages); + +- if (max_pages > max_pfn) +- extra_pages += max_pages - max_pfn; ++ if (max_pages > ini_nr_pages) ++ extra_pages += max_pages - ini_nr_pages; + + /* + * Clamp the amount of extra memory to a EXTRA_MEM_RATIO +@@ -806,8 +892,8 @@ char * __init xen_memory_setup(void) + * Make sure we have no memory above max_pages, as this area + * isn't handled by the p2m management. + */ +- extra_pages = min3(EXTRA_MEM_RATIO * min(max_pfn, PFN_DOWN(MAXMEM)), +- extra_pages, max_pages - max_pfn); ++ maxmem_pages = EXTRA_MEM_RATIO * min(ini_nr_pages, PFN_DOWN(MAXMEM)); ++ extra_pages = min3(maxmem_pages, extra_pages, max_pages - ini_nr_pages); + i = 0; + addr = xen_e820_table.entries[0].addr; + size = xen_e820_table.entries[0].size; +@@ -863,23 +949,6 @@ char * __init xen_memory_setup(void) + + e820__update_table(e820_table); + +- /* +- * Check whether the kernel itself conflicts with the target E820 map. +- * Failing now is better than running into weird problems later due +- * to relocating (and even reusing) pages with kernel text or data. +- */ +- if (xen_is_e820_reserved(__pa_symbol(_text), +- __pa_symbol(__bss_stop) - __pa_symbol(_text))) { +- xen_raw_console_write("Xen hypervisor allocated kernel memory conflicts with E820 map\n"); +- BUG(); +- } +- +- /* +- * Check for a conflict of the hypervisor supplied page tables with +- * the target E820 map. +- */ +- xen_pt_check_e820(); +- + xen_reserve_xen_mfnlist(); + + /* Check for a conflict of the initrd with the target E820 map. */ +@@ -907,7 +976,7 @@ char * __init xen_memory_setup(void) + * Set identity map on non-RAM pages and prepare remapping the + * underlying RAM. + */ +- xen_foreach_remap_area(max_pfn, xen_set_identity_and_remap_chunk); ++ xen_foreach_remap_area(xen_set_identity_and_remap_chunk); + + pr_info("Released %ld page(s)\n", xen_released_pages); + +diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c +index 4b0d6fff88de5a..1fb9a1644d944b 100644 +--- a/arch/x86/xen/smp.c ++++ b/arch/x86/xen/smp.c +@@ -65,6 +65,8 @@ int xen_smp_intr_init(unsigned int cpu) + char *resched_name, *callfunc_name, *debug_name; + + resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu); ++ if (!resched_name) ++ goto fail_mem; + per_cpu(xen_resched_irq, cpu).name = resched_name; + rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR, + cpu, +@@ -77,6 +79,8 @@ int xen_smp_intr_init(unsigned int cpu) + per_cpu(xen_resched_irq, cpu).irq = rc; + + callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu); ++ if (!callfunc_name) ++ goto fail_mem; + per_cpu(xen_callfunc_irq, cpu).name = callfunc_name; + rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR, + cpu, +@@ -90,6 +94,9 @@ int xen_smp_intr_init(unsigned int cpu) + + if (!xen_fifo_events) { + debug_name = kasprintf(GFP_KERNEL, "debug%d", cpu); ++ if (!debug_name) ++ goto fail_mem; ++ + per_cpu(xen_debug_irq, cpu).name = debug_name; + rc = bind_virq_to_irqhandler(VIRQ_DEBUG, cpu, + xen_debug_interrupt, +@@ -101,6 +108,9 @@ int xen_smp_intr_init(unsigned int cpu) + } + + callfunc_name = kasprintf(GFP_KERNEL, "callfuncsingle%d", cpu); ++ if (!callfunc_name) ++ goto fail_mem; ++ + per_cpu(xen_callfuncsingle_irq, cpu).name = callfunc_name; + rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_SINGLE_VECTOR, + cpu, +@@ -114,6 +124,8 @@ int xen_smp_intr_init(unsigned int cpu) + + return 0; + ++ fail_mem: ++ rc = -ENOMEM; + fail: + xen_smp_intr_free(cpu); + return rc; +diff --git a/arch/x86/xen/xen-asm.S b/arch/x86/xen/xen-asm.S +index 9e5e680087853a..1a9cd18dfbd312 100644 +--- a/arch/x86/xen/xen-asm.S ++++ b/arch/x86/xen/xen-asm.S +@@ -156,7 +156,7 @@ xen_pv_trap asm_xenpv_exc_machine_check + #endif /* CONFIG_X86_MCE */ + xen_pv_trap asm_exc_simd_coprocessor_error + #ifdef CONFIG_IA32_EMULATION +-xen_pv_trap entry_INT80_compat ++xen_pv_trap asm_int80_emulation + #endif + xen_pv_trap asm_exc_xen_unknown_trap + xen_pv_trap asm_exc_xen_hypervisor_callback +diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h +index 408a2aa66c6922..a6a21dd0552700 100644 +--- a/arch/x86/xen/xen-ops.h ++++ b/arch/x86/xen/xen-ops.h +@@ -21,7 +21,7 @@ extern void *xen_initial_gdt; + struct trap_info; + void xen_copy_trap_info(struct trap_info *traps); + +-DECLARE_PER_CPU(struct vcpu_info, xen_vcpu_info); ++DECLARE_PER_CPU_ALIGNED(struct vcpu_info, xen_vcpu_info); + DECLARE_PER_CPU(unsigned long, xen_cr3); + DECLARE_PER_CPU(unsigned long, xen_current_cr3); + +@@ -43,8 +43,12 @@ void xen_mm_unpin_all(void); + #ifdef CONFIG_X86_64 + void __init xen_relocate_p2m(void); + #endif ++void __init xen_do_remap_nonram(void); ++void __init xen_add_remap_nonram(phys_addr_t maddr, phys_addr_t paddr, ++ unsigned long size); + +-bool __init xen_is_e820_reserved(phys_addr_t start, phys_addr_t size); ++void __init xen_chk_is_e820_usable(phys_addr_t start, phys_addr_t size, ++ const char *component); + unsigned long __ref xen_chk_extra_mem(unsigned long pfn); + void __init xen_inv_extra_mem(void); + void __init xen_remap_memory(void); +@@ -163,4 +167,18 @@ void xen_hvm_post_suspend(int suspend_cancelled); + static inline void xen_hvm_post_suspend(int suspend_cancelled) {} + #endif + ++/* ++ * The maximum amount of extra memory compared to the base size. The ++ * main scaling factor is the size of struct page. At extreme ratios ++ * of base:extra, all the base memory can be filled with page ++ * structures for the extra memory, leaving no space for anything ++ * else. ++ * ++ * 10x seems like a reasonable balance between scaling flexibility and ++ * leaving a practically usable system. ++ */ ++#define EXTRA_MEM_RATIO (10) ++ ++void xen_add_extra_mem(unsigned long start_pfn, unsigned long n_pfns); ++ + #endif /* XEN_OPS_H */ +diff --git a/arch/xtensa/include/asm/cacheflush.h b/arch/xtensa/include/asm/cacheflush.h +index 785a00ce83c11e..38bcecb0e457d9 100644 +--- a/arch/xtensa/include/asm/cacheflush.h ++++ b/arch/xtensa/include/asm/cacheflush.h +@@ -116,8 +116,9 @@ void flush_cache_page(struct vm_area_struct*, + #define flush_cache_mm(mm) flush_cache_all() + #define flush_cache_dup_mm(mm) flush_cache_mm(mm) + +-#define flush_cache_vmap(start,end) flush_cache_all() +-#define flush_cache_vunmap(start,end) flush_cache_all() ++#define flush_cache_vmap(start,end) flush_cache_all() ++#define flush_cache_vmap_early(start,end) do { } while (0) ++#define flush_cache_vunmap(start,end) flush_cache_all() + + void flush_dcache_folio(struct folio *folio); + #define flush_dcache_folio flush_dcache_folio +@@ -140,6 +141,7 @@ void local_flush_cache_page(struct vm_area_struct *vma, + #define flush_cache_dup_mm(mm) do { } while (0) + + #define flush_cache_vmap(start,end) do { } while (0) ++#define flush_cache_vmap_early(start,end) do { } while (0) + #define flush_cache_vunmap(start,end) do { } while (0) + + #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0 +diff --git a/arch/xtensa/include/asm/jump_label.h b/arch/xtensa/include/asm/jump_label.h +index c812bf85021c02..46c8596259d2d9 100644 +--- a/arch/xtensa/include/asm/jump_label.h ++++ b/arch/xtensa/include/asm/jump_label.h +@@ -13,7 +13,7 @@ + static __always_inline bool arch_static_branch(struct static_key *key, + bool branch) + { +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + "_nop\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".word 1b, %l[l_yes], %c0\n\t" +@@ -38,7 +38,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, + * make it reachable and wrap both into a no-transform block + * to avoid any assembler interference with this. + */ +- asm_volatile_goto("1:\n\t" ++ asm goto("1:\n\t" + ".begin no-transform\n\t" + "_j %l[l_yes]\n\t" + "2:\n\t" +diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h +index d008a153a2b9f7..7ed1a2085bd728 100644 +--- a/arch/xtensa/include/asm/processor.h ++++ b/arch/xtensa/include/asm/processor.h +@@ -115,9 +115,9 @@ + #define MAKE_RA_FOR_CALL(ra,ws) (((ra) & 0x3fffffff) | (ws) << 30) + + /* Convert return address to a valid pc +- * Note: We assume that the stack pointer is in the same 1GB ranges as the ra ++ * Note: 'text' is the address within the same 1GB range as the ra + */ +-#define MAKE_PC_FROM_RA(ra,sp) (((ra) & 0x3fffffff) | ((sp) & 0xc0000000)) ++#define MAKE_PC_FROM_RA(ra, text) (((ra) & 0x3fffffff) | ((unsigned long)(text) & 0xc0000000)) + + #elif defined(__XTENSA_CALL0_ABI__) + +@@ -127,9 +127,9 @@ + #define MAKE_RA_FOR_CALL(ra, ws) (ra) + + /* Convert return address to a valid pc +- * Note: We assume that the stack pointer is in the same 1GB ranges as the ra ++ * Note: 'text' is not used as 'ra' is always the full address + */ +-#define MAKE_PC_FROM_RA(ra, sp) (ra) ++#define MAKE_PC_FROM_RA(ra, text) (ra) + + #else + #error Unsupported Xtensa ABI +diff --git a/arch/xtensa/include/asm/ptrace.h b/arch/xtensa/include/asm/ptrace.h +index a270467556dc84..86c70117371bb7 100644 +--- a/arch/xtensa/include/asm/ptrace.h ++++ b/arch/xtensa/include/asm/ptrace.h +@@ -87,7 +87,7 @@ struct pt_regs { + # define user_mode(regs) (((regs)->ps & 0x00000020)!=0) + # define instruction_pointer(regs) ((regs)->pc) + # define return_pointer(regs) (MAKE_PC_FROM_RA((regs)->areg[0], \ +- (regs)->areg[1])) ++ (regs)->pc)) + + # ifndef CONFIG_SMP + # define profile_pc(regs) instruction_pointer(regs) +diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c +index a815577d25fd02..7bd66677f7b6de 100644 +--- a/arch/xtensa/kernel/process.c ++++ b/arch/xtensa/kernel/process.c +@@ -47,6 +47,7 @@ + #include + #include + #include ++#include + #include + + extern void ret_from_fork(void); +@@ -380,7 +381,7 @@ unsigned long __get_wchan(struct task_struct *p) + int count = 0; + + sp = p->thread.sp; +- pc = MAKE_PC_FROM_RA(p->thread.ra, p->thread.sp); ++ pc = MAKE_PC_FROM_RA(p->thread.ra, _text); + + do { + if (sp < stack_page + sizeof(struct task_struct) || +@@ -392,7 +393,7 @@ unsigned long __get_wchan(struct task_struct *p) + + /* Stack layout: sp-4: ra, sp-3: sp' */ + +- pc = MAKE_PC_FROM_RA(SPILL_SLOT(sp, 0), sp); ++ pc = MAKE_PC_FROM_RA(SPILL_SLOT(sp, 0), _text); + sp = SPILL_SLOT(sp, 1); + } while (count++ < 16); + return 0; +diff --git a/arch/xtensa/kernel/stacktrace.c b/arch/xtensa/kernel/stacktrace.c +index 831ffb648bda7e..ed324fdf2a2f91 100644 +--- a/arch/xtensa/kernel/stacktrace.c ++++ b/arch/xtensa/kernel/stacktrace.c +@@ -13,6 +13,7 @@ + #include + + #include ++#include + #include + #include + #include +@@ -189,7 +190,7 @@ void walk_stackframe(unsigned long *sp, + if (a1 <= (unsigned long)sp) + break; + +- frame.pc = MAKE_PC_FROM_RA(a0, a1); ++ frame.pc = MAKE_PC_FROM_RA(a0, _text); + frame.sp = a1; + + if (fn(&frame, data)) +diff --git a/block/bdev.c b/block/bdev.c +index f3b13aa1b7d428..5a54977518eeae 100644 +--- a/block/bdev.c ++++ b/block/bdev.c +@@ -425,6 +425,8 @@ void bdev_set_nr_sectors(struct block_device *bdev, sector_t sectors) + + void bdev_add(struct block_device *bdev, dev_t dev) + { ++ if (bdev_stable_writes(bdev)) ++ mapping_set_stable_writes(bdev->bd_inode->i_mapping); + bdev->bd_dev = dev; + bdev->bd_inode->i_rdev = dev; + bdev->bd_inode->i_ino = dev; +@@ -829,6 +831,25 @@ struct block_device *blkdev_get_by_dev(dev_t dev, blk_mode_t mode, void *holder, + } + EXPORT_SYMBOL(blkdev_get_by_dev); + ++struct bdev_handle *bdev_open_by_dev(dev_t dev, blk_mode_t mode, void *holder, ++ const struct blk_holder_ops *hops) ++{ ++ struct bdev_handle *handle = kmalloc(sizeof(*handle), GFP_KERNEL); ++ struct block_device *bdev; ++ ++ if (!handle) ++ return ERR_PTR(-ENOMEM); ++ bdev = blkdev_get_by_dev(dev, mode, holder, hops); ++ if (IS_ERR(bdev)) { ++ kfree(handle); ++ return ERR_CAST(bdev); ++ } ++ handle->bdev = bdev; ++ handle->holder = holder; ++ return handle; ++} ++EXPORT_SYMBOL(bdev_open_by_dev); ++ + /** + * blkdev_get_by_path - open a block device by name + * @path: path to the block device to open +@@ -867,6 +888,28 @@ struct block_device *blkdev_get_by_path(const char *path, blk_mode_t mode, + } + EXPORT_SYMBOL(blkdev_get_by_path); + ++struct bdev_handle *bdev_open_by_path(const char *path, blk_mode_t mode, ++ void *holder, const struct blk_holder_ops *hops) ++{ ++ struct bdev_handle *handle; ++ dev_t dev; ++ int error; ++ ++ error = lookup_bdev(path, &dev); ++ if (error) ++ return ERR_PTR(error); ++ ++ handle = bdev_open_by_dev(dev, mode, holder, hops); ++ if (!IS_ERR(handle) && (mode & BLK_OPEN_WRITE) && ++ bdev_read_only(handle->bdev)) { ++ bdev_release(handle); ++ return ERR_PTR(-EACCES); ++ } ++ ++ return handle; ++} ++EXPORT_SYMBOL(bdev_open_by_path); ++ + void blkdev_put(struct block_device *bdev, void *holder) + { + struct gendisk *disk = bdev->bd_disk; +@@ -903,6 +946,13 @@ void blkdev_put(struct block_device *bdev, void *holder) + } + EXPORT_SYMBOL(blkdev_put); + ++void bdev_release(struct bdev_handle *handle) ++{ ++ blkdev_put(handle->bdev, handle->holder); ++ kfree(handle); ++} ++EXPORT_SYMBOL(bdev_release); ++ + /** + * lookup_bdev() - Look up a struct block_device by name. + * @pathname: Name of the block device in the filesystem. +diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c +index 3cce6de464a7b7..7e0dcded5713a0 100644 +--- a/block/bfq-iosched.c ++++ b/block/bfq-iosched.c +@@ -2911,8 +2911,12 @@ bfq_setup_cooperator(struct bfq_data *bfqd, struct bfq_queue *bfqq, + struct bfq_iocq_bfqq_data *bfqq_data = &bic->bfqq_data[a_idx]; + + /* if a merge has already been setup, then proceed with that first */ +- if (bfqq->new_bfqq) +- return bfqq->new_bfqq; ++ new_bfqq = bfqq->new_bfqq; ++ if (new_bfqq) { ++ while (new_bfqq->new_bfqq) ++ new_bfqq = new_bfqq->new_bfqq; ++ return new_bfqq; ++ } + + /* + * Check delayed stable merge for rotational or non-queueing +@@ -3125,10 +3129,12 @@ void bfq_release_process_ref(struct bfq_data *bfqd, struct bfq_queue *bfqq) + bfq_put_queue(bfqq); + } + +-static void +-bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic, +- struct bfq_queue *bfqq, struct bfq_queue *new_bfqq) ++static struct bfq_queue *bfq_merge_bfqqs(struct bfq_data *bfqd, ++ struct bfq_io_cq *bic, ++ struct bfq_queue *bfqq) + { ++ struct bfq_queue *new_bfqq = bfqq->new_bfqq; ++ + bfq_log_bfqq(bfqd, bfqq, "merging with queue %lu", + (unsigned long)new_bfqq->pid); + /* Save weight raising and idle window of the merged queues */ +@@ -3222,6 +3228,8 @@ bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic, + bfq_reassign_last_bfqq(bfqq, new_bfqq); + + bfq_release_process_ref(bfqd, bfqq); ++ ++ return new_bfqq; + } + + static bool bfq_allow_bio_merge(struct request_queue *q, struct request *rq, +@@ -3257,14 +3265,8 @@ static bool bfq_allow_bio_merge(struct request_queue *q, struct request *rq, + * fulfilled, i.e., bic can be redirected to new_bfqq + * and bfqq can be put. + */ +- bfq_merge_bfqqs(bfqd, bfqd->bio_bic, bfqq, +- new_bfqq); +- /* +- * If we get here, bio will be queued into new_queue, +- * so use new_bfqq to decide whether bio and rq can be +- * merged. +- */ +- bfqq = new_bfqq; ++ while (bfqq != new_bfqq) ++ bfqq = bfq_merge_bfqqs(bfqd, bfqd->bio_bic, bfqq); + + /* + * Change also bqfd->bio_bfqq, as +@@ -5699,9 +5701,7 @@ bfq_do_early_stable_merge(struct bfq_data *bfqd, struct bfq_queue *bfqq, + * state before killing it. + */ + bfqq->bic = bic; +- bfq_merge_bfqqs(bfqd, bic, bfqq, new_bfqq); +- +- return new_bfqq; ++ return bfq_merge_bfqqs(bfqd, bic, bfqq); + } + + /* +@@ -6156,6 +6156,7 @@ static bool __bfq_insert_request(struct bfq_data *bfqd, struct request *rq) + bool waiting, idle_timer_disabled = false; + + if (new_bfqq) { ++ struct bfq_queue *old_bfqq = bfqq; + /* + * Release the request's reference to the old bfqq + * and make sure one is taken to the shared queue. +@@ -6172,18 +6173,18 @@ static bool __bfq_insert_request(struct bfq_data *bfqd, struct request *rq) + * new_bfqq. + */ + if (bic_to_bfqq(RQ_BIC(rq), true, +- bfq_actuator_index(bfqd, rq->bio)) == bfqq) +- bfq_merge_bfqqs(bfqd, RQ_BIC(rq), +- bfqq, new_bfqq); ++ bfq_actuator_index(bfqd, rq->bio)) == bfqq) { ++ while (bfqq != new_bfqq) ++ bfqq = bfq_merge_bfqqs(bfqd, RQ_BIC(rq), bfqq); ++ } + +- bfq_clear_bfqq_just_created(bfqq); ++ bfq_clear_bfqq_just_created(old_bfqq); + /* + * rq is about to be enqueued into new_bfqq, + * release rq reference on bfqq + */ +- bfq_put_queue(bfqq); ++ bfq_put_queue(old_bfqq); + rq->elv.priv[1] = new_bfqq; +- bfqq = new_bfqq; + } + + bfq_update_io_thinktime(bfqd, bfqq); +@@ -6721,7 +6722,7 @@ bfq_split_bfqq(struct bfq_io_cq *bic, struct bfq_queue *bfqq) + { + bfq_log_bfqq(bfqq->bfqd, bfqq, "splitting queue"); + +- if (bfqq_process_refs(bfqq) == 1) { ++ if (bfqq_process_refs(bfqq) == 1 && !bfqq->new_bfqq) { + bfqq->pid = current->pid; + bfq_clear_bfqq_coop(bfqq); + bfq_clear_bfqq_split_coop(bfqq); +@@ -6819,6 +6820,31 @@ static void bfq_prepare_request(struct request *rq) + rq->elv.priv[0] = rq->elv.priv[1] = NULL; + } + ++static struct bfq_queue *bfq_waker_bfqq(struct bfq_queue *bfqq) ++{ ++ struct bfq_queue *new_bfqq = bfqq->new_bfqq; ++ struct bfq_queue *waker_bfqq = bfqq->waker_bfqq; ++ ++ if (!waker_bfqq) ++ return NULL; ++ ++ while (new_bfqq) { ++ if (new_bfqq == waker_bfqq) { ++ /* ++ * If waker_bfqq is in the merge chain, and current ++ * is the only procress. ++ */ ++ if (bfqq_process_refs(waker_bfqq) == 1) ++ return NULL; ++ break; ++ } ++ ++ new_bfqq = new_bfqq->new_bfqq; ++ } ++ ++ return waker_bfqq; ++} ++ + /* + * If needed, init rq, allocate bfq data structures associated with + * rq, and increment reference counters in the destination bfq_queue +@@ -6880,7 +6906,7 @@ static struct bfq_queue *bfq_init_rq(struct request *rq) + /* If the queue was seeky for too long, break it apart. */ + if (bfq_bfqq_coop(bfqq) && bfq_bfqq_split_coop(bfqq) && + !bic->bfqq_data[a_idx].stably_merged) { +- struct bfq_queue *old_bfqq = bfqq; ++ struct bfq_queue *waker_bfqq = bfq_waker_bfqq(bfqq); + + /* Update bic before losing reference to bfqq */ + if (bfq_bfqq_in_large_burst(bfqq)) +@@ -6900,7 +6926,7 @@ static struct bfq_queue *bfq_init_rq(struct request *rq) + bfqq_already_existing = true; + + if (!bfqq_already_existing) { +- bfqq->waker_bfqq = old_bfqq->waker_bfqq; ++ bfqq->waker_bfqq = waker_bfqq; + bfqq->tentative_waker_bfqq = NULL; + + /* +@@ -6910,7 +6936,7 @@ static struct bfq_queue *bfq_init_rq(struct request *rq) + * woken_list of the waker. See + * bfq_check_waker for details. + */ +- if (bfqq->waker_bfqq) ++ if (waker_bfqq) + hlist_add_head(&bfqq->woken_list_node, + &bfqq->waker_bfqq->woken_list); + } +@@ -6932,7 +6958,8 @@ static struct bfq_queue *bfq_init_rq(struct request *rq) + * addition, if the queue has also just been split, we have to + * resume its state. + */ +- if (likely(bfqq != &bfqd->oom_bfqq) && bfqq_process_refs(bfqq) == 1) { ++ if (likely(bfqq != &bfqd->oom_bfqq) && !bfqq->new_bfqq && ++ bfqq_process_refs(bfqq) == 1) { + bfqq->bic = bic; + if (split) { + /* +diff --git a/block/bio-integrity.c b/block/bio-integrity.c +index ec8ac8cf6e1b98..15e444b2fcc123 100644 +--- a/block/bio-integrity.c ++++ b/block/bio-integrity.c +@@ -217,6 +217,7 @@ bool bio_integrity_prep(struct bio *bio) + unsigned long start, end; + unsigned int len, nr_pages; + unsigned int bytes, offset, i; ++ gfp_t gfp = GFP_NOIO; + + if (!bi) + return true; +@@ -239,11 +240,19 @@ bool bio_integrity_prep(struct bio *bio) + if (!bi->profile->generate_fn || + !(bi->flags & BLK_INTEGRITY_GENERATE)) + return true; ++ ++ /* ++ * Zero the memory allocated to not leak uninitialized kernel ++ * memory to disk. For PI this only affects the app tag, but ++ * for non-integrity metadata it affects the entire metadata ++ * buffer. ++ */ ++ gfp |= __GFP_ZERO; + } + + /* Allocate kernel buffer for protection data */ + len = bio_integrity_bytes(bi, bio_sectors(bio)); +- buf = kmalloc(len, GFP_NOIO); ++ buf = kmalloc(len, gfp); + if (unlikely(buf == NULL)) { + printk(KERN_ERR "could not allocate integrity buffer\n"); + goto err_end_io; +diff --git a/block/bio.c b/block/bio.c +index 816d412c06e9b4..62419aa09d7319 100644 +--- a/block/bio.c ++++ b/block/bio.c +@@ -944,7 +944,7 @@ bool bvec_try_merge_hw_page(struct request_queue *q, struct bio_vec *bv, + + if ((addr1 | mask) != (addr2 | mask)) + return false; +- if (bv->bv_len + len > queue_max_segment_size(q)) ++ if (len > queue_max_segment_size(q) - bv->bv_len) + return false; + return bvec_try_merge_page(bv, page, len, offset, same_page); + } +@@ -1145,13 +1145,23 @@ EXPORT_SYMBOL(bio_add_folio); + + void __bio_release_pages(struct bio *bio, bool mark_dirty) + { +- struct bvec_iter_all iter_all; +- struct bio_vec *bvec; ++ struct folio_iter fi; ++ ++ bio_for_each_folio_all(fi, bio) { ++ struct page *page; ++ size_t nr_pages; + +- bio_for_each_segment_all(bvec, bio, iter_all) { +- if (mark_dirty && !PageCompound(bvec->bv_page)) +- set_page_dirty_lock(bvec->bv_page); +- bio_release_page(bio, bvec->bv_page); ++ if (mark_dirty) { ++ folio_lock(fi.folio); ++ folio_mark_dirty(fi.folio); ++ folio_unlock(fi.folio); ++ } ++ page = folio_page(fi.folio, fi.offset / PAGE_SIZE); ++ nr_pages = (fi.offset + fi.length - 1) / PAGE_SIZE - ++ fi.offset / PAGE_SIZE + 1; ++ do { ++ bio_release_page(bio, page++); ++ } while (--nr_pages != 0); + } + } + EXPORT_SYMBOL_GPL(__bio_release_pages); +@@ -1439,18 +1449,12 @@ EXPORT_SYMBOL(bio_free_pages); + * bio_set_pages_dirty() and bio_check_pages_dirty() are support functions + * for performing direct-IO in BIOs. + * +- * The problem is that we cannot run set_page_dirty() from interrupt context ++ * The problem is that we cannot run folio_mark_dirty() from interrupt context + * because the required locks are not interrupt-safe. So what we can do is to + * mark the pages dirty _before_ performing IO. And in interrupt context, + * check that the pages are still dirty. If so, fine. If not, redirty them + * in process context. + * +- * We special-case compound pages here: normally this means reads into hugetlb +- * pages. The logic in here doesn't really work right for compound pages +- * because the VM does not uniformly chase down the head page in all cases. +- * But dirtiness of compound pages is pretty meaningless anyway: the VM doesn't +- * handle them at all. So we skip compound pages here at an early stage. +- * + * Note that this code is very hard to test under normal circumstances because + * direct-io pins the pages with get_user_pages(). This makes + * is_page_cache_freeable return false, and the VM will not clean the pages. +@@ -1466,12 +1470,12 @@ EXPORT_SYMBOL(bio_free_pages); + */ + void bio_set_pages_dirty(struct bio *bio) + { +- struct bio_vec *bvec; +- struct bvec_iter_all iter_all; ++ struct folio_iter fi; + +- bio_for_each_segment_all(bvec, bio, iter_all) { +- if (!PageCompound(bvec->bv_page)) +- set_page_dirty_lock(bvec->bv_page); ++ bio_for_each_folio_all(fi, bio) { ++ folio_lock(fi.folio); ++ folio_mark_dirty(fi.folio); ++ folio_unlock(fi.folio); + } + } + EXPORT_SYMBOL_GPL(bio_set_pages_dirty); +@@ -1515,12 +1519,11 @@ static void bio_dirty_fn(struct work_struct *work) + + void bio_check_pages_dirty(struct bio *bio) + { +- struct bio_vec *bvec; ++ struct folio_iter fi; + unsigned long flags; +- struct bvec_iter_all iter_all; + +- bio_for_each_segment_all(bvec, bio, iter_all) { +- if (!PageDirty(bvec->bv_page) && !PageCompound(bvec->bv_page)) ++ bio_for_each_folio_all(fi, bio) { ++ if (!folio_test_dirty(fi.folio)) + goto defer; + } + +diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c +index 4a42ea2972ad85..4fb045d26bd5ad 100644 +--- a/block/blk-cgroup.c ++++ b/block/blk-cgroup.c +@@ -323,6 +323,7 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct gendisk *disk, + blkg->q = disk->queue; + INIT_LIST_HEAD(&blkg->q_node); + blkg->blkcg = blkcg; ++ blkg->iostat.blkg = blkg; + #ifdef CONFIG_BLK_CGROUP_PUNT_BIO + spin_lock_init(&blkg->async_bio_lock); + bio_list_init(&blkg->async_bios); +@@ -577,6 +578,7 @@ static void blkg_destroy_all(struct gendisk *disk) + struct request_queue *q = disk->queue; + struct blkcg_gq *blkg, *n; + int count = BLKG_DESTROY_BATCH_SIZE; ++ int i; + + restart: + spin_lock_irq(&q->queue_lock); +@@ -602,16 +604,61 @@ static void blkg_destroy_all(struct gendisk *disk) + } + } + ++ /* ++ * Mark policy deactivated since policy offline has been done, and ++ * the free is scheduled, so future blkcg_deactivate_policy() can ++ * be bypassed ++ */ ++ for (i = 0; i < BLKCG_MAX_POLS; i++) { ++ struct blkcg_policy *pol = blkcg_policy[i]; ++ ++ if (pol) ++ __clear_bit(pol->plid, q->blkcg_pols); ++ } ++ + q->root_blkg = NULL; + spin_unlock_irq(&q->queue_lock); + } + ++static void blkg_iostat_set(struct blkg_iostat *dst, struct blkg_iostat *src) ++{ ++ int i; ++ ++ for (i = 0; i < BLKG_IOSTAT_NR; i++) { ++ dst->bytes[i] = src->bytes[i]; ++ dst->ios[i] = src->ios[i]; ++ } ++} ++ ++static void __blkg_clear_stat(struct blkg_iostat_set *bis) ++{ ++ struct blkg_iostat cur = {0}; ++ unsigned long flags; ++ ++ flags = u64_stats_update_begin_irqsave(&bis->sync); ++ blkg_iostat_set(&bis->cur, &cur); ++ blkg_iostat_set(&bis->last, &cur); ++ u64_stats_update_end_irqrestore(&bis->sync, flags); ++} ++ ++static void blkg_clear_stat(struct blkcg_gq *blkg) ++{ ++ int cpu; ++ ++ for_each_possible_cpu(cpu) { ++ struct blkg_iostat_set *s = per_cpu_ptr(blkg->iostat_cpu, cpu); ++ ++ __blkg_clear_stat(s); ++ } ++ __blkg_clear_stat(&blkg->iostat); ++} ++ + static int blkcg_reset_stats(struct cgroup_subsys_state *css, + struct cftype *cftype, u64 val) + { + struct blkcg *blkcg = css_to_blkcg(css); + struct blkcg_gq *blkg; +- int i, cpu; ++ int i; + + mutex_lock(&blkcg_pol_mutex); + spin_lock_irq(&blkcg->lock); +@@ -622,18 +669,7 @@ static int blkcg_reset_stats(struct cgroup_subsys_state *css, + * anyway. If you get hit by a race, retry. + */ + hlist_for_each_entry(blkg, &blkcg->blkg_list, blkcg_node) { +- for_each_possible_cpu(cpu) { +- struct blkg_iostat_set *bis = +- per_cpu_ptr(blkg->iostat_cpu, cpu); +- memset(bis, 0, sizeof(*bis)); +- +- /* Re-initialize the cleared blkg_iostat_set */ +- u64_stats_init(&bis->sync); +- bis->blkg = blkg; +- } +- memset(&blkg->iostat, 0, sizeof(blkg->iostat)); +- u64_stats_init(&blkg->iostat.sync); +- ++ blkg_clear_stat(blkg); + for (i = 0; i < BLKCG_MAX_POLS; i++) { + struct blkcg_policy *pol = blkcg_policy[i]; + +@@ -936,16 +972,6 @@ void blkg_conf_exit(struct blkg_conf_ctx *ctx) + } + EXPORT_SYMBOL_GPL(blkg_conf_exit); + +-static void blkg_iostat_set(struct blkg_iostat *dst, struct blkg_iostat *src) +-{ +- int i; +- +- for (i = 0; i < BLKG_IOSTAT_NR; i++) { +- dst->bytes[i] = src->bytes[i]; +- dst->ios[i] = src->ios[i]; +- } +-} +- + static void blkg_iostat_add(struct blkg_iostat *dst, struct blkg_iostat *src) + { + int i; +@@ -1011,7 +1037,19 @@ static void __blkcg_rstat_flush(struct blkcg *blkcg, int cpu) + struct blkg_iostat cur; + unsigned int seq; + ++ /* ++ * Order assignment of `next_bisc` from `bisc->lnode.next` in ++ * llist_for_each_entry_safe and clearing `bisc->lqueued` for ++ * avoiding to assign `next_bisc` with new next pointer added ++ * in blk_cgroup_bio_start() in case of re-ordering. ++ * ++ * The pair barrier is implied in llist_add() in blk_cgroup_bio_start(). ++ */ ++ smp_mb(); ++ + WRITE_ONCE(bisc->lqueued, false); ++ if (bisc == &blkg->iostat) ++ goto propagate_up; /* propagate up to parent only */ + + /* fetch the current per-cpu values */ + do { +@@ -1021,10 +1059,24 @@ static void __blkcg_rstat_flush(struct blkcg *blkcg, int cpu) + + blkcg_iostat_update(blkg, &cur, &bisc->last); + ++propagate_up: + /* propagate global delta to parent (unless that's root) */ +- if (parent && parent->parent) ++ if (parent && parent->parent) { + blkcg_iostat_update(parent, &blkg->iostat.cur, + &blkg->iostat.last); ++ /* ++ * Queue parent->iostat to its blkcg's lockless ++ * list to propagate up to the grandparent if the ++ * iostat hasn't been queued yet. ++ */ ++ if (!parent->iostat.lqueued) { ++ struct llist_head *plhead; ++ ++ plhead = per_cpu_ptr(parent->blkcg->lhead, cpu); ++ llist_add(&parent->iostat.lnode, plhead); ++ parent->iostat.lqueued = true; ++ } ++ } + } + raw_spin_unlock_irqrestore(&blkg_stat_lock, flags); + out: +@@ -1396,6 +1448,12 @@ static int blkcg_css_online(struct cgroup_subsys_state *css) + return 0; + } + ++void blkg_init_queue(struct request_queue *q) ++{ ++ INIT_LIST_HEAD(&q->blkg_list); ++ mutex_init(&q->blkcg_mutex); ++} ++ + int blkcg_init_disk(struct gendisk *disk) + { + struct request_queue *q = disk->queue; +@@ -1403,9 +1461,6 @@ int blkcg_init_disk(struct gendisk *disk) + bool preloaded; + int ret; + +- INIT_LIST_HEAD(&q->blkg_list); +- mutex_init(&q->blkcg_mutex); +- + new_blkg = blkg_alloc(&blkcg_root, disk, GFP_KERNEL); + if (!new_blkg) + return -ENOMEM; +diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h +index 624c03c8fe64e3..5b0bdc268ade9f 100644 +--- a/block/blk-cgroup.h ++++ b/block/blk-cgroup.h +@@ -188,6 +188,7 @@ struct blkcg_policy { + extern struct blkcg blkcg_root; + extern bool blkcg_debug_stats; + ++void blkg_init_queue(struct request_queue *q); + int blkcg_init_disk(struct gendisk *disk); + void blkcg_exit_disk(struct gendisk *disk); + +@@ -249,12 +250,11 @@ static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg, + { + struct blkcg_gq *blkg; + +- WARN_ON_ONCE(!rcu_read_lock_held()); +- + if (blkcg == &blkcg_root) + return q->root_blkg; + +- blkg = rcu_dereference(blkcg->blkg_hint); ++ blkg = rcu_dereference_check(blkcg->blkg_hint, ++ lockdep_is_held(&q->queue_lock)); + if (blkg && blkg->q == q) + return blkg; + +@@ -482,6 +482,7 @@ struct blkcg { + }; + + static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg, void *key) { return NULL; } ++static inline void blkg_init_queue(struct request_queue *q) { } + static inline int blkcg_init_disk(struct gendisk *disk) { return 0; } + static inline void blkcg_exit_disk(struct gendisk *disk) { } + static inline int blkcg_policy_register(struct blkcg_policy *pol) { return 0; } +diff --git a/block/blk-core.c b/block/blk-core.c +index 9d51e9894ece78..4f25d2c4bc7055 100644 +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -49,6 +49,7 @@ + #include "blk-pm.h" + #include "blk-cgroup.h" + #include "blk-throttle.h" ++#include "blk-ioprio.h" + + struct dentry *blk_debugfs_root; + +@@ -430,6 +431,8 @@ struct request_queue *blk_alloc_queue(int node_id) + init_waitqueue_head(&q->mq_freeze_wq); + mutex_init(&q->mq_freeze_lock); + ++ blkg_init_queue(q); ++ + /* + * Init percpu_ref in atomic mode so that it's faster to shutdown. + * See blk_register_queue() for details. +@@ -501,9 +504,17 @@ static inline void bio_check_ro(struct bio *bio) + if (op_is_write(bio_op(bio)) && bdev_read_only(bio->bi_bdev)) { + if (op_is_flush(bio->bi_opf) && !bio_sectors(bio)) + return; ++ ++ if (bio->bi_bdev->bd_ro_warned) ++ return; ++ ++ bio->bi_bdev->bd_ro_warned = true; ++ /* ++ * Use ioctl to set underlying disk of raid/dm to read-only ++ * will trigger this. ++ */ + pr_warn("Trying to write to read-only block-device %pg\n", + bio->bi_bdev); +- /* Older lvm-tools actually trigger this */ + } + } + +@@ -809,6 +820,14 @@ void submit_bio_noacct(struct bio *bio) + } + EXPORT_SYMBOL(submit_bio_noacct); + ++static void bio_set_ioprio(struct bio *bio) ++{ ++ /* Nobody set ioprio so far? Initialize it based on task's nice value */ ++ if (IOPRIO_PRIO_CLASS(bio->bi_ioprio) == IOPRIO_CLASS_NONE) ++ bio->bi_ioprio = get_current_ioprio(); ++ blkcg_set_ioprio(bio); ++} ++ + /** + * submit_bio - submit a bio to the block device layer for I/O + * @bio: The &struct bio which describes the I/O +@@ -831,6 +850,7 @@ void submit_bio(struct bio *bio) + count_vm_events(PGPGOUT, bio_sectors(bio)); + } + ++ bio_set_ioprio(bio); + submit_bio_noacct(bio); + } + EXPORT_SYMBOL(submit_bio); +@@ -940,10 +960,11 @@ void update_io_ticks(struct block_device *part, unsigned long now, bool end) + unsigned long stamp; + again: + stamp = READ_ONCE(part->bd_stamp); +- if (unlikely(time_after(now, stamp))) { +- if (likely(try_cmpxchg(&part->bd_stamp, &stamp, now))) +- __part_stat_add(part, io_ticks, end ? now - stamp : 1); +- } ++ if (unlikely(time_after(now, stamp)) && ++ likely(try_cmpxchg(&part->bd_stamp, &stamp, now)) && ++ (end || part_in_flight(part))) ++ __part_stat_add(part, io_ticks, now - stamp); ++ + if (part->bd_partno) { + part = bdev_whole(part); + goto again; +diff --git a/block/blk-flush.c b/block/blk-flush.c +index e73dc22d05c1d1..313f0ffcce42e7 100644 +--- a/block/blk-flush.c ++++ b/block/blk-flush.c +@@ -183,7 +183,7 @@ static void blk_flush_complete_seq(struct request *rq, + /* queue for flush */ + if (list_empty(pending)) + fq->flush_pending_since = jiffies; +- list_move_tail(&rq->queuelist, pending); ++ list_add_tail(&rq->queuelist, pending); + break; + + case REQ_FSEQ_DATA: +@@ -261,6 +261,7 @@ static enum rq_end_io_ret flush_end_io(struct request *flush_rq, + unsigned int seq = blk_flush_cur_seq(rq); + + BUG_ON(seq != REQ_FSEQ_PREFLUSH && seq != REQ_FSEQ_POSTFLUSH); ++ list_del_init(&rq->queuelist); + blk_flush_complete_seq(rq, fq, seq, error); + } + +diff --git a/block/blk-integrity.c b/block/blk-integrity.c +index d4e9b4556d14b2..5276c556a9df91 100644 +--- a/block/blk-integrity.c ++++ b/block/blk-integrity.c +@@ -396,8 +396,6 @@ void blk_integrity_unregister(struct gendisk *disk) + if (!bi->profile) + return; + +- /* ensure all bios are off the integrity workqueue */ +- blk_flush_integrity(); + blk_queue_flag_clear(QUEUE_FLAG_STABLE_WRITES, disk->queue); + memset(bi, 0, sizeof(*bi)); + } +diff --git a/block/blk-iocost.c b/block/blk-iocost.c +index 089fcb9cfce370..c3cb9c20b306cf 100644 +--- a/block/blk-iocost.c ++++ b/block/blk-iocost.c +@@ -1347,16 +1347,24 @@ static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now) + { + struct ioc *ioc = iocg->ioc; + struct blkcg_gq *blkg = iocg_to_blkg(iocg); +- u64 tdelta, delay, new_delay; ++ u64 tdelta, delay, new_delay, shift; + s64 vover, vover_pct; + u32 hwa; + + lockdep_assert_held(&iocg->waitq.lock); + ++ /* ++ * If the delay is set by another CPU, we may be in the past. No need to ++ * change anything if so. This avoids decay calculation underflow. ++ */ ++ if (time_before64(now->now, iocg->delay_at)) ++ return false; ++ + /* calculate the current delay in effect - 1/2 every second */ + tdelta = now->now - iocg->delay_at; +- if (iocg->delay) +- delay = iocg->delay >> div64_u64(tdelta, USEC_PER_SEC); ++ shift = div64_u64(tdelta, USEC_PER_SEC); ++ if (iocg->delay && shift < BITS_PER_LONG) ++ delay = iocg->delay >> shift; + else + delay = 0; + +@@ -1431,8 +1439,11 @@ static void iocg_pay_debt(struct ioc_gq *iocg, u64 abs_vpay, + lockdep_assert_held(&iocg->ioc->lock); + lockdep_assert_held(&iocg->waitq.lock); + +- /* make sure that nobody messed with @iocg */ +- WARN_ON_ONCE(list_empty(&iocg->active_list)); ++ /* ++ * make sure that nobody messed with @iocg. Check iocg->pd.online ++ * to avoid warn when removing blkcg or disk. ++ */ ++ WARN_ON_ONCE(list_empty(&iocg->active_list) && iocg->pd.online); + WARN_ON_ONCE(iocg->inuse > 1); + + iocg->abs_vdebt -= min(abs_vpay, iocg->abs_vdebt); +@@ -2065,7 +2076,7 @@ static void ioc_forgive_debts(struct ioc *ioc, u64 usage_us_sum, int nr_debtors, + struct ioc_now *now) + { + struct ioc_gq *iocg; +- u64 dur, usage_pct, nr_cycles; ++ u64 dur, usage_pct, nr_cycles, nr_cycles_shift; + + /* if no debtor, reset the cycle */ + if (!nr_debtors) { +@@ -2127,10 +2138,12 @@ static void ioc_forgive_debts(struct ioc *ioc, u64 usage_us_sum, int nr_debtors, + old_debt = iocg->abs_vdebt; + old_delay = iocg->delay; + ++ nr_cycles_shift = min_t(u64, nr_cycles, BITS_PER_LONG - 1); + if (iocg->abs_vdebt) +- iocg->abs_vdebt = iocg->abs_vdebt >> nr_cycles ?: 1; ++ iocg->abs_vdebt = iocg->abs_vdebt >> nr_cycles_shift ?: 1; ++ + if (iocg->delay) +- iocg->delay = iocg->delay >> nr_cycles ?: 1; ++ iocg->delay = iocg->delay >> nr_cycles_shift ?: 1; + + iocg_kick_waitq(iocg, true, now); + +diff --git a/block/blk-map.c b/block/blk-map.c +index 8584babf3ea0ca..71210cdb34426d 100644 +--- a/block/blk-map.c ++++ b/block/blk-map.c +@@ -205,12 +205,19 @@ static int bio_copy_user_iov(struct request *rq, struct rq_map_data *map_data, + /* + * success + */ +- if ((iov_iter_rw(iter) == WRITE && +- (!map_data || !map_data->null_mapped)) || +- (map_data && map_data->from_user)) { ++ if (iov_iter_rw(iter) == WRITE && ++ (!map_data || !map_data->null_mapped)) { + ret = bio_copy_from_iter(bio, iter); + if (ret) + goto cleanup; ++ } else if (map_data && map_data->from_user) { ++ struct iov_iter iter2 = *iter; ++ ++ /* This is the copy-in part of SG_DXFER_TO_FROM_DEV. */ ++ iter2.data_source = ITER_SOURCE; ++ ret = bio_copy_from_iter(bio, &iter2); ++ if (ret) ++ goto cleanup; + } else { + if (bmd->is_our_pages) + zero_fill_bio(bio); +diff --git a/block/blk-merge.c b/block/blk-merge.c +index 65e75efa9bd366..07bf758c523a9c 100644 +--- a/block/blk-merge.c ++++ b/block/blk-merge.c +@@ -783,6 +783,8 @@ static void blk_account_io_merge_request(struct request *req) + if (blk_do_io_stat(req)) { + part_stat_lock(); + part_stat_inc(req->part, merges[op_stat_group(req_op(req))]); ++ part_stat_local_dec(req->part, ++ in_flight[op_is_write(req_op(req))]); + part_stat_unlock(); + } + } +diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c +index cc57e2dd9a0bb3..2cafcf11ee8bee 100644 +--- a/block/blk-mq-tag.c ++++ b/block/blk-mq-tag.c +@@ -38,6 +38,7 @@ static void blk_mq_update_wake_batch(struct blk_mq_tags *tags, + void __blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx) + { + unsigned int users; ++ unsigned long flags; + struct blk_mq_tags *tags = hctx->tags; + + /* +@@ -56,11 +57,11 @@ void __blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx) + return; + } + +- spin_lock_irq(&tags->lock); ++ spin_lock_irqsave(&tags->lock, flags); + users = tags->active_queues + 1; + WRITE_ONCE(tags->active_queues, users); + blk_mq_update_wake_batch(tags, users); +- spin_unlock_irq(&tags->lock); ++ spin_unlock_irqrestore(&tags->lock, flags); + } + + /* +diff --git a/block/blk-mq.c b/block/blk-mq.c +index 1fafd54dce3cb9..733d72f4d1cc9d 100644 +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -40,7 +40,6 @@ + #include "blk-stat.h" + #include "blk-mq-sched.h" + #include "blk-rq-qos.h" +-#include "blk-ioprio.h" + + static DEFINE_PER_CPU(struct llist_head, blk_cpu_done); + static DEFINE_PER_CPU(call_single_data_t, blk_cpu_csd); +@@ -447,6 +446,10 @@ static struct request *__blk_mq_alloc_requests(struct blk_mq_alloc_data *data) + if (data->cmd_flags & REQ_NOWAIT) + data->flags |= BLK_MQ_REQ_NOWAIT; + ++retry: ++ data->ctx = blk_mq_get_ctx(q); ++ data->hctx = blk_mq_map_queue(q, data->cmd_flags, data->ctx); ++ + if (q->elevator) { + /* + * All requests use scheduler tags when an I/O scheduler is +@@ -468,13 +471,9 @@ static struct request *__blk_mq_alloc_requests(struct blk_mq_alloc_data *data) + if (ops->limit_depth) + ops->limit_depth(data->cmd_flags, data); + } +- } +- +-retry: +- data->ctx = blk_mq_get_ctx(q); +- data->hctx = blk_mq_map_queue(q, data->cmd_flags, data->ctx); +- if (!(data->rq_flags & RQF_SCHED_TAGS)) ++ } else { + blk_mq_tag_busy(data->hctx); ++ } + + if (data->flags & BLK_MQ_REQ_RESERVED) + data->rq_flags |= RQF_RESV; +@@ -994,6 +993,8 @@ static inline void blk_account_io_done(struct request *req, u64 now) + update_io_ticks(req->part, jiffies, true); + part_stat_inc(req->part, ios[sgrp]); + part_stat_add(req->part, nsecs[sgrp], now - req->start_time_ns); ++ part_stat_local_dec(req->part, ++ in_flight[op_is_write(req_op(req))]); + part_stat_unlock(); + } + } +@@ -1016,6 +1017,8 @@ static inline void blk_account_io_start(struct request *req) + + part_stat_lock(); + update_io_ticks(req->part, jiffies, false); ++ part_stat_local_inc(req->part, ++ in_flight[op_is_write(req_op(req))]); + part_stat_unlock(); + } + } +@@ -1511,14 +1514,26 @@ void blk_mq_delay_kick_requeue_list(struct request_queue *q, + } + EXPORT_SYMBOL(blk_mq_delay_kick_requeue_list); + ++static bool blk_is_flush_data_rq(struct request *rq) ++{ ++ return (rq->rq_flags & RQF_FLUSH_SEQ) && !is_flush_rq(rq); ++} ++ + static bool blk_mq_rq_inflight(struct request *rq, void *priv) + { + /* + * If we find a request that isn't idle we know the queue is busy + * as it's checked in the iter. + * Return false to stop the iteration. ++ * ++ * In case of queue quiesce, if one flush data request is completed, ++ * don't count it as inflight given the flush sequence is suspended, ++ * and the original flush data request is invisible to driver, just ++ * like other pending requests because of quiesce + */ +- if (blk_mq_request_started(rq)) { ++ if (blk_mq_request_started(rq) && !(blk_queue_quiesced(rq->q) && ++ blk_is_flush_data_rq(rq) && ++ blk_mq_request_completed(rq))) { + bool *busy = priv; + + *busy = true; +@@ -1858,6 +1873,22 @@ static bool blk_mq_mark_tag_wait(struct blk_mq_hw_ctx *hctx, + wait->flags &= ~WQ_FLAG_EXCLUSIVE; + __add_wait_queue(wq, wait); + ++ /* ++ * Add one explicit barrier since blk_mq_get_driver_tag() may ++ * not imply barrier in case of failure. ++ * ++ * Order adding us to wait queue and allocating driver tag. ++ * ++ * The pair is the one implied in sbitmap_queue_wake_up() which ++ * orders clearing sbitmap tag bits and waitqueue_active() in ++ * __sbitmap_queue_wake_up(), since waitqueue_active() is lockless ++ * ++ * Otherwise, re-order of adding wait queue and getting driver tag ++ * may cause __sbitmap_queue_wake_up() to wake up nothing because ++ * the waitqueue_active() may not observe us in wait queue. ++ */ ++ smp_mb(); ++ + /* + * It's possible that a tag was freed in the window between the + * allocation failure and adding the hardware queue to the wait +@@ -2875,11 +2906,8 @@ static struct request *blk_mq_get_new_requests(struct request_queue *q, + }; + struct request *rq; + +- if (unlikely(bio_queue_enter(bio))) +- return NULL; +- + if (blk_mq_attempt_bio_merge(q, bio, nsegs)) +- goto queue_exit; ++ return NULL; + + rq_qos_throttle(q, bio); + +@@ -2895,35 +2923,23 @@ static struct request *blk_mq_get_new_requests(struct request_queue *q, + rq_qos_cleanup(q, bio); + if (bio->bi_opf & REQ_NOWAIT) + bio_wouldblock_error(bio); +-queue_exit: +- blk_queue_exit(q); + return NULL; + } + +-static inline struct request *blk_mq_get_cached_request(struct request_queue *q, +- struct blk_plug *plug, struct bio **bio, unsigned int nsegs) ++/* return true if this @rq can be used for @bio */ ++static bool blk_mq_can_use_cached_rq(struct request *rq, struct blk_plug *plug, ++ struct bio *bio) + { +- struct request *rq; +- enum hctx_type type, hctx_type; +- +- if (!plug) +- return NULL; +- rq = rq_list_peek(&plug->cached_rq); +- if (!rq || rq->q != q) +- return NULL; ++ enum hctx_type type = blk_mq_get_hctx_type(bio->bi_opf); ++ enum hctx_type hctx_type = rq->mq_hctx->type; + +- if (blk_mq_attempt_bio_merge(q, *bio, nsegs)) { +- *bio = NULL; +- return NULL; +- } ++ WARN_ON_ONCE(rq_list_peek(&plug->cached_rq) != rq); + +- type = blk_mq_get_hctx_type((*bio)->bi_opf); +- hctx_type = rq->mq_hctx->type; + if (type != hctx_type && + !(type == HCTX_TYPE_READ && hctx_type == HCTX_TYPE_DEFAULT)) +- return NULL; +- if (op_is_flush(rq->cmd_flags) != op_is_flush((*bio)->bi_opf)) +- return NULL; ++ return false; ++ if (op_is_flush(rq->cmd_flags) != op_is_flush(bio->bi_opf)) ++ return false; + + /* + * If any qos ->throttle() end up blocking, we will have flushed the +@@ -2931,20 +2947,12 @@ static inline struct request *blk_mq_get_cached_request(struct request_queue *q, + * before we throttle. + */ + plug->cached_rq = rq_list_next(rq); +- rq_qos_throttle(q, *bio); ++ rq_qos_throttle(rq->q, bio); + + blk_mq_rq_time_init(rq, 0); +- rq->cmd_flags = (*bio)->bi_opf; ++ rq->cmd_flags = bio->bi_opf; + INIT_LIST_HEAD(&rq->queuelist); +- return rq; +-} +- +-static void bio_set_ioprio(struct bio *bio) +-{ +- /* Nobody set ioprio so far? Initialize it based on task's nice value */ +- if (IOPRIO_PRIO_CLASS(bio->bi_ioprio) == IOPRIO_CLASS_NONE) +- bio->bi_ioprio = get_current_ioprio(); +- blkcg_set_ioprio(bio); ++ return true; + } + + /** +@@ -2966,31 +2974,50 @@ void blk_mq_submit_bio(struct bio *bio) + struct blk_plug *plug = blk_mq_plug(bio); + const int is_sync = op_is_sync(bio->bi_opf); + struct blk_mq_hw_ctx *hctx; +- struct request *rq; ++ struct request *rq = NULL; + unsigned int nr_segs = 1; + blk_status_t ret; + + bio = blk_queue_bounce(bio, q); +- if (bio_may_exceed_limits(bio, &q->limits)) { +- bio = __bio_split_to_limits(bio, &q->limits, &nr_segs); +- if (!bio) ++ ++ if (plug) { ++ rq = rq_list_peek(&plug->cached_rq); ++ if (rq && rq->q != q) ++ rq = NULL; ++ } ++ if (rq) { ++ if (unlikely(bio_may_exceed_limits(bio, &q->limits))) { ++ bio = __bio_split_to_limits(bio, &q->limits, &nr_segs); ++ if (!bio) ++ return; ++ } ++ if (!bio_integrity_prep(bio)) ++ return; ++ if (blk_mq_attempt_bio_merge(q, bio, nr_segs)) ++ return; ++ if (blk_mq_can_use_cached_rq(rq, plug, bio)) ++ goto done; ++ percpu_ref_get(&q->q_usage_counter); ++ } else { ++ if (unlikely(bio_queue_enter(bio))) + return; ++ if (unlikely(bio_may_exceed_limits(bio, &q->limits))) { ++ bio = __bio_split_to_limits(bio, &q->limits, &nr_segs); ++ if (!bio) ++ goto fail; ++ } ++ if (!bio_integrity_prep(bio)) ++ goto fail; + } + +- if (!bio_integrity_prep(bio)) ++ rq = blk_mq_get_new_requests(q, plug, bio, nr_segs); ++ if (unlikely(!rq)) { ++fail: ++ blk_queue_exit(q); + return; +- +- bio_set_ioprio(bio); +- +- rq = blk_mq_get_cached_request(q, plug, &bio, nr_segs); +- if (!rq) { +- if (!bio) +- return; +- rq = blk_mq_get_new_requests(q, plug, bio, nr_segs); +- if (unlikely(!rq)) +- return; + } + ++done: + trace_block_getrq(bio); + + rq_qos_track(q, rq, bio); +diff --git a/block/blk-rq-qos.c b/block/blk-rq-qos.c +index dd7310c94713c9..dc510f493ba572 100644 +--- a/block/blk-rq-qos.c ++++ b/block/blk-rq-qos.c +@@ -219,8 +219,8 @@ static int rq_qos_wake_function(struct wait_queue_entry *curr, + + data->got_token = true; + smp_wmb(); +- list_del_init(&curr->entry); + wake_up_process(data->task); ++ list_del_init_careful(&curr->entry); + return 1; + } + +diff --git a/block/blk-settings.c b/block/blk-settings.c +index 0046b447268f91..7019b8e204d965 100644 +--- a/block/blk-settings.c ++++ b/block/blk-settings.c +@@ -686,6 +686,10 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, + t->zone_write_granularity = max(t->zone_write_granularity, + b->zone_write_granularity); + t->zoned = max(t->zoned, b->zoned); ++ if (!t->zoned) { ++ t->zone_write_granularity = 0; ++ t->max_zone_append_sectors = 0; ++ } + return ret; + } + EXPORT_SYMBOL(blk_stack_limits); +diff --git a/block/blk-stat.c b/block/blk-stat.c +index 7ff76ae6c76a95..e42c263e53fb99 100644 +--- a/block/blk-stat.c ++++ b/block/blk-stat.c +@@ -27,7 +27,7 @@ void blk_rq_stat_init(struct blk_rq_stat *stat) + /* src is a per-cpu stat, mean isn't initialized */ + void blk_rq_stat_sum(struct blk_rq_stat *dst, struct blk_rq_stat *src) + { +- if (!src->nr_samples) ++ if (dst->nr_samples + src->nr_samples <= dst->nr_samples) + return; + + dst->min = min(dst->min, src->min); +diff --git a/block/blk-throttle.c b/block/blk-throttle.c +index 13e4377a8b2865..16f5766620a410 100644 +--- a/block/blk-throttle.c ++++ b/block/blk-throttle.c +@@ -1320,6 +1320,7 @@ static void tg_conf_updated(struct throtl_grp *tg, bool global) + tg_bps_limit(tg, READ), tg_bps_limit(tg, WRITE), + tg_iops_limit(tg, READ), tg_iops_limit(tg, WRITE)); + ++ rcu_read_lock(); + /* + * Update has_rules[] flags for the updated tg's subtree. A tg is + * considered to have rules if either the tg itself or any of its +@@ -1347,6 +1348,7 @@ static void tg_conf_updated(struct throtl_grp *tg, bool global) + this_tg->latency_target = max(this_tg->latency_target, + parent_tg->latency_target); + } ++ rcu_read_unlock(); + + /* + * We're already holding queue_lock and know @tg is valid. Let's +diff --git a/block/blk-wbt.c b/block/blk-wbt.c +index 0bb613139becbb..f8fda9cf583e1c 100644 +--- a/block/blk-wbt.c ++++ b/block/blk-wbt.c +@@ -165,9 +165,9 @@ static void wb_timestamp(struct rq_wb *rwb, unsigned long *var) + */ + static bool wb_recent_wait(struct rq_wb *rwb) + { +- struct bdi_writeback *wb = &rwb->rqos.disk->bdi->wb; ++ struct backing_dev_info *bdi = rwb->rqos.disk->bdi; + +- return time_before(jiffies, wb->dirty_sleep + HZ); ++ return time_before(jiffies, bdi->last_bdp_sleep + HZ); + } + + static inline struct rq_wait *get_rq_wait(struct rq_wb *rwb, +diff --git a/block/blk.h b/block/blk.h +index 08a358bc0919e2..67915b04b3c179 100644 +--- a/block/blk.h ++++ b/block/blk.h +@@ -344,6 +344,7 @@ static inline bool blk_do_io_stat(struct request *rq) + } + + void update_io_ticks(struct block_device *part, unsigned long now, bool end); ++unsigned int part_in_flight(struct block_device *part); + + static inline void req_set_nomerge(struct request_queue *q, struct request *req) + { +diff --git a/block/fops.c b/block/fops.c +index 73e42742543f6a..1df187b3067920 100644 +--- a/block/fops.c ++++ b/block/fops.c +@@ -387,7 +387,7 @@ static int blkdev_iomap_begin(struct inode *inode, loff_t offset, loff_t length, + + iomap->bdev = bdev; + iomap->offset = ALIGN_DOWN(offset, bdev_logical_block_size(bdev)); +- if (iomap->offset >= isize) ++ if (offset >= isize) + return -EIO; + iomap->type = IOMAP_MAPPED; + iomap->addr = iomap->offset; +diff --git a/block/genhd.c b/block/genhd.c +index cc32a0c704eb84..203c880c3e1cd2 100644 +--- a/block/genhd.c ++++ b/block/genhd.c +@@ -118,7 +118,7 @@ static void part_stat_read_all(struct block_device *part, + } + } + +-static unsigned int part_in_flight(struct block_device *part) ++unsigned int part_in_flight(struct block_device *part) + { + unsigned int inflight = 0; + int cpu; +@@ -345,9 +345,7 @@ int disk_scan_partitions(struct gendisk *disk, blk_mode_t mode) + struct block_device *bdev; + int ret = 0; + +- if (disk->flags & (GENHD_FL_NO_PART | GENHD_FL_HIDDEN)) +- return -EINVAL; +- if (test_bit(GD_SUPPRESS_PART_SCAN, &disk->state)) ++ if (!disk_has_partscan(disk)) + return -EINVAL; + if (disk->open_partitions) + return -EBUSY; +@@ -432,7 +430,9 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk, + DISK_MAX_PARTS); + disk->minors = DISK_MAX_PARTS; + } +- if (disk->first_minor + disk->minors > MINORMASK + 1) ++ if (disk->first_minor > MINORMASK || ++ disk->minors > MINORMASK + 1 || ++ disk->first_minor + disk->minors > MINORMASK + 1) + goto out_exit_elevator; + } else { + if (WARN_ON(disk->minors)) +@@ -501,8 +501,7 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk, + goto out_unregister_bdi; + + /* Make sure the first partition scan will be proceed */ +- if (get_capacity(disk) && !(disk->flags & GENHD_FL_NO_PART) && +- !test_bit(GD_SUPPRESS_PART_SCAN, &disk->state)) ++ if (get_capacity(disk) && disk_has_partscan(disk)) + set_bit(GD_NEED_PART_SCAN, &disk->state); + + bdev_add(disk->part0, ddev->devt); +@@ -542,6 +541,7 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk, + kobject_put(disk->part0->bd_holder_dir); + out_del_block_link: + sysfs_remove_link(block_depr, dev_name(ddev)); ++ pm_runtime_set_memalloc_noio(ddev, false); + out_device_del: + device_del(ddev); + out_free_ext_minor: +@@ -655,12 +655,12 @@ void del_gendisk(struct gendisk *disk) + */ + if (!test_bit(GD_DEAD, &disk->state)) + blk_report_disk_dead(disk, false); +- __blk_mark_disk_dead(disk); + + /* + * Drop all partitions now that the disk is marked dead. + */ + mutex_lock(&disk->open_mutex); ++ __blk_mark_disk_dead(disk); + xa_for_each_start(&disk->part_tbl, idx, part, 1) + drop_partition(part); + mutex_unlock(&disk->open_mutex); +@@ -1037,6 +1037,12 @@ static ssize_t diskseq_show(struct device *dev, + return sprintf(buf, "%llu\n", disk->diskseq); + } + ++static ssize_t partscan_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ return sprintf(buf, "%u\n", disk_has_partscan(dev_to_disk(dev))); ++} ++ + static DEVICE_ATTR(range, 0444, disk_range_show, NULL); + static DEVICE_ATTR(ext_range, 0444, disk_ext_range_show, NULL); + static DEVICE_ATTR(removable, 0444, disk_removable_show, NULL); +@@ -1050,6 +1056,7 @@ static DEVICE_ATTR(stat, 0444, part_stat_show, NULL); + static DEVICE_ATTR(inflight, 0444, part_inflight_show, NULL); + static DEVICE_ATTR(badblocks, 0644, disk_badblocks_show, disk_badblocks_store); + static DEVICE_ATTR(diskseq, 0444, diskseq_show, NULL); ++static DEVICE_ATTR(partscan, 0444, partscan_show, NULL); + + #ifdef CONFIG_FAIL_MAKE_REQUEST + ssize_t part_fail_show(struct device *dev, +@@ -1096,6 +1103,7 @@ static struct attribute *disk_attrs[] = { + &dev_attr_events_async.attr, + &dev_attr_events_poll_msecs.attr, + &dev_attr_diskseq.attr, ++ &dev_attr_partscan.attr, + #ifdef CONFIG_FAIL_MAKE_REQUEST + &dev_attr_fail.attr, + #endif +diff --git a/block/ioctl.c b/block/ioctl.c +index d5f5cd61efd7fc..3786033342848d 100644 +--- a/block/ioctl.c ++++ b/block/ioctl.c +@@ -18,10 +18,8 @@ static int blkpg_do_ioctl(struct block_device *bdev, + { + struct gendisk *disk = bdev->bd_disk; + struct blkpg_partition p; +- long long start, length; ++ sector_t 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))) +@@ -35,14 +33,17 @@ static int blkpg_do_ioctl(struct block_device *bdev, + if (op == BLKPG_DEL_PARTITION) + return bdev_del_partition(disk, p.pno); + ++ if (p.start < 0 || p.length <= 0 || LLONG_MAX - p.length < p.start) ++ return -EINVAL; ++ /* Check that the partition is aligned to the block size */ ++ if (!IS_ALIGNED(p.start | p.length, bdev_logical_block_size(bdev))) ++ return -EINVAL; ++ + start = p.start >> SECTOR_SHIFT; + length = p.length >> SECTOR_SHIFT; + + switch (op) { + case BLKPG_ADD_PARTITION: +- /* check if partition is aligned to blocksize */ +- if (p.start & (bdev_logical_block_size(bdev) - 1)) +- return -EINVAL; + return bdev_add_partition(disk, p.pno, start, length); + case BLKPG_RESIZE_PARTITION: + return bdev_resize_partition(disk, p.pno, start, length); +@@ -88,7 +89,7 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode, + unsigned long arg) + { + uint64_t range[2]; +- uint64_t start, len; ++ uint64_t start, len, end; + struct inode *inode = bdev->bd_inode; + int err; + +@@ -109,7 +110,8 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode, + if (len & 511) + return -EINVAL; + +- if (start + len > bdev_nr_bytes(bdev)) ++ if (check_add_overflow(start, len, &end) || ++ end > bdev_nr_bytes(bdev)) + return -EINVAL; + + filemap_invalidate_lock(inode->i_mapping); +diff --git a/block/mq-deadline.c b/block/mq-deadline.c +index f958e79277b8bc..78a8aa204c1565 100644 +--- a/block/mq-deadline.c ++++ b/block/mq-deadline.c +@@ -621,6 +621,20 @@ static struct request *dd_dispatch_request(struct blk_mq_hw_ctx *hctx) + return rq; + } + ++/* ++ * 'depth' is a number in the range 1..INT_MAX representing a number of ++ * requests. Scale it with a factor (1 << bt->sb.shift) / q->nr_requests since ++ * 1..(1 << bt->sb.shift) is the range expected by sbitmap_get_shallow(). ++ * Values larger than q->nr_requests have the same effect as q->nr_requests. ++ */ ++static int dd_to_word_depth(struct blk_mq_hw_ctx *hctx, unsigned int qdepth) ++{ ++ struct sbitmap_queue *bt = &hctx->sched_tags->bitmap_tags; ++ const unsigned int nrr = hctx->queue->nr_requests; ++ ++ return ((qdepth << bt->sb.shift) + nrr - 1) / nrr; ++} ++ + /* + * Called by __blk_mq_alloc_request(). The shallow_depth value set by this + * function is used by __blk_mq_get_tag(). +@@ -637,7 +651,7 @@ static void dd_limit_depth(blk_opf_t opf, struct blk_mq_alloc_data *data) + * Throttle asynchronous requests and writes such that these requests + * do not block the allocation of synchronous requests. + */ +- data->shallow_depth = dd->async_depth; ++ data->shallow_depth = dd_to_word_depth(data->hctx, dd->async_depth); + } + + /* Called by blk_mq_update_nr_requests(). */ +@@ -646,11 +660,10 @@ 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(1U, 3 * (1U << shift) / 4); ++ dd->async_depth = q->nr_requests; + +- sbitmap_queue_min_shallow_depth(&tags->bitmap_tags, dd->async_depth); ++ sbitmap_queue_min_shallow_depth(&tags->bitmap_tags, 1); + } + + /* Called by blk_mq_init_hctx() and blk_mq_init_sched(). */ +diff --git a/block/opal_proto.h b/block/opal_proto.h +index dec7ce3a3edb70..d247a457bf6e3f 100644 +--- a/block/opal_proto.h ++++ b/block/opal_proto.h +@@ -71,6 +71,7 @@ enum opal_response_token { + #define SHORT_ATOM_BYTE 0xBF + #define MEDIUM_ATOM_BYTE 0xDF + #define LONG_ATOM_BYTE 0xE3 ++#define EMPTY_ATOM_BYTE 0xFF + + #define OPAL_INVAL_PARAM 12 + #define OPAL_MANUFACTURED_INACTIVE 0x08 +diff --git a/block/partitions/cmdline.c b/block/partitions/cmdline.c +index c03bc105e57539..152c85df92b20e 100644 +--- a/block/partitions/cmdline.c ++++ b/block/partitions/cmdline.c +@@ -70,8 +70,8 @@ static int parse_subpart(struct cmdline_subpart **subpart, char *partdef) + } + + if (*partdef == '(') { +- int length; +- char *next = strchr(++partdef, ')'); ++ partdef++; ++ char *next = strsep(&partdef, ")"); + + if (!next) { + pr_warn("cmdline partition format is invalid."); +@@ -79,11 +79,7 @@ static int parse_subpart(struct cmdline_subpart **subpart, char *partdef) + goto fail; + } + +- length = min_t(int, next - partdef, +- sizeof(new_subpart->name) - 1); +- strscpy(new_subpart->name, partdef, length); +- +- partdef = ++next; ++ strscpy(new_subpart->name, next, sizeof(new_subpart->name)); + } else + new_subpart->name[0] = '\0'; + +@@ -117,14 +113,12 @@ static void free_subpart(struct cmdline_parts *parts) + } + } + +-static int parse_parts(struct cmdline_parts **parts, const char *bdevdef) ++static int parse_parts(struct cmdline_parts **parts, char *bdevdef) + { + int ret = -EINVAL; + char *next; +- int length; + struct cmdline_subpart **next_subpart; + struct cmdline_parts *newparts; +- char buf[BDEVNAME_SIZE + 32 + 4]; + + *parts = NULL; + +@@ -132,28 +126,19 @@ static int parse_parts(struct cmdline_parts **parts, const char *bdevdef) + if (!newparts) + return -ENOMEM; + +- next = strchr(bdevdef, ':'); ++ next = strsep(&bdevdef, ":"); + if (!next) { + pr_warn("cmdline partition has no block device."); + goto fail; + } + +- length = min_t(int, next - bdevdef, sizeof(newparts->name) - 1); +- strscpy(newparts->name, bdevdef, length); ++ strscpy(newparts->name, next, sizeof(newparts->name)); + newparts->nr_subparts = 0; + + next_subpart = &newparts->subpart; + +- while (next && *(++next)) { +- bdevdef = next; +- next = strchr(bdevdef, ','); +- +- length = (!next) ? (sizeof(buf) - 1) : +- min_t(int, next - bdevdef, sizeof(buf) - 1); +- +- strscpy(buf, bdevdef, length); +- +- ret = parse_subpart(next_subpart, buf); ++ while ((next = strsep(&bdevdef, ","))) { ++ ret = parse_subpart(next_subpart, next); + if (ret) + goto fail; + +@@ -199,24 +184,17 @@ static int cmdline_parts_parse(struct cmdline_parts **parts, + + *parts = NULL; + +- next = pbuf = buf = kstrdup(cmdline, GFP_KERNEL); ++ pbuf = buf = kstrdup(cmdline, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + next_parts = parts; + +- while (next && *pbuf) { +- next = strchr(pbuf, ';'); +- if (next) +- *next = '\0'; +- +- ret = parse_parts(next_parts, pbuf); ++ while ((next = strsep(&pbuf, ";"))) { ++ ret = parse_parts(next_parts, next); + if (ret) + goto fail; + +- if (next) +- pbuf = ++next; +- + next_parts = &(*next_parts)->next_parts; + } + +@@ -250,7 +228,6 @@ static struct cmdline_parts *bdev_parts; + static int add_part(int slot, struct cmdline_subpart *subpart, + struct parsed_partitions *state) + { +- int label_min; + struct partition_meta_info *info; + char tmp[sizeof(info->volname) + 4]; + +@@ -262,9 +239,7 @@ static int add_part(int slot, struct cmdline_subpart *subpart, + + info = &state->parts[slot].info; + +- label_min = min_t(int, sizeof(info->volname) - 1, +- sizeof(subpart->name)); +- strscpy(info->volname, subpart->name, label_min); ++ strscpy(info->volname, subpart->name, sizeof(info->volname)); + + snprintf(tmp, sizeof(tmp), "(%s)", info->volname); + strlcat(state->pp_buf, tmp, PAGE_SIZE); +diff --git a/block/partitions/core.c b/block/partitions/core.c +index e137a87f4db0d3..fc0ab5d8ab705b 100644 +--- a/block/partitions/core.c ++++ b/block/partitions/core.c +@@ -458,6 +458,11 @@ int bdev_add_partition(struct gendisk *disk, int partno, sector_t start, + goto out; + } + ++ if (disk->flags & GENHD_FL_NO_PART) { ++ ret = -EINVAL; ++ goto out; ++ } ++ + if (partition_overlaps(disk, start, length, -1)) { + ret = -EBUSY; + goto out; +@@ -569,9 +574,11 @@ static bool blk_add_partition(struct gendisk *disk, + + part = add_partition(disk, p, from, size, state->parts[p].flags, + &state->parts[p].info); +- if (IS_ERR(part) && PTR_ERR(part) != -ENXIO) { +- printk(KERN_ERR " %s: p%d could not be added: %ld\n", +- disk->disk_name, p, -PTR_ERR(part)); ++ if (IS_ERR(part)) { ++ if (PTR_ERR(part) != -ENXIO) { ++ printk(KERN_ERR " %s: p%d could not be added: %pe\n", ++ disk->disk_name, p, part); ++ } + return true; + } + +@@ -587,10 +594,7 @@ static int blk_add_partitions(struct gendisk *disk) + struct parsed_partitions *state; + int ret = -EAGAIN, p; + +- if (disk->flags & GENHD_FL_NO_PART) +- return 0; +- +- if (test_bit(GD_SUPPRESS_PART_SCAN, &disk->state)) ++ if (!disk_has_partscan(disk)) + return 0; + + state = check_partition(disk); +diff --git a/block/sed-opal.c b/block/sed-opal.c +index 04f38a3f5d9597..1a1cb35bf4b798 100644 +--- a/block/sed-opal.c ++++ b/block/sed-opal.c +@@ -313,7 +313,7 @@ static int read_sed_opal_key(const char *key_name, u_char *buffer, int buflen) + &key_type_user, key_name, true); + + if (IS_ERR(kref)) +- ret = PTR_ERR(kref); ++ return PTR_ERR(kref); + + key = key_ref_to_ptr(kref); + down_read(&key->sem); +@@ -1055,16 +1055,20 @@ static int response_parse(const u8 *buf, size_t length, + token_length = response_parse_medium(iter, pos); + else if (pos[0] <= LONG_ATOM_BYTE) /* long atom */ + token_length = response_parse_long(iter, pos); ++ else if (pos[0] == EMPTY_ATOM_BYTE) /* empty atom */ ++ token_length = 1; + else /* TOKEN */ + token_length = response_parse_token(iter, pos); + + if (token_length < 0) + return token_length; + ++ if (pos[0] != EMPTY_ATOM_BYTE) ++ num_entries++; ++ + pos += token_length; + total -= token_length; + iter++; +- num_entries++; + } + + resp->num = num_entries; +diff --git a/crypto/Kconfig b/crypto/Kconfig +index 650b1b3620d818..fc0f75d8be01d2 100644 +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -1291,10 +1291,11 @@ config CRYPTO_JITTERENTROPY + + A non-physical non-deterministic ("true") RNG (e.g., an entropy source + compliant with NIST SP800-90B) intended to provide a seed to a +- deterministic RNG (e.g. per NIST SP800-90C). ++ deterministic RNG (e.g., per NIST SP800-90C). + This RNG does not perform any cryptographic whitening of the generated ++ random numbers. + +- See https://www.chronox.de/jent.html ++ See https://www.chronox.de/jent/ + + config CRYPTO_JITTERENTROPY_TESTINTERFACE + bool "CPU Jitter RNG Test Interface" +diff --git a/crypto/aead.c b/crypto/aead.c +index d5ba204ebdbfa6..ecab683016b7df 100644 +--- a/crypto/aead.c ++++ b/crypto/aead.c +@@ -45,8 +45,7 @@ static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, + alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); + memcpy(alignbuffer, key, keylen); + ret = crypto_aead_alg(tfm)->setkey(tfm, alignbuffer, keylen); +- memset(alignbuffer, 0, keylen); +- kfree(buffer); ++ kfree_sensitive(buffer); + return ret; + } + +diff --git a/crypto/af_alg.c b/crypto/af_alg.c +index ea6fb8e89d0653..68cc9290cabe9a 100644 +--- a/crypto/af_alg.c ++++ b/crypto/af_alg.c +@@ -1116,9 +1116,13 @@ EXPORT_SYMBOL_GPL(af_alg_sendmsg); + void af_alg_free_resources(struct af_alg_async_req *areq) + { + struct sock *sk = areq->sk; ++ struct af_alg_ctx *ctx; + + af_alg_free_areq_sgls(areq); + sock_kfree_s(sk, areq, areq->areqlen); ++ ++ ctx = alg_sk(sk)->private; ++ ctx->inflight = false; + } + EXPORT_SYMBOL_GPL(af_alg_free_resources); + +@@ -1188,11 +1192,19 @@ EXPORT_SYMBOL_GPL(af_alg_poll); + struct af_alg_async_req *af_alg_alloc_areq(struct sock *sk, + unsigned int areqlen) + { +- struct af_alg_async_req *areq = sock_kmalloc(sk, areqlen, GFP_KERNEL); ++ struct af_alg_ctx *ctx = alg_sk(sk)->private; ++ struct af_alg_async_req *areq; ++ ++ /* Only one AIO request can be in flight. */ ++ if (ctx->inflight) ++ return ERR_PTR(-EBUSY); + ++ areq = sock_kmalloc(sk, areqlen, GFP_KERNEL); + if (unlikely(!areq)) + return ERR_PTR(-ENOMEM); + ++ ctx->inflight = true; ++ + areq->areqlen = areqlen; + areq->sk = sk; + areq->first_rsgl.sgl.sgt.sgl = areq->first_rsgl.sgl.sgl; +diff --git a/crypto/algapi.c b/crypto/algapi.c +index 4fe95c44804733..85bc279b4233fa 100644 +--- a/crypto/algapi.c ++++ b/crypto/algapi.c +@@ -341,6 +341,7 @@ __crypto_register_alg(struct crypto_alg *alg, struct list_head *algs_to_put) + } + + if (!strcmp(q->cra_driver_name, alg->cra_name) || ++ !strcmp(q->cra_driver_name, alg->cra_driver_name) || + !strcmp(q->cra_name, alg->cra_driver_name)) + goto err; + } +diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c +index 82c44d4899b967..e24c829d7a0154 100644 +--- a/crypto/algif_hash.c ++++ b/crypto/algif_hash.c +@@ -91,13 +91,13 @@ static int hash_sendmsg(struct socket *sock, struct msghdr *msg, + if (!(msg->msg_flags & MSG_MORE)) { + err = hash_alloc_result(sk, ctx); + if (err) +- goto unlock_free; ++ goto unlock_free_result; + ahash_request_set_crypt(&ctx->req, NULL, + ctx->result, 0); + err = crypto_wait_req(crypto_ahash_final(&ctx->req), + &ctx->wait); + if (err) +- goto unlock_free; ++ goto unlock_free_result; + } + goto done_more; + } +@@ -170,6 +170,7 @@ static int hash_sendmsg(struct socket *sock, struct msghdr *msg, + + unlock_free: + af_alg_free_sg(&ctx->sgl); ++unlock_free_result: + hash_free_result(sk, ctx); + ctx->more = false; + goto unlock; +diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig +index 1ef3b46d6f6e5c..684767ab23e24d 100644 +--- a/crypto/asymmetric_keys/Kconfig ++++ b/crypto/asymmetric_keys/Kconfig +@@ -15,6 +15,7 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE + select MPILIB + select CRYPTO_HASH_INFO + select CRYPTO_AKCIPHER ++ select CRYPTO_SIG + select CRYPTO_HASH + help + This option provides support for asymmetric public key type handling. +@@ -76,7 +77,7 @@ config SIGNED_PE_FILE_VERIFICATION + signed PE binary. + + config FIPS_SIGNATURE_SELFTEST +- bool "Run FIPS selftests on the X.509+PKCS7 signature verification" ++ tristate "Run FIPS selftests on the X.509+PKCS7 signature verification" + help + This option causes some selftests to be run on the signature + verification code, using some built in data. This is required +@@ -84,5 +85,8 @@ config FIPS_SIGNATURE_SELFTEST + depends on KEYS + depends on ASYMMETRIC_KEY_TYPE + depends on PKCS7_MESSAGE_PARSER=X509_CERTIFICATE_PARSER ++ depends on X509_CERTIFICATE_PARSER ++ depends on CRYPTO_RSA ++ depends on CRYPTO_SHA256 + + endif # ASYMMETRIC_KEY_TYPE +diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile +index 0d1fa1b692c6b2..1a273d6df3ebf4 100644 +--- a/crypto/asymmetric_keys/Makefile ++++ b/crypto/asymmetric_keys/Makefile +@@ -22,7 +22,8 @@ x509_key_parser-y := \ + x509_cert_parser.o \ + x509_loader.o \ + x509_public_key.o +-x509_key_parser-$(CONFIG_FIPS_SIGNATURE_SELFTEST) += selftest.o ++obj-$(CONFIG_FIPS_SIGNATURE_SELFTEST) += x509_selftest.o ++x509_selftest-y += selftest.o + + $(obj)/x509_cert_parser.o: \ + $(obj)/x509.asn1.h \ +diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c +index a5da8ccd353ef7..43af5fa510c09f 100644 +--- a/crypto/asymmetric_keys/asymmetric_type.c ++++ b/crypto/asymmetric_keys/asymmetric_type.c +@@ -60,17 +60,18 @@ struct key *find_asymmetric_key(struct key *keyring, + char *req, *p; + int len; + +- WARN_ON(!id_0 && !id_1 && !id_2); +- + if (id_0) { + lookup = id_0->data; + len = id_0->len; + } else if (id_1) { + lookup = id_1->data; + len = id_1->len; +- } else { ++ } else if (id_2) { + lookup = id_2->data; + len = id_2->len; ++ } else { ++ WARN_ON(1); ++ return ERR_PTR(-EINVAL); + } + + /* Construct an identifier "id:". */ +diff --git a/crypto/asymmetric_keys/selftest.c b/crypto/asymmetric_keys/selftest.c +index fa0bf7f2428495..c50da7ef90ae99 100644 +--- a/crypto/asymmetric_keys/selftest.c ++++ b/crypto/asymmetric_keys/selftest.c +@@ -4,10 +4,11 @@ + * Written by David Howells (dhowells@redhat.com) + */ + +-#include ++#include + #include ++#include + #include +-#include ++#include + #include "x509_parser.h" + + struct certs_test { +@@ -175,7 +176,7 @@ static const struct certs_test certs_tests[] __initconst = { + TEST(certs_selftest_1_data, certs_selftest_1_pkcs7), + }; + +-int __init fips_signature_selftest(void) ++static int __init fips_signature_selftest(void) + { + struct key *keyring; + int ret, i; +@@ -222,3 +223,9 @@ int __init fips_signature_selftest(void) + key_put(keyring); + return 0; + } ++ ++late_initcall(fips_signature_selftest); ++ ++MODULE_DESCRIPTION("X.509 self tests"); ++MODULE_AUTHOR("Red Hat, Inc."); ++MODULE_LICENSE("GPL"); +diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h +index a299c9c56f409e..97a886cbe01c3d 100644 +--- a/crypto/asymmetric_keys/x509_parser.h ++++ b/crypto/asymmetric_keys/x509_parser.h +@@ -40,15 +40,6 @@ struct x509_certificate { + bool blacklisted; + }; + +-/* +- * selftest.c +- */ +-#ifdef CONFIG_FIPS_SIGNATURE_SELFTEST +-extern int __init fips_signature_selftest(void); +-#else +-static inline int fips_signature_selftest(void) { return 0; } +-#endif +- + /* + * x509_cert_parser.c + */ +diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c +index 7c71db3ac23d48..6a4f00be22fc10 100644 +--- a/crypto/asymmetric_keys/x509_public_key.c ++++ b/crypto/asymmetric_keys/x509_public_key.c +@@ -262,15 +262,9 @@ static struct asymmetric_key_parser x509_key_parser = { + /* + * Module stuff + */ +-extern int __init certs_selftest(void); + static int __init x509_key_init(void) + { +- int ret; +- +- ret = register_asymmetric_key_parser(&x509_key_parser); +- if (ret < 0) +- return ret; +- return fips_signature_selftest(); ++ return register_asymmetric_key_parser(&x509_key_parser); + } + + static void __exit x509_key_exit(void) +diff --git a/crypto/cipher.c b/crypto/cipher.c +index 47c77a3e597833..40cae908788eca 100644 +--- a/crypto/cipher.c ++++ b/crypto/cipher.c +@@ -34,8 +34,7 @@ static int setkey_unaligned(struct crypto_cipher *tfm, const u8 *key, + alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); + memcpy(alignbuffer, key, keylen); + ret = cia->cia_setkey(crypto_cipher_tfm(tfm), alignbuffer, keylen); +- memset(alignbuffer, 0, keylen); +- kfree(buffer); ++ kfree_sensitive(buffer); + return ret; + + } +diff --git a/crypto/ecdh.c b/crypto/ecdh.c +index 80afee3234fbe7..3049f147e0117b 100644 +--- a/crypto/ecdh.c ++++ b/crypto/ecdh.c +@@ -33,6 +33,8 @@ static int ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, + params.key_size > sizeof(u64) * ctx->ndigits) + return -EINVAL; + ++ memset(ctx->private_key, 0, sizeof(ctx->private_key)); ++ + if (!params.key || !params.key_size) + return ecc_gen_privkey(ctx->curve_id, ctx->ndigits, + ctx->private_key); +diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c +index fbd76498aba834..3f9ec273a121fd 100644 +--- a/crypto/ecdsa.c ++++ b/crypto/ecdsa.c +@@ -373,4 +373,7 @@ module_exit(ecdsa_exit); + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Stefan Berger "); + MODULE_DESCRIPTION("ECDSA generic algorithm"); ++MODULE_ALIAS_CRYPTO("ecdsa-nist-p192"); ++MODULE_ALIAS_CRYPTO("ecdsa-nist-p256"); ++MODULE_ALIAS_CRYPTO("ecdsa-nist-p384"); + MODULE_ALIAS_CRYPTO("ecdsa-generic"); +diff --git a/crypto/ecrdsa.c b/crypto/ecrdsa.c +index f3c6b5e15e75ba..3811f3805b5d88 100644 +--- a/crypto/ecrdsa.c ++++ b/crypto/ecrdsa.c +@@ -294,4 +294,5 @@ module_exit(ecrdsa_mod_fini); + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Vitaly Chikunov "); + MODULE_DESCRIPTION("EC-RDSA generic algorithm"); ++MODULE_ALIAS_CRYPTO("ecrdsa"); + MODULE_ALIAS_CRYPTO("ecrdsa-generic"); +diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c +index 8c1d0ca412137f..d0d954fe9d54f3 100644 +--- a/crypto/pcrypt.c ++++ b/crypto/pcrypt.c +@@ -117,6 +117,8 @@ static int pcrypt_aead_encrypt(struct aead_request *req) + err = padata_do_parallel(ictx->psenc, padata, &ctx->cb_cpu); + if (!err) + return -EINPROGRESS; ++ if (err == -EBUSY) ++ return -EAGAIN; + + return err; + } +@@ -164,6 +166,8 @@ static int pcrypt_aead_decrypt(struct aead_request *req) + err = padata_do_parallel(ictx->psdec, padata, &ctx->cb_cpu); + if (!err) + return -EINPROGRESS; ++ if (err == -EBUSY) ++ return -EAGAIN; + + return err; + } +diff --git a/crypto/rsa.c b/crypto/rsa.c +index c79613cdce6e44..b9cd11fb7d3672 100644 +--- a/crypto/rsa.c ++++ b/crypto/rsa.c +@@ -220,6 +220,8 @@ static int rsa_check_exponent_fips(MPI e) + } + + e_max = mpi_alloc(0); ++ if (!e_max) ++ return -ENOMEM; + mpi_set_bit(e_max, 256); + + if (mpi_cmp(e, e_max) >= 0) { +diff --git a/crypto/scompress.c b/crypto/scompress.c +index 442a82c9de7def..b108a30a760014 100644 +--- a/crypto/scompress.c ++++ b/crypto/scompress.c +@@ -117,6 +117,7 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir) + struct crypto_scomp *scomp = *tfm_ctx; + void **ctx = acomp_request_ctx(req); + struct scomp_scratch *scratch; ++ unsigned int dlen; + int ret; + + if (!req->src || !req->slen || req->slen > SCOMP_SCRATCH_SIZE) +@@ -128,6 +129,8 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir) + if (!req->dlen || req->dlen > SCOMP_SCRATCH_SIZE) + req->dlen = SCOMP_SCRATCH_SIZE; + ++ dlen = req->dlen; ++ + scratch = raw_cpu_ptr(&scomp_scratch); + spin_lock(&scratch->lock); + +@@ -145,6 +148,9 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir) + ret = -ENOMEM; + goto out; + } ++ } else if (req->dlen > dlen) { ++ ret = -ENOSPC; ++ goto out; + } + scatterwalk_map_and_copy(scratch->dst, req->dst, 0, req->dlen, + 1); +diff --git a/crypto/simd.c b/crypto/simd.c +index edaa479a1ec5e5..d109866641a265 100644 +--- a/crypto/simd.c ++++ b/crypto/simd.c +@@ -136,27 +136,19 @@ static int simd_skcipher_init(struct crypto_skcipher *tfm) + return 0; + } + +-struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname, ++struct simd_skcipher_alg *simd_skcipher_create_compat(struct skcipher_alg *ialg, ++ const char *algname, + const char *drvname, + const char *basename) + { + struct simd_skcipher_alg *salg; +- struct crypto_skcipher *tfm; +- struct skcipher_alg *ialg; + struct skcipher_alg *alg; + int err; + +- tfm = crypto_alloc_skcipher(basename, CRYPTO_ALG_INTERNAL, +- CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC); +- if (IS_ERR(tfm)) +- return ERR_CAST(tfm); +- +- ialg = crypto_skcipher_alg(tfm); +- + salg = kzalloc(sizeof(*salg), GFP_KERNEL); + if (!salg) { + salg = ERR_PTR(-ENOMEM); +- goto out_put_tfm; ++ goto out; + } + + salg->ialg_name = basename; +@@ -195,30 +187,16 @@ struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname, + if (err) + goto out_free_salg; + +-out_put_tfm: +- crypto_free_skcipher(tfm); ++out: + return salg; + + out_free_salg: + kfree(salg); + salg = ERR_PTR(err); +- goto out_put_tfm; ++ goto out; + } + EXPORT_SYMBOL_GPL(simd_skcipher_create_compat); + +-struct simd_skcipher_alg *simd_skcipher_create(const char *algname, +- const char *basename) +-{ +- char drvname[CRYPTO_MAX_ALG_NAME]; +- +- if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >= +- CRYPTO_MAX_ALG_NAME) +- return ERR_PTR(-ENAMETOOLONG); +- +- return simd_skcipher_create_compat(algname, drvname, basename); +-} +-EXPORT_SYMBOL_GPL(simd_skcipher_create); +- + void simd_skcipher_free(struct simd_skcipher_alg *salg) + { + crypto_unregister_skcipher(&salg->alg); +@@ -246,7 +224,7 @@ int simd_register_skciphers_compat(struct skcipher_alg *algs, int count, + algname = algs[i].base.cra_name + 2; + drvname = algs[i].base.cra_driver_name + 2; + basename = algs[i].base.cra_driver_name; +- simd = simd_skcipher_create_compat(algname, drvname, basename); ++ simd = simd_skcipher_create_compat(algs + i, algname, drvname, basename); + err = PTR_ERR(simd); + if (IS_ERR(simd)) + goto err_unregister; +@@ -383,27 +361,19 @@ static int simd_aead_init(struct crypto_aead *tfm) + return 0; + } + +-struct simd_aead_alg *simd_aead_create_compat(const char *algname, +- const char *drvname, +- const char *basename) ++static struct simd_aead_alg *simd_aead_create_compat(struct aead_alg *ialg, ++ const char *algname, ++ const char *drvname, ++ const char *basename) + { + struct simd_aead_alg *salg; +- struct crypto_aead *tfm; +- struct aead_alg *ialg; + struct aead_alg *alg; + int err; + +- tfm = crypto_alloc_aead(basename, CRYPTO_ALG_INTERNAL, +- CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC); +- if (IS_ERR(tfm)) +- return ERR_CAST(tfm); +- +- ialg = crypto_aead_alg(tfm); +- + salg = kzalloc(sizeof(*salg), GFP_KERNEL); + if (!salg) { + salg = ERR_PTR(-ENOMEM); +- goto out_put_tfm; ++ goto out; + } + + salg->ialg_name = basename; +@@ -442,36 +412,20 @@ struct simd_aead_alg *simd_aead_create_compat(const char *algname, + if (err) + goto out_free_salg; + +-out_put_tfm: +- crypto_free_aead(tfm); ++out: + return salg; + + out_free_salg: + kfree(salg); + salg = ERR_PTR(err); +- goto out_put_tfm; +-} +-EXPORT_SYMBOL_GPL(simd_aead_create_compat); +- +-struct simd_aead_alg *simd_aead_create(const char *algname, +- const char *basename) +-{ +- char drvname[CRYPTO_MAX_ALG_NAME]; +- +- if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >= +- CRYPTO_MAX_ALG_NAME) +- return ERR_PTR(-ENAMETOOLONG); +- +- return simd_aead_create_compat(algname, drvname, basename); ++ goto out; + } +-EXPORT_SYMBOL_GPL(simd_aead_create); + +-void simd_aead_free(struct simd_aead_alg *salg) ++static void simd_aead_free(struct simd_aead_alg *salg) + { + crypto_unregister_aead(&salg->alg); + kfree(salg); + } +-EXPORT_SYMBOL_GPL(simd_aead_free); + + int simd_register_aeads_compat(struct aead_alg *algs, int count, + struct simd_aead_alg **simd_algs) +@@ -493,7 +447,7 @@ int simd_register_aeads_compat(struct aead_alg *algs, int count, + algname = algs[i].base.cra_name + 2; + drvname = algs[i].base.cra_driver_name + 2; + basename = algs[i].base.cra_driver_name; +- simd = simd_aead_create_compat(algname, drvname, basename); ++ simd = simd_aead_create_compat(algs + i, algname, drvname, basename); + err = PTR_ERR(simd); + if (IS_ERR(simd)) + goto err_unregister; +diff --git a/crypto/xor.c b/crypto/xor.c +index 8e72e5d5db0ded..56aa3169e87171 100644 +--- a/crypto/xor.c ++++ b/crypto/xor.c +@@ -83,33 +83,30 @@ static void __init + do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2) + { + int speed; +- int i, j; +- ktime_t min, start, diff; ++ unsigned long reps; ++ ktime_t min, start, t0; + + tmpl->next = template_list; + template_list = tmpl; + + preempt_disable(); + +- min = (ktime_t)S64_MAX; +- for (i = 0; i < 3; i++) { +- start = ktime_get(); +- for (j = 0; j < REPS; j++) { +- mb(); /* prevent loop optimization */ +- tmpl->do_2(BENCH_SIZE, b1, b2); +- mb(); +- } +- diff = ktime_sub(ktime_get(), start); +- if (diff < min) +- min = diff; +- } ++ reps = 0; ++ t0 = ktime_get(); ++ /* delay start until time has advanced */ ++ while ((start = ktime_get()) == t0) ++ cpu_relax(); ++ do { ++ mb(); /* prevent loop optimization */ ++ tmpl->do_2(BENCH_SIZE, b1, b2); ++ mb(); ++ } while (reps++ < REPS || (t0 = ktime_get()) == start); ++ min = ktime_sub(t0, start); + + preempt_enable(); + + // bytes/ns == GB/s, multiply by 1000 to get MB/s [not MiB/s] +- if (!min) +- min = 1; +- speed = (1000 * REPS * BENCH_SIZE) / (unsigned int)ktime_to_ns(min); ++ speed = (1000 * reps * BENCH_SIZE) / (unsigned int)ktime_to_ns(min); + tmpl->speed = speed; + + pr_info(" %-16s: %5d MB/sec\n", tmpl->name, speed); +diff --git a/crypto/xts.c b/crypto/xts.c +index 548b302c6c6a00..038f60dd512d9f 100644 +--- a/crypto/xts.c ++++ b/crypto/xts.c +@@ -28,7 +28,7 @@ struct xts_tfm_ctx { + + struct xts_instance_ctx { + struct crypto_skcipher_spawn spawn; +- char name[CRYPTO_MAX_ALG_NAME]; ++ struct crypto_cipher_spawn tweak_spawn; + }; + + struct xts_request_ctx { +@@ -306,7 +306,7 @@ static int xts_init_tfm(struct crypto_skcipher *tfm) + + ctx->child = child; + +- tweak = crypto_alloc_cipher(ictx->name, 0, 0); ++ tweak = crypto_spawn_cipher(&ictx->tweak_spawn); + if (IS_ERR(tweak)) { + crypto_free_skcipher(ctx->child); + return PTR_ERR(tweak); +@@ -333,11 +333,13 @@ static void xts_free_instance(struct skcipher_instance *inst) + struct xts_instance_ctx *ictx = skcipher_instance_ctx(inst); + + crypto_drop_skcipher(&ictx->spawn); ++ crypto_drop_cipher(&ictx->tweak_spawn); + kfree(inst); + } + + static int xts_create(struct crypto_template *tmpl, struct rtattr **tb) + { ++ char name[CRYPTO_MAX_ALG_NAME]; + struct skcipher_instance *inst; + struct xts_instance_ctx *ctx; + struct skcipher_alg *alg; +@@ -363,13 +365,13 @@ static int xts_create(struct crypto_template *tmpl, struct rtattr **tb) + cipher_name, 0, mask); + if (err == -ENOENT) { + err = -ENAMETOOLONG; +- if (snprintf(ctx->name, CRYPTO_MAX_ALG_NAME, "ecb(%s)", ++ if (snprintf(name, CRYPTO_MAX_ALG_NAME, "ecb(%s)", + cipher_name) >= CRYPTO_MAX_ALG_NAME) + goto err_free_inst; + + err = crypto_grab_skcipher(&ctx->spawn, + skcipher_crypto_instance(inst), +- ctx->name, 0, mask); ++ name, 0, mask); + } + + if (err) +@@ -398,23 +400,28 @@ static int xts_create(struct crypto_template *tmpl, struct rtattr **tb) + if (!strncmp(cipher_name, "ecb(", 4)) { + int len; + +- len = strscpy(ctx->name, cipher_name + 4, sizeof(ctx->name)); ++ len = strscpy(name, cipher_name + 4, sizeof(name)); + if (len < 2) + goto err_free_inst; + +- if (ctx->name[len - 1] != ')') ++ if (name[len - 1] != ')') + goto err_free_inst; + +- ctx->name[len - 1] = 0; ++ name[len - 1] = 0; + + if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, +- "xts(%s)", ctx->name) >= CRYPTO_MAX_ALG_NAME) { ++ "xts(%s)", name) >= CRYPTO_MAX_ALG_NAME) { + err = -ENAMETOOLONG; + goto err_free_inst; + } + } else + goto err_free_inst; + ++ err = crypto_grab_cipher(&ctx->tweak_spawn, ++ skcipher_crypto_instance(inst), name, 0, mask); ++ if (err) ++ goto err_free_inst; ++ + inst->alg.base.cra_priority = alg->base.cra_priority; + inst->alg.base.cra_blocksize = XTS_BLOCK_SIZE; + inst->alg.base.cra_alignmask = alg->base.cra_alignmask | +diff --git a/drivers/accel/drm_accel.c b/drivers/accel/drm_accel.c +index 4a9baf02439e42..8827cb78ca9d8c 100644 +--- a/drivers/accel/drm_accel.c ++++ b/drivers/accel/drm_accel.c +@@ -8,7 +8,7 @@ + + #include + #include +-#include ++#include + + #include + #include +@@ -17,8 +17,7 @@ + #include + #include + +-static DEFINE_SPINLOCK(accel_minor_lock); +-static struct idr accel_minors_idr; ++DEFINE_XARRAY_ALLOC(accel_minors_xa); + + static struct dentry *accel_debugfs_root; + static struct class *accel_class; +@@ -120,99 +119,6 @@ void accel_set_device_instance_params(struct device *kdev, int index) + kdev->type = &accel_sysfs_device_minor; + } + +-/** +- * accel_minor_alloc() - Allocates a new accel minor +- * +- * This function access the accel minors idr and allocates from it +- * a new id to represent a new accel minor +- * +- * Return: A new id on success or error code in case idr_alloc failed +- */ +-int accel_minor_alloc(void) +-{ +- unsigned long flags; +- int r; +- +- spin_lock_irqsave(&accel_minor_lock, flags); +- r = idr_alloc(&accel_minors_idr, NULL, 0, ACCEL_MAX_MINORS, GFP_NOWAIT); +- spin_unlock_irqrestore(&accel_minor_lock, flags); +- +- return r; +-} +- +-/** +- * accel_minor_remove() - Remove an accel minor +- * @index: The minor id to remove. +- * +- * This function access the accel minors idr and removes from +- * it the member with the id that is passed to this function. +- */ +-void accel_minor_remove(int index) +-{ +- unsigned long flags; +- +- spin_lock_irqsave(&accel_minor_lock, flags); +- idr_remove(&accel_minors_idr, index); +- spin_unlock_irqrestore(&accel_minor_lock, flags); +-} +- +-/** +- * accel_minor_replace() - Replace minor pointer in accel minors idr. +- * @minor: Pointer to the new minor. +- * @index: The minor id to replace. +- * +- * This function access the accel minors idr structure and replaces the pointer +- * that is associated with an existing id. Because the minor pointer can be +- * NULL, we need to explicitly pass the index. +- * +- * Return: 0 for success, negative value for error +- */ +-void accel_minor_replace(struct drm_minor *minor, int index) +-{ +- unsigned long flags; +- +- spin_lock_irqsave(&accel_minor_lock, flags); +- idr_replace(&accel_minors_idr, minor, index); +- spin_unlock_irqrestore(&accel_minor_lock, flags); +-} +- +-/* +- * Looks up the given minor-ID and returns the respective DRM-minor object. The +- * refence-count of the underlying device is increased so you must release this +- * object with accel_minor_release(). +- * +- * The object can be only a drm_minor that represents an accel device. +- * +- * As long as you hold this minor, it is guaranteed that the object and the +- * minor->dev pointer will stay valid! However, the device may get unplugged and +- * unregistered while you hold the minor. +- */ +-static struct drm_minor *accel_minor_acquire(unsigned int minor_id) +-{ +- struct drm_minor *minor; +- unsigned long flags; +- +- spin_lock_irqsave(&accel_minor_lock, flags); +- minor = idr_find(&accel_minors_idr, minor_id); +- if (minor) +- drm_dev_get(minor->dev); +- spin_unlock_irqrestore(&accel_minor_lock, flags); +- +- if (!minor) { +- return ERR_PTR(-ENODEV); +- } else if (drm_dev_is_unplugged(minor->dev)) { +- drm_dev_put(minor->dev); +- return ERR_PTR(-ENODEV); +- } +- +- return minor; +-} +- +-static void accel_minor_release(struct drm_minor *minor) +-{ +- drm_dev_put(minor->dev); +-} +- + /** + * accel_open - open method for ACCEL file + * @inode: device inode +@@ -230,7 +136,7 @@ int accel_open(struct inode *inode, struct file *filp) + struct drm_minor *minor; + int retcode; + +- minor = accel_minor_acquire(iminor(inode)); ++ minor = drm_minor_acquire(&accel_minors_xa, iminor(inode)); + if (IS_ERR(minor)) + return PTR_ERR(minor); + +@@ -249,7 +155,7 @@ int accel_open(struct inode *inode, struct file *filp) + + err_undo: + atomic_dec(&dev->open_count); +- accel_minor_release(minor); ++ drm_minor_release(minor); + return retcode; + } + EXPORT_SYMBOL_GPL(accel_open); +@@ -260,7 +166,7 @@ static int accel_stub_open(struct inode *inode, struct file *filp) + struct drm_minor *minor; + int err; + +- minor = accel_minor_acquire(iminor(inode)); ++ minor = drm_minor_acquire(&accel_minors_xa, iminor(inode)); + if (IS_ERR(minor)) + return PTR_ERR(minor); + +@@ -277,7 +183,7 @@ static int accel_stub_open(struct inode *inode, struct file *filp) + err = 0; + + out: +- accel_minor_release(minor); ++ drm_minor_release(minor); + + return err; + } +@@ -293,15 +199,13 @@ void accel_core_exit(void) + unregister_chrdev(ACCEL_MAJOR, "accel"); + debugfs_remove(accel_debugfs_root); + accel_sysfs_destroy(); +- idr_destroy(&accel_minors_idr); ++ WARN_ON(!xa_empty(&accel_minors_xa)); + } + + int __init accel_core_init(void) + { + int ret; + +- idr_init(&accel_minors_idr); +- + ret = accel_sysfs_init(); + if (ret < 0) { + DRM_ERROR("Cannot create ACCEL class: %d\n", ret); +diff --git a/drivers/accel/habanalabs/common/debugfs.c b/drivers/accel/habanalabs/common/debugfs.c +index 9e84a47a21dcf4..7d733e4d506114 100644 +--- a/drivers/accel/habanalabs/common/debugfs.c ++++ b/drivers/accel/habanalabs/common/debugfs.c +@@ -1645,19 +1645,19 @@ static void add_files_to_device(struct hl_device *hdev, struct hl_dbg_device_ent + &hl_data64b_fops); + + debugfs_create_file("set_power_state", +- 0200, ++ 0644, + root, + dev_entry, + &hl_power_fops); + + debugfs_create_file("device", +- 0200, ++ 0644, + root, + dev_entry, + &hl_device_fops); + + debugfs_create_file("clk_gate", +- 0200, ++ 0644, + root, + dev_entry, + &hl_clk_gate_fops); +@@ -1669,13 +1669,13 @@ static void add_files_to_device(struct hl_device *hdev, struct hl_dbg_device_ent + &hl_stop_on_err_fops); + + debugfs_create_file("dump_security_violations", +- 0644, ++ 0400, + root, + dev_entry, + &hl_security_violations_fops); + + debugfs_create_file("dump_razwi_events", +- 0644, ++ 0400, + root, + dev_entry, + &hl_razwi_check_fops); +@@ -1708,7 +1708,7 @@ static void add_files_to_device(struct hl_device *hdev, struct hl_dbg_device_ent + &hdev->reset_info.skip_reset_on_timeout); + + debugfs_create_file("state_dump", +- 0600, ++ 0644, + root, + dev_entry, + &hl_state_dump_fops); +@@ -1726,7 +1726,7 @@ static void add_files_to_device(struct hl_device *hdev, struct hl_dbg_device_ent + + for (i = 0, entry = dev_entry->entry_arr ; i < count ; i++, entry++) { + debugfs_create_file(hl_debugfs_list[i].name, +- 0444, ++ 0644, + root, + entry, + &hl_debugfs_fops); +diff --git a/drivers/accel/habanalabs/common/device.c b/drivers/accel/habanalabs/common/device.c +index b97339d1f7c6ea..ebef56478e1852 100644 +--- a/drivers/accel/habanalabs/common/device.c ++++ b/drivers/accel/habanalabs/common/device.c +@@ -808,6 +808,9 @@ static int device_early_init(struct hl_device *hdev) + gaudi2_set_asic_funcs(hdev); + strscpy(hdev->asic_name, "GAUDI2B", sizeof(hdev->asic_name)); + break; ++ case ASIC_GAUDI2C: ++ gaudi2_set_asic_funcs(hdev); ++ strscpy(hdev->asic_name, "GAUDI2C", sizeof(hdev->asic_name)); + break; + default: + dev_err(hdev->dev, "Unrecognized ASIC type %d\n", +diff --git a/drivers/accel/habanalabs/common/habanalabs.h b/drivers/accel/habanalabs/common/habanalabs.h +index 2f027d5a820647..179e5e7013a120 100644 +--- a/drivers/accel/habanalabs/common/habanalabs.h ++++ b/drivers/accel/habanalabs/common/habanalabs.h +@@ -1220,6 +1220,7 @@ struct hl_dec { + * @ASIC_GAUDI_SEC: Gaudi secured device (HL-2000). + * @ASIC_GAUDI2: Gaudi2 device. + * @ASIC_GAUDI2B: Gaudi2B device. ++ * @ASIC_GAUDI2C: Gaudi2C device. + */ + enum hl_asic_type { + ASIC_INVALID, +@@ -1228,6 +1229,7 @@ enum hl_asic_type { + ASIC_GAUDI_SEC, + ASIC_GAUDI2, + ASIC_GAUDI2B, ++ ASIC_GAUDI2C, + }; + + struct hl_cs_parser; +@@ -2506,7 +2508,7 @@ struct hl_state_dump_specs { + * DEVICES + */ + +-#define HL_STR_MAX 32 ++#define HL_STR_MAX 64 + + #define HL_DEV_STS_MAX (HL_DEVICE_STATUS_LAST + 1) + +diff --git a/drivers/accel/habanalabs/common/habanalabs_drv.c b/drivers/accel/habanalabs/common/habanalabs_drv.c +index 7263e84c1a4dc3..010bf63fcca394 100644 +--- a/drivers/accel/habanalabs/common/habanalabs_drv.c ++++ b/drivers/accel/habanalabs/common/habanalabs_drv.c +@@ -101,6 +101,9 @@ static enum hl_asic_type get_asic_type(struct hl_device *hdev) + case REV_ID_B: + asic_type = ASIC_GAUDI2B; + break; ++ case REV_ID_C: ++ asic_type = ASIC_GAUDI2C; ++ break; + default: + break; + } +diff --git a/drivers/accel/habanalabs/common/habanalabs_ioctl.c b/drivers/accel/habanalabs/common/habanalabs_ioctl.c +index 6a45a92344e9bd..a7f6c54c123eff 100644 +--- a/drivers/accel/habanalabs/common/habanalabs_ioctl.c ++++ b/drivers/accel/habanalabs/common/habanalabs_ioctl.c +@@ -682,7 +682,7 @@ static int sec_attest_info(struct hl_fpriv *hpriv, struct hl_info_args *args) + if (!sec_attest_info) + return -ENOMEM; + +- info = kmalloc(sizeof(*info), GFP_KERNEL); ++ info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + rc = -ENOMEM; + goto free_sec_attest_info; +diff --git a/drivers/accel/habanalabs/common/irq.c b/drivers/accel/habanalabs/common/irq.c +index b1010d206c2ef1..813315cea4a7b0 100644 +--- a/drivers/accel/habanalabs/common/irq.c ++++ b/drivers/accel/habanalabs/common/irq.c +@@ -271,6 +271,9 @@ static int handle_registration_node(struct hl_device *hdev, struct hl_user_pendi + free_node->cq_cb = pend->ts_reg_info.cq_cb; + list_add(&free_node->free_objects_node, *free_list); + ++ /* Mark TS record as free */ ++ pend->ts_reg_info.in_use = false; ++ + return 0; + } + +diff --git a/drivers/accel/habanalabs/common/memory.c b/drivers/accel/habanalabs/common/memory.c +index 4fc72a07d2f59a..5b7d9a351133fe 100644 +--- a/drivers/accel/habanalabs/common/memory.c ++++ b/drivers/accel/habanalabs/common/memory.c +@@ -1878,16 +1878,16 @@ static int export_dmabuf(struct hl_ctx *ctx, + + static int validate_export_params_common(struct hl_device *hdev, u64 device_addr, u64 size) + { +- if (!IS_ALIGNED(device_addr, PAGE_SIZE)) { ++ if (!PAGE_ALIGNED(device_addr)) { + dev_dbg(hdev->dev, +- "exported device memory address 0x%llx should be aligned to 0x%lx\n", ++ "exported device memory address 0x%llx should be aligned to PAGE_SIZE 0x%lx\n", + device_addr, PAGE_SIZE); + return -EINVAL; + } + +- if (size < PAGE_SIZE) { ++ if (!size || !PAGE_ALIGNED(size)) { + dev_dbg(hdev->dev, +- "exported device memory size %llu should be equal to or greater than %lu\n", ++ "exported device memory size %llu should be a multiple of PAGE_SIZE %lu\n", + size, PAGE_SIZE); + return -EINVAL; + } +@@ -1938,6 +1938,13 @@ static int validate_export_params(struct hl_device *hdev, u64 device_addr, u64 s + if (rc) + return rc; + ++ if (!PAGE_ALIGNED(offset)) { ++ dev_dbg(hdev->dev, ++ "exported device memory offset %llu should be a multiple of PAGE_SIZE %lu\n", ++ offset, PAGE_SIZE); ++ return -EINVAL; ++ } ++ + if ((offset + size) > phys_pg_pack->total_size) { + dev_dbg(hdev->dev, "offset %#llx and size %#llx exceed total map size %#llx\n", + offset, size, phys_pg_pack->total_size); +diff --git a/drivers/accel/habanalabs/common/mmu/mmu.c b/drivers/accel/habanalabs/common/mmu/mmu.c +index b2145716c60533..b654302a68fc08 100644 +--- a/drivers/accel/habanalabs/common/mmu/mmu.c ++++ b/drivers/accel/habanalabs/common/mmu/mmu.c +@@ -596,6 +596,7 @@ int hl_mmu_if_set_funcs(struct hl_device *hdev) + break; + case ASIC_GAUDI2: + case ASIC_GAUDI2B: ++ case ASIC_GAUDI2C: + /* MMUs in Gaudi2 are always host resident */ + hl_mmu_v2_hr_set_funcs(hdev, &hdev->mmu_func[MMU_HR_PGT]); + break; +diff --git a/drivers/accel/habanalabs/common/sysfs.c b/drivers/accel/habanalabs/common/sysfs.c +index 01f89f029355e6..27860637305556 100644 +--- a/drivers/accel/habanalabs/common/sysfs.c ++++ b/drivers/accel/habanalabs/common/sysfs.c +@@ -251,6 +251,9 @@ static ssize_t device_type_show(struct device *dev, + case ASIC_GAUDI2B: + str = "GAUDI2B"; + break; ++ case ASIC_GAUDI2C: ++ str = "GAUDI2C"; ++ break; + default: + dev_err(hdev->dev, "Unrecognized ASIC type %d\n", + hdev->asic_type); +diff --git a/drivers/accel/habanalabs/gaudi2/gaudi2.c b/drivers/accel/habanalabs/gaudi2/gaudi2.c +index 20c4583f12b0d2..31c74ca70a2e5c 100644 +--- a/drivers/accel/habanalabs/gaudi2/gaudi2.c ++++ b/drivers/accel/habanalabs/gaudi2/gaudi2.c +@@ -8149,11 +8149,11 @@ static int gaudi2_psoc_razwi_get_engines(struct gaudi2_razwi_info *razwi_info, u + eng_id[num_of_eng] = razwi_info[i].eng_id; + base[num_of_eng] = razwi_info[i].rtr_ctrl; + if (!num_of_eng) +- str_size += snprintf(eng_name + str_size, ++ str_size += scnprintf(eng_name + str_size, + PSOC_RAZWI_ENG_STR_SIZE - str_size, "%s", + razwi_info[i].eng_name); + else +- str_size += snprintf(eng_name + str_size, ++ str_size += scnprintf(eng_name + str_size, + PSOC_RAZWI_ENG_STR_SIZE - str_size, " or %s", + razwi_info[i].eng_name); + num_of_eng++; +diff --git a/drivers/accel/habanalabs/gaudi2/gaudi2_security.c b/drivers/accel/habanalabs/gaudi2/gaudi2_security.c +index 2742b1f801eb2a..493e556cd31b74 100644 +--- a/drivers/accel/habanalabs/gaudi2/gaudi2_security.c ++++ b/drivers/accel/habanalabs/gaudi2/gaudi2_security.c +@@ -479,6 +479,7 @@ static const u32 gaudi2_pb_dcr0_edma0_unsecured_regs[] = { + mmDCORE0_EDMA0_CORE_CTX_TE_NUMROWS, + mmDCORE0_EDMA0_CORE_CTX_IDX, + mmDCORE0_EDMA0_CORE_CTX_IDX_INC, ++ mmDCORE0_EDMA0_CORE_WR_COMP_MAX_OUTSTAND, + mmDCORE0_EDMA0_CORE_RD_LBW_RATE_LIM_CFG, + mmDCORE0_EDMA0_QM_CQ_CFG0_0, + mmDCORE0_EDMA0_QM_CQ_CFG0_1, +@@ -1601,6 +1602,7 @@ static const u32 gaudi2_pb_dcr0_tpc0_unsecured_regs[] = { + mmDCORE0_TPC0_CFG_KERNEL_SRF_30, + mmDCORE0_TPC0_CFG_KERNEL_SRF_31, + mmDCORE0_TPC0_CFG_TPC_SB_L0CD, ++ mmDCORE0_TPC0_CFG_TPC_COUNT, + mmDCORE0_TPC0_CFG_TPC_ID, + mmDCORE0_TPC0_CFG_QM_KERNEL_ID_INC, + mmDCORE0_TPC0_CFG_QM_TID_BASE_SIZE_HIGH_DIM_0, +diff --git a/drivers/accel/habanalabs/include/hw_ip/pci/pci_general.h b/drivers/accel/habanalabs/include/hw_ip/pci/pci_general.h +index f5d497dc9bdc17..4f951cada07766 100644 +--- a/drivers/accel/habanalabs/include/hw_ip/pci/pci_general.h ++++ b/drivers/accel/habanalabs/include/hw_ip/pci/pci_general.h +@@ -25,6 +25,7 @@ enum hl_revision_id { + REV_ID_INVALID = 0x00, + REV_ID_A = 0x01, + REV_ID_B = 0x02, ++ REV_ID_C = 0x03 + }; + + #endif /* INCLUDE_PCI_GENERAL_H_ */ +diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c +index 7e9359611d69ca..5619980d9edda7 100644 +--- a/drivers/accel/ivpu/ivpu_drv.c ++++ b/drivers/accel/ivpu/ivpu_drv.c +@@ -467,9 +467,8 @@ static int ivpu_pci_init(struct ivpu_device *vdev) + /* Clear any pending errors */ + pcie_capability_clear_word(pdev, PCI_EXP_DEVSTA, 0x3f); + +- /* VPU 37XX does not require 10m D3hot delay */ +- if (ivpu_hw_gen(vdev) == IVPU_HW_37XX) +- pdev->d3hot_delay = 0; ++ /* NPU does not require 10m D3hot delay */ ++ pdev->d3hot_delay = 0; + + ret = pcim_enable_device(pdev); + if (ret) { +@@ -518,7 +517,7 @@ static int ivpu_dev_init(struct ivpu_device *vdev) + vdev->context_xa_limit.min = IVPU_USER_CONTEXT_MIN_SSID; + vdev->context_xa_limit.max = IVPU_USER_CONTEXT_MAX_SSID; + atomic64_set(&vdev->unique_id_counter, 0); +- xa_init_flags(&vdev->context_xa, XA_FLAGS_ALLOC); ++ xa_init_flags(&vdev->context_xa, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ); + xa_init_flags(&vdev->submitted_jobs_xa, XA_FLAGS_ALLOC1); + lockdep_set_class(&vdev->submitted_jobs_xa.xa_lock, &submitted_jobs_xa_lock_class_key); + +diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h +index 2adc349126bb66..6853dfe1c7e585 100644 +--- a/drivers/accel/ivpu/ivpu_drv.h ++++ b/drivers/accel/ivpu/ivpu_drv.h +@@ -76,6 +76,11 @@ + + #define IVPU_WA(wa_name) (vdev->wa.wa_name) + ++#define IVPU_PRINT_WA(wa_name) do { \ ++ if (IVPU_WA(wa_name)) \ ++ ivpu_dbg(vdev, MISC, "Using WA: " #wa_name "\n"); \ ++} while (0) ++ + struct ivpu_wa_table { + bool punit_disabled; + bool clear_runtime_mem; +diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c +index a277bbae78fc45..3b35d262ddd43a 100644 +--- a/drivers/accel/ivpu/ivpu_fw.c ++++ b/drivers/accel/ivpu/ivpu_fw.c +@@ -55,6 +55,10 @@ static struct { + { IVPU_HW_40XX, "intel/vpu/vpu_40xx_v0.0.bin" }, + }; + ++/* Production fw_names from the table above */ ++MODULE_FIRMWARE("intel/vpu/vpu_37xx_v0.0.bin"); ++MODULE_FIRMWARE("intel/vpu/vpu_40xx_v0.0.bin"); ++ + static int ivpu_fw_request(struct ivpu_device *vdev) + { + int ret = -ENOENT; +diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c +index 18be8b98e9a8b3..c0de7c0c991f56 100644 +--- a/drivers/accel/ivpu/ivpu_hw_37xx.c ++++ b/drivers/accel/ivpu/ivpu_hw_37xx.c +@@ -53,10 +53,12 @@ + + #define ICB_0_1_IRQ_MASK ((((u64)ICB_1_IRQ_MASK) << 32) | ICB_0_IRQ_MASK) + +-#define BUTTRESS_IRQ_MASK ((REG_FLD(VPU_37XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE)) | \ +- (REG_FLD(VPU_37XX_BUTTRESS_INTERRUPT_STAT, ATS_ERR)) | \ ++#define BUTTRESS_IRQ_MASK ((REG_FLD(VPU_37XX_BUTTRESS_INTERRUPT_STAT, ATS_ERR)) | \ + (REG_FLD(VPU_37XX_BUTTRESS_INTERRUPT_STAT, UFI_ERR))) + ++#define BUTTRESS_ALL_IRQ_MASK (BUTTRESS_IRQ_MASK | \ ++ (REG_FLD(VPU_37XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE))) ++ + #define BUTTRESS_IRQ_ENABLE_MASK ((u32)~BUTTRESS_IRQ_MASK) + #define BUTTRESS_IRQ_DISABLE_MASK ((u32)-1) + +@@ -102,8 +104,17 @@ static void ivpu_hw_wa_init(struct ivpu_device *vdev) + vdev->wa.clear_runtime_mem = false; + vdev->wa.d3hot_after_power_off = true; + +- if (ivpu_device_id(vdev) == PCI_DEVICE_ID_MTL && ivpu_revision(vdev) < 4) ++ REGB_WR32(VPU_37XX_BUTTRESS_INTERRUPT_STAT, BUTTRESS_ALL_IRQ_MASK); ++ if (REGB_RD32(VPU_37XX_BUTTRESS_INTERRUPT_STAT) == BUTTRESS_ALL_IRQ_MASK) { ++ /* Writing 1s does not clear the interrupt status register */ + vdev->wa.interrupt_clear_with_0 = true; ++ REGB_WR32(VPU_37XX_BUTTRESS_INTERRUPT_STAT, 0x0); ++ } ++ ++ IVPU_PRINT_WA(punit_disabled); ++ IVPU_PRINT_WA(clear_runtime_mem); ++ IVPU_PRINT_WA(d3hot_after_power_off); ++ IVPU_PRINT_WA(interrupt_clear_with_0); + } + + static void ivpu_hw_timeouts_init(struct ivpu_device *vdev) +@@ -536,12 +547,22 @@ static int ivpu_boot_pwr_domain_enable(struct ivpu_device *vdev) + return ret; + } + ++static int ivpu_boot_pwr_domain_disable(struct ivpu_device *vdev) ++{ ++ ivpu_boot_dpu_active_drive(vdev, false); ++ ivpu_boot_pwr_island_isolation_drive(vdev, true); ++ ivpu_boot_pwr_island_trickle_drive(vdev, false); ++ ivpu_boot_pwr_island_drive(vdev, false); ++ ++ return ivpu_boot_wait_for_pwr_island_status(vdev, 0x0); ++} ++ + static void ivpu_boot_no_snoop_enable(struct ivpu_device *vdev) + { + u32 val = REGV_RD32(VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES); + + val = REG_SET_FLD(VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES, NOSNOOP_OVERRIDE_EN, val); +- val = REG_SET_FLD(VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES, AW_NOSNOOP_OVERRIDE, val); ++ val = REG_CLR_FLD(VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES, AW_NOSNOOP_OVERRIDE, val); + val = REG_SET_FLD(VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES, AR_NOSNOOP_OVERRIDE, val); + + REGV_WR32(VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES, val); +@@ -625,30 +646,26 @@ static int ivpu_hw_37xx_info_init(struct ivpu_device *vdev) + ivpu_hw_init_range(&hw->ranges.shave, 0x180000000, SZ_2G); + ivpu_hw_init_range(&hw->ranges.dma, 0x200000000, SZ_8G); + ++ ivpu_hw_read_platform(vdev); ++ ivpu_hw_wa_init(vdev); ++ ivpu_hw_timeouts_init(vdev); ++ + return 0; + } + + static int ivpu_hw_37xx_reset(struct ivpu_device *vdev) + { +- int ret; +- u32 val; +- +- if (IVPU_WA(punit_disabled)) +- return 0; ++ int ret = 0; + +- ret = REGB_POLL_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US); +- if (ret) { +- ivpu_err(vdev, "Timed out waiting for TRIGGER bit\n"); +- return ret; ++ if (ivpu_boot_pwr_domain_disable(vdev)) { ++ ivpu_err(vdev, "Failed to disable power domain\n"); ++ ret = -EIO; + } + +- val = REGB_RD32(VPU_37XX_BUTTRESS_VPU_IP_RESET); +- val = REG_SET_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, val); +- REGB_WR32(VPU_37XX_BUTTRESS_VPU_IP_RESET, val); +- +- ret = REGB_POLL_FLD(VPU_37XX_BUTTRESS_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US); +- if (ret) +- ivpu_err(vdev, "Timed out waiting for RESET completion\n"); ++ if (ivpu_pll_disable(vdev)) { ++ ivpu_err(vdev, "Failed to disable PLL\n"); ++ ret = -EIO; ++ } + + return ret; + } +@@ -681,14 +698,6 @@ static int ivpu_hw_37xx_power_up(struct ivpu_device *vdev) + { + int ret; + +- ivpu_hw_read_platform(vdev); +- ivpu_hw_wa_init(vdev); +- ivpu_hw_timeouts_init(vdev); +- +- ret = ivpu_hw_37xx_reset(vdev); +- if (ret) +- ivpu_warn(vdev, "Failed to reset HW: %d\n", ret); +- + ret = ivpu_hw_37xx_d0i3_disable(vdev); + if (ret) + ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret); +@@ -756,11 +765,11 @@ static int ivpu_hw_37xx_power_down(struct ivpu_device *vdev) + { + int ret = 0; + +- if (!ivpu_hw_37xx_is_idle(vdev) && ivpu_hw_37xx_reset(vdev)) +- ivpu_err(vdev, "Failed to reset the VPU\n"); ++ if (!ivpu_hw_37xx_is_idle(vdev)) ++ ivpu_warn(vdev, "VPU not idle during power down\n"); + +- if (ivpu_pll_disable(vdev)) { +- ivpu_err(vdev, "Failed to disable PLL\n"); ++ if (ivpu_hw_37xx_reset(vdev)) { ++ ivpu_err(vdev, "Failed to reset VPU\n"); + ret = -EIO; + } + +diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c +index 85171a408363fa..cced6278c4f893 100644 +--- a/drivers/accel/ivpu/ivpu_hw_40xx.c ++++ b/drivers/accel/ivpu/ivpu_hw_40xx.c +@@ -24,7 +24,7 @@ + #define SKU_HW_ID_SHIFT 16u + #define SKU_HW_ID_MASK 0xffff0000u + +-#define PLL_CONFIG_DEFAULT 0x1 ++#define PLL_CONFIG_DEFAULT 0x0 + #define PLL_CDYN_DEFAULT 0x80 + #define PLL_EPP_DEFAULT 0x80 + #define PLL_REF_CLK_FREQ (50 * 1000000) +@@ -125,6 +125,10 @@ static void ivpu_hw_wa_init(struct ivpu_device *vdev) + + if (ivpu_hw_gen(vdev) == IVPU_HW_40XX) + vdev->wa.disable_clock_relinquish = true; ++ ++ IVPU_PRINT_WA(punit_disabled); ++ IVPU_PRINT_WA(clear_runtime_mem); ++ IVPU_PRINT_WA(disable_clock_relinquish); + } + + static void ivpu_hw_timeouts_init(struct ivpu_device *vdev) +@@ -519,7 +523,7 @@ static void ivpu_boot_no_snoop_enable(struct ivpu_device *vdev) + u32 val = REGV_RD32(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES); + + val = REG_SET_FLD(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES, SNOOP_OVERRIDE_EN, val); +- val = REG_CLR_FLD(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES, AW_SNOOP_OVERRIDE, val); ++ val = REG_SET_FLD(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES, AW_SNOOP_OVERRIDE, val); + val = REG_CLR_FLD(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES, AR_SNOOP_OVERRIDE, val); + + REGV_WR32(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES, val); +@@ -693,7 +697,6 @@ static int ivpu_hw_40xx_info_init(struct ivpu_device *vdev) + { + struct ivpu_hw_info *hw = vdev->hw; + u32 tile_disable; +- u32 tile_enable; + u32 fuse; + + fuse = REGB_RD32(VPU_40XX_BUTTRESS_TILE_FUSE); +@@ -714,10 +717,6 @@ static int ivpu_hw_40xx_info_init(struct ivpu_device *vdev) + else + ivpu_dbg(vdev, MISC, "Fuse: All %d tiles enabled\n", TILE_MAX_NUM); + +- tile_enable = (~tile_disable) & TILE_MAX_MASK; +- +- hw->sku = REG_SET_FLD_NUM(SKU, HW_ID, LNL_HW_ID, hw->sku); +- hw->sku = REG_SET_FLD_NUM(SKU, TILE, tile_enable, hw->sku); + hw->tile_fuse = tile_disable; + hw->pll.profiling_freq = PLL_PROFILING_FREQ_DEFAULT; + +@@ -728,6 +727,10 @@ static int ivpu_hw_40xx_info_init(struct ivpu_device *vdev) + ivpu_hw_init_range(&vdev->hw->ranges.shave, 0x80000000 + SZ_256M, SZ_2G - SZ_256M); + ivpu_hw_init_range(&vdev->hw->ranges.dma, 0x200000000, SZ_8G); + ++ ivpu_hw_read_platform(vdev); ++ ivpu_hw_wa_init(vdev); ++ ivpu_hw_timeouts_init(vdev); ++ + return 0; + } + +@@ -819,10 +822,6 @@ static int ivpu_hw_40xx_power_up(struct ivpu_device *vdev) + return ret; + } + +- ivpu_hw_read_platform(vdev); +- ivpu_hw_wa_init(vdev); +- ivpu_hw_timeouts_init(vdev); +- + ret = ivpu_hw_40xx_d0i3_disable(vdev); + if (ret) + ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret); +diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c +index de9e69f70af7e2..76f468c9f761bf 100644 +--- a/drivers/accel/ivpu/ivpu_job.c ++++ b/drivers/accel/ivpu/ivpu_job.c +@@ -618,6 +618,5 @@ int ivpu_job_done_thread_init(struct ivpu_device *vdev) + + void ivpu_job_done_thread_fini(struct ivpu_device *vdev) + { +- kthread_stop(vdev->job_done_thread); +- put_task_struct(vdev->job_done_thread); ++ kthread_stop_put(vdev->job_done_thread); + } +diff --git a/drivers/accel/ivpu/ivpu_mmu.c b/drivers/accel/ivpu/ivpu_mmu.c +index baefaf7bb3cbb9..d04a28e0524855 100644 +--- a/drivers/accel/ivpu/ivpu_mmu.c ++++ b/drivers/accel/ivpu/ivpu_mmu.c +@@ -491,7 +491,6 @@ static int ivpu_mmu_reset(struct ivpu_device *vdev) + mmu->cmdq.cons = 0; + + memset(mmu->evtq.base, 0, IVPU_MMU_EVTQ_SIZE); +- clflush_cache_range(mmu->evtq.base, IVPU_MMU_EVTQ_SIZE); + mmu->evtq.prod = 0; + mmu->evtq.cons = 0; + +@@ -805,8 +804,6 @@ static u32 *ivpu_mmu_get_event(struct ivpu_device *vdev) + if (!CIRC_CNT(IVPU_MMU_Q_IDX(evtq->prod), IVPU_MMU_Q_IDX(evtq->cons), IVPU_MMU_Q_COUNT)) + return NULL; + +- clflush_cache_range(evt, IVPU_MMU_EVTQ_CMD_SIZE); +- + evtq->cons = (evtq->cons + 1) & IVPU_MMU_Q_WRAP_MASK; + REGV_WR32(VPU_37XX_HOST_MMU_EVTQ_CONS_SEC, evtq->cons); + +diff --git a/drivers/accel/qaic/mhi_controller.c b/drivers/accel/qaic/mhi_controller.c +index 5036e58e7235bd..1405623b03e4ee 100644 +--- a/drivers/accel/qaic/mhi_controller.c ++++ b/drivers/accel/qaic/mhi_controller.c +@@ -404,8 +404,21 @@ static struct mhi_controller_config aic100_config = { + + static int mhi_read_reg(struct mhi_controller *mhi_cntrl, void __iomem *addr, u32 *out) + { +- u32 tmp = readl_relaxed(addr); ++ u32 tmp; + ++ /* ++ * SOC_HW_VERSION quirk ++ * The SOC_HW_VERSION register (offset 0x224) is not reliable and ++ * may contain uninitialized values, including 0xFFFFFFFF. This could ++ * cause a false positive link down error. Instead, intercept any ++ * reads and provide the correct value of the register. ++ */ ++ if (addr - mhi_cntrl->regs == 0x224) { ++ *out = 0x60110200; ++ return 0; ++ } ++ ++ tmp = readl_relaxed(addr); + if (tmp == U32_MAX) + return -EIO; + +diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c +index f4b06792c6f1c0..ed1a5af434f246 100644 +--- a/drivers/accel/qaic/qaic_data.c ++++ b/drivers/accel/qaic/qaic_data.c +@@ -766,7 +766,6 @@ struct drm_gem_object *qaic_gem_prime_import(struct drm_device *dev, struct dma_ + struct dma_buf_attachment *attach; + struct drm_gem_object *obj; + struct qaic_bo *bo; +- size_t size; + int ret; + + bo = qaic_alloc_init_bo(); +@@ -784,13 +783,12 @@ struct drm_gem_object *qaic_gem_prime_import(struct drm_device *dev, struct dma_ + goto attach_fail; + } + +- size = PAGE_ALIGN(attach->dmabuf->size); +- if (size == 0) { ++ if (!attach->dmabuf->size) { + ret = -EINVAL; + goto size_align_fail; + } + +- drm_gem_private_object_init(dev, obj, size); ++ drm_gem_private_object_init(dev, obj, attach->dmabuf->size); + /* + * skipping dma_buf_map_attachment() as we do not know the direction + * just yet. Once the direction is known in the subsequent IOCTL to +diff --git a/drivers/accessibility/speakup/main.c b/drivers/accessibility/speakup/main.c +index 1fbc9b921c4fcc..f677ad2177c2f2 100644 +--- a/drivers/accessibility/speakup/main.c ++++ b/drivers/accessibility/speakup/main.c +@@ -574,7 +574,7 @@ static u_long get_word(struct vc_data *vc) + } + attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr); + buf[cnt++] = attr_ch; +- while (tmpx < vc->vc_cols - 1) { ++ while (tmpx < vc->vc_cols - 1 && cnt < ARRAY_SIZE(buf) - 1) { + tmp_pos += 2; + tmpx++; + ch = get_char(vc, (u_short *)tmp_pos, &temp); +diff --git a/drivers/accessibility/speakup/synth.c b/drivers/accessibility/speakup/synth.c +index eea2a2fa4f0159..45f90610313382 100644 +--- a/drivers/accessibility/speakup/synth.c ++++ b/drivers/accessibility/speakup/synth.c +@@ -208,8 +208,10 @@ void spk_do_flush(void) + wake_up_process(speakup_task); + } + +-void synth_write(const char *buf, size_t count) ++void synth_write(const char *_buf, size_t count) + { ++ const unsigned char *buf = (const unsigned char *) _buf; ++ + while (count--) + synth_buffer_add(*buf++); + synth_start(); +diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c +index e120a96e1eaee8..ca87a093913599 100644 +--- a/drivers/acpi/acpi_extlog.c ++++ b/drivers/acpi/acpi_extlog.c +@@ -145,9 +145,14 @@ static int extlog_print(struct notifier_block *nb, unsigned long val, + static u32 err_seq; + + estatus = extlog_elog_entry_check(cpu, bank); +- if (estatus == NULL || (mce->kflags & MCE_HANDLED_CEC)) ++ if (!estatus) + return NOTIFY_DONE; + ++ if (mce->kflags & MCE_HANDLED_CEC) { ++ estatus->block_status = 0; ++ return NOTIFY_DONE; ++ } ++ + memcpy(elog_buf, (void *)estatus, ELOG_ENTRY_LEN); + /* clear record status to enable BIOS to update it again */ + estatus->block_status = 0; +@@ -303,9 +308,10 @@ static int __init extlog_init(void) + static void __exit extlog_exit(void) + { + mce_unregister_decode_chain(&extlog_mce_dec); +- ((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN; +- if (extlog_l1_addr) ++ if (extlog_l1_addr) { ++ ((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN; + acpi_os_unmap_iomem(extlog_l1_addr, l1_size); ++ } + if (elog_addr) + acpi_os_unmap_iomem(elog_addr, elog_size); + release_mem_region(elog_base, elog_size); +diff --git a/drivers/acpi/acpi_fpdt.c b/drivers/acpi/acpi_fpdt.c +index a2056c4c8cb709..271092f2700a1e 100644 +--- a/drivers/acpi/acpi_fpdt.c ++++ b/drivers/acpi/acpi_fpdt.c +@@ -194,12 +194,19 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type) + record_header = (void *)subtable_header + offset; + offset += record_header->length; + ++ if (!record_header->length) { ++ pr_err(FW_BUG "Zero-length record found in FPTD.\n"); ++ result = -EINVAL; ++ goto err; ++ } ++ + switch (record_header->type) { + case RECORD_S3_RESUME: + if (subtable_type != SUBTABLE_S3PT) { + pr_err(FW_BUG "Invalid record %d for subtable %s\n", + record_header->type, signature); +- return -EINVAL; ++ result = -EINVAL; ++ goto err; + } + if (record_resume) { + pr_err("Duplicate resume performance record found.\n"); +@@ -208,7 +215,7 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type) + record_resume = (struct resume_performance_record *)record_header; + result = sysfs_create_group(fpdt_kobj, &resume_attr_group); + if (result) +- return result; ++ goto err; + break; + case RECORD_S3_SUSPEND: + if (subtable_type != SUBTABLE_S3PT) { +@@ -223,13 +230,14 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type) + record_suspend = (struct suspend_performance_record *)record_header; + result = sysfs_create_group(fpdt_kobj, &suspend_attr_group); + if (result) +- return result; ++ goto err; + break; + case RECORD_BOOT: + if (subtable_type != SUBTABLE_FBPT) { + pr_err(FW_BUG "Invalid %d for subtable %s\n", + record_header->type, signature); +- return -EINVAL; ++ result = -EINVAL; ++ goto err; + } + if (record_boot) { + pr_err("Duplicate boot performance record found.\n"); +@@ -238,7 +246,7 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type) + record_boot = (struct boot_performance_record *)record_header; + result = sysfs_create_group(fpdt_kobj, &boot_attr_group); + if (result) +- return result; ++ goto err; + break; + + default: +@@ -247,6 +255,18 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type) + } + } + return 0; ++ ++err: ++ if (record_boot) ++ sysfs_remove_group(fpdt_kobj, &boot_attr_group); ++ ++ if (record_suspend) ++ sysfs_remove_group(fpdt_kobj, &suspend_attr_group); ++ ++ if (record_resume) ++ sysfs_remove_group(fpdt_kobj, &resume_attr_group); ++ ++ return result; + } + + static int __init acpi_init_fpdt(void) +@@ -255,6 +275,7 @@ static int __init acpi_init_fpdt(void) + struct acpi_table_header *header; + struct fpdt_subtable_entry *subtable; + u32 offset = sizeof(*header); ++ int result; + + status = acpi_get_table(ACPI_SIG_FPDT, 0, &header); + +@@ -263,8 +284,8 @@ static int __init acpi_init_fpdt(void) + + fpdt_kobj = kobject_create_and_add("fpdt", acpi_kobj); + if (!fpdt_kobj) { +- acpi_put_table(header); +- return -ENOMEM; ++ result = -ENOMEM; ++ goto err_nomem; + } + + while (offset < header->length) { +@@ -272,8 +293,10 @@ static int __init acpi_init_fpdt(void) + switch (subtable->type) { + case SUBTABLE_FBPT: + case SUBTABLE_S3PT: +- fpdt_process_subtable(subtable->address, ++ result = fpdt_process_subtable(subtable->address, + subtable->type); ++ if (result) ++ goto err_subtable; + break; + default: + /* Other types are reserved in ACPI 6.4 spec. */ +@@ -282,6 +305,12 @@ static int __init acpi_init_fpdt(void) + offset += sizeof(*subtable); + } + return 0; ++err_subtable: ++ kobject_put(fpdt_kobj); ++ ++err_nomem: ++ acpi_put_table(header); ++ return result; + } + + fs_initcall(acpi_init_fpdt); +diff --git a/drivers/acpi/acpi_lpit.c b/drivers/acpi/acpi_lpit.c +index c5598b6d5db8b0..794962c5c88e95 100644 +--- a/drivers/acpi/acpi_lpit.c ++++ b/drivers/acpi/acpi_lpit.c +@@ -105,7 +105,7 @@ static void lpit_update_residency(struct lpit_residency_info *info, + return; + + info->frequency = lpit_native->counter_frequency ? +- lpit_native->counter_frequency : tsc_khz * 1000; ++ lpit_native->counter_frequency : mul_u32_u32(tsc_khz, 1000U); + if (!info->frequency) + info->frequency = 1; + +diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c +index 539e700de4d289..98a2ab3b684428 100644 +--- a/drivers/acpi/acpi_lpss.c ++++ b/drivers/acpi/acpi_lpss.c +@@ -333,6 +333,7 @@ static const struct lpss_device_desc bsw_i2c_dev_desc = { + + static const struct property_entry bsw_spi_properties[] = { + PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type", LPSS_BSW_SSP), ++ PROPERTY_ENTRY_U32("num-cs", 2), + { } + }; + +@@ -465,8 +466,9 @@ static int register_device_clock(struct acpi_device *adev, + if (!clk_name) + return -ENOMEM; + clk = clk_register_fractional_divider(NULL, clk_name, parent, ++ 0, prv_base, 1, 15, 16, 15, + CLK_FRAC_DIVIDER_POWER_OF_TWO_PS, +- prv_base, 1, 15, 16, 15, 0, NULL); ++ NULL); + parent = clk_name; + + clk_name = kasprintf(GFP_KERNEL, "%s-update", devname); +diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c +index 7a453c5ff303a9..71e25c79897628 100644 +--- a/drivers/acpi/acpi_pad.c ++++ b/drivers/acpi/acpi_pad.c +@@ -131,8 +131,10 @@ static void exit_round_robin(unsigned int tsk_index) + { + struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits); + +- cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus); +- tsk_in_cpu[tsk_index] = -1; ++ if (tsk_in_cpu[tsk_index] != -1) { ++ cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus); ++ tsk_in_cpu[tsk_index] = -1; ++ } + } + + static unsigned int idle_pct = 5; /* percentage */ +diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c +index 0f5218e361df5c..7053f1b9fc1ddc 100644 +--- a/drivers/acpi/acpi_processor.c ++++ b/drivers/acpi/acpi_processor.c +@@ -415,7 +415,7 @@ static int acpi_processor_add(struct acpi_device *device, + + result = acpi_processor_get_info(device); + if (result) /* Processor is not physically present or unavailable */ +- return 0; ++ goto err_clear_driver_data; + + BUG_ON(pr->id >= nr_cpu_ids); + +@@ -430,7 +430,7 @@ static int acpi_processor_add(struct acpi_device *device, + "BIOS reported wrong ACPI id %d for the processor\n", + pr->id); + /* Give up, but do not abort the namespace scan. */ +- goto err; ++ goto err_clear_driver_data; + } + /* + * processor_device_array is not cleared on errors to allow buggy BIOS +@@ -442,12 +442,12 @@ static int acpi_processor_add(struct acpi_device *device, + dev = get_cpu_device(pr->id); + if (!dev) { + result = -ENODEV; +- goto err; ++ goto err_clear_per_cpu; + } + + result = acpi_bind_one(dev, device); + if (result) +- goto err; ++ goto err_clear_per_cpu; + + pr->dev = dev; + +@@ -458,10 +458,11 @@ static int acpi_processor_add(struct acpi_device *device, + dev_err(dev, "Processor driver could not be attached\n"); + acpi_unbind_one(dev); + +- err: +- free_cpumask_var(pr->throttling.shared_cpu_map); +- device->driver_data = NULL; ++ err_clear_per_cpu: + per_cpu(processors, pr->id) = NULL; ++ err_clear_driver_data: ++ device->driver_data = NULL; ++ free_cpumask_var(pr->throttling.shared_cpu_map); + err_free_pr: + kfree(pr); + return result; +diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c +index b411948594ff89..a971770e24ff90 100644 +--- a/drivers/acpi/acpi_video.c ++++ b/drivers/acpi/acpi_video.c +@@ -253,8 +253,7 @@ static const struct backlight_ops acpi_backlight_ops = { + static int video_get_max_state(struct thermal_cooling_device *cooling_dev, + unsigned long *state) + { +- struct acpi_device *device = cooling_dev->devdata; +- struct acpi_video_device *video = acpi_driver_data(device); ++ struct acpi_video_device *video = cooling_dev->devdata; + + *state = video->brightness->count - ACPI_VIDEO_FIRST_LEVEL - 1; + return 0; +@@ -263,8 +262,7 @@ static int video_get_max_state(struct thermal_cooling_device *cooling_dev, + static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, + unsigned long *state) + { +- struct acpi_device *device = cooling_dev->devdata; +- struct acpi_video_device *video = acpi_driver_data(device); ++ struct acpi_video_device *video = cooling_dev->devdata; + unsigned long long level; + int offset; + +@@ -283,8 +281,7 @@ static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, + static int + video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long state) + { +- struct acpi_device *device = cooling_dev->devdata; +- struct acpi_video_device *video = acpi_driver_data(device); ++ struct acpi_video_device *video = cooling_dev->devdata; + int level; + + if (state >= video->brightness->count - ACPI_VIDEO_FIRST_LEVEL) +@@ -503,6 +500,15 @@ static const struct dmi_system_id video_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3350"), + }, + }, ++ { ++ .callback = video_set_report_key_events, ++ .driver_data = (void *)((uintptr_t)REPORT_BRIGHTNESS_KEY_EVENTS), ++ .ident = "COLORFUL X15 AT 23", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "COLORFUL"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "X15 AT 23"), ++ }, ++ }, + /* + * Some machines change the brightness themselves when a brightness + * hotkey gets pressed, despite us telling them not to. In this case +@@ -1125,7 +1131,6 @@ static int acpi_video_bus_get_one_device(struct acpi_device *device, void *arg) + + strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); +- device->driver_data = data; + + data->device_id = device_id; + data->video = video; +@@ -1717,12 +1722,12 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device) + return; + count++; + +- acpi_get_parent(device->dev->handle, &acpi_parent); +- +- pdev = acpi_get_pci_dev(acpi_parent); +- if (pdev) { +- parent = &pdev->dev; +- pci_dev_put(pdev); ++ if (ACPI_SUCCESS(acpi_get_parent(device->dev->handle, &acpi_parent))) { ++ pdev = acpi_get_pci_dev(acpi_parent); ++ if (pdev) { ++ parent = &pdev->dev; ++ pci_dev_put(pdev); ++ } + } + + memset(&props, 0, sizeof(struct backlight_properties)); +@@ -1747,8 +1752,8 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device) + device->backlight->props.brightness = + acpi_video_get_brightness(device->backlight); + +- device->cooling_dev = thermal_cooling_device_register("LCD", +- device->dev, &video_cooling_ops); ++ device->cooling_dev = thermal_cooling_device_register("LCD", device, ++ &video_cooling_ops); + if (IS_ERR(device->cooling_dev)) { + /* + * Set cooling_dev to NULL so we don't crash trying to free it. +@@ -2031,7 +2036,7 @@ static int acpi_video_bus_add(struct acpi_device *device) + * HP ZBook Fury 16 G10 requires ACPI video's child devices have _PS0 + * evaluated to have functional panel brightness control. + */ +- acpi_device_fix_up_power_extended(device); ++ acpi_device_fix_up_power_children(device); + + pr_info("%s [%s] (multi-head: %s rom: %s post: %s)\n", + ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device), +diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile +index 30f3fc13c29d12..8d18af396de92c 100644 +--- a/drivers/acpi/acpica/Makefile ++++ b/drivers/acpi/acpica/Makefile +@@ -5,6 +5,7 @@ + + ccflags-y := -D_LINUX -DBUILDING_ACPICA + ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT ++CFLAGS_tbfind.o += $(call cc-disable-warning, stringop-truncation) + + # use acpi.o to put all files here into acpi.o modparam namespace + obj-y += acpi.o +diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h +index ddd072cbc738d4..1c5218b79fc2ac 100644 +--- a/drivers/acpi/acpica/acevents.h ++++ b/drivers/acpi/acpica/acevents.h +@@ -188,7 +188,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj, + u8 acpi_ns_is_locked); + + void +-acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, ++acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, u32 max_depth, + acpi_adr_space_type space_id, u32 function); + + acpi_status +diff --git a/drivers/acpi/acpica/dbconvert.c b/drivers/acpi/acpica/dbconvert.c +index 2b84ac093698a3..8dbab693204998 100644 +--- a/drivers/acpi/acpica/dbconvert.c ++++ b/drivers/acpi/acpica/dbconvert.c +@@ -174,6 +174,8 @@ acpi_status acpi_db_convert_to_package(char *string, union acpi_object *object) + elements = + ACPI_ALLOCATE_ZEROED(DB_DEFAULT_PKG_ELEMENTS * + sizeof(union acpi_object)); ++ if (!elements) ++ return (AE_NO_MEMORY); + + this = string; + for (i = 0; i < (DB_DEFAULT_PKG_ELEMENTS - 1); i++) { +diff --git a/drivers/acpi/acpica/dbnames.c b/drivers/acpi/acpica/dbnames.c +index b91155ea9c343c..c9131259f717b0 100644 +--- a/drivers/acpi/acpica/dbnames.c ++++ b/drivers/acpi/acpica/dbnames.c +@@ -550,8 +550,12 @@ acpi_db_walk_for_fields(acpi_handle obj_handle, + ACPI_FREE(buffer.pointer); + + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; +- acpi_evaluate_object(obj_handle, NULL, NULL, &buffer); +- ++ status = acpi_evaluate_object(obj_handle, NULL, NULL, &buffer); ++ if (ACPI_FAILURE(status)) { ++ acpi_os_printf("Could Not evaluate object %p\n", ++ obj_handle); ++ return (AE_OK); ++ } + /* + * Since this is a field unit, surround the output in braces + */ +diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c +index 18fdf2bc2d499a..cf53b9535f18e0 100644 +--- a/drivers/acpi/acpica/evregion.c ++++ b/drivers/acpi/acpica/evregion.c +@@ -65,6 +65,7 @@ acpi_status acpi_ev_initialize_op_regions(void) + acpi_gbl_default_address_spaces + [i])) { + acpi_ev_execute_reg_methods(acpi_gbl_root_node, ++ ACPI_UINT32_MAX, + acpi_gbl_default_address_spaces + [i], ACPI_REG_CONNECT); + } +@@ -672,6 +673,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) + * FUNCTION: acpi_ev_execute_reg_methods + * + * PARAMETERS: node - Namespace node for the device ++ * max_depth - Depth to which search for _REG + * space_id - The address space ID + * function - Passed to _REG: On (1) or Off (0) + * +@@ -683,7 +685,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) + ******************************************************************************/ + + void +-acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, ++acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, u32 max_depth, + acpi_adr_space_type space_id, u32 function) + { + struct acpi_reg_walk_info info; +@@ -717,7 +719,7 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, + * regions and _REG methods. (i.e. handlers must be installed for all + * regions of this Space ID before we can run any _REG methods) + */ +- (void)acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, ++ (void)acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, max_depth, + ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, NULL, + &info, NULL); + +diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c +index 3197e6303c5b08..95f78383bbdba1 100644 +--- a/drivers/acpi/acpica/evxfregn.c ++++ b/drivers/acpi/acpica/evxfregn.c +@@ -85,7 +85,8 @@ acpi_install_address_space_handler_internal(acpi_handle device, + /* Run all _REG methods for this address space */ + + if (run_reg) { +- acpi_ev_execute_reg_methods(node, space_id, ACPI_REG_CONNECT); ++ acpi_ev_execute_reg_methods(node, ACPI_UINT32_MAX, space_id, ++ ACPI_REG_CONNECT); + } + + unlock_and_exit: +@@ -263,6 +264,7 @@ ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler) + * FUNCTION: acpi_execute_reg_methods + * + * PARAMETERS: device - Handle for the device ++ * max_depth - Depth to which search for _REG + * space_id - The address space ID + * + * RETURN: Status +@@ -271,7 +273,8 @@ ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler) + * + ******************************************************************************/ + acpi_status +-acpi_execute_reg_methods(acpi_handle device, acpi_adr_space_type space_id) ++acpi_execute_reg_methods(acpi_handle device, u32 max_depth, ++ acpi_adr_space_type space_id) + { + struct acpi_namespace_node *node; + acpi_status status; +@@ -296,7 +299,8 @@ acpi_execute_reg_methods(acpi_handle device, acpi_adr_space_type space_id) + + /* Run all _REG methods for this address space */ + +- acpi_ev_execute_reg_methods(node, space_id, ACPI_REG_CONNECT); ++ acpi_ev_execute_reg_methods(node, max_depth, space_id, ++ ACPI_REG_CONNECT); + } else { + status = AE_BAD_PARAMETER; + } +diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c +index 08196fa17080e2..82b1fa2d201fed 100644 +--- a/drivers/acpi/acpica/exprep.c ++++ b/drivers/acpi/acpica/exprep.c +@@ -437,6 +437,9 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) + + if (info->connection_node) { + second_desc = info->connection_node->object; ++ if (second_desc == NULL) { ++ break; ++ } + if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = + acpi_ds_get_buffer_arguments(second_desc); +diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c +index 8907b8bf42672a..c49b9f8de723d8 100644 +--- a/drivers/acpi/acpica/exregion.c ++++ b/drivers/acpi/acpica/exregion.c +@@ -44,7 +44,6 @@ acpi_ex_system_memory_space_handler(u32 function, + struct acpi_mem_mapping *mm = mem_info->cur_mm; + u32 length; + acpi_size map_length; +- acpi_size page_boundary_map_length; + #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED + u32 remainder; + #endif +@@ -138,26 +137,8 @@ acpi_ex_system_memory_space_handler(u32 function, + map_length = (acpi_size) + ((mem_info->address + mem_info->length) - address); + +- /* +- * If mapping the entire remaining portion of the region will cross +- * a page boundary, just map up to the page boundary, do not cross. +- * On some systems, crossing a page boundary while mapping regions +- * can cause warnings if the pages have different attributes +- * due to resource management. +- * +- * This has the added benefit of constraining a single mapping to +- * one page, which is similar to the original code that used a 4k +- * maximum window. +- */ +- page_boundary_map_length = (acpi_size) +- (ACPI_ROUND_UP(address, ACPI_DEFAULT_PAGE_SIZE) - address); +- if (page_boundary_map_length == 0) { +- page_boundary_map_length = ACPI_DEFAULT_PAGE_SIZE; +- } +- +- if (map_length > page_boundary_map_length) { +- map_length = page_boundary_map_length; +- } ++ if (map_length > ACPI_DEFAULT_PAGE_SIZE) ++ map_length = ACPI_DEFAULT_PAGE_SIZE; + + /* Create a new mapping starting at the address given */ + +diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c +index 422c074ed2897b..28582adfc0acaf 100644 +--- a/drivers/acpi/acpica/psargs.c ++++ b/drivers/acpi/acpica/psargs.c +@@ -25,6 +25,8 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state); + static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state + *parser_state); + ++static void acpi_ps_free_field_list(union acpi_parse_object *start); ++ + /******************************************************************************* + * + * FUNCTION: acpi_ps_get_next_package_length +@@ -683,6 +685,39 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state + return_PTR(field); + } + ++/******************************************************************************* ++ * ++ * FUNCTION: acpi_ps_free_field_list ++ * ++ * PARAMETERS: start - First Op in field list ++ * ++ * RETURN: None. ++ * ++ * DESCRIPTION: Free all Op objects inside a field list. ++ * ++ ******************************************************************************/ ++ ++static void acpi_ps_free_field_list(union acpi_parse_object *start) ++{ ++ union acpi_parse_object *cur = start; ++ union acpi_parse_object *next; ++ union acpi_parse_object *arg; ++ ++ while (cur) { ++ next = cur->common.next; ++ ++ /* AML_INT_CONNECTION_OP can have a single argument */ ++ ++ arg = acpi_ps_get_arg(cur, 0); ++ if (arg) { ++ acpi_ps_free_op(arg); ++ } ++ ++ acpi_ps_free_op(cur); ++ cur = next; ++ } ++} ++ + /******************************************************************************* + * + * FUNCTION: acpi_ps_get_next_arg +@@ -751,6 +786,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, + while (parser_state->aml < parser_state->pkg_end) { + field = acpi_ps_get_next_field(parser_state); + if (!field) { ++ if (arg) { ++ acpi_ps_free_field_list(arg); ++ } ++ + return_ACPI_STATUS(AE_NO_MEMORY); + } + +@@ -820,6 +859,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, + acpi_ps_get_next_namepath(walk_state, parser_state, + arg, + ACPI_NOT_METHOD_CALL); ++ if (ACPI_FAILURE(status)) { ++ acpi_ps_free_op(arg); ++ return_ACPI_STATUS(status); ++ } + } else { + /* Single complex argument, nothing returned */ + +@@ -854,6 +897,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, + acpi_ps_get_next_namepath(walk_state, parser_state, + arg, + ACPI_POSSIBLE_METHOD_CALL); ++ if (ACPI_FAILURE(status)) { ++ acpi_ps_free_op(arg); ++ return_ACPI_STATUS(status); ++ } + + if (arg->common.aml_opcode == AML_INT_METHODCALL_OP) { + +diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c +index ef59d6ea16da0f..ab2a82cb1b0b48 100644 +--- a/drivers/acpi/apei/ghes.c ++++ b/drivers/acpi/apei/ghes.c +@@ -101,6 +101,20 @@ static inline bool is_hest_type_generic_v2(struct ghes *ghes) + return ghes->generic->header.type == ACPI_HEST_TYPE_GENERIC_ERROR_V2; + } + ++/* ++ * A platform may describe one error source for the handling of synchronous ++ * errors (e.g. MCE or SEA), or for handling asynchronous errors (e.g. SCI ++ * or External Interrupt). On x86, the HEST notifications are always ++ * asynchronous, so only SEA on ARM is delivered as a synchronous ++ * notification. ++ */ ++static inline bool is_hest_sync_notify(struct ghes *ghes) ++{ ++ u8 notify_type = ghes->generic->notify.type; ++ ++ return notify_type == ACPI_HEST_NOTIFY_SEA; ++} ++ + /* + * This driver isn't really modular, however for the time being, + * continuing to use module_param is the easiest way to remain +@@ -209,6 +223,20 @@ int ghes_estatus_pool_init(unsigned int num_ghes) + return -ENOMEM; + } + ++/** ++ * ghes_estatus_pool_region_free - free previously allocated memory ++ * from the ghes_estatus_pool. ++ * @addr: address of memory to free. ++ * @size: size of memory to free. ++ * ++ * Returns none. ++ */ ++void ghes_estatus_pool_region_free(unsigned long addr, u32 size) ++{ ++ gen_pool_free(ghes_estatus_pool, addr, size); ++} ++EXPORT_SYMBOL_GPL(ghes_estatus_pool_region_free); ++ + static int map_gen_v2(struct ghes *ghes) + { + return apei_map_generic_address(&ghes->generic_v2->read_ack_register); +@@ -475,7 +503,7 @@ static bool ghes_do_memory_failure(u64 physical_addr, int flags) + } + + static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, +- int sev) ++ int sev, bool sync) + { + int flags = -1; + int sec_sev = ghes_severity(gdata->error_severity); +@@ -489,7 +517,7 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, + (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED)) + flags = MF_SOFT_OFFLINE; + if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE) +- flags = 0; ++ flags = sync ? MF_ACTION_REQUIRED : 0; + + if (flags != -1) + return ghes_do_memory_failure(mem_err->physical_addr, flags); +@@ -497,9 +525,11 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, + return false; + } + +-static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int sev) ++static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, ++ int sev, bool sync) + { + struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata); ++ int flags = sync ? MF_ACTION_REQUIRED : 0; + bool queued = false; + int sec_sev, i; + char *p; +@@ -524,7 +554,7 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int s + * and don't filter out 'corrected' error here. + */ + if (is_cache && has_pa) { +- queued = ghes_do_memory_failure(err_info->physical_fault_addr, 0); ++ queued = ghes_do_memory_failure(err_info->physical_fault_addr, flags); + p += err_info->length; + continue; + } +@@ -564,6 +594,7 @@ static void ghes_handle_aer(struct acpi_hest_generic_data *gdata) + pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) { + unsigned int devfn; + int aer_severity; ++ u8 *aer_info; + + devfn = PCI_DEVFN(pcie_err->device_id.device, + pcie_err->device_id.function); +@@ -577,11 +608,17 @@ static void ghes_handle_aer(struct acpi_hest_generic_data *gdata) + if (gdata->flags & CPER_SEC_RESET) + aer_severity = AER_FATAL; + ++ aer_info = (void *)gen_pool_alloc(ghes_estatus_pool, ++ sizeof(struct aer_capability_regs)); ++ if (!aer_info) ++ return; ++ memcpy(aer_info, pcie_err->aer_info, sizeof(struct aer_capability_regs)); ++ + aer_recover_queue(pcie_err->device_id.segment, + pcie_err->device_id.bus, + devfn, aer_severity, + (struct aer_capability_regs *) +- pcie_err->aer_info); ++ aer_info); + } + #endif + } +@@ -645,6 +682,7 @@ static bool ghes_do_proc(struct ghes *ghes, + const guid_t *fru_id = &guid_null; + char *fru_text = ""; + bool queued = false; ++ bool sync = is_hest_sync_notify(ghes); + + sev = ghes_severity(estatus->error_severity); + apei_estatus_for_each_section(estatus, gdata) { +@@ -662,13 +700,13 @@ static bool ghes_do_proc(struct ghes *ghes, + atomic_notifier_call_chain(&ghes_report_chain, sev, mem_err); + + arch_apei_report_mem_error(sev, mem_err); +- queued = ghes_handle_memory_failure(gdata, sev); ++ queued = ghes_handle_memory_failure(gdata, sev, sync); + } + else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { + ghes_handle_aer(gdata); + } + else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { +- queued = ghes_handle_arm_hw_error(gdata, sev); ++ queued = ghes_handle_arm_hw_error(gdata, sev, sync); + } else { + void *err = acpi_hest_get_payload(gdata); + +diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c +index 969bf81e8d546a..e3cbaf3c3bbc15 100644 +--- a/drivers/acpi/battery.c ++++ b/drivers/acpi/battery.c +@@ -678,12 +678,18 @@ static ssize_t acpi_battery_alarm_store(struct device *dev, + return count; + } + +-static const struct device_attribute alarm_attr = { ++static struct device_attribute alarm_attr = { + .attr = {.name = "alarm", .mode = 0644}, + .show = acpi_battery_alarm_show, + .store = acpi_battery_alarm_store, + }; + ++static struct attribute *acpi_battery_attrs[] = { ++ &alarm_attr.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(acpi_battery); ++ + /* + * The Battery Hooking API + * +@@ -697,28 +703,35 @@ static LIST_HEAD(acpi_battery_list); + static LIST_HEAD(battery_hook_list); + static DEFINE_MUTEX(hook_mutex); + +-static void __battery_hook_unregister(struct acpi_battery_hook *hook, int lock) ++static void battery_hook_unregister_unlocked(struct acpi_battery_hook *hook) + { + struct acpi_battery *battery; ++ + /* + * In order to remove a hook, we first need to + * de-register all the batteries that are registered. + */ +- if (lock) +- mutex_lock(&hook_mutex); + list_for_each_entry(battery, &acpi_battery_list, list) { + if (!hook->remove_battery(battery->bat, hook)) + power_supply_changed(battery->bat); + } +- list_del(&hook->list); +- if (lock) +- mutex_unlock(&hook_mutex); ++ list_del_init(&hook->list); ++ + pr_info("extension unregistered: %s\n", hook->name); + } + + void battery_hook_unregister(struct acpi_battery_hook *hook) + { +- __battery_hook_unregister(hook, 1); ++ mutex_lock(&hook_mutex); ++ /* ++ * Ignore already unregistered battery hooks. This might happen ++ * if a battery hook was previously unloaded due to an error when ++ * adding a new battery. ++ */ ++ if (!list_empty(&hook->list)) ++ battery_hook_unregister_unlocked(hook); ++ ++ mutex_unlock(&hook_mutex); + } + EXPORT_SYMBOL_GPL(battery_hook_unregister); + +@@ -727,7 +740,6 @@ void battery_hook_register(struct acpi_battery_hook *hook) + struct acpi_battery *battery; + + mutex_lock(&hook_mutex); +- INIT_LIST_HEAD(&hook->list); + list_add(&hook->list, &battery_hook_list); + /* + * Now that the driver is registered, we need +@@ -744,7 +756,7 @@ void battery_hook_register(struct acpi_battery_hook *hook) + * hooks. + */ + pr_err("extension failed to load: %s", hook->name); +- __battery_hook_unregister(hook, 0); ++ battery_hook_unregister_unlocked(hook); + goto end; + } + +@@ -783,7 +795,7 @@ static void battery_hook_add_battery(struct acpi_battery *battery) + */ + pr_err("error in extension, unloading: %s", + hook_node->name); +- __battery_hook_unregister(hook_node, 0); ++ battery_hook_unregister_unlocked(hook_node); + } + } + mutex_unlock(&hook_mutex); +@@ -816,14 +828,17 @@ static void __exit battery_hook_exit(void) + * need to remove the hooks. + */ + list_for_each_entry_safe(hook, ptr, &battery_hook_list, list) { +- __battery_hook_unregister(hook, 1); ++ battery_hook_unregister(hook); + } + mutex_destroy(&hook_mutex); + } + + static int sysfs_add_battery(struct acpi_battery *battery) + { +- struct power_supply_config psy_cfg = { .drv_data = battery, }; ++ struct power_supply_config psy_cfg = { ++ .drv_data = battery, ++ .attr_grp = acpi_battery_groups, ++ }; + bool full_cap_broken = false; + + if (!ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity) && +@@ -868,7 +883,7 @@ static int sysfs_add_battery(struct acpi_battery *battery) + return result; + } + battery_hook_add_battery(battery); +- return device_create_file(&battery->bat->dev, &alarm_attr); ++ return 0; + } + + static void sysfs_remove_battery(struct acpi_battery *battery) +@@ -879,7 +894,6 @@ static void sysfs_remove_battery(struct acpi_battery *battery) + return; + } + battery_hook_remove_battery(battery); +- device_remove_file(&battery->bat->dev, &alarm_attr); + power_supply_unregister(battery->bat); + battery->bat = NULL; + mutex_unlock(&battery->sysfs_lock); +diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c +index 7ff269a78c2088..7aced0b9bad7cc 100644 +--- a/drivers/acpi/cppc_acpi.c ++++ b/drivers/acpi/cppc_acpi.c +@@ -100,6 +100,11 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr); + (cpc)->cpc_entry.reg.space_id == \ + ACPI_ADR_SPACE_PLATFORM_COMM) + ++/* Check if a CPC register is in FFH */ ++#define CPC_IN_FFH(cpc) ((cpc)->type == ACPI_TYPE_BUFFER && \ ++ (cpc)->cpc_entry.reg.space_id == \ ++ ACPI_ADR_SPACE_FIXED_HARDWARE) ++ + /* Check if a CPC register is in SystemMemory */ + #define CPC_IN_SYSTEM_MEMORY(cpc) ((cpc)->type == ACPI_TYPE_BUFFER && \ + (cpc)->cpc_entry.reg.space_id == \ +@@ -163,6 +168,16 @@ show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_freq); + show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, reference_perf); + show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time); + ++/* Check for valid access_width, otherwise, fallback to using bit_width */ ++#define GET_BIT_WIDTH(reg) ((reg)->access_width ? (8 << ((reg)->access_width - 1)) : (reg)->bit_width) ++ ++/* Shift and apply the mask for CPC reads/writes */ ++#define MASK_VAL_READ(reg, val) (((val) >> (reg)->bit_offset) & \ ++ GENMASK(((reg)->bit_width) - 1, 0)) ++#define MASK_VAL_WRITE(reg, prev_val, val) \ ++ ((((val) & GENMASK(((reg)->bit_width) - 1, 0)) << (reg)->bit_offset) | \ ++ ((prev_val) & ~(GENMASK(((reg)->bit_width) - 1, 0) << (reg)->bit_offset))) \ ++ + static ssize_t show_feedback_ctrs(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) + { +@@ -777,6 +792,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) + } else if (gas_t->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { + if (gas_t->address) { + void __iomem *addr; ++ size_t access_width; + + if (!osc_cpc_flexible_adr_space_confirmed) { + pr_debug("Flexible address space capability not supported\n"); +@@ -784,7 +800,8 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) + goto out_free; + } + +- addr = ioremap(gas_t->address, gas_t->bit_width/8); ++ access_width = GET_BIT_WIDTH(gas_t) / 8; ++ addr = ioremap(gas_t->address, access_width); + if (!addr) + goto out_free; + cpc_ptr->cpc_regs[i-2].sys_mem_vaddr = addr; +@@ -843,6 +860,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) + + /* Store CPU Logical ID */ + cpc_ptr->cpu_id = pr->id; ++ spin_lock_init(&cpc_ptr->rmw_lock); + + /* Parse PSD data for this CPU */ + ret = acpi_get_psd(cpc_ptr, handle); +@@ -980,6 +998,7 @@ int __weak cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val) + static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val) + { + void __iomem *vaddr = NULL; ++ int size; + int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); + struct cpc_reg *reg = ®_res->cpc_entry.reg; + +@@ -989,14 +1008,14 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val) + } + + *val = 0; ++ size = GET_BIT_WIDTH(reg); + + if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { +- u32 width = 8 << (reg->access_width - 1); + u32 val_u32; + acpi_status status; + + status = acpi_os_read_port((acpi_io_address)reg->address, +- &val_u32, width); ++ &val_u32, size); + if (ACPI_FAILURE(status)) { + pr_debug("Error: Failed to read SystemIO port %llx\n", + reg->address); +@@ -1005,17 +1024,24 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val) + + *val = val_u32; + return 0; +- } else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0) ++ } else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0) { ++ /* ++ * For registers in PCC space, the register size is determined ++ * by the bit width field; the access size is used to indicate ++ * the PCC subspace id. ++ */ ++ size = reg->bit_width; + vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id); ++ } + else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + vaddr = reg_res->sys_mem_vaddr; + else if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) + return cpc_read_ffh(cpu, reg, val); + else + return acpi_os_read_memory((acpi_physical_address)reg->address, +- val, reg->bit_width); ++ val, size); + +- switch (reg->bit_width) { ++ switch (size) { + case 8: + *val = readb_relaxed(vaddr); + break; +@@ -1029,27 +1055,39 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val) + *val = readq_relaxed(vaddr); + break; + default: +- pr_debug("Error: Cannot read %u bit width from PCC for ss: %d\n", +- reg->bit_width, pcc_ss_id); ++ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { ++ pr_debug("Error: Cannot read %u bit width from system memory: 0x%llx\n", ++ size, reg->address); ++ } else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { ++ pr_debug("Error: Cannot read %u bit width from PCC for ss: %d\n", ++ size, pcc_ss_id); ++ } + return -EFAULT; + } + ++ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) ++ *val = MASK_VAL_READ(reg, *val); ++ + return 0; + } + + static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val) + { + int ret_val = 0; ++ int size; ++ u64 prev_val; + void __iomem *vaddr = NULL; + int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); + struct cpc_reg *reg = ®_res->cpc_entry.reg; ++ struct cpc_desc *cpc_desc; ++ ++ size = GET_BIT_WIDTH(reg); + + if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { +- u32 width = 8 << (reg->access_width - 1); + acpi_status status; + + status = acpi_os_write_port((acpi_io_address)reg->address, +- (u32)val, width); ++ (u32)val, size); + if (ACPI_FAILURE(status)) { + pr_debug("Error: Failed to write SystemIO port %llx\n", + reg->address); +@@ -1057,17 +1095,53 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val) + } + + return 0; +- } else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0) ++ } else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0) { ++ /* ++ * For registers in PCC space, the register size is determined ++ * by the bit width field; the access size is used to indicate ++ * the PCC subspace id. ++ */ ++ size = reg->bit_width; + vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id); ++ } + else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + vaddr = reg_res->sys_mem_vaddr; + else if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) + return cpc_write_ffh(cpu, reg, val); + else + return acpi_os_write_memory((acpi_physical_address)reg->address, +- val, reg->bit_width); ++ val, size); ++ ++ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { ++ cpc_desc = per_cpu(cpc_desc_ptr, cpu); ++ if (!cpc_desc) { ++ pr_debug("No CPC descriptor for CPU:%d\n", cpu); ++ return -ENODEV; ++ } ++ ++ spin_lock(&cpc_desc->rmw_lock); ++ switch (size) { ++ case 8: ++ prev_val = readb_relaxed(vaddr); ++ break; ++ case 16: ++ prev_val = readw_relaxed(vaddr); ++ break; ++ case 32: ++ prev_val = readl_relaxed(vaddr); ++ break; ++ case 64: ++ prev_val = readq_relaxed(vaddr); ++ break; ++ default: ++ spin_unlock(&cpc_desc->rmw_lock); ++ return -EFAULT; ++ } ++ val = MASK_VAL_WRITE(reg, prev_val, val); ++ val |= prev_val; ++ } + +- switch (reg->bit_width) { ++ switch (size) { + case 8: + writeb_relaxed(val, vaddr); + break; +@@ -1081,12 +1155,20 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val) + writeq_relaxed(val, vaddr); + break; + default: +- pr_debug("Error: Cannot write %u bit width to PCC for ss: %d\n", +- reg->bit_width, pcc_ss_id); ++ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { ++ pr_debug("Error: Cannot write %u bit width to system memory: 0x%llx\n", ++ size, reg->address); ++ } else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { ++ pr_debug("Error: Cannot write %u bit width to PCC for ss: %d\n", ++ size, pcc_ss_id); ++ } + ret_val = -EFAULT; + break; + } + ++ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) ++ spin_unlock(&cpc_desc->rmw_lock); ++ + return ret_val; + } + +@@ -1154,6 +1236,19 @@ int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf) + return cppc_get_perf(cpunum, NOMINAL_PERF, nominal_perf); + } + ++/** ++ * cppc_get_highest_perf - Get the highest performance register value. ++ * @cpunum: CPU from which to get highest performance. ++ * @highest_perf: Return address. ++ * ++ * Return: 0 for success, -EIO otherwise. ++ */ ++int cppc_get_highest_perf(int cpunum, u64 *highest_perf) ++{ ++ return cppc_get_perf(cpunum, HIGHEST_PERF, highest_perf); ++} ++EXPORT_SYMBOL_GPL(cppc_get_highest_perf); ++ + /** + * cppc_get_epp_perf - Get the epp register value. + * @cpunum: CPU from which to get epp preference value. +@@ -1424,9 +1519,12 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable) + /* after writing CPC, transfer the ownership of PCC to platform */ + ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE); + up_write(&pcc_ss_data->pcc_lock); ++ } else if (osc_cpc_flexible_adr_space_confirmed && ++ CPC_SUPPORTED(epp_set_reg) && CPC_IN_FFH(epp_set_reg)) { ++ ret = cpc_write(cpu, epp_set_reg, perf_ctrls->energy_perf); + } else { + ret = -ENOTSUPP; +- pr_debug("_CPC in PCC is not supported\n"); ++ pr_debug("_CPC in PCC and _CPC in FFH are not supported\n"); + } + + return ret; +diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c +index f007116a842762..3b4d048c494173 100644 +--- a/drivers/acpi/device_pm.c ++++ b/drivers/acpi/device_pm.c +@@ -397,6 +397,19 @@ void acpi_device_fix_up_power_extended(struct acpi_device *adev) + } + EXPORT_SYMBOL_GPL(acpi_device_fix_up_power_extended); + ++/** ++ * acpi_device_fix_up_power_children - Force a device's children into D0. ++ * @adev: Parent device object whose children's power state is to be fixed up. ++ * ++ * Call acpi_device_fix_up_power() for @adev's children so long as they ++ * are reported as present and enabled. ++ */ ++void acpi_device_fix_up_power_children(struct acpi_device *adev) ++{ ++ acpi_dev_for_each_child(adev, fix_up_power_if_applicable, NULL); ++} ++EXPORT_SYMBOL_GPL(acpi_device_fix_up_power_children); ++ + int acpi_device_update_power(struct acpi_device *device, int *state_p) + { + int state; +diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c +index b9bbf074619921..6ed5e9e56be2f4 100644 +--- a/drivers/acpi/device_sysfs.c ++++ b/drivers/acpi/device_sysfs.c +@@ -158,8 +158,8 @@ static int create_pnp_modalias(const struct acpi_device *acpi_dev, char *modalia + return 0; + + len = snprintf(modalias, size, "acpi:"); +- if (len <= 0) +- return len; ++ if (len >= size) ++ return -ENOMEM; + + size -= len; + +@@ -212,8 +212,10 @@ static int create_of_modalias(const struct acpi_device *acpi_dev, char *modalias + len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer); + ACPI_FREE(buf.pointer); + +- if (len <= 0) +- return len; ++ if (len >= size) ++ return -ENOMEM; ++ ++ size -= len; + + of_compatible = acpi_dev->data.of_compatible; + if (of_compatible->type == ACPI_TYPE_PACKAGE) { +@@ -542,8 +544,9 @@ int acpi_device_setup_files(struct acpi_device *dev) + * If device has _STR, 'description' file is created + */ + if (acpi_has_method(dev->handle, "_STR")) { +- status = acpi_evaluate_object(dev->handle, "_STR", +- NULL, &buffer); ++ status = acpi_evaluate_object_typed(dev->handle, "_STR", ++ NULL, &buffer, ++ ACPI_TYPE_BUFFER); + if (ACPI_FAILURE(status)) + buffer.pointer = NULL; + dev->pnp.str_obj = buffer.pointer; +diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c +index c95d0edb0be9e5..115994dfefec1e 100644 +--- a/drivers/acpi/ec.c ++++ b/drivers/acpi/ec.c +@@ -783,6 +783,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, + unsigned long tmp; + int ret = 0; + ++ if (t->rdata) ++ memset(t->rdata, 0, t->rlen); ++ + /* start transaction */ + spin_lock_irqsave(&ec->lock, tmp); + /* Enable GPE for command processing (IBF=0/OBF=1) */ +@@ -819,8 +822,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) + + if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata)) + return -EINVAL; +- if (t->rdata) +- memset(t->rdata, 0, t->rlen); + + mutex_lock(&ec->mutex); + if (ec->global_lock) { +@@ -847,7 +848,7 @@ static int acpi_ec_burst_enable(struct acpi_ec *ec) + .wdata = NULL, .rdata = &d, + .wlen = 0, .rlen = 1}; + +- return acpi_ec_transaction(ec, &t); ++ return acpi_ec_transaction_unlocked(ec, &t); + } + + static int acpi_ec_burst_disable(struct acpi_ec *ec) +@@ -857,7 +858,7 @@ static int acpi_ec_burst_disable(struct acpi_ec *ec) + .wlen = 0, .rlen = 0}; + + return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ? +- acpi_ec_transaction(ec, &t) : 0; ++ acpi_ec_transaction_unlocked(ec, &t) : 0; + } + + static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) +@@ -873,6 +874,19 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) + return result; + } + ++static int acpi_ec_read_unlocked(struct acpi_ec *ec, u8 address, u8 *data) ++{ ++ int result; ++ u8 d; ++ struct transaction t = {.command = ACPI_EC_COMMAND_READ, ++ .wdata = &address, .rdata = &d, ++ .wlen = 1, .rlen = 1}; ++ ++ result = acpi_ec_transaction_unlocked(ec, &t); ++ *data = d; ++ return result; ++} ++ + static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) + { + u8 wdata[2] = { address, data }; +@@ -883,6 +897,16 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) + return acpi_ec_transaction(ec, &t); + } + ++static int acpi_ec_write_unlocked(struct acpi_ec *ec, u8 address, u8 data) ++{ ++ u8 wdata[2] = { address, data }; ++ struct transaction t = {.command = ACPI_EC_COMMAND_WRITE, ++ .wdata = wdata, .rdata = NULL, ++ .wlen = 2, .rlen = 0}; ++ ++ return acpi_ec_transaction_unlocked(ec, &t); ++} ++ + int ec_read(u8 addr, u8 *val) + { + int err; +@@ -1323,6 +1347,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, + struct acpi_ec *ec = handler_context; + int result = 0, i, bytes = bits / 8; + u8 *value = (u8 *)value64; ++ u32 glk; + + if ((address > 0xFF) || !value || !handler_context) + return AE_BAD_PARAMETER; +@@ -1330,17 +1355,38 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, + if (function != ACPI_READ && function != ACPI_WRITE) + return AE_BAD_PARAMETER; + ++ mutex_lock(&ec->mutex); ++ ++ if (ec->global_lock) { ++ acpi_status status; ++ ++ status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); ++ if (ACPI_FAILURE(status)) { ++ result = -ENODEV; ++ goto unlock; ++ } ++ } ++ + if (ec->busy_polling || bits > 8) + acpi_ec_burst_enable(ec); + +- for (i = 0; i < bytes; ++i, ++address, ++value) ++ for (i = 0; i < bytes; ++i, ++address, ++value) { + result = (function == ACPI_READ) ? +- acpi_ec_read(ec, address, value) : +- acpi_ec_write(ec, address, *value); ++ acpi_ec_read_unlocked(ec, address, value) : ++ acpi_ec_write_unlocked(ec, address, *value); ++ if (result < 0) ++ break; ++ } + + if (ec->busy_polling || bits > 8) + acpi_ec_burst_disable(ec); + ++ if (ec->global_lock) ++ acpi_release_global_lock(glk); ++ ++unlock: ++ mutex_unlock(&ec->mutex); ++ + switch (result) { + case -EINVAL: + return AE_BAD_PARAMETER; +@@ -1348,8 +1394,10 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, + return AE_NOT_FOUND; + case -ETIME: + return AE_TIME; +- default: ++ case 0: + return AE_OK; ++ default: ++ return AE_ERROR; + } + } + +@@ -1487,8 +1535,10 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device, + acpi_ec_start(ec, false); + + if (!test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) { ++ acpi_handle scope_handle = ec == first_ec ? ACPI_ROOT_OBJECT : ec->handle; ++ + acpi_ec_enter_noirq(ec); +- status = acpi_install_address_space_handler_no_reg(ec->handle, ++ status = acpi_install_address_space_handler_no_reg(scope_handle, + ACPI_ADR_SPACE_EC, + &acpi_ec_space_handler, + NULL, ec); +@@ -1497,11 +1547,10 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device, + return -ENODEV; + } + set_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags); +- ec->address_space_handler_holder = ec->handle; + } + + if (call_reg && !test_bit(EC_FLAGS_EC_REG_CALLED, &ec->flags)) { +- acpi_execute_reg_methods(ec->handle, ACPI_ADR_SPACE_EC); ++ acpi_execute_reg_methods(ec->handle, ACPI_UINT32_MAX, ACPI_ADR_SPACE_EC); + set_bit(EC_FLAGS_EC_REG_CALLED, &ec->flags); + } + +@@ -1553,10 +1602,13 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device, + + static void ec_remove_handlers(struct acpi_ec *ec) + { ++ acpi_handle scope_handle = ec == first_ec ? ACPI_ROOT_OBJECT : ec->handle; ++ + if (test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) { + if (ACPI_FAILURE(acpi_remove_address_space_handler( +- ec->address_space_handler_holder, +- ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) ++ scope_handle, ++ ACPI_ADR_SPACE_EC, ++ &acpi_ec_space_handler))) + pr_err("failed to remove space handler\n"); + clear_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags); + } +@@ -1595,14 +1647,18 @@ static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device, bool ca + { + int ret; + +- ret = ec_install_handlers(ec, device, call_reg); +- if (ret) +- return ret; +- + /* First EC capable of handling transactions */ + if (!first_ec) + first_ec = ec; + ++ ret = ec_install_handlers(ec, device, call_reg); ++ if (ret) { ++ if (ec == first_ec) ++ first_ec = NULL; ++ ++ return ret; ++ } ++ + pr_info("EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", ec->command_addr, + ec->data_addr); + +@@ -1709,6 +1765,12 @@ static void acpi_ec_remove(struct acpi_device *device) + } + } + ++void acpi_ec_register_opregions(struct acpi_device *adev) ++{ ++ if (first_ec && first_ec->handle != adev->handle) ++ acpi_execute_reg_methods(adev->handle, 1, ACPI_ADR_SPACE_EC); ++} ++ + static acpi_status + ec_parse_io_ports(struct acpi_resource *resource, void *context) + { +@@ -1924,6 +1986,16 @@ static const struct dmi_system_id ec_dmi_table[] __initconst = { + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Gaming Laptop 15-dk1xxx"), + }, + }, ++ { ++ /* ++ * HP 250 G7 Notebook PC ++ */ ++ .callback = ec_honor_dsdt_gpe, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "HP"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP 250 G7 Notebook PC"), ++ }, ++ }, + { + /* + * Samsung hardware +diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h +index 866c7c4ed23317..1e8ee97fc85f38 100644 +--- a/drivers/acpi/internal.h ++++ b/drivers/acpi/internal.h +@@ -167,7 +167,6 @@ enum acpi_ec_event_state { + + struct acpi_ec { + acpi_handle handle; +- acpi_handle address_space_handler_holder; + int gpe; + int irq; + unsigned long command_addr; +@@ -205,6 +204,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, + acpi_handle handle, acpi_ec_query_func func, + void *data); + void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit); ++void acpi_ec_register_opregions(struct acpi_device *adev); + + #ifdef CONFIG_PM_SLEEP + void acpi_ec_flush_work(void); +diff --git a/drivers/acpi/numa/srat.c b/drivers/acpi/numa/srat.c +index 1f4fc5f8a819d3..a44c0761fd1c06 100644 +--- a/drivers/acpi/numa/srat.c ++++ b/drivers/acpi/numa/srat.c +@@ -183,7 +183,7 @@ static int __init slit_valid(struct acpi_table_slit *slit) + int i, j; + int d = slit->locality_count; + for (i = 0; i < d; i++) { +- for (j = 0; j < d; j++) { ++ for (j = 0; j < d; j++) { + u8 val = slit->entry[d*i + j]; + if (i == j) { + if (val != LOCAL_DISTANCE) +@@ -206,6 +206,11 @@ int __init srat_disabled(void) + return acpi_numa < 0; + } + ++__weak int __init numa_fill_memblks(u64 start, u64 end) ++{ ++ return NUMA_NO_MEMBLK; ++} ++ + #if defined(CONFIG_X86) || defined(CONFIG_ARM64) || defined(CONFIG_LOONGARCH) + /* + * Callback for SLIT parsing. pxm_to_node() returns NUMA_NO_NODE for +@@ -310,11 +315,16 @@ static int __init acpi_parse_cfmws(union acpi_subtable_headers *header, + start = cfmws->base_hpa; + end = cfmws->base_hpa + cfmws->window_size; + +- /* Skip if the SRAT already described the NUMA details for this HPA */ +- node = phys_to_target_node(start); +- if (node != NUMA_NO_NODE) ++ /* ++ * The SRAT may have already described NUMA details for all, ++ * or a portion of, this CFMWS HPA range. Extend the memblks ++ * found for any portion of the window to cover the entire ++ * window. ++ */ ++ if (!numa_fill_memblks(start, end)) + return 0; + ++ /* No SRAT description. Create a new node. */ + node = acpi_map_pxm_to_node(*fake_pxm); + + if (node == NUMA_NO_NODE) { +@@ -527,7 +537,7 @@ int __init acpi_numa_init(void) + */ + + /* fake_pxm is the next unused PXM value after SRAT parsing */ +- for (i = 0, fake_pxm = -1; i < MAX_NUMNODES - 1; i++) { ++ for (i = 0, fake_pxm = -1; i < MAX_NUMNODES; i++) { + if (node_to_pxm_map[i] > fake_pxm) + fake_pxm = node_to_pxm_map[i]; + } +diff --git a/drivers/acpi/pmic/tps68470_pmic.c b/drivers/acpi/pmic/tps68470_pmic.c +index ebd03e4729555a..0d1a82eeb4b0b6 100644 +--- a/drivers/acpi/pmic/tps68470_pmic.c ++++ b/drivers/acpi/pmic/tps68470_pmic.c +@@ -376,10 +376,8 @@ static int tps68470_pmic_opregion_probe(struct platform_device *pdev) + struct tps68470_pmic_opregion *opregion; + acpi_status status; + +- if (!dev || !tps68470_regmap) { +- dev_warn(dev, "dev or regmap is NULL\n"); +- return -EINVAL; +- } ++ if (!tps68470_regmap) ++ return dev_err_probe(dev, -EINVAL, "regmap is missing\n"); + + if (!handle) { + dev_warn(dev, "acpi handle is NULL\n"); +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index 3a34a8c425fe4a..831fa4a1215985 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -16,7 +16,6 @@ + #include + #include + #include /* need_resched() */ +-#include + #include + #include + #include +@@ -386,25 +385,24 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr, + acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 1); + } + +-static int acpi_cst_latency_cmp(const void *a, const void *b) ++static void acpi_cst_latency_sort(struct acpi_processor_cx *states, size_t length) + { +- const struct acpi_processor_cx *x = a, *y = b; ++ int i, j, k; + +- if (!(x->valid && y->valid)) +- return 0; +- if (x->latency > y->latency) +- return 1; +- if (x->latency < y->latency) +- return -1; +- return 0; +-} +-static void acpi_cst_latency_swap(void *a, void *b, int n) +-{ +- struct acpi_processor_cx *x = a, *y = b; ++ for (i = 1; i < length; i++) { ++ if (!states[i].valid) ++ continue; + +- if (!(x->valid && y->valid)) +- return; +- swap(x->latency, y->latency); ++ for (j = i - 1, k = i; j >= 0; j--) { ++ if (!states[j].valid) ++ continue; ++ ++ if (states[j].latency > states[k].latency) ++ swap(states[j].latency, states[k].latency); ++ ++ k = j; ++ } ++ } + } + + static int acpi_processor_power_verify(struct acpi_processor *pr) +@@ -449,10 +447,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) + + if (buggy_latency) { + pr_notice("FW issue: working around C-state latencies out of order\n"); +- sort(&pr->power.states[1], max_cstate, +- sizeof(struct acpi_processor_cx), +- acpi_cst_latency_cmp, +- acpi_cst_latency_swap); ++ acpi_cst_latency_sort(&pr->power.states[1], max_cstate); + } + + lapic_timer_propagate_broadcast(pr); +@@ -592,7 +587,7 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) + while (1) { + + if (cx->entry_method == ACPI_CSTATE_HALT) +- safe_halt(); ++ raw_safe_halt(); + else if (cx->entry_method == ACPI_CSTATE_SYSTEMIO) { + io_idle(cx->address); + } else +@@ -1430,6 +1425,8 @@ int acpi_processor_power_exit(struct acpi_processor *pr) + acpi_processor_registered--; + if (acpi_processor_registered == 0) + cpuidle_unregister_driver(&acpi_idle_driver); ++ ++ kfree(dev); + } + + pr->flags.power_setup_done = 0; +diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c +index 413e4fcadcaf7b..4d958a165da058 100644 +--- a/drivers/acpi/property.c ++++ b/drivers/acpi/property.c +@@ -851,6 +851,7 @@ static int acpi_get_ref_args(struct fwnode_reference_args *args, + * @index: Index of the reference to return + * @num_args: Maximum number of arguments after each reference + * @args: Location to store the returned reference with optional arguments ++ * (may be NULL) + * + * Find property with @name, verifify that it is a package containing at least + * one object reference and if so, store the ACPI device object pointer to the +@@ -907,6 +908,9 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, + if (!device) + return -EINVAL; + ++ if (!args) ++ return 0; ++ + args->fwnode = acpi_fwnode_handle(device); + args->nargs = 0; + return 0; +@@ -1102,25 +1106,26 @@ static int acpi_data_prop_read(const struct acpi_device_data *data, + switch (proptype) { + case DEV_PROP_STRING: + break; +- case DEV_PROP_U8 ... DEV_PROP_U64: ++ default: + if (obj->type == ACPI_TYPE_BUFFER) { + if (nval > obj->buffer.length) + return -EOVERFLOW; +- break; ++ } else { ++ if (nval > obj->package.count) ++ return -EOVERFLOW; + } +- fallthrough; +- default: +- if (nval > obj->package.count) +- return -EOVERFLOW; + break; + } + if (nval == 0) + return -EINVAL; + +- if (obj->type != ACPI_TYPE_BUFFER) +- items = obj->package.elements; +- else ++ if (obj->type == ACPI_TYPE_BUFFER) { ++ if (proptype != DEV_PROP_U8) ++ return -EPROTO; + items = obj; ++ } else { ++ items = obj->package.elements; ++ } + + switch (proptype) { + case DEV_PROP_U8: +diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c +index 297a88587031e6..95233b413c1ac5 100644 +--- a/drivers/acpi/resource.c ++++ b/drivers/acpi/resource.c +@@ -439,6 +439,13 @@ static const struct dmi_system_id asus_laptop[] = { + DMI_MATCH(DMI_BOARD_NAME, "S5602ZA"), + }, + }, ++ { ++ /* Asus Vivobook X1704VAP */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_BOARD_NAME, "X1704VAP"), ++ }, ++ }, + { + .ident = "Asus ExpertBook B1402CBA", + .matches = { +@@ -446,6 +453,13 @@ static const struct dmi_system_id asus_laptop[] = { + DMI_MATCH(DMI_BOARD_NAME, "B1402CBA"), + }, + }, ++ { ++ /* Asus ExpertBook B1402CVA */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_BOARD_NAME, "B1402CVA"), ++ }, ++ }, + { + .ident = "Asus ExpertBook B1502CBA", + .matches = { +@@ -495,6 +509,38 @@ static const struct dmi_system_id maingear_laptop[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "MG-VCP2-15A3070T"), + } + }, ++ { ++ /* Asus ExpertBook B2502CVA */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_BOARD_NAME, "B2502CVA"), ++ }, ++ }, ++ { ++ /* TongFang GMxXGxx/TUXEDO Polaris 15 Gen5 AMD */ ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GMxXGxx"), ++ }, ++ }, ++ { ++ /* TongFang GMxXGxX/TUXEDO Polaris 15 Gen5 AMD */ ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GMxXGxX"), ++ }, ++ }, ++ { ++ /* TongFang GMxXGxx sold as Eluktronics Inc. RP-15 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Eluktronics Inc."), ++ DMI_MATCH(DMI_BOARD_NAME, "RP-15"), ++ }, ++ }, ++ { ++ /* TongFang GM6XGxX/TUXEDO Stellaris 16 Gen5 AMD */ ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GM6XGxX"), ++ }, ++ }, + { + .ident = "MAINGEAR Vector Pro 2 17", + .matches = { +@@ -524,6 +570,39 @@ static const struct dmi_system_id pcspecialist_laptop[] = { + DMI_MATCH(DMI_BOARD_NAME, "GM6BG0Q"), + }, + }, ++ { ++ /* Infinity E15-5A165-BM */ ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GM5RG1E0009COM"), ++ }, ++ }, ++ { ++ /* Infinity E15-5A305-1M */ ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GM5RGEE0016COM"), ++ }, ++ }, ++ { ++ /* Lunnen Ground 15 / AMD Ryzen 5 5500U */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Lunnen"), ++ DMI_MATCH(DMI_BOARD_NAME, "LLL5DAW"), ++ }, ++ }, ++ { ++ /* Lunnen Ground 16 / AMD Ryzen 7 5800U */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Lunnen"), ++ DMI_MATCH(DMI_BOARD_NAME, "LL6FA"), ++ }, ++ }, ++ { ++ /* MAIBENBEN X577 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "MAIBENBEN"), ++ DMI_MATCH(DMI_BOARD_NAME, "X577"), ++ }, ++ }, + { } + }; + +@@ -535,6 +614,18 @@ static const struct dmi_system_id lg_laptop[] = { + DMI_MATCH(DMI_BOARD_NAME, "17U70P"), + }, + }, ++ { ++ /* TongFang GXxHRXx/TUXEDO InfinityBook Pro Gen9 AMD */ ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GXxHRXx"), ++ }, ++ }, ++ { ++ /* TongFang GMxHGxx/TUXEDO Stellaris Slim Gen1 AMD */ ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GMxHGxx"), ++ }, ++ }, + { } + }; + +diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c +index 94e3c000df2e16..fdeb46ed21d69f 100644 +--- a/drivers/acpi/sbs.c ++++ b/drivers/acpi/sbs.c +@@ -77,7 +77,6 @@ struct acpi_battery { + u16 spec; + u8 id; + u8 present:1; +- u8 have_sysfs_alarm:1; + }; + + #define to_acpi_battery(x) power_supply_get_drvdata(x) +@@ -462,12 +461,18 @@ static ssize_t acpi_battery_alarm_store(struct device *dev, + return count; + } + +-static const struct device_attribute alarm_attr = { ++static struct device_attribute alarm_attr = { + .attr = {.name = "alarm", .mode = 0644}, + .show = acpi_battery_alarm_show, + .store = acpi_battery_alarm_store, + }; + ++static struct attribute *acpi_battery_attrs[] = { ++ &alarm_attr.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(acpi_battery); ++ + /* -------------------------------------------------------------------------- + Driver Interface + -------------------------------------------------------------------------- */ +@@ -518,7 +523,10 @@ static int acpi_battery_read(struct acpi_battery *battery) + static int acpi_battery_add(struct acpi_sbs *sbs, int id) + { + struct acpi_battery *battery = &sbs->battery[id]; +- struct power_supply_config psy_cfg = { .drv_data = battery, }; ++ struct power_supply_config psy_cfg = { ++ .drv_data = battery, ++ .attr_grp = acpi_battery_groups, ++ }; + int result; + + battery->id = id; +@@ -548,10 +556,6 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) + goto end; + } + +- result = device_create_file(&battery->bat->dev, &alarm_attr); +- if (result) +- goto end; +- battery->have_sysfs_alarm = 1; + end: + pr_info("%s [%s]: Battery Slot [%s] (battery %s)\n", + ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), +@@ -563,11 +567,8 @@ static void acpi_battery_remove(struct acpi_sbs *sbs, int id) + { + struct acpi_battery *battery = &sbs->battery[id]; + +- if (battery->bat) { +- if (battery->have_sysfs_alarm) +- device_remove_file(&battery->bat->dev, &alarm_attr); ++ if (battery->bat) + power_supply_unregister(battery->bat); +- } + } + + static int acpi_charger_add(struct acpi_sbs *sbs) +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index 691d4b7686ee7e..c0c5c5c58ae1e7 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -314,18 +314,14 @@ static int acpi_scan_device_check(struct acpi_device *adev) + * again). + */ + if (adev->handler) { +- dev_warn(&adev->dev, "Already enumerated\n"); +- return -EALREADY; ++ dev_dbg(&adev->dev, "Already enumerated\n"); ++ return 0; + } + error = acpi_bus_scan(adev->handle); + if (error) { + dev_warn(&adev->dev, "Namespace scan failure\n"); + return error; + } +- if (!adev->handler) { +- dev_warn(&adev->dev, "Enumeration failure\n"); +- error = -ENODEV; +- } + } else { + error = acpi_scan_device_not_present(adev); + } +@@ -1568,17 +1564,22 @@ static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev, + int err; + const struct iommu_ops *ops; + ++ /* Serialise to make dev->iommu stable under our potential fwspec */ ++ mutex_lock(&iommu_probe_device_lock); + /* + * If we already translated the fwspec there is nothing left to do, + * return the iommu_ops. + */ + ops = acpi_iommu_fwspec_ops(dev); +- if (ops) ++ if (ops) { ++ mutex_unlock(&iommu_probe_device_lock); + return ops; ++ } + + err = iort_iommu_configure_id(dev, id_in); + if (err && err != -EPROBE_DEFER) + err = viot_iommu_configure(dev); ++ mutex_unlock(&iommu_probe_device_lock); + + /* + * If we have reason to believe the IOMMU driver missed the initial +@@ -1797,7 +1798,8 @@ static void acpi_scan_dep_init(struct acpi_device *adev) + if (dep->honor_dep) + adev->flags.honor_deps = 1; + +- adev->dep_unmet++; ++ if (!dep->met) ++ adev->dep_unmet++; + } + } + } +@@ -2196,6 +2198,8 @@ static int acpi_bus_attach(struct acpi_device *device, void *first_pass) + if (device->handler) + goto ok; + ++ acpi_ec_register_opregions(device); ++ + if (!device->flags.initialized) { + device->flags.power_manageable = + device->power.states[ACPI_STATE_D0].flags.valid; +diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c +index 808484d1120976..728acfeb774d83 100644 +--- a/drivers/acpi/sleep.c ++++ b/drivers/acpi/sleep.c +@@ -385,18 +385,6 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = { + DMI_MATCH(DMI_PRODUCT_NAME, "20GGA00L00"), + }, + }, +- /* +- * ASUS B1400CEAE hangs on resume from suspend (see +- * https://bugzilla.kernel.org/show_bug.cgi?id=215742). +- */ +- { +- .callback = init_default_s3, +- .ident = "ASUS B1400CEAE", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), +- DMI_MATCH(DMI_PRODUCT_NAME, "ASUS EXPERTBOOK B1400CEAE"), +- }, +- }, + {}, + }; + +diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c +index 312730f8272eec..8263508415a8d0 100644 +--- a/drivers/acpi/thermal.c ++++ b/drivers/acpi/thermal.c +@@ -778,9 +778,9 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) + + static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) + { ++ thermal_zone_device_disable(tz->thermal_zone); + acpi_thermal_zone_sysfs_remove(tz); + thermal_zone_device_unregister(tz->thermal_zone); +- kfree(tz->trip_table); + tz->thermal_zone = NULL; + } + +@@ -985,7 +985,7 @@ static void acpi_thermal_remove(struct acpi_device *device) + + flush_workqueue(acpi_thermal_pm_queue); + acpi_thermal_unregister_thermal_zone(tz); +- ++ kfree(tz->trip_table); + kfree(tz); + } + +diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c +index 442396f6ed1f9c..e96afb1622f95f 100644 +--- a/drivers/acpi/video_detect.c ++++ b/drivers/acpi/video_detect.c +@@ -130,6 +130,16 @@ static int video_detect_force_native(const struct dmi_system_id *d) + return 0; + } + ++static int video_detect_portege_r100(const struct dmi_system_id *d) ++{ ++ struct pci_dev *dev; ++ /* Search for Trident CyberBlade XP4m32 to confirm Portégé R100 */ ++ dev = pci_get_device(PCI_VENDOR_ID_TRIDENT, 0x2100, NULL); ++ if (dev) ++ acpi_backlight_dmi = acpi_backlight_vendor; ++ return 0; ++} ++ + static const struct dmi_system_id video_detect_dmi_table[] = { + /* + * Models which should use the vendor backlight interface, +@@ -250,6 +260,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "PCG-FRV35"), + }, + }, ++ { ++ .callback = video_detect_force_vendor, ++ /* Panasonic Toughbook CF-18 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Matsushita Electric Industrial"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"), ++ }, ++ }, + + /* + * Toshiba models with Transflective display, these need to use +@@ -270,6 +288,22 @@ static const struct dmi_system_id video_detect_dmi_table[] = { + }, + }, + ++ /* ++ * Toshiba Portégé R100 has working both acpi_video and toshiba_acpi ++ * vendor driver. But none of them gets activated as it has a VGA with ++ * no kernel driver (Trident CyberBlade XP4m32). ++ * The DMI strings are generic so check for the VGA chip in callback. ++ */ ++ { ++ .callback = video_detect_portege_r100, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Portable PC"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "Version 1.0"), ++ DMI_MATCH(DMI_BOARD_NAME, "Portable PC") ++ }, ++ }, ++ + /* + * Models which need acpi_video backlight control where the GPU drivers + * do not call acpi_video_register_backlight() because no internal panel +@@ -479,6 +513,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "82BK"), + }, + }, ++ { ++ .callback = video_detect_force_native, ++ /* Lenovo Slim 7 16ARH7 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "82UX"), ++ }, ++ }, + { + .callback = video_detect_force_native, + /* Lenovo ThinkPad X131e (3371 AMD version) */ +diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c +index 63d834dd381122..e035cec614dc8f 100644 +--- a/drivers/acpi/x86/utils.c ++++ b/drivers/acpi/x86/utils.c +@@ -198,16 +198,16 @@ bool acpi_device_override_status(struct acpi_device *adev, unsigned long long *s + } + + /* +- * AMD systems from Renoir and Lucienne *require* that the NVME controller ++ * AMD systems from Renoir onwards *require* that the NVME controller + * is put into D3 over a Modern Standby / suspend-to-idle cycle. + * + * This is "typically" accomplished using the `StorageD3Enable` + * property in the _DSD that is checked via the `acpi_storage_d3` function +- * but this property was introduced after many of these systems launched +- * and most OEM systems don't have it in their BIOS. ++ * but some OEM systems still don't have it in their BIOS. + * + * The Microsoft documentation for StorageD3Enable mentioned that Windows has +- * a hardcoded allowlist for D3 support, which was used for these platforms. ++ * a hardcoded allowlist for D3 support as well as a registry key to override ++ * the BIOS, which has been used for these cases. + * + * This allows quirking on Linux in a similar fashion. + * +@@ -220,19 +220,15 @@ bool acpi_device_override_status(struct acpi_device *adev, unsigned long long *s + * https://bugzilla.kernel.org/show_bug.cgi?id=216773 + * https://bugzilla.kernel.org/show_bug.cgi?id=217003 + * 2) On at least one HP system StorageD3Enable is missing on the second NVME +- disk in the system. ++ * disk in the system. ++ * 3) On at least one HP Rembrandt system StorageD3Enable is missing on the only ++ * NVME device. + */ +-static const struct x86_cpu_id storage_d3_cpu_ids[] = { +- X86_MATCH_VENDOR_FAM_MODEL(AMD, 23, 24, NULL), /* Picasso */ +- X86_MATCH_VENDOR_FAM_MODEL(AMD, 23, 96, NULL), /* Renoir */ +- X86_MATCH_VENDOR_FAM_MODEL(AMD, 23, 104, NULL), /* Lucienne */ +- X86_MATCH_VENDOR_FAM_MODEL(AMD, 25, 80, NULL), /* Cezanne */ +- {} +-}; +- + bool force_storage_d3(void) + { +- return x86_match_cpu(storage_d3_cpu_ids); ++ if (!cpu_feature_enabled(X86_FEATURE_ZEN)) ++ return false; ++ return acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0; + } + + /* +@@ -261,9 +257,10 @@ bool force_storage_d3(void) + #define ACPI_QUIRK_SKIP_I2C_CLIENTS BIT(0) + #define ACPI_QUIRK_UART1_SKIP BIT(1) + #define ACPI_QUIRK_UART1_TTY_UART2_SKIP BIT(2) +-#define ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY BIT(3) +-#define ACPI_QUIRK_USE_ACPI_AC_AND_BATTERY BIT(4) +-#define ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS BIT(5) ++#define ACPI_QUIRK_PNP_UART1_SKIP BIT(3) ++#define ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY BIT(4) ++#define ACPI_QUIRK_USE_ACPI_AC_AND_BATTERY BIT(5) ++#define ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS BIT(6) + + static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = { + /* +@@ -343,6 +340,7 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = { + DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"), + }, + .driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS | ++ ACPI_QUIRK_PNP_UART1_SKIP | + ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY), + }, + { +@@ -429,7 +427,7 @@ bool acpi_quirk_skip_i2c_client_enumeration(struct acpi_device *adev) + } + EXPORT_SYMBOL_GPL(acpi_quirk_skip_i2c_client_enumeration); + +-int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip) ++static int acpi_dmi_skip_serdev_enumeration(struct device *controller_parent, bool *skip) + { + struct acpi_device *adev = ACPI_COMPANION(controller_parent); + const struct dmi_system_id *dmi_id; +@@ -437,20 +435,22 @@ int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *s + u64 uid; + int ret; + +- *skip = false; +- + ret = acpi_dev_uid_to_integer(adev, &uid); + if (ret) + return 0; + +- /* to not match on PNP enumerated debug UARTs */ +- if (!dev_is_platform(controller_parent)) +- return 0; +- + dmi_id = dmi_first_match(acpi_quirk_skip_dmi_ids); + if (dmi_id) + quirks = (unsigned long)dmi_id->driver_data; + ++ if (!dev_is_platform(controller_parent)) { ++ /* PNP enumerated UARTs */ ++ if ((quirks & ACPI_QUIRK_PNP_UART1_SKIP) && uid == 1) ++ *skip = true; ++ ++ return 0; ++ } ++ + if ((quirks & ACPI_QUIRK_UART1_SKIP) && uid == 1) + *skip = true; + +@@ -464,7 +464,6 @@ int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *s + + return 0; + } +-EXPORT_SYMBOL_GPL(acpi_quirk_skip_serdev_enumeration); + + bool acpi_quirk_skip_gpio_event_handlers(void) + { +@@ -479,8 +478,21 @@ bool acpi_quirk_skip_gpio_event_handlers(void) + return (quirks & ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS); + } + EXPORT_SYMBOL_GPL(acpi_quirk_skip_gpio_event_handlers); ++#else ++static int acpi_dmi_skip_serdev_enumeration(struct device *controller_parent, bool *skip) ++{ ++ return 0; ++} + #endif + ++int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip) ++{ ++ *skip = false; ++ ++ return acpi_dmi_skip_serdev_enumeration(controller_parent, skip); ++} ++EXPORT_SYMBOL_GPL(acpi_quirk_skip_serdev_enumeration); ++ + /* Lists of PMIC ACPI HIDs with an (often better) native charger driver */ + static const struct { + const char *hid; +diff --git a/drivers/android/binder.c b/drivers/android/binder.c +index 92128aae2d0601..94f10c6eb336a5 100644 +--- a/drivers/android/binder.c ++++ b/drivers/android/binder.c +@@ -478,6 +478,16 @@ binder_enqueue_thread_work_ilocked(struct binder_thread *thread, + { + WARN_ON(!list_empty(&thread->waiting_thread_node)); + binder_enqueue_work_ilocked(work, &thread->todo); ++ ++ /* (e)poll-based threads require an explicit wakeup signal when ++ * queuing their own work; they rely on these events to consume ++ * messages without I/O block. Without it, threads risk waiting ++ * indefinitely without handling the work. ++ */ ++ if (thread->looper & BINDER_LOOPER_STATE_POLL && ++ thread->pid == current->pid && !thread->process_todo) ++ wake_up_interruptible_sync(&thread->wait); ++ + thread->process_todo = true; + } + +@@ -560,9 +570,7 @@ static bool binder_has_work(struct binder_thread *thread, bool do_proc_work) + static bool binder_available_for_proc_work_ilocked(struct binder_thread *thread) + { + return !thread->transaction_stack && +- binder_worklist_empty_ilocked(&thread->todo) && +- (thread->looper & (BINDER_LOOPER_STATE_ENTERED | +- BINDER_LOOPER_STATE_REGISTERED)); ++ binder_worklist_empty_ilocked(&thread->todo); + } + + static void binder_wakeup_poll_threads_ilocked(struct binder_proc *proc, +@@ -1698,8 +1706,10 @@ static size_t binder_get_object(struct binder_proc *proc, + size_t object_size = 0; + + read_size = min_t(size_t, sizeof(*object), buffer->data_size - offset); +- if (offset > buffer->data_size || read_size < sizeof(*hdr)) ++ if (offset > buffer->data_size || read_size < sizeof(*hdr) || ++ !IS_ALIGNED(offset, sizeof(u32))) + return 0; ++ + if (u) { + if (copy_from_user(object, u + offset, read_size)) + return 0; +@@ -3332,6 +3342,7 @@ static void binder_transaction(struct binder_proc *proc, + */ + copy_size = object_offset - user_offset; + if (copy_size && (user_offset > object_offset || ++ object_offset > tr->data_size || + binder_alloc_copy_user_to_buffer( + &target_proc->alloc, + t->buffer, user_offset, +@@ -5030,7 +5041,7 @@ static __poll_t binder_poll(struct file *filp, + + thread = binder_get_thread(proc); + if (!thread) +- return POLLERR; ++ return EPOLLERR; + + binder_inner_proc_lock(thread->proc); + thread->looper |= BINDER_LOOPER_STATE_POLL; +@@ -5356,7 +5367,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + goto err; + break; + case BINDER_SET_MAX_THREADS: { +- int max_threads; ++ u32 max_threads; + + if (copy_from_user(&max_threads, ubuf, + sizeof(max_threads))) { +diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c +index e3db8297095a2f..34c27223cb7dd2 100644 +--- a/drivers/android/binder_alloc.c ++++ b/drivers/android/binder_alloc.c +@@ -271,7 +271,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, + } + if (mm) { + mmap_write_unlock(mm); +- mmput(mm); ++ mmput_async(mm); + } + return 0; + +@@ -304,7 +304,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, + err_no_vma: + if (mm) { + mmap_write_unlock(mm); +- mmput(mm); ++ mmput_async(mm); + } + return vma ? -ENOMEM : -ESRCH; + } +@@ -344,8 +344,7 @@ static bool debug_low_async_space_locked(struct binder_alloc *alloc, int pid) + continue; + if (!buffer->async_transaction) + continue; +- total_alloc_size += binder_alloc_buffer_size(alloc, buffer) +- + sizeof(struct binder_buffer); ++ total_alloc_size += binder_alloc_buffer_size(alloc, buffer); + num_buffers++; + } + +@@ -407,17 +406,17 @@ static struct binder_buffer *binder_alloc_new_buf_locked( + alloc->pid, extra_buffers_size); + return ERR_PTR(-EINVAL); + } +- if (is_async && +- alloc->free_async_space < size + sizeof(struct binder_buffer)) { ++ ++ /* Pad 0-size buffers so they get assigned unique addresses */ ++ size = max(size, sizeof(void *)); ++ ++ if (is_async && alloc->free_async_space < size) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd failed, no async space left\n", + alloc->pid, size); + return ERR_PTR(-ENOSPC); + } + +- /* Pad 0-size buffers so they get assigned unique addresses */ +- size = max(size, sizeof(void *)); +- + while (n) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + BUG_ON(!buffer->free); +@@ -519,7 +518,7 @@ static struct binder_buffer *binder_alloc_new_buf_locked( + buffer->pid = pid; + buffer->oneway_spam_suspect = false; + if (is_async) { +- alloc->free_async_space -= size + sizeof(struct binder_buffer); ++ alloc->free_async_space -= size; + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, + "%d: binder_alloc_buf size %zd async free %zd\n", + alloc->pid, size, alloc->free_async_space); +@@ -557,7 +556,7 @@ static struct binder_buffer *binder_alloc_new_buf_locked( + * is the sum of the three given sizes (each rounded up to + * pointer-sized boundary) + * +- * Return: The allocated buffer or %NULL if error ++ * Return: The allocated buffer or %ERR_PTR(-errno) if error + */ + struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, + size_t data_size, +@@ -657,8 +656,7 @@ static void binder_free_buf_locked(struct binder_alloc *alloc, + BUG_ON(buffer->user_data > alloc->buffer + alloc->buffer_size); + + if (buffer->async_transaction) { +- alloc->free_async_space += buffer_size + sizeof(struct binder_buffer); +- ++ alloc->free_async_space += buffer_size; + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, + "%d: binder_free_buf size %zd async free %zd\n", + alloc->pid, size, alloc->free_async_space); +@@ -706,7 +704,7 @@ void binder_alloc_free_buf(struct binder_alloc *alloc, + /* + * We could eliminate the call to binder_alloc_clear_buf() + * from binder_alloc_deferred_release() by moving this to +- * binder_alloc_free_buf_locked(). However, that could ++ * binder_free_buf_locked(). However, that could + * increase contention for the alloc mutex if clear_on_free + * is used frequently for large buffers. The mutex is not + * needed for correctness here. +@@ -1005,7 +1003,9 @@ enum lru_status binder_alloc_free_page(struct list_head *item, + goto err_mmget; + if (!mmap_read_trylock(mm)) + goto err_mmap_read_lock_failed; +- vma = binder_alloc_get_vma(alloc); ++ vma = vma_lookup(mm, page_addr); ++ if (vma && vma != binder_alloc_get_vma(alloc)) ++ goto err_invalid_vma; + + list_lru_isolate(lru, item); + spin_unlock(lock); +@@ -1031,6 +1031,8 @@ enum lru_status binder_alloc_free_page(struct list_head *item, + mutex_unlock(&alloc->mutex); + return LRU_REMOVED_RETRY; + ++err_invalid_vma: ++ mmap_read_unlock(mm); + err_mmap_read_lock_failed: + mmput_async(mm); + err_mmget: +diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h +index 7270d4d2220702..5b7c80b99ae865 100644 +--- a/drivers/android/binder_internal.h ++++ b/drivers/android/binder_internal.h +@@ -421,7 +421,7 @@ struct binder_proc { + struct list_head todo; + struct binder_stats stats; + struct list_head delivered_death; +- int max_threads; ++ u32 max_threads; + int requested_threads; + int requested_threads_started; + int tmp_ref; +diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c +index 08745e7db8201f..6e76780fb43083 100644 +--- a/drivers/ata/ahci.c ++++ b/drivers/ata/ahci.c +@@ -48,6 +48,7 @@ enum { + enum board_ids { + /* board IDs by feature in alphabetical order */ + board_ahci, ++ board_ahci_43bit_dma, + board_ahci_ign_iferr, + board_ahci_low_power, + board_ahci_no_debounce_delay, +@@ -128,6 +129,13 @@ static const struct ata_port_info ahci_port_info[] = { + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, ++ [board_ahci_43bit_dma] = { ++ AHCI_HFLAGS (AHCI_HFLAG_43BIT_ONLY), ++ .flags = AHCI_FLAG_COMMON, ++ .pio_mask = ATA_PIO4, ++ .udma_mask = ATA_UDMA6, ++ .port_ops = &ahci_ops, ++ }, + [board_ahci_ign_iferr] = { + AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), + .flags = AHCI_FLAG_COMMON, +@@ -596,14 +604,19 @@ static const struct pci_device_id ahci_pci_tbl[] = { + { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */ + { PCI_VDEVICE(PROMISE, 0x3781), board_ahci }, /* FastTrak TX8660 ahci-mode */ + +- /* Asmedia */ +- { PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci }, /* ASM1060 */ +- { PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci }, /* ASM1060 */ +- { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */ +- { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */ +- { PCI_VDEVICE(ASMEDIA, 0x0621), board_ahci }, /* ASM1061R */ +- { PCI_VDEVICE(ASMEDIA, 0x0622), board_ahci }, /* ASM1062R */ +- { PCI_VDEVICE(ASMEDIA, 0x0624), board_ahci }, /* ASM1062+JMB575 */ ++ /* ASMedia */ ++ { PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci_43bit_dma }, /* ASM1060 */ ++ { PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci_43bit_dma }, /* ASM1060 */ ++ { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci_43bit_dma }, /* ASM1061 */ ++ { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci_43bit_dma }, /* ASM1061/1062 */ ++ { PCI_VDEVICE(ASMEDIA, 0x0621), board_ahci_43bit_dma }, /* ASM1061R */ ++ { PCI_VDEVICE(ASMEDIA, 0x0622), board_ahci_43bit_dma }, /* ASM1062R */ ++ { PCI_VDEVICE(ASMEDIA, 0x0624), board_ahci_43bit_dma }, /* ASM1062+JMB575 */ ++ { PCI_VDEVICE(ASMEDIA, 0x1062), board_ahci }, /* ASM1062A */ ++ { PCI_VDEVICE(ASMEDIA, 0x1064), board_ahci }, /* ASM1064 */ ++ { PCI_VDEVICE(ASMEDIA, 0x1164), board_ahci }, /* ASM1164 */ ++ { PCI_VDEVICE(ASMEDIA, 0x1165), board_ahci }, /* ASM1165 */ ++ { PCI_VDEVICE(ASMEDIA, 0x1166), board_ahci }, /* ASM1166 */ + + /* + * Samsung SSDs found on some macbooks. NCQ times out if MSI is +@@ -654,6 +667,87 @@ static int mobile_lpm_policy = -1; + module_param(mobile_lpm_policy, int, 0644); + MODULE_PARM_DESC(mobile_lpm_policy, "Default LPM policy for mobile chipsets"); + ++static char *ahci_mask_port_map; ++module_param_named(mask_port_map, ahci_mask_port_map, charp, 0444); ++MODULE_PARM_DESC(mask_port_map, ++ "32-bits port map masks to ignore controllers ports. " ++ "Valid values are: " ++ "\"\" to apply the same mask to all AHCI controller " ++ "devices, and \"=,=,...\" to " ++ "specify different masks for the controllers specified, " ++ "where is the PCI ID of an AHCI controller in the " ++ "form \"domain:bus:dev.func\""); ++ ++static void ahci_apply_port_map_mask(struct device *dev, ++ struct ahci_host_priv *hpriv, char *mask_s) ++{ ++ unsigned int mask; ++ ++ if (kstrtouint(mask_s, 0, &mask)) { ++ dev_err(dev, "Invalid port map mask\n"); ++ return; ++ } ++ ++ hpriv->mask_port_map = mask; ++} ++ ++static void ahci_get_port_map_mask(struct device *dev, ++ struct ahci_host_priv *hpriv) ++{ ++ char *param, *end, *str, *mask_s; ++ char *name; ++ ++ if (!strlen(ahci_mask_port_map)) ++ return; ++ ++ str = kstrdup(ahci_mask_port_map, GFP_KERNEL); ++ if (!str) ++ return; ++ ++ /* Handle single mask case */ ++ if (!strchr(str, '=')) { ++ ahci_apply_port_map_mask(dev, hpriv, str); ++ goto free; ++ } ++ ++ /* ++ * Mask list case: parse the parameter to apply the mask only if ++ * the device name matches. ++ */ ++ param = str; ++ end = param + strlen(param); ++ while (param && param < end && *param) { ++ name = param; ++ param = strchr(name, '='); ++ if (!param) ++ break; ++ ++ *param = '\0'; ++ param++; ++ if (param >= end) ++ break; ++ ++ if (strcmp(dev_name(dev), name) != 0) { ++ param = strchr(param, ','); ++ if (param) ++ param++; ++ continue; ++ } ++ ++ mask_s = param; ++ param = strchr(mask_s, ','); ++ if (param) { ++ *param = '\0'; ++ param++; ++ } ++ ++ ahci_apply_port_map_mask(dev, hpriv, mask_s); ++ } ++ ++free: ++ kfree(str); ++} ++ + static void ahci_pci_save_initial_config(struct pci_dev *pdev, + struct ahci_host_priv *hpriv) + { +@@ -676,6 +770,10 @@ static void ahci_pci_save_initial_config(struct pci_dev *pdev, + "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n"); + } + ++ /* Handle port map masks passed as module parameter. */ ++ if (ahci_mask_port_map) ++ ahci_get_port_map_mask(&pdev->dev, hpriv); ++ + ahci_save_initial_config(&pdev->dev, hpriv); + } + +@@ -943,11 +1041,20 @@ static int ahci_pci_device_resume(struct device *dev) + + #endif /* CONFIG_PM */ + +-static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) ++static int ahci_configure_dma_masks(struct pci_dev *pdev, ++ struct ahci_host_priv *hpriv) + { +- const int dma_bits = using_dac ? 64 : 32; ++ int dma_bits; + int rc; + ++ if (hpriv->cap & HOST_CAP_64) { ++ dma_bits = 64; ++ if (hpriv->flags & AHCI_HFLAG_43BIT_ONLY) ++ dma_bits = 43; ++ } else { ++ dma_bits = 32; ++ } ++ + /* + * If the device fixup already set the dma_mask to some non-standard + * value, don't extend it here. This happens on STA2X11, for example. +@@ -1868,8 +1975,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); + + host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); +- if (!host) +- return -ENOMEM; ++ if (!host) { ++ rc = -ENOMEM; ++ goto err_rm_sysfs_file; ++ } + host->private_data = hpriv; + + if (ahci_init_msi(pdev, n_ports, hpriv) < 0) { +@@ -1920,13 +2029,13 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + ahci_gtf_filter_workaround(host); + + /* initialize adapter */ +- rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); ++ rc = ahci_configure_dma_masks(pdev, hpriv); + if (rc) +- return rc; ++ goto err_rm_sysfs_file; + + rc = ahci_pci_reset_controller(host); + if (rc) +- return rc; ++ goto err_rm_sysfs_file; + + ahci_pci_init_controller(host); + ahci_pci_print_info(host); +@@ -1935,10 +2044,15 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + + rc = ahci_host_activate(host, &ahci_sht); + if (rc) +- return rc; ++ goto err_rm_sysfs_file; + + pm_runtime_put_noidle(&pdev->dev); + return 0; ++ ++err_rm_sysfs_file: ++ sysfs_remove_file_from_group(&pdev->dev.kobj, ++ &dev_attr_remapped_nvme.attr, NULL); ++ return rc; + } + + static void ahci_shutdown_one(struct pci_dev *pdev) +diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h +index 4bae95b06ae3c9..df8f8a1a3a34c3 100644 +--- a/drivers/ata/ahci.h ++++ b/drivers/ata/ahci.h +@@ -247,6 +247,7 @@ enum { + AHCI_HFLAG_SUSPEND_PHYS = BIT(26), /* handle PHYs during + suspend/resume */ + AHCI_HFLAG_NO_SXS = BIT(28), /* SXS not supported */ ++ AHCI_HFLAG_43BIT_ONLY = BIT(29), /* 43bit DMA addr limit */ + + /* ap->flags bits */ + +diff --git a/drivers/ata/ahci_ceva.c b/drivers/ata/ahci_ceva.c +index 64f7f7d6ba84e0..11a2c199a7c246 100644 +--- a/drivers/ata/ahci_ceva.c ++++ b/drivers/ata/ahci_ceva.c +@@ -88,7 +88,6 @@ struct ceva_ahci_priv { + u32 axicc; + bool is_cci_enabled; + int flags; +- struct reset_control *rst; + }; + + static unsigned int ceva_ahci_read_id(struct ata_device *dev, +@@ -189,6 +188,60 @@ static const struct scsi_host_template ahci_platform_sht = { + AHCI_SHT(DRV_NAME), + }; + ++static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv) ++{ ++ int rc, i; ++ ++ rc = ahci_platform_enable_regulators(hpriv); ++ if (rc) ++ return rc; ++ ++ rc = ahci_platform_enable_clks(hpriv); ++ if (rc) ++ goto disable_regulator; ++ ++ /* Assert the controller reset */ ++ rc = ahci_platform_assert_rsts(hpriv); ++ if (rc) ++ goto disable_clks; ++ ++ for (i = 0; i < hpriv->nports; i++) { ++ rc = phy_init(hpriv->phys[i]); ++ if (rc) ++ goto disable_rsts; ++ } ++ ++ /* De-assert the controller reset */ ++ ahci_platform_deassert_rsts(hpriv); ++ ++ for (i = 0; i < hpriv->nports; i++) { ++ rc = phy_power_on(hpriv->phys[i]); ++ if (rc) { ++ phy_exit(hpriv->phys[i]); ++ goto disable_phys; ++ } ++ } ++ ++ return 0; ++ ++disable_rsts: ++ ahci_platform_deassert_rsts(hpriv); ++ ++disable_phys: ++ while (--i >= 0) { ++ phy_power_off(hpriv->phys[i]); ++ phy_exit(hpriv->phys[i]); ++ } ++ ++disable_clks: ++ ahci_platform_disable_clks(hpriv); ++ ++disable_regulator: ++ ahci_platform_disable_regulators(hpriv); ++ ++ return rc; ++} ++ + static int ceva_ahci_probe(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; +@@ -203,47 +256,19 @@ static int ceva_ahci_probe(struct platform_device *pdev) + return -ENOMEM; + + cevapriv->ahci_pdev = pdev; +- +- cevapriv->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, +- NULL); +- if (IS_ERR(cevapriv->rst)) +- dev_err_probe(&pdev->dev, PTR_ERR(cevapriv->rst), +- "failed to get reset\n"); +- + hpriv = ahci_platform_get_resources(pdev, 0); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); + +- if (!cevapriv->rst) { +- rc = ahci_platform_enable_resources(hpriv); +- if (rc) +- return rc; +- } else { +- int i; ++ hpriv->rsts = devm_reset_control_get_optional_exclusive(&pdev->dev, ++ NULL); ++ if (IS_ERR(hpriv->rsts)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(hpriv->rsts), ++ "failed to get reset\n"); + +- rc = ahci_platform_enable_clks(hpriv); +- if (rc) +- return rc; +- /* Assert the controller reset */ +- reset_control_assert(cevapriv->rst); +- +- for (i = 0; i < hpriv->nports; i++) { +- rc = phy_init(hpriv->phys[i]); +- if (rc) +- return rc; +- } +- +- /* De-assert the controller reset */ +- reset_control_deassert(cevapriv->rst); +- +- for (i = 0; i < hpriv->nports; i++) { +- rc = phy_power_on(hpriv->phys[i]); +- if (rc) { +- phy_exit(hpriv->phys[i]); +- return rc; +- } +- } +- } ++ rc = ceva_ahci_platform_enable_resources(hpriv); ++ if (rc) ++ return rc; + + if (of_property_read_bool(np, "ceva,broken-gen2")) + cevapriv->flags = CEVA_FLAG_BROKEN_GEN2; +@@ -252,52 +277,60 @@ static int ceva_ahci_probe(struct platform_device *pdev) + if (of_property_read_u8_array(np, "ceva,p0-cominit-params", + (u8 *)&cevapriv->pp2c[0], 4) < 0) { + dev_warn(dev, "ceva,p0-cominit-params property not defined\n"); +- return -EINVAL; ++ rc = -EINVAL; ++ goto disable_resources; + } + + if (of_property_read_u8_array(np, "ceva,p1-cominit-params", + (u8 *)&cevapriv->pp2c[1], 4) < 0) { + dev_warn(dev, "ceva,p1-cominit-params property not defined\n"); +- return -EINVAL; ++ rc = -EINVAL; ++ goto disable_resources; + } + + /* Read OOB timing value for COMWAKE from device-tree*/ + if (of_property_read_u8_array(np, "ceva,p0-comwake-params", + (u8 *)&cevapriv->pp3c[0], 4) < 0) { + dev_warn(dev, "ceva,p0-comwake-params property not defined\n"); +- return -EINVAL; ++ rc = -EINVAL; ++ goto disable_resources; + } + + if (of_property_read_u8_array(np, "ceva,p1-comwake-params", + (u8 *)&cevapriv->pp3c[1], 4) < 0) { + dev_warn(dev, "ceva,p1-comwake-params property not defined\n"); +- return -EINVAL; ++ rc = -EINVAL; ++ goto disable_resources; + } + + /* Read phy BURST timing value from device-tree */ + if (of_property_read_u8_array(np, "ceva,p0-burst-params", + (u8 *)&cevapriv->pp4c[0], 4) < 0) { + dev_warn(dev, "ceva,p0-burst-params property not defined\n"); +- return -EINVAL; ++ rc = -EINVAL; ++ goto disable_resources; + } + + if (of_property_read_u8_array(np, "ceva,p1-burst-params", + (u8 *)&cevapriv->pp4c[1], 4) < 0) { + dev_warn(dev, "ceva,p1-burst-params property not defined\n"); +- return -EINVAL; ++ rc = -EINVAL; ++ goto disable_resources; + } + + /* Read phy RETRY interval timing value from device-tree */ + if (of_property_read_u16_array(np, "ceva,p0-retry-params", + (u16 *)&cevapriv->pp5c[0], 2) < 0) { + dev_warn(dev, "ceva,p0-retry-params property not defined\n"); +- return -EINVAL; ++ rc = -EINVAL; ++ goto disable_resources; + } + + if (of_property_read_u16_array(np, "ceva,p1-retry-params", + (u16 *)&cevapriv->pp5c[1], 2) < 0) { + dev_warn(dev, "ceva,p1-retry-params property not defined\n"); +- return -EINVAL; ++ rc = -EINVAL; ++ goto disable_resources; + } + + /* +@@ -335,7 +368,7 @@ static int __maybe_unused ceva_ahci_resume(struct device *dev) + struct ahci_host_priv *hpriv = host->private_data; + int rc; + +- rc = ahci_platform_enable_resources(hpriv); ++ rc = ceva_ahci_platform_enable_resources(hpriv); + if (rc) + return rc; + +diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c +index d8cc1e27a125f0..4ed90d46a017a8 100644 +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -2034,6 +2034,10 @@ void ata_dev_power_set_active(struct ata_device *dev) + struct ata_taskfile tf; + unsigned int err_mask; + ++ /* If the device is already sleeping, do nothing. */ ++ if (dev->flags & ATA_DFLAG_SLEEPING) ++ return; ++ + /* + * Issue READ VERIFY SECTORS command for 1 sector at lba=0 only + * if supported by the device. +@@ -2489,7 +2493,7 @@ static void ata_dev_config_cdl(struct ata_device *dev) + bool cdl_enabled; + u64 val; + +- if (ata_id_major_version(dev->id) < 12) ++ if (ata_id_major_version(dev->id) < 11) + goto not_supported; + + if (!ata_log_supported(dev, ATA_LOG_IDENTIFY_DEVICE) || +@@ -5495,6 +5499,18 @@ struct ata_port *ata_port_alloc(struct ata_host *host) + return ap; + } + ++void ata_port_free(struct ata_port *ap) ++{ ++ if (!ap) ++ return; ++ ++ kfree(ap->pmp_link); ++ kfree(ap->slave_link); ++ kfree(ap->ncq_sense_buf); ++ kfree(ap); ++} ++EXPORT_SYMBOL_GPL(ata_port_free); ++ + static void ata_devres_release(struct device *gendev, void *res) + { + struct ata_host *host = dev_get_drvdata(gendev); +@@ -5521,12 +5537,7 @@ static void ata_host_release(struct kref *kref) + int i; + + for (i = 0; i < host->n_ports; i++) { +- struct ata_port *ap = host->ports[i]; +- +- kfree(ap->pmp_link); +- kfree(ap->slave_link); +- kfree(ap->ncq_sense_buf); +- kfree(ap); ++ ata_port_free(host->ports[i]); + host->ports[i] = NULL; + } + kfree(host); +@@ -5576,12 +5587,16 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports) + if (!host) + return NULL; + +- if (!devres_open_group(dev, NULL, GFP_KERNEL)) +- goto err_free; ++ if (!devres_open_group(dev, NULL, GFP_KERNEL)) { ++ kfree(host); ++ return NULL; ++ } + + dr = devres_alloc(ata_devres_release, 0, GFP_KERNEL); +- if (!dr) ++ if (!dr) { ++ kfree(host); + goto err_out; ++ } + + devres_add(dev, dr); + dev_set_drvdata(dev, host); +@@ -5609,8 +5624,6 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports) + + err_out: + devres_release_group(dev, NULL); +- err_free: +- kfree(host); + return NULL; + } + EXPORT_SYMBOL_GPL(ata_host_alloc); +@@ -5909,7 +5922,7 @@ int ata_host_register(struct ata_host *host, const struct scsi_host_template *sh + * allocation time. + */ + for (i = host->n_ports; host->ports[i]; i++) +- kfree(host->ports[i]); ++ ata_port_free(host->ports[i]); + + /* give ports names and add SCSI hosts */ + for (i = 0; i < host->n_ports; i++) { +diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c +index 5686353e442cf4..a96566e1b2b84c 100644 +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -618,6 +618,14 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, + list_for_each_entry_safe(scmd, tmp, eh_work_q, eh_entry) { + struct ata_queued_cmd *qc; + ++ /* ++ * If the scmd was added to EH, via ata_qc_schedule_eh() -> ++ * scsi_timeout() -> scsi_eh_scmd_add(), scsi_timeout() will ++ * have set DID_TIME_OUT (since libata does not have an abort ++ * handler). Thus, to clear DID_TIME_OUT, clear the host byte. ++ */ ++ set_host_byte(scmd, DID_OK); ++ + ata_qc_for_each_raw(ap, qc, i) { + if (qc->flags & ATA_QCFLAG_ACTIVE && + qc->scsicmd == scmd) +@@ -700,8 +708,10 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) + ehc->saved_ncq_enabled |= 1 << devno; + + /* If we are resuming, wake up the device */ +- if (ap->pflags & ATA_PFLAG_RESUMING) ++ if (ap->pflags & ATA_PFLAG_RESUMING) { ++ dev->flags |= ATA_DFLAG_RESUMING; + ehc->i.dev_action[devno] |= ATA_EH_SET_ACTIVE; ++ } + } + } + +@@ -3170,6 +3180,7 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, + return 0; + + err: ++ dev->flags &= ~ATA_DFLAG_RESUMING; + *r_failed_dev = dev; + return rc; + } +@@ -4038,10 +4049,20 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap) + + WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED); + +- /* Set all devices attached to the port in standby mode */ +- ata_for_each_link(link, ap, HOST_FIRST) { +- ata_for_each_dev(dev, link, ENABLED) +- ata_dev_power_set_standby(dev); ++ /* ++ * We will reach this point for all of the PM events: ++ * PM_EVENT_SUSPEND (if runtime pm, PM_EVENT_AUTO will also be set) ++ * PM_EVENT_FREEZE, and PM_EVENT_HIBERNATE. ++ * ++ * We do not want to perform disk spin down for PM_EVENT_FREEZE. ++ * (Spin down will be performed by the subsequent PM_EVENT_HIBERNATE.) ++ */ ++ if (!(ap->pm_mesg.event & PM_EVENT_FREEZE)) { ++ /* Set all devices attached to the port in standby mode */ ++ ata_for_each_link(link, ap, HOST_FIRST) { ++ ata_for_each_dev(dev, link, ENABLED) ++ ata_dev_power_set_standby(dev); ++ } + } + + /* +diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c +index 3a957c4da40927..5377d094bf7548 100644 +--- a/drivers/ata/libata-scsi.c ++++ b/drivers/ata/libata-scsi.c +@@ -230,6 +230,87 @@ void ata_scsi_set_sense_information(struct ata_device *dev, + SCSI_SENSE_BUFFERSIZE, information); + } + ++/** ++ * ata_scsi_set_passthru_sense_fields - Set ATA fields in sense buffer ++ * @qc: ATA PASS-THROUGH command. ++ * ++ * Populates "ATA Status Return sense data descriptor" / "Fixed format ++ * sense data" with ATA taskfile fields. ++ * ++ * LOCKING: ++ * None. ++ */ ++static void ata_scsi_set_passthru_sense_fields(struct ata_queued_cmd *qc) ++{ ++ struct ata_device *dev = qc->dev; ++ struct scsi_cmnd *cmd = qc->scsicmd; ++ struct ata_taskfile *tf = &qc->result_tf; ++ unsigned char *sb = cmd->sense_buffer; ++ ++ if (!(qc->flags & ATA_QCFLAG_RTF_FILLED)) { ++ ata_dev_dbg(dev, ++ "missing result TF: can't set ATA PT sense fields\n"); ++ return; ++ } ++ ++ if ((sb[0] & 0x7f) >= 0x72) { ++ unsigned char *desc; ++ u8 len; ++ ++ /* descriptor format */ ++ len = sb[7]; ++ desc = (char *)scsi_sense_desc_find(sb, len + 8, 9); ++ if (!desc) { ++ if (SCSI_SENSE_BUFFERSIZE < len + 14) ++ return; ++ sb[7] = len + 14; ++ desc = sb + 8 + len; ++ } ++ desc[0] = 9; ++ desc[1] = 12; ++ /* ++ * Copy registers into sense buffer. ++ */ ++ desc[2] = 0x00; ++ desc[3] = tf->error; ++ desc[5] = tf->nsect; ++ desc[7] = tf->lbal; ++ desc[9] = tf->lbam; ++ desc[11] = tf->lbah; ++ desc[12] = tf->device; ++ desc[13] = tf->status; ++ ++ /* ++ * Fill in Extend bit, and the high order bytes ++ * if applicable. ++ */ ++ if (tf->flags & ATA_TFLAG_LBA48) { ++ desc[2] |= 0x01; ++ desc[4] = tf->hob_nsect; ++ desc[6] = tf->hob_lbal; ++ desc[8] = tf->hob_lbam; ++ desc[10] = tf->hob_lbah; ++ } ++ } else { ++ /* Fixed sense format */ ++ sb[0] |= 0x80; ++ sb[3] = tf->error; ++ sb[4] = tf->status; ++ sb[5] = tf->device; ++ sb[6] = tf->nsect; ++ if (tf->flags & ATA_TFLAG_LBA48) { ++ sb[8] |= 0x80; ++ if (tf->hob_nsect) ++ sb[8] |= 0x40; ++ if (tf->hob_lbal || tf->hob_lbam || tf->hob_lbah) ++ sb[8] |= 0x20; ++ } ++ sb[9] = tf->lbal; ++ sb[10] = tf->lbam; ++ sb[11] = tf->lbah; ++ } ++} ++ + static void ata_scsi_set_invalid_field(struct ata_device *dev, + struct scsi_cmnd *cmd, u16 field, u8 bit) + { +@@ -837,10 +918,8 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, + * ata_gen_passthru_sense - Generate check condition sense block. + * @qc: Command that completed. + * +- * This function is specific to the ATA descriptor format sense +- * block specified for the ATA pass through commands. Regardless +- * of whether the command errored or not, return a sense +- * block. Copy all controller registers into the sense ++ * This function is specific to the ATA pass through commands. ++ * Regardless of whether the command errored or not, return a sense + * block. If there was no error, we get the request from an ATA + * passthrough command, so we use the following sense data: + * sk = RECOVERED ERROR +@@ -852,13 +931,16 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, + */ + static void ata_gen_passthru_sense(struct ata_queued_cmd *qc) + { ++ struct ata_device *dev = qc->dev; + struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_taskfile *tf = &qc->result_tf; +- unsigned char *sb = cmd->sense_buffer; +- unsigned char *desc = sb + 8; + u8 sense_key, asc, ascq; + +- memset(sb, 0, SCSI_SENSE_BUFFERSIZE); ++ if (!(qc->flags & ATA_QCFLAG_RTF_FILLED)) { ++ ata_dev_dbg(dev, ++ "missing result TF: can't generate ATA PT sense data\n"); ++ return; ++ } + + /* + * Use ata_to_sense_error() to map status register bits +@@ -872,66 +954,18 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc) + } else { + /* + * ATA PASS-THROUGH INFORMATION AVAILABLE +- * Always in descriptor format sense. ++ * ++ * Note: we are supposed to call ata_scsi_set_sense(), which ++ * respects the D_SENSE bit, instead of unconditionally ++ * generating the sense data in descriptor format. However, ++ * because hdparm, hddtemp, and udisks incorrectly assume sense ++ * data in descriptor format, without even looking at the ++ * RESPONSE CODE field in the returned sense data (to see which ++ * format the returned sense data is in), we are stuck with ++ * being bug compatible with older kernels. + */ + scsi_build_sense(cmd, 1, RECOVERED_ERROR, 0, 0x1D); + } +- +- if ((cmd->sense_buffer[0] & 0x7f) >= 0x72) { +- u8 len; +- +- /* descriptor format */ +- len = sb[7]; +- desc = (char *)scsi_sense_desc_find(sb, len + 8, 9); +- if (!desc) { +- if (SCSI_SENSE_BUFFERSIZE < len + 14) +- return; +- sb[7] = len + 14; +- desc = sb + 8 + len; +- } +- desc[0] = 9; +- desc[1] = 12; +- /* +- * Copy registers into sense buffer. +- */ +- desc[2] = 0x00; +- desc[3] = tf->error; +- desc[5] = tf->nsect; +- desc[7] = tf->lbal; +- desc[9] = tf->lbam; +- desc[11] = tf->lbah; +- desc[12] = tf->device; +- desc[13] = tf->status; +- +- /* +- * Fill in Extend bit, and the high order bytes +- * if applicable. +- */ +- if (tf->flags & ATA_TFLAG_LBA48) { +- desc[2] |= 0x01; +- desc[4] = tf->hob_nsect; +- desc[6] = tf->hob_lbal; +- desc[8] = tf->hob_lbam; +- desc[10] = tf->hob_lbah; +- } +- } else { +- /* Fixed sense format */ +- desc[0] = tf->error; +- desc[1] = tf->status; +- desc[2] = tf->device; +- desc[3] = tf->nsect; +- desc[7] = 0; +- if (tf->flags & ATA_TFLAG_LBA48) { +- desc[8] |= 0x80; +- if (tf->hob_nsect) +- desc[8] |= 0x40; +- if (tf->hob_lbal || tf->hob_lbam || tf->hob_lbah) +- desc[8] |= 0x20; +- } +- desc[9] = tf->lbal; +- desc[10] = tf->lbam; +- desc[11] = tf->lbah; +- } + } + + /** +@@ -953,14 +987,19 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc) + u64 block; + u8 sense_key, asc, ascq; + +- memset(sb, 0, SCSI_SENSE_BUFFERSIZE); +- + if (ata_dev_disabled(dev)) { + /* Device disabled after error recovery */ + /* LOGICAL UNIT NOT READY, HARD RESET REQUIRED */ + ata_scsi_set_sense(dev, cmd, NOT_READY, 0x04, 0x21); + return; + } ++ ++ if (!(qc->flags & ATA_QCFLAG_RTF_FILLED)) { ++ ata_dev_dbg(dev, ++ "missing result TF: can't generate sense data\n"); ++ return; ++ } ++ + /* Use ata_to_sense_error() to map status register bits + * onto sense key, asc & ascq. + */ +@@ -1055,9 +1094,14 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev) + * Ask the sd driver to issue START STOP UNIT on runtime suspend + * and resume and shutdown only. For system level suspend/resume, + * devices power state is handled directly by libata EH. ++ * Given that disks are always spun up on system resume, also ++ * make sure that the sd driver forces runtime suspended disks ++ * to be resumed to correctly reflect the power state of the ++ * device. + */ +- sdev->manage_runtime_start_stop = true; +- sdev->manage_shutdown = true; ++ sdev->manage_runtime_start_stop = 1; ++ sdev->manage_shutdown = 1; ++ sdev->force_runtime_start_on_system_start = 1; + } + + /* +@@ -1659,26 +1703,29 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) + { + struct scsi_cmnd *cmd = qc->scsicmd; + u8 *cdb = cmd->cmnd; +- int need_sense = (qc->err_mask != 0) && +- !(qc->flags & ATA_QCFLAG_SENSE_VALID); ++ bool have_sense = qc->flags & ATA_QCFLAG_SENSE_VALID; ++ bool is_ata_passthru = cdb[0] == ATA_16 || cdb[0] == ATA_12; ++ bool is_ck_cond_request = cdb[2] & 0x20; ++ bool is_error = qc->err_mask != 0; + + /* For ATA pass thru (SAT) commands, generate a sense block if + * user mandated it or if there's an error. Note that if we +- * generate because the user forced us to [CK_COND =1], a check ++ * generate because the user forced us to [CK_COND=1], a check + * condition is generated and the ATA register values are returned + * whether the command completed successfully or not. If there +- * was no error, we use the following sense data: ++ * was no error, and CK_COND=1, we use the following sense data: + * sk = RECOVERED ERROR + * asc,ascq = ATA PASS-THROUGH INFORMATION AVAILABLE + */ +- if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) && +- ((cdb[2] & 0x20) || need_sense)) +- ata_gen_passthru_sense(qc); +- else if (need_sense) ++ if (is_ata_passthru && (is_ck_cond_request || is_error || have_sense)) { ++ if (!have_sense) ++ ata_gen_passthru_sense(qc); ++ ata_scsi_set_passthru_sense_fields(qc); ++ if (is_ck_cond_request) ++ set_status_byte(qc->scsicmd, SAM_STAT_CHECK_CONDITION); ++ } else if (is_error && !have_sense) { + ata_gen_ata_sense(qc); +- else +- /* Keep the SCSI ML and status byte, clear host byte. */ +- cmd->result &= 0x0000ffff; ++ } + + ata_qc_done(qc); + } +@@ -2343,7 +2390,7 @@ static unsigned int ata_msense_control(struct ata_device *dev, u8 *buf, + case ALL_SUB_MPAGES: + n = ata_msense_control_spg0(dev, buf, changeable); + n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE); +- n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE); ++ n += ata_msense_control_spgt2(dev, buf + n, CDL_T2B_SUB_MPAGE); + n += ata_msense_control_ata_feature(dev, buf + n); + return n; + default: +@@ -2617,14 +2664,8 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) + /* handle completion from EH */ + if (unlikely(err_mask || qc->flags & ATA_QCFLAG_SENSE_VALID)) { + +- if (!(qc->flags & ATA_QCFLAG_SENSE_VALID)) { +- /* FIXME: not quite right; we don't want the +- * translation of taskfile registers into a +- * sense descriptors, since that's only +- * correct for ATA, not ATAPI +- */ ++ if (!(qc->flags & ATA_QCFLAG_SENSE_VALID)) + ata_gen_passthru_sense(qc); +- } + + /* SCSI EH automatically locks door if sdev->locked is + * set. Sometimes door lock request continues to +@@ -4760,6 +4801,7 @@ void ata_scsi_dev_rescan(struct work_struct *work) + struct ata_link *link; + struct ata_device *dev; + unsigned long flags; ++ bool do_resume; + int ret = 0; + + mutex_lock(&ap->scsi_scan_mutex); +@@ -4774,25 +4816,34 @@ void ata_scsi_dev_rescan(struct work_struct *work) + * bail out. + */ + if (ap->pflags & ATA_PFLAG_SUSPENDED) +- goto unlock; ++ goto unlock_ap; + + if (!sdev) + continue; + if (scsi_device_get(sdev)) + continue; + ++ do_resume = dev->flags & ATA_DFLAG_RESUMING; ++ + spin_unlock_irqrestore(ap->lock, flags); ++ if (do_resume) { ++ ret = scsi_resume_device(sdev); ++ if (ret == -EWOULDBLOCK) ++ goto unlock_scan; ++ dev->flags &= ~ATA_DFLAG_RESUMING; ++ } + ret = scsi_rescan_device(sdev); + scsi_device_put(sdev); + spin_lock_irqsave(ap->lock, flags); + + if (ret) +- goto unlock; ++ goto unlock_ap; + } + } + +-unlock: ++unlock_ap: + spin_unlock_irqrestore(ap->lock, flags); ++unlock_scan: + mutex_unlock(&ap->scsi_scan_mutex); + + /* Reschedule with a delay if scsi_rescan_device() returned an error */ +diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c +index 25a63d043c8e1f..0f77e042406619 100644 +--- a/drivers/ata/pata_isapnp.c ++++ b/drivers/ata/pata_isapnp.c +@@ -82,6 +82,9 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev + if (pnp_port_valid(idev, 1)) { + ctl_addr = devm_ioport_map(&idev->dev, + pnp_port_start(idev, 1), 1); ++ if (!ctl_addr) ++ return -ENOMEM; ++ + ap->ioaddr.altstatus_addr = ctl_addr; + ap->ioaddr.ctl_addr = ctl_addr; + ap->ops = &isapnp_port_ops; +diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c +index 448a511cbc179a..e7ac142c2423dd 100644 +--- a/drivers/ata/pata_legacy.c ++++ b/drivers/ata/pata_legacy.c +@@ -173,8 +173,6 @@ static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 }; + static struct legacy_probe probe_list[NR_HOST]; + static struct legacy_data legacy_data[NR_HOST]; + static struct ata_host *legacy_host[NR_HOST]; +-static int nr_legacy_host; +- + + /** + * legacy_probe_add - Add interface to probe list +@@ -1276,9 +1274,11 @@ static __exit void legacy_exit(void) + { + int i; + +- for (i = 0; i < nr_legacy_host; i++) { ++ for (i = 0; i < NR_HOST; i++) { + struct legacy_data *ld = &legacy_data[i]; +- ata_host_detach(legacy_host[i]); ++ ++ if (legacy_host[i]) ++ ata_host_detach(legacy_host[i]); + platform_device_unregister(ld->platform_dev); + } + } +diff --git a/drivers/ata/pata_macio.c b/drivers/ata/pata_macio.c +index 17f6ccee53c7c2..ffbb2e8591cefc 100644 +--- a/drivers/ata/pata_macio.c ++++ b/drivers/ata/pata_macio.c +@@ -541,7 +541,8 @@ static enum ata_completion_errors pata_macio_qc_prep(struct ata_queued_cmd *qc) + + while (sg_len) { + /* table overflow should never happen */ +- BUG_ON (pi++ >= MAX_DCMDS); ++ if (WARN_ON_ONCE(pi >= MAX_DCMDS)) ++ return AC_ERR_SYSTEM; + + len = (sg_len < MAX_DBDMA_SEG) ? sg_len : MAX_DBDMA_SEG; + table->command = cpu_to_le16(write ? OUTPUT_MORE: INPUT_MORE); +@@ -553,11 +554,13 @@ static enum ata_completion_errors pata_macio_qc_prep(struct ata_queued_cmd *qc) + addr += len; + sg_len -= len; + ++table; ++ ++pi; + } + } + + /* Should never happen according to Tejun */ +- BUG_ON(!pi); ++ if (WARN_ON_ONCE(!pi)) ++ return AC_ERR_SYSTEM; + + /* Convert the last command to an input/output */ + table--; +diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c +index 549ff24a982311..4edddf6bcc1507 100644 +--- a/drivers/ata/pata_serverworks.c ++++ b/drivers/ata/pata_serverworks.c +@@ -46,10 +46,11 @@ + #define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ + #define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ + +-/* Seagate Barracuda ATA IV Family drives in UDMA mode 5 +- * can overrun their FIFOs when used with the CSB5 */ +- +-static const char *csb_bad_ata100[] = { ++/* ++ * Seagate Barracuda ATA IV Family drives in UDMA mode 5 ++ * can overrun their FIFOs when used with the CSB5. ++ */ ++static const char * const csb_bad_ata100[] = { + "ST320011A", + "ST340016A", + "ST360021A", +@@ -163,10 +164,11 @@ static unsigned int serverworks_osb4_filter(struct ata_device *adev, unsigned in + * @adev: ATA device + * @mask: Mask of proposed modes + * +- * Check the blacklist and disable UDMA5 if matched ++ * Check the list of devices with broken UDMA5 and ++ * disable UDMA5 if matched. + */ +- +-static unsigned int serverworks_csb_filter(struct ata_device *adev, unsigned int mask) ++static unsigned int serverworks_csb_filter(struct ata_device *adev, ++ unsigned int mask) + { + const char *p; + char model_num[ATA_ID_PROD_LEN + 1]; +diff --git a/drivers/ata/sata_gemini.c b/drivers/ata/sata_gemini.c +index 400b22ee99c33a..4c270999ba3ccd 100644 +--- a/drivers/ata/sata_gemini.c ++++ b/drivers/ata/sata_gemini.c +@@ -200,7 +200,10 @@ int gemini_sata_start_bridge(struct sata_gemini *sg, unsigned int bridge) + pclk = sg->sata0_pclk; + else + pclk = sg->sata1_pclk; +- clk_enable(pclk); ++ ret = clk_enable(pclk); ++ if (ret) ++ return ret; ++ + msleep(10); + + /* Do not keep clocking a bridge that is not online */ +diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c +index 45e48d653c60b5..80a45e11fb5b60 100644 +--- a/drivers/ata/sata_mv.c ++++ b/drivers/ata/sata_mv.c +@@ -787,37 +787,6 @@ static const struct ata_port_info mv_port_info[] = { + }, + }; + +-static const struct pci_device_id mv_pci_tbl[] = { +- { PCI_VDEVICE(MARVELL, 0x5040), chip_504x }, +- { PCI_VDEVICE(MARVELL, 0x5041), chip_504x }, +- { PCI_VDEVICE(MARVELL, 0x5080), chip_5080 }, +- { PCI_VDEVICE(MARVELL, 0x5081), chip_508x }, +- /* RocketRAID 1720/174x have different identifiers */ +- { PCI_VDEVICE(TTI, 0x1720), chip_6042 }, +- { PCI_VDEVICE(TTI, 0x1740), chip_6042 }, +- { PCI_VDEVICE(TTI, 0x1742), chip_6042 }, +- +- { PCI_VDEVICE(MARVELL, 0x6040), chip_604x }, +- { PCI_VDEVICE(MARVELL, 0x6041), chip_604x }, +- { PCI_VDEVICE(MARVELL, 0x6042), chip_6042 }, +- { PCI_VDEVICE(MARVELL, 0x6080), chip_608x }, +- { PCI_VDEVICE(MARVELL, 0x6081), chip_608x }, +- +- { PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x }, +- +- /* Adaptec 1430SA */ +- { PCI_VDEVICE(ADAPTEC2, 0x0243), chip_7042 }, +- +- /* Marvell 7042 support */ +- { PCI_VDEVICE(MARVELL, 0x7042), chip_7042 }, +- +- /* Highpoint RocketRAID PCIe series */ +- { PCI_VDEVICE(TTI, 0x2300), chip_7042 }, +- { PCI_VDEVICE(TTI, 0x2310), chip_7042 }, +- +- { } /* terminate list */ +-}; +- + static const struct mv_hw_ops mv5xxx_ops = { + .phy_errata = mv5_phy_errata, + .enable_leds = mv5_enable_leds, +@@ -4300,6 +4269,36 @@ static int mv_pci_init_one(struct pci_dev *pdev, + static int mv_pci_device_resume(struct pci_dev *pdev); + #endif + ++static const struct pci_device_id mv_pci_tbl[] = { ++ { PCI_VDEVICE(MARVELL, 0x5040), chip_504x }, ++ { PCI_VDEVICE(MARVELL, 0x5041), chip_504x }, ++ { PCI_VDEVICE(MARVELL, 0x5080), chip_5080 }, ++ { PCI_VDEVICE(MARVELL, 0x5081), chip_508x }, ++ /* RocketRAID 1720/174x have different identifiers */ ++ { PCI_VDEVICE(TTI, 0x1720), chip_6042 }, ++ { PCI_VDEVICE(TTI, 0x1740), chip_6042 }, ++ { PCI_VDEVICE(TTI, 0x1742), chip_6042 }, ++ ++ { PCI_VDEVICE(MARVELL, 0x6040), chip_604x }, ++ { PCI_VDEVICE(MARVELL, 0x6041), chip_604x }, ++ { PCI_VDEVICE(MARVELL, 0x6042), chip_6042 }, ++ { PCI_VDEVICE(MARVELL, 0x6080), chip_608x }, ++ { PCI_VDEVICE(MARVELL, 0x6081), chip_608x }, ++ ++ { PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x }, ++ ++ /* Adaptec 1430SA */ ++ { PCI_VDEVICE(ADAPTEC2, 0x0243), chip_7042 }, ++ ++ /* Marvell 7042 support */ ++ { PCI_VDEVICE(MARVELL, 0x7042), chip_7042 }, ++ ++ /* Highpoint RocketRAID PCIe series */ ++ { PCI_VDEVICE(TTI, 0x2300), chip_7042 }, ++ { PCI_VDEVICE(TTI, 0x2310), chip_7042 }, ++ ++ { } /* terminate list */ ++}; + + static struct pci_driver mv_pci_driver = { + .name = DRV_NAME, +@@ -4312,6 +4311,7 @@ static struct pci_driver mv_pci_driver = { + #endif + + }; ++MODULE_DEVICE_TABLE(pci, mv_pci_tbl); + + /** + * mv_print_info - Dump key info to kernel log for perusal. +@@ -4484,7 +4484,6 @@ static void __exit mv_exit(void) + MODULE_AUTHOR("Brett Russ"); + MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers"); + MODULE_LICENSE("GPL v2"); +-MODULE_DEVICE_TABLE(pci, mv_pci_tbl); + MODULE_VERSION(DRV_VERSION); + MODULE_ALIAS("platform:" DRV_NAME); + +diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c +index cc77c024828431..df095659bae0f5 100644 +--- a/drivers/ata/sata_sil.c ++++ b/drivers/ata/sata_sil.c +@@ -128,7 +128,7 @@ static const struct pci_device_id sil_pci_tbl[] = { + static const struct sil_drivelist { + const char *product; + unsigned int quirk; +-} sil_blacklist [] = { ++} sil_quirks[] = { + { "ST320012AS", SIL_QUIRK_MOD15WRITE }, + { "ST330013AS", SIL_QUIRK_MOD15WRITE }, + { "ST340017AS", SIL_QUIRK_MOD15WRITE }, +@@ -600,8 +600,8 @@ static void sil_thaw(struct ata_port *ap) + * list, and apply the fixups to only the specific + * devices/hosts/firmwares that need it. + * +- * 20040111 - Seagate drives affected by the Mod15Write bug are blacklisted +- * The Maxtor quirk is in the blacklist, but I'm keeping the original ++ * 20040111 - Seagate drives affected by the Mod15Write bug are quirked ++ * The Maxtor quirk is in sil_quirks, but I'm keeping the original + * pessimistic fix for the following reasons... + * - There seems to be less info on it, only one device gleaned off the + * Windows driver, maybe only one is affected. More info would be greatly +@@ -620,9 +620,9 @@ static void sil_dev_config(struct ata_device *dev) + + ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); + +- for (n = 0; sil_blacklist[n].product; n++) +- if (!strcmp(sil_blacklist[n].product, model_num)) { +- quirks = sil_blacklist[n].quirk; ++ for (n = 0; sil_quirks[n].product; n++) ++ if (!strcmp(sil_quirks[n].product, model_num)) { ++ quirks = sil_quirks[n].quirk; + break; + } + +diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c +index b51d7a9d0d90ce..a482741eb181ff 100644 +--- a/drivers/ata/sata_sx4.c ++++ b/drivers/ata/sata_sx4.c +@@ -957,8 +957,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource, + + offset -= (idx * window_size); + idx++; +- dist = ((long) (window_size - (offset + size))) >= 0 ? size : +- (long) (window_size - offset); ++ dist = min(size, window_size - offset); + memcpy_fromio(psource, dimm_mmio + offset / 4, dist); + + psource += dist; +@@ -1005,8 +1004,7 @@ static void pdc20621_put_to_dimm(struct ata_host *host, void *psource, + readl(mmio + PDC_DIMM_WINDOW_CTLR); + offset -= (idx * window_size); + idx++; +- dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size : +- (long) (window_size - offset); ++ dist = min(size, window_size - offset); + memcpy_toio(dimm_mmio + offset / 4, psource, dist); + writel(0x01, mmio + PDC_GENERAL_CTLR); + readl(mmio + PDC_GENERAL_CTLR); +diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c +index e327a0229dc173..a876024d8a05f9 100644 +--- a/drivers/atm/idt77252.c ++++ b/drivers/atm/idt77252.c +@@ -1118,8 +1118,8 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) + rpp->len += skb->len; + + if (stat & SAR_RSQE_EPDU) { ++ unsigned int len, truesize; + unsigned char *l1l2; +- unsigned int len; + + l1l2 = (unsigned char *) ((unsigned long) skb->data + skb->len - 6); + +@@ -1189,14 +1189,15 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) + ATM_SKB(skb)->vcc = vcc; + __net_timestamp(skb); + ++ truesize = skb->truesize; + vcc->push(vcc, skb); + atomic_inc(&vcc->stats->rx); + +- if (skb->truesize > SAR_FB_SIZE_3) ++ if (truesize > SAR_FB_SIZE_3) + add_rx_skb(card, 3, SAR_FB_SIZE_3, 1); +- else if (skb->truesize > SAR_FB_SIZE_2) ++ else if (truesize > SAR_FB_SIZE_2) + add_rx_skb(card, 2, SAR_FB_SIZE_2, 1); +- else if (skb->truesize > SAR_FB_SIZE_1) ++ else if (truesize > SAR_FB_SIZE_1) + add_rx_skb(card, 1, SAR_FB_SIZE_1, 1); + else + add_rx_skb(card, 0, SAR_FB_SIZE_0, 1); +@@ -2930,6 +2931,8 @@ open_card_ubr0(struct idt77252_dev *card) + vc->scq = alloc_scq(card, vc->class); + if (!vc->scq) { + printk("%s: can't get SCQ.\n", card->name); ++ kfree(card->vcs[0]); ++ card->vcs[0] = NULL; + return -ENOMEM; + } + +diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c +index 32414868695305..9bba8f280a4d4c 100644 +--- a/drivers/atm/iphase.c ++++ b/drivers/atm/iphase.c +@@ -2291,19 +2291,21 @@ static int get_esi(struct atm_dev *dev) + static int reset_sar(struct atm_dev *dev) + { + IADEV *iadev; +- int i, error = 1; ++ int i, error; + unsigned int pci[64]; + + iadev = INPH_IA_DEV(dev); +- for(i=0; i<64; i++) +- if ((error = pci_read_config_dword(iadev->pci, +- i*4, &pci[i])) != PCIBIOS_SUCCESSFUL) +- return error; ++ for (i = 0; i < 64; i++) { ++ error = pci_read_config_dword(iadev->pci, i * 4, &pci[i]); ++ if (error != PCIBIOS_SUCCESSFUL) ++ return error; ++ } + writel(0, iadev->reg+IPHASE5575_EXT_RESET); +- for(i=0; i<64; i++) +- if ((error = pci_write_config_dword(iadev->pci, +- i*4, pci[i])) != PCIBIOS_SUCCESSFUL) +- return error; ++ for (i = 0; i < 64; i++) { ++ error = pci_write_config_dword(iadev->pci, i * 4, pci[i]); ++ if (error != PCIBIOS_SUCCESSFUL) ++ return error; ++ } + udelay(5); + return 0; + } +diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c +index 94fbc3abe60e6a..d3c30a28c410ea 100644 +--- a/drivers/atm/solos-pci.c ++++ b/drivers/atm/solos-pci.c +@@ -449,9 +449,9 @@ static ssize_t console_show(struct device *dev, struct device_attribute *attr, + struct sk_buff *skb; + unsigned int len; + +- spin_lock(&card->cli_queue_lock); ++ spin_lock_bh(&card->cli_queue_lock); + skb = skb_dequeue(&card->cli_queue[SOLOS_CHAN(atmdev)]); +- spin_unlock(&card->cli_queue_lock); ++ spin_unlock_bh(&card->cli_queue_lock); + if(skb == NULL) + return sprintf(buf, "No data.\n"); + +@@ -956,14 +956,14 @@ static void pclose(struct atm_vcc *vcc) + struct pkt_hdr *header; + + /* Remove any yet-to-be-transmitted packets from the pending queue */ +- spin_lock(&card->tx_queue_lock); ++ spin_lock_bh(&card->tx_queue_lock); + skb_queue_walk_safe(&card->tx_queue[port], skb, tmpskb) { + if (SKB_CB(skb)->vcc == vcc) { + skb_unlink(skb, &card->tx_queue[port]); + solos_pop(vcc, skb); + } + } +- spin_unlock(&card->tx_queue_lock); ++ spin_unlock_bh(&card->tx_queue_lock); + + skb = alloc_skb(sizeof(*header), GFP_KERNEL); + if (!skb) { +diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c +index 3a2d883872249e..b360ddefc4238b 100644 +--- a/drivers/auxdisplay/ht16k33.c ++++ b/drivers/auxdisplay/ht16k33.c +@@ -507,6 +507,7 @@ static int ht16k33_led_probe(struct device *dev, struct led_classdev *led, + led->max_brightness = MAX_BRIGHTNESS; + + err = devm_led_classdev_register_ext(dev, led, &init_data); ++ fwnode_handle_put(init_data.fwnode); + if (err) + dev_err(dev, "Failed to register LED\n"); + +diff --git a/drivers/base/arch_numa.c b/drivers/base/arch_numa.c +index eaa31e567d1ece..5b59d133b6af4f 100644 +--- a/drivers/base/arch_numa.c ++++ b/drivers/base/arch_numa.c +@@ -144,7 +144,7 @@ void __init early_map_cpu_to_node(unsigned int cpu, int nid) + unsigned long __per_cpu_offset[NR_CPUS] __read_mostly; + EXPORT_SYMBOL(__per_cpu_offset); + +-static int __init early_cpu_to_node(int cpu) ++int __init early_cpu_to_node(int cpu) + { + return cpu_to_node_map[cpu]; + } +diff --git a/drivers/base/base.h b/drivers/base/base.h +index eb4c0ace924201..a8e3d8165232fd 100644 +--- a/drivers/base/base.h ++++ b/drivers/base/base.h +@@ -192,11 +192,14 @@ extern struct kset *devices_kset; + void devices_kset_move_last(struct device *dev); + + #if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS) +-void module_add_driver(struct module *mod, struct device_driver *drv); ++int module_add_driver(struct module *mod, struct device_driver *drv); + void module_remove_driver(struct device_driver *drv); + #else +-static inline void module_add_driver(struct module *mod, +- struct device_driver *drv) { } ++static inline int module_add_driver(struct module *mod, ++ struct device_driver *drv) ++{ ++ return 0; ++} + static inline void module_remove_driver(struct device_driver *drv) { } + #endif + +diff --git a/drivers/base/bus.c b/drivers/base/bus.c +index 84a21084d67d16..d4361ad3b433f5 100644 +--- a/drivers/base/bus.c ++++ b/drivers/base/bus.c +@@ -152,7 +152,8 @@ static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr, + { + struct bus_attribute *bus_attr = to_bus_attr(attr); + struct subsys_private *subsys_priv = to_subsys_private(kobj); +- ssize_t ret = 0; ++ /* return -EIO for reading a bus attribute without show() */ ++ ssize_t ret = -EIO; + + if (bus_attr->show) + ret = bus_attr->show(subsys_priv->bus, buf); +@@ -164,7 +165,8 @@ static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr, + { + struct bus_attribute *bus_attr = to_bus_attr(attr); + struct subsys_private *subsys_priv = to_subsys_private(kobj); +- ssize_t ret = 0; ++ /* return -EIO for writing a bus attribute without store() */ ++ ssize_t ret = -EIO; + + if (bus_attr->store) + ret = bus_attr->store(subsys_priv->bus, buf, count); +@@ -674,7 +676,12 @@ int bus_add_driver(struct device_driver *drv) + if (error) + goto out_del_list; + } +- module_add_driver(drv->owner, drv); ++ error = module_add_driver(drv->owner, drv); ++ if (error) { ++ printk(KERN_ERR "%s: failed to create module links for %s\n", ++ __func__, drv->name); ++ goto out_detach; ++ } + + error = driver_create_file(drv, &driver_attr_uevent); + if (error) { +@@ -699,6 +706,8 @@ int bus_add_driver(struct device_driver *drv) + + return 0; + ++out_detach: ++ driver_detach(drv); + out_del_list: + klist_del(&priv->knode_bus); + out_unregister: +@@ -913,6 +922,8 @@ int bus_register(const struct bus_type *bus) + bus_remove_file(bus, &bus_attr_uevent); + bus_uevent_fail: + kset_unregister(&priv->subsys); ++ /* Above kset_unregister() will kfree @priv */ ++ priv = NULL; + out: + kfree(priv); + return retval; +diff --git a/drivers/base/class.c b/drivers/base/class.c +index 05d9df90f621be..9cd489a5770866 100644 +--- a/drivers/base/class.c ++++ b/drivers/base/class.c +@@ -215,6 +215,7 @@ int class_register(const struct class *cls) + return 0; + + err_out: ++ lockdep_unregister_key(key); + kfree(cp); + return error; + } +diff --git a/drivers/base/core.c b/drivers/base/core.c +index 4d8b315c48a15a..60a0a4630a5bb2 100644 +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -44,6 +45,7 @@ static bool fw_devlink_is_permissive(void); + static void __fw_devlink_link_to_consumers(struct device *dev); + static bool fw_devlink_drv_reg_done; + static bool fw_devlink_best_effort; ++static struct workqueue_struct *device_link_wq; + + /** + * __fwnode_link_add - Create a link between two fwnode_handles. +@@ -283,10 +285,12 @@ static bool device_is_ancestor(struct device *dev, struct device *target) + return false; + } + ++#define DL_MARKER_FLAGS (DL_FLAG_INFERRED | \ ++ DL_FLAG_CYCLE | \ ++ DL_FLAG_MANAGED) + static inline bool device_link_flag_is_sync_state_only(u32 flags) + { +- return (flags & ~(DL_FLAG_INFERRED | DL_FLAG_CYCLE)) == +- (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED); ++ return (flags & ~DL_MARKER_FLAGS) == DL_FLAG_SYNC_STATE_ONLY; + } + + /** +@@ -529,12 +533,26 @@ static void devlink_dev_release(struct device *dev) + /* + * It may take a while to complete this work because of the SRCU + * synchronization in device_link_release_fn() and if the consumer or +- * supplier devices get deleted when it runs, so put it into the "long" +- * workqueue. ++ * supplier devices get deleted when it runs, so put it into the ++ * dedicated workqueue. + */ +- queue_work(system_long_wq, &link->rm_work); ++ queue_work(device_link_wq, &link->rm_work); + } + ++/** ++ * device_link_wait_removal - Wait for ongoing devlink removal jobs to terminate ++ */ ++void device_link_wait_removal(void) ++{ ++ /* ++ * devlink removal jobs are queued in the dedicated work queue. ++ * To be sure that all removal jobs are terminated, ensure that any ++ * scheduled work has run to completion. ++ */ ++ flush_workqueue(device_link_wq); ++} ++EXPORT_SYMBOL_GPL(device_link_wait_removal); ++ + static struct class devlink_class = { + .name = "devlink", + .dev_groups = devlink_groups, +@@ -2057,9 +2075,14 @@ static int fw_devlink_create_devlink(struct device *con, + + /* + * SYNC_STATE_ONLY device links don't block probing and supports cycles. +- * So cycle detection isn't necessary and shouldn't be done. ++ * So, one might expect that cycle detection isn't necessary for them. ++ * However, if the device link was marked as SYNC_STATE_ONLY because ++ * it's part of a cycle, then we still need to do cycle detection. This ++ * is because the consumer and supplier might be part of multiple cycles ++ * and we need to detect all those cycles. + */ +- if (!(flags & DL_FLAG_SYNC_STATE_ONLY)) { ++ if (!device_link_flag_is_sync_state_only(flags) || ++ flags & DL_FLAG_CYCLE) { + device_links_write_lock(); + if (__fw_devlink_relax_cycles(con, sup_handle)) { + __fwnode_link_cycle(link); +@@ -2543,6 +2566,7 @@ static const char *dev_uevent_name(const struct kobject *kobj) + static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env) + { + const struct device *dev = kobj_to_dev(kobj); ++ struct device_driver *driver; + int retval = 0; + + /* add device node properties if present */ +@@ -2571,8 +2595,12 @@ static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env) + if (dev->type && dev->type->name) + add_uevent_var(env, "DEVTYPE=%s", dev->type->name); + +- if (dev->driver) +- add_uevent_var(env, "DRIVER=%s", dev->driver->name); ++ /* Synchronize with module_remove_driver() */ ++ rcu_read_lock(); ++ driver = READ_ONCE(dev->driver); ++ if (driver) ++ add_uevent_var(env, "DRIVER=%s", driver->name); ++ rcu_read_unlock(); + + /* Add common DT information about the device */ + of_device_uevent(dev, env); +@@ -4083,9 +4111,14 @@ int __init devices_init(void) + sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj); + if (!sysfs_dev_char_kobj) + goto char_kobj_err; ++ device_link_wq = alloc_workqueue("device_link_wq", 0, 0); ++ if (!device_link_wq) ++ goto wq_err; + + return 0; + ++ wq_err: ++ kobject_put(sysfs_dev_char_kobj); + char_kobj_err: + kobject_put(sysfs_dev_block_kobj); + block_kobj_err: +@@ -4452,9 +4485,11 @@ EXPORT_SYMBOL_GPL(device_destroy); + */ + int device_rename(struct device *dev, const char *new_name) + { ++ struct subsys_private *sp = NULL; + struct kobject *kobj = &dev->kobj; + char *old_device_name = NULL; + int error; ++ bool is_link_renamed = false; + + dev = get_device(dev); + if (!dev) +@@ -4469,7 +4504,7 @@ int device_rename(struct device *dev, const char *new_name) + } + + if (dev->class) { +- struct subsys_private *sp = class_to_subsys(dev->class); ++ sp = class_to_subsys(dev->class); + + if (!sp) { + error = -EINVAL; +@@ -4478,16 +4513,19 @@ int device_rename(struct device *dev, const char *new_name) + + error = sysfs_rename_link_ns(&sp->subsys.kobj, kobj, old_device_name, + new_name, kobject_namespace(kobj)); +- subsys_put(sp); + if (error) + goto out; ++ ++ is_link_renamed = true; + } + + error = kobject_rename(kobj, new_name); +- if (error) +- goto out; +- + out: ++ if (error && is_link_renamed) ++ sysfs_rename_link_ns(&sp->subsys.kobj, kobj, new_name, ++ old_device_name, kobject_namespace(kobj)); ++ subsys_put(sp); ++ + put_device(dev); + + kfree(old_device_name); +diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c +index 9ea22e165acd67..ef427ee787a99b 100644 +--- a/drivers/base/cpu.c ++++ b/drivers/base/cpu.c +@@ -144,7 +144,7 @@ static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store); + #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ + #endif /* CONFIG_HOTPLUG_CPU */ + +-#ifdef CONFIG_KEXEC ++#ifdef CONFIG_KEXEC_CORE + #include + + static ssize_t crash_notes_show(struct device *dev, +@@ -189,14 +189,14 @@ static const struct attribute_group crash_note_cpu_attr_group = { + #endif + + static const struct attribute_group *common_cpu_attr_groups[] = { +-#ifdef CONFIG_KEXEC ++#ifdef CONFIG_KEXEC_CORE + &crash_note_cpu_attr_group, + #endif + NULL + }; + + static const struct attribute_group *hotplugable_cpu_attr_groups[] = { +-#ifdef CONFIG_KEXEC ++#ifdef CONFIG_KEXEC_CORE + &crash_note_cpu_attr_group, + #endif + NULL +@@ -565,6 +565,7 @@ CPU_SHOW_VULN_FALLBACK(mmio_stale_data); + CPU_SHOW_VULN_FALLBACK(retbleed); + CPU_SHOW_VULN_FALLBACK(spec_rstack_overflow); + CPU_SHOW_VULN_FALLBACK(gds); ++CPU_SHOW_VULN_FALLBACK(reg_file_data_sampling); + + static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); + static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); +@@ -579,6 +580,7 @@ static DEVICE_ATTR(mmio_stale_data, 0444, cpu_show_mmio_stale_data, NULL); + static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL); + static DEVICE_ATTR(spec_rstack_overflow, 0444, cpu_show_spec_rstack_overflow, NULL); + static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gds, NULL); ++static DEVICE_ATTR(reg_file_data_sampling, 0444, cpu_show_reg_file_data_sampling, NULL); + + static struct attribute *cpu_root_vulnerabilities_attrs[] = { + &dev_attr_meltdown.attr, +@@ -594,6 +596,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = { + &dev_attr_retbleed.attr, + &dev_attr_spec_rstack_overflow.attr, + &dev_attr_gather_data_sampling.attr, ++ &dev_attr_reg_file_data_sampling.attr, + NULL + }; + +diff --git a/drivers/base/dd.c b/drivers/base/dd.c +index a528cec24264ab..0c3725c3eefa46 100644 +--- a/drivers/base/dd.c ++++ b/drivers/base/dd.c +@@ -1274,8 +1274,8 @@ static void __device_release_driver(struct device *dev, struct device *parent) + if (dev->bus && dev->bus->dma_cleanup) + dev->bus->dma_cleanup(dev); + +- device_links_driver_cleanup(dev); + device_unbind_cleanup(dev); ++ device_links_driver_cleanup(dev); + + klist_remove(&dev->p->knode_driver); + device_pm_check_callbacks(dev); +diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c +index 91536ee05f144e..7e2d1f0d903a6e 100644 +--- a/drivers/base/devcoredump.c ++++ b/drivers/base/devcoredump.c +@@ -362,6 +362,7 @@ void dev_coredumpm(struct device *dev, struct module *owner, + devcd->devcd_dev.class = &devcd_class; + + mutex_lock(&devcd->mutex); ++ dev_set_uevent_suppress(&devcd->devcd_dev, true); + if (device_add(&devcd->devcd_dev)) + goto put_device; + +@@ -376,6 +377,8 @@ void dev_coredumpm(struct device *dev, struct module *owner, + "devcoredump")) + dev_warn(dev, "devcoredump create_link failed\n"); + ++ dev_set_uevent_suppress(&devcd->devcd_dev, false); ++ kobject_uevent(&devcd->devcd_dev.kobj, KOBJ_ADD); + INIT_DELAYED_WORK(&devcd->del_wk, devcd_del); + schedule_delayed_work(&devcd->del_wk, DEVCD_TIMEOUT); + mutex_unlock(&devcd->mutex); +diff --git a/drivers/base/devres.c b/drivers/base/devres.c +index 3df0025d12aa48..e9b0d94aeabd90 100644 +--- a/drivers/base/devres.c ++++ b/drivers/base/devres.c +@@ -567,6 +567,7 @@ void * devres_open_group(struct device *dev, void *id, gfp_t gfp) + grp->id = grp; + if (id) + grp->id = id; ++ grp->color = 0; + + spin_lock_irqsave(&dev->devres_lock, flags); + add_dr(dev, &grp->node[0]); +@@ -896,9 +897,12 @@ void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp) + /* + * Otherwise: allocate new, larger chunk. We need to allocate before + * taking the lock as most probably the caller uses GFP_KERNEL. ++ * alloc_dr() will call check_dr_size() to reserve extra memory ++ * for struct devres automatically, so size @new_size user request ++ * is delivered to it directly as devm_kmalloc() does. + */ + new_dr = alloc_dr(devm_kmalloc_release, +- total_new_size, gfp, dev_to_node(dev)); ++ new_size, gfp, dev_to_node(dev)); + if (!new_dr) + return NULL; + +@@ -1222,7 +1226,11 @@ EXPORT_SYMBOL_GPL(__devm_alloc_percpu); + */ + void devm_free_percpu(struct device *dev, void __percpu *pdata) + { +- WARN_ON(devres_destroy(dev, devm_percpu_release, devm_percpu_match, ++ /* ++ * Use devres_release() to prevent memory leakage as ++ * devm_free_pages() does. ++ */ ++ WARN_ON(devres_release(dev, devm_percpu_release, devm_percpu_match, + (__force void *)pdata)); + } + EXPORT_SYMBOL_GPL(devm_free_percpu); +diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c +index b58c42f1b1ce65..0b18c6b46e65d8 100644 +--- a/drivers/base/firmware_loader/main.c ++++ b/drivers/base/firmware_loader/main.c +@@ -844,6 +844,26 @@ static void fw_log_firmware_info(const struct firmware *fw, const char *name, + {} + #endif + ++/* ++ * Reject firmware file names with ".." path components. ++ * There are drivers that construct firmware file names from device-supplied ++ * strings, and we don't want some device to be able to tell us "I would like to ++ * be sent my firmware from ../../../etc/shadow, please". ++ * ++ * Search for ".." surrounded by either '/' or start/end of string. ++ * ++ * This intentionally only looks at the firmware name, not at the firmware base ++ * directory or at symlink contents. ++ */ ++static bool name_contains_dotdot(const char *name) ++{ ++ size_t name_len = strlen(name); ++ ++ return strcmp(name, "..") == 0 || strncmp(name, "../", 3) == 0 || ++ strstr(name, "/../") != NULL || ++ (name_len >= 3 && strcmp(name+name_len-3, "/..") == 0); ++} ++ + /* called from request_firmware() and request_firmware_work_func() */ + static int + _request_firmware(const struct firmware **firmware_p, const char *name, +@@ -864,6 +884,14 @@ _request_firmware(const struct firmware **firmware_p, const char *name, + goto out; + } + ++ if (name_contains_dotdot(name)) { ++ dev_warn(device, ++ "Firmware load for '%s' refused, path contains '..' component\n", ++ name); ++ ret = -EINVAL; ++ goto out; ++ } ++ + ret = _request_firmware_prepare(&fw, name, device, buf, size, + offset, opt_flags); + if (ret <= 0) /* error or already assigned */ +@@ -941,6 +969,8 @@ _request_firmware(const struct firmware **firmware_p, const char *name, + * @name will be used as $FIRMWARE in the uevent environment and + * should be distinctive enough not to be confused with any other + * firmware image for this or any other device. ++ * It must not contain any ".." path components - "foo/bar..bin" is ++ * allowed, but "foo/../bar.bin" is not. + * + * Caller must hold the reference count of @device. + * +diff --git a/drivers/base/memory.c b/drivers/base/memory.c +index f3b9a4d0fa3bb2..8a13babd826ce3 100644 +--- a/drivers/base/memory.c ++++ b/drivers/base/memory.c +@@ -180,6 +180,9 @@ static inline unsigned long memblk_nr_poison(struct memory_block *mem) + } + #endif + ++/* ++ * Must acquire mem_hotplug_lock in write mode. ++ */ + static int memory_block_online(struct memory_block *mem) + { + unsigned long start_pfn = section_nr_to_pfn(mem->start_section_nr); +@@ -204,10 +207,11 @@ static int memory_block_online(struct memory_block *mem) + if (mem->altmap) + nr_vmemmap_pages = mem->altmap->free; + ++ mem_hotplug_begin(); + if (nr_vmemmap_pages) { + ret = mhp_init_memmap_on_memory(start_pfn, nr_vmemmap_pages, zone); + if (ret) +- return ret; ++ goto out; + } + + ret = online_pages(start_pfn + nr_vmemmap_pages, +@@ -215,7 +219,7 @@ static int memory_block_online(struct memory_block *mem) + if (ret) { + if (nr_vmemmap_pages) + mhp_deinit_memmap_on_memory(start_pfn, nr_vmemmap_pages); +- return ret; ++ goto out; + } + + /* +@@ -227,9 +231,14 @@ static int memory_block_online(struct memory_block *mem) + nr_vmemmap_pages); + + mem->zone = zone; ++out: ++ mem_hotplug_done(); + return ret; + } + ++/* ++ * Must acquire mem_hotplug_lock in write mode. ++ */ + static int memory_block_offline(struct memory_block *mem) + { + unsigned long start_pfn = section_nr_to_pfn(mem->start_section_nr); +@@ -247,6 +256,7 @@ static int memory_block_offline(struct memory_block *mem) + if (mem->altmap) + nr_vmemmap_pages = mem->altmap->free; + ++ mem_hotplug_begin(); + if (nr_vmemmap_pages) + adjust_present_page_count(pfn_to_page(start_pfn), mem->group, + -nr_vmemmap_pages); +@@ -258,13 +268,15 @@ static int memory_block_offline(struct memory_block *mem) + if (nr_vmemmap_pages) + adjust_present_page_count(pfn_to_page(start_pfn), + mem->group, nr_vmemmap_pages); +- return ret; ++ goto out; + } + + if (nr_vmemmap_pages) + mhp_deinit_memmap_on_memory(start_pfn, nr_vmemmap_pages); + + mem->zone = NULL; ++out: ++ mem_hotplug_done(); + return ret; + } + +diff --git a/drivers/base/module.c b/drivers/base/module.c +index 46ad4d636731dd..0d5c5da367f720 100644 +--- a/drivers/base/module.c ++++ b/drivers/base/module.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include "base.h" + + static char *make_driver_name(struct device_driver *drv) +@@ -30,14 +31,14 @@ static void module_create_drivers_dir(struct module_kobject *mk) + mutex_unlock(&drivers_dir_mutex); + } + +-void module_add_driver(struct module *mod, struct device_driver *drv) ++int module_add_driver(struct module *mod, struct device_driver *drv) + { + char *driver_name; +- int no_warn; + struct module_kobject *mk = NULL; ++ int ret; + + if (!drv) +- return; ++ return 0; + + if (mod) + mk = &mod->mkobj; +@@ -56,17 +57,41 @@ void module_add_driver(struct module *mod, struct device_driver *drv) + } + + if (!mk) +- return; ++ return 0; ++ ++ ret = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); ++ if (ret) ++ return ret; + +- /* Don't check return codes; these calls are idempotent */ +- no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); + driver_name = make_driver_name(drv); +- if (driver_name) { +- module_create_drivers_dir(mk); +- no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj, +- driver_name); +- kfree(driver_name); ++ if (!driver_name) { ++ ret = -ENOMEM; ++ goto out_remove_kobj; + } ++ ++ module_create_drivers_dir(mk); ++ if (!mk->drivers_dir) { ++ ret = -EINVAL; ++ goto out_free_driver_name; ++ } ++ ++ ret = sysfs_create_link(mk->drivers_dir, &drv->p->kobj, driver_name); ++ if (ret) ++ goto out_remove_drivers_dir; ++ ++ kfree(driver_name); ++ ++ return 0; ++ ++out_remove_drivers_dir: ++ sysfs_remove_link(mk->drivers_dir, driver_name); ++ ++out_free_driver_name: ++ kfree(driver_name); ++ ++out_remove_kobj: ++ sysfs_remove_link(&drv->p->kobj, "module"); ++ return ret; + } + + void module_remove_driver(struct device_driver *drv) +@@ -77,6 +102,9 @@ void module_remove_driver(struct device_driver *drv) + if (!drv) + return; + ++ /* Synchronize with dev_uevent() */ ++ synchronize_rcu(); ++ + sysfs_remove_link(&drv->p->kobj, "module"); + + if (drv->owner) +diff --git a/drivers/base/node.c b/drivers/base/node.c +index 493d533f837556..4d588f4658c85c 100644 +--- a/drivers/base/node.c ++++ b/drivers/base/node.c +@@ -868,11 +868,15 @@ int __register_one_node(int nid) + { + int error; + int cpu; ++ struct node *node; + +- node_devices[nid] = kzalloc(sizeof(struct node), GFP_KERNEL); +- if (!node_devices[nid]) ++ node = kzalloc(sizeof(struct node), GFP_KERNEL); ++ if (!node) + return -ENOMEM; + ++ INIT_LIST_HEAD(&node->access_list); ++ node_devices[nid] = node; ++ + error = register_node(node_devices[nid], nid); + + /* link cpu under this node */ +@@ -881,7 +885,6 @@ int __register_one_node(int nid) + register_cpu_under_node(cpu, nid); + } + +- INIT_LIST_HEAD(&node_devices[nid]->access_list); + node_init_caches(nid); + + return error; +diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c +index 5cb2023581d4db..582564f8dde6f9 100644 +--- a/drivers/base/power/domain.c ++++ b/drivers/base/power/domain.c +@@ -1102,7 +1102,7 @@ static int __init genpd_power_off_unused(void) + + return 0; + } +-late_initcall(genpd_power_off_unused); ++late_initcall_sync(genpd_power_off_unused); + + #ifdef CONFIG_PM_SLEEP + +@@ -3135,7 +3135,7 @@ static int genpd_summary_one(struct seq_file *s, + else + snprintf(state, sizeof(state), "%s", + status_lookup[genpd->status]); +- seq_printf(s, "%-30s %-50s %u", genpd->name, state, genpd->performance_state); ++ seq_printf(s, "%-30s %-49s %u", genpd->name, state, genpd->performance_state); + + /* + * Modifications on the list require holding locks on both +diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c +index f85f3515c258fc..9c5a5f4dba5a6e 100644 +--- a/drivers/base/power/main.c ++++ b/drivers/base/power/main.c +@@ -579,7 +579,7 @@ bool dev_pm_skip_resume(struct device *dev) + } + + /** +- * device_resume_noirq - Execute a "noirq resume" callback for given device. ++ * __device_resume_noirq - Execute a "noirq resume" callback for given device. + * @dev: Device to handle. + * @state: PM transition of the system being carried out. + * @async: If true, the device is being resumed asynchronously. +@@ -587,7 +587,7 @@ bool dev_pm_skip_resume(struct device *dev) + * The driver of @dev will not receive interrupts while this function is being + * executed. + */ +-static int device_resume_noirq(struct device *dev, pm_message_t state, bool async) ++static void __device_resume_noirq(struct device *dev, pm_message_t state, bool async) + { + pm_callback_t callback = NULL; + const char *info = NULL; +@@ -655,7 +655,13 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn + Out: + complete_all(&dev->power.completion); + TRACE_RESUME(error); +- return error; ++ ++ if (error) { ++ suspend_stats.failed_resume_noirq++; ++ dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); ++ dpm_save_failed_dev(dev_name(dev)); ++ pm_dev_err(dev, state, async ? " async noirq" : " noirq", error); ++ } + } + + static bool is_async(struct device *dev) +@@ -668,11 +674,15 @@ static bool dpm_async_fn(struct device *dev, async_func_t func) + { + reinit_completion(&dev->power.completion); + +- if (is_async(dev)) { +- get_device(dev); +- async_schedule_dev(func, dev); ++ if (!is_async(dev)) ++ return false; ++ ++ get_device(dev); ++ ++ if (async_schedule_dev_nocall(func, dev)) + return true; +- } ++ ++ put_device(dev); + + return false; + } +@@ -680,15 +690,19 @@ static bool dpm_async_fn(struct device *dev, async_func_t func) + static void async_resume_noirq(void *data, async_cookie_t cookie) + { + struct device *dev = data; +- int error; +- +- error = device_resume_noirq(dev, pm_transition, true); +- if (error) +- pm_dev_err(dev, pm_transition, " async", error); + ++ __device_resume_noirq(dev, pm_transition, true); + put_device(dev); + } + ++static void device_resume_noirq(struct device *dev) ++{ ++ if (dpm_async_fn(dev, async_resume_noirq)) ++ return; ++ ++ __device_resume_noirq(dev, pm_transition, false); ++} ++ + static void dpm_noirq_resume_devices(pm_message_t state) + { + struct device *dev; +@@ -698,14 +712,6 @@ static void dpm_noirq_resume_devices(pm_message_t state) + mutex_lock(&dpm_list_mtx); + pm_transition = state; + +- /* +- * Advanced the async threads upfront, +- * in case the starting of async threads is +- * delayed by non-async resuming devices. +- */ +- list_for_each_entry(dev, &dpm_noirq_list, power.entry) +- dpm_async_fn(dev, async_resume_noirq); +- + while (!list_empty(&dpm_noirq_list)) { + dev = to_device(dpm_noirq_list.next); + get_device(dev); +@@ -713,17 +719,7 @@ static void dpm_noirq_resume_devices(pm_message_t state) + + mutex_unlock(&dpm_list_mtx); + +- if (!is_async(dev)) { +- int error; +- +- error = device_resume_noirq(dev, state, false); +- if (error) { +- suspend_stats.failed_resume_noirq++; +- dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); +- dpm_save_failed_dev(dev_name(dev)); +- pm_dev_err(dev, state, " noirq", error); +- } +- } ++ device_resume_noirq(dev); + + put_device(dev); + +@@ -751,14 +747,14 @@ void dpm_resume_noirq(pm_message_t state) + } + + /** +- * device_resume_early - Execute an "early resume" callback for given device. ++ * __device_resume_early - Execute an "early resume" callback for given device. + * @dev: Device to handle. + * @state: PM transition of the system being carried out. + * @async: If true, the device is being resumed asynchronously. + * + * Runtime PM is disabled for @dev while this function is being executed. + */ +-static int device_resume_early(struct device *dev, pm_message_t state, bool async) ++static void __device_resume_early(struct device *dev, pm_message_t state, bool async) + { + pm_callback_t callback = NULL; + const char *info = NULL; +@@ -811,21 +807,31 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn + + pm_runtime_enable(dev); + complete_all(&dev->power.completion); +- return error; ++ ++ if (error) { ++ suspend_stats.failed_resume_early++; ++ dpm_save_failed_step(SUSPEND_RESUME_EARLY); ++ dpm_save_failed_dev(dev_name(dev)); ++ pm_dev_err(dev, state, async ? " async early" : " early", error); ++ } + } + + static void async_resume_early(void *data, async_cookie_t cookie) + { + struct device *dev = data; +- int error; +- +- error = device_resume_early(dev, pm_transition, true); +- if (error) +- pm_dev_err(dev, pm_transition, " async", error); + ++ __device_resume_early(dev, pm_transition, true); + put_device(dev); + } + ++static void device_resume_early(struct device *dev) ++{ ++ if (dpm_async_fn(dev, async_resume_early)) ++ return; ++ ++ __device_resume_early(dev, pm_transition, false); ++} ++ + /** + * dpm_resume_early - Execute "early resume" callbacks for all devices. + * @state: PM transition of the system being carried out. +@@ -839,14 +845,6 @@ void dpm_resume_early(pm_message_t state) + mutex_lock(&dpm_list_mtx); + pm_transition = state; + +- /* +- * Advanced the async threads upfront, +- * in case the starting of async threads is +- * delayed by non-async resuming devices. +- */ +- list_for_each_entry(dev, &dpm_late_early_list, power.entry) +- dpm_async_fn(dev, async_resume_early); +- + while (!list_empty(&dpm_late_early_list)) { + dev = to_device(dpm_late_early_list.next); + get_device(dev); +@@ -854,17 +852,7 @@ void dpm_resume_early(pm_message_t state) + + mutex_unlock(&dpm_list_mtx); + +- if (!is_async(dev)) { +- int error; +- +- error = device_resume_early(dev, state, false); +- if (error) { +- suspend_stats.failed_resume_early++; +- dpm_save_failed_step(SUSPEND_RESUME_EARLY); +- dpm_save_failed_dev(dev_name(dev)); +- pm_dev_err(dev, state, " early", error); +- } +- } ++ device_resume_early(dev); + + put_device(dev); + +@@ -888,12 +876,12 @@ void dpm_resume_start(pm_message_t state) + EXPORT_SYMBOL_GPL(dpm_resume_start); + + /** +- * device_resume - Execute "resume" callbacks for given device. ++ * __device_resume - Execute "resume" callbacks for given device. + * @dev: Device to handle. + * @state: PM transition of the system being carried out. + * @async: If true, the device is being resumed asynchronously. + */ +-static int device_resume(struct device *dev, pm_message_t state, bool async) ++static void __device_resume(struct device *dev, pm_message_t state, bool async) + { + pm_callback_t callback = NULL; + const char *info = NULL; +@@ -975,20 +963,30 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) + + TRACE_RESUME(error); + +- return error; ++ if (error) { ++ suspend_stats.failed_resume++; ++ dpm_save_failed_step(SUSPEND_RESUME); ++ dpm_save_failed_dev(dev_name(dev)); ++ pm_dev_err(dev, state, async ? " async" : "", error); ++ } + } + + static void async_resume(void *data, async_cookie_t cookie) + { + struct device *dev = data; +- int error; + +- error = device_resume(dev, pm_transition, true); +- if (error) +- pm_dev_err(dev, pm_transition, " async", error); ++ __device_resume(dev, pm_transition, true); + put_device(dev); + } + ++static void device_resume(struct device *dev) ++{ ++ if (dpm_async_fn(dev, async_resume)) ++ return; ++ ++ __device_resume(dev, pm_transition, false); ++} ++ + /** + * dpm_resume - Execute "resume" callbacks for non-sysdev devices. + * @state: PM transition of the system being carried out. +@@ -1008,27 +1006,17 @@ void dpm_resume(pm_message_t state) + pm_transition = state; + async_error = 0; + +- list_for_each_entry(dev, &dpm_suspended_list, power.entry) +- dpm_async_fn(dev, async_resume); +- + while (!list_empty(&dpm_suspended_list)) { + dev = to_device(dpm_suspended_list.next); ++ + get_device(dev); +- if (!is_async(dev)) { +- int error; + +- mutex_unlock(&dpm_list_mtx); ++ mutex_unlock(&dpm_list_mtx); ++ ++ device_resume(dev); + +- error = device_resume(dev, state, false); +- if (error) { +- suspend_stats.failed_resume++; +- dpm_save_failed_step(SUSPEND_RESUME); +- dpm_save_failed_dev(dev_name(dev)); +- pm_dev_err(dev, state, "", error); +- } ++ mutex_lock(&dpm_list_mtx); + +- mutex_lock(&dpm_list_mtx); +- } + if (!list_empty(&dev->power.entry)) + list_move_tail(&dev->power.entry, &dpm_prepared_list); + +diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c +index 72b7a92337b188..cd6e559648b21b 100644 +--- a/drivers/base/power/trace.c ++++ b/drivers/base/power/trace.c +@@ -120,7 +120,7 @@ static unsigned int read_magic_time(void) + struct rtc_time time; + unsigned int val; + +- if (mc146818_get_time(&time) < 0) { ++ if (mc146818_get_time(&time, 1000) < 0) { + pr_err("Unable to read current time from RTC\n"); + return 0; + } +diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c +index 42171f766dcba6..5a5a9e978e85f3 100644 +--- a/drivers/base/power/wakeirq.c ++++ b/drivers/base/power/wakeirq.c +@@ -313,8 +313,10 @@ void dev_pm_enable_wake_irq_complete(struct device *dev) + return; + + if (wirq->status & WAKE_IRQ_DEDICATED_MANAGED && +- wirq->status & WAKE_IRQ_DEDICATED_REVERSE) ++ wirq->status & WAKE_IRQ_DEDICATED_REVERSE) { + enable_irq(wirq->irq); ++ wirq->status |= WAKE_IRQ_DEDICATED_ENABLED; ++ } + } + + /** +diff --git a/drivers/base/regmap/regcache-maple.c b/drivers/base/regmap/regcache-maple.c +index 41edd6a430eb45..0b6c2277128b42 100644 +--- a/drivers/base/regmap/regcache-maple.c ++++ b/drivers/base/regmap/regcache-maple.c +@@ -110,9 +110,10 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min, + struct maple_tree *mt = map->cache; + MA_STATE(mas, mt, min, max); + unsigned long *entry, *lower, *upper; +- unsigned long lower_index, lower_last; ++ /* initialized to work around false-positive -Wuninitialized warning */ ++ unsigned long lower_index = 0, lower_last = 0; + unsigned long upper_index, upper_last; +- int ret; ++ int ret = 0; + + lower = NULL; + upper = NULL; +@@ -145,7 +146,7 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min, + upper_index = max + 1; + upper_last = mas.last; + +- upper = kmemdup(&entry[max + 1], ++ upper = kmemdup(&entry[max - mas.index + 1], + ((mas.last - max) * + sizeof(unsigned long)), + map->alloc_flags); +@@ -244,7 +245,7 @@ static int regcache_maple_sync(struct regmap *map, unsigned int min, + unsigned long lmin = min; + unsigned long lmax = max; + unsigned int r, v, sync_start; +- int ret; ++ int ret = 0; + bool sync_needed = false; + + map->cache_bypass = true; +diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c +index c5d151e9c48159..ac63a73ccdaaa2 100644 +--- a/drivers/base/regmap/regcache.c ++++ b/drivers/base/regmap/regcache.c +@@ -334,6 +334,11 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, + return 0; + } + ++static int rbtree_all(const void *key, const struct rb_node *node) ++{ ++ return 0; ++} ++ + /** + * regcache_sync - Sync the register cache with the hardware. + * +@@ -351,6 +356,7 @@ int regcache_sync(struct regmap *map) + unsigned int i; + const char *name; + bool bypass; ++ struct rb_node *node; + + if (WARN_ON(map->cache_type == REGCACHE_NONE)) + return -EINVAL; +@@ -392,6 +398,29 @@ int regcache_sync(struct regmap *map) + /* Restore the bypass state */ + map->cache_bypass = bypass; + map->no_sync_defaults = false; ++ ++ /* ++ * If we did any paging with cache bypassed and a cached ++ * paging register then the register and cache state might ++ * have gone out of sync, force writes of all the paging ++ * registers. ++ */ ++ rb_for_each(node, 0, &map->range_tree, rbtree_all) { ++ struct regmap_range_node *this = ++ rb_entry(node, struct regmap_range_node, node); ++ ++ /* If there's nothing in the cache there's nothing to sync */ ++ if (regcache_read(map, this->selector_reg, &i) != 0) ++ continue; ++ ++ ret = _regmap_write(map, this->selector_reg, i); ++ if (ret != 0) { ++ dev_err(map->dev, "Failed to write %x = %x: %d\n", ++ this->selector_reg, i, ret); ++ break; ++ } ++ } ++ + map->unlock(map->lock_arg); + + regmap_async_complete(map); +diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c +index f36027591e1a8d..bdd80b73c3e6c1 100644 +--- a/drivers/base/regmap/regmap-debugfs.c ++++ b/drivers/base/regmap/regmap-debugfs.c +@@ -48,7 +48,7 @@ static ssize_t regmap_name_read_file(struct file *file, + name = map->dev->driver->name; + + ret = snprintf(buf, PAGE_SIZE, "%s\n", name); +- if (ret < 0) { ++ if (ret >= PAGE_SIZE) { + kfree(buf); + return ret; + } +diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c +index 3ec611dc0c09fb..a905e955bbfc78 100644 +--- a/drivers/base/regmap/regmap-i2c.c ++++ b/drivers/base/regmap/regmap-i2c.c +@@ -350,7 +350,8 @@ static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, + + if (quirks->max_write_len && + (bus->max_raw_write == 0 || bus->max_raw_write > quirks->max_write_len)) +- max_write = quirks->max_write_len; ++ max_write = quirks->max_write_len - ++ (config->reg_bits + config->pad_bits) / BITS_PER_BYTE; + + if (max_read || max_write) { + ret_bus = kmemdup(bus, sizeof(*bus), GFP_KERNEL); +diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c +index 264d29b3fced0b..5f1e914646cd91 100644 +--- a/drivers/base/regmap/regmap-kunit.c ++++ b/drivers/base/regmap/regmap-kunit.c +@@ -9,6 +9,23 @@ + + #define BLOCK_TEST_SIZE 12 + ++static void get_changed_bytes(void *orig, void *new, size_t size) ++{ ++ char *o = orig; ++ char *n = new; ++ int i; ++ ++ get_random_bytes(new, size); ++ ++ /* ++ * This could be nicer and more efficient but we shouldn't ++ * super care. ++ */ ++ for (i = 0; i < size; i++) ++ while (n[i] == o[i]) ++ get_random_bytes(&n[i], 1); ++} ++ + static const struct regmap_config test_regmap_config = { + .max_register = BLOCK_TEST_SIZE, + .reg_stride = 1, +@@ -1131,7 +1148,7 @@ static void raw_sync(struct kunit *test) + struct regmap *map; + struct regmap_config config; + struct regmap_ram_data *data; +- u16 val[2]; ++ u16 val[3]; + u16 *hw_buf; + unsigned int rval; + int i; +@@ -1145,17 +1162,13 @@ static void raw_sync(struct kunit *test) + + hw_buf = (u16 *)data->vals; + +- get_random_bytes(&val, sizeof(val)); ++ get_changed_bytes(&hw_buf[2], &val[0], sizeof(val)); + + /* Do a regular write and a raw write in cache only mode */ + regcache_cache_only(map, true); +- KUNIT_EXPECT_EQ(test, 0, regmap_raw_write(map, 2, val, sizeof(val))); +- if (config.val_format_endian == REGMAP_ENDIAN_BIG) +- KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 6, +- be16_to_cpu(val[0]))); +- else +- KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 6, +- le16_to_cpu(val[0]))); ++ KUNIT_EXPECT_EQ(test, 0, regmap_raw_write(map, 2, val, ++ sizeof(u16) * 2)); ++ KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 4, val[2])); + + /* We should read back the new values, and defaults for the rest */ + for (i = 0; i < config.max_register + 1; i++) { +@@ -1164,24 +1177,34 @@ static void raw_sync(struct kunit *test) + switch (i) { + case 2: + case 3: +- case 6: + if (config.val_format_endian == REGMAP_ENDIAN_BIG) { + KUNIT_EXPECT_EQ(test, rval, +- be16_to_cpu(val[i % 2])); ++ be16_to_cpu(val[i - 2])); + } else { + KUNIT_EXPECT_EQ(test, rval, +- le16_to_cpu(val[i % 2])); ++ le16_to_cpu(val[i - 2])); + } + break; ++ case 4: ++ KUNIT_EXPECT_EQ(test, rval, val[i - 2]); ++ break; + default: + KUNIT_EXPECT_EQ(test, config.reg_defaults[i].def, rval); + break; + } + } ++ ++ /* ++ * The value written via _write() was translated by the core, ++ * translate the original copy for comparison purposes. ++ */ ++ if (config.val_format_endian == REGMAP_ENDIAN_BIG) ++ val[2] = cpu_to_be16(val[2]); ++ else ++ val[2] = cpu_to_le16(val[2]); + + /* The values should not appear in the "hardware" */ +- KUNIT_EXPECT_MEMNEQ(test, &hw_buf[2], val, sizeof(val)); +- KUNIT_EXPECT_MEMNEQ(test, &hw_buf[6], val, sizeof(u16)); ++ KUNIT_EXPECT_MEMNEQ(test, &hw_buf[2], &val[0], sizeof(val)); + + for (i = 0; i < config.max_register + 1; i++) + data->written[i] = false; +@@ -1192,8 +1215,7 @@ static void raw_sync(struct kunit *test) + KUNIT_EXPECT_EQ(test, 0, regcache_sync(map)); + + /* The values should now appear in the "hardware" */ +- KUNIT_EXPECT_MEMEQ(test, &hw_buf[2], val, sizeof(val)); +- KUNIT_EXPECT_MEMEQ(test, &hw_buf[6], val, sizeof(u16)); ++ KUNIT_EXPECT_MEMEQ(test, &hw_buf[2], &val[0], sizeof(val)); + + regmap_exit(map); + } +diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c +index 37ab23a9d0345a..7f14c5ed1e2294 100644 +--- a/drivers/base/regmap/regmap-spi.c ++++ b/drivers/base/regmap/regmap-spi.c +@@ -122,8 +122,7 @@ static const struct regmap_bus *regmap_get_spi_bus(struct spi_device *spi, + return ERR_PTR(-ENOMEM); + + max_msg_size = spi_max_message_size(spi); +- reg_reserve_size = config->reg_bits / BITS_PER_BYTE +- + config->pad_bits / BITS_PER_BYTE; ++ reg_reserve_size = (config->reg_bits + config->pad_bits) / BITS_PER_BYTE; + if (max_size + reg_reserve_size > max_msg_size) + max_size -= reg_reserve_size; + +diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c +index 234a84ecde8b1b..c5b5241891a5a6 100644 +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -1620,17 +1620,19 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg, + } + + if (!map->cache_bypass && map->format.parse_val) { +- unsigned int ival; ++ unsigned int ival, offset; + int val_bytes = map->format.val_bytes; +- for (i = 0; i < val_len / val_bytes; i++) { +- ival = map->format.parse_val(val + (i * val_bytes)); +- ret = regcache_write(map, +- reg + regmap_get_offset(map, i), +- ival); ++ ++ /* Cache the last written value for noinc writes */ ++ i = noinc ? val_len - val_bytes : 0; ++ for (; i < val_len; i += val_bytes) { ++ ival = map->format.parse_val(val + i); ++ offset = noinc ? 0 : regmap_get_offset(map, i / val_bytes); ++ ret = regcache_write(map, reg + offset, ival); + if (ret) { + dev_err(map->dev, + "Error in caching of register: %x ret: %d\n", +- reg + regmap_get_offset(map, i), ret); ++ reg + offset, ret); + return ret; + } + } +@@ -2834,6 +2836,43 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val) + } + EXPORT_SYMBOL_GPL(regmap_read); + ++/** ++ * regmap_read_bypassed() - Read a value from a single register direct ++ * from the device, bypassing the cache ++ * ++ * @map: Register map to read from ++ * @reg: Register to be read from ++ * @val: Pointer to store read value ++ * ++ * A value of zero will be returned on success, a negative errno will ++ * be returned in error cases. ++ */ ++int regmap_read_bypassed(struct regmap *map, unsigned int reg, unsigned int *val) ++{ ++ int ret; ++ bool bypass, cache_only; ++ ++ if (!IS_ALIGNED(reg, map->reg_stride)) ++ return -EINVAL; ++ ++ map->lock(map->lock_arg); ++ ++ bypass = map->cache_bypass; ++ cache_only = map->cache_only; ++ map->cache_bypass = true; ++ map->cache_only = false; ++ ++ ret = _regmap_read(map, reg, val); ++ ++ map->cache_bypass = bypass; ++ map->cache_only = cache_only; ++ ++ map->unlock(map->lock_arg); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(regmap_read_bypassed); ++ + /** + * regmap_raw_read() - Read raw data from the device + * +diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c +index 1886995a0b3a30..079bd14bdedc7c 100644 +--- a/drivers/base/swnode.c ++++ b/drivers/base/swnode.c +@@ -541,6 +541,9 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode, + if (nargs > NR_FWNODE_REFERENCE_ARGS) + return -EINVAL; + ++ if (!args) ++ return 0; ++ + args->fwnode = software_node_get(refnode); + args->nargs = nargs; + +diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c +index cf6883756155a3..37eff1c9745155 100644 +--- a/drivers/block/aoe/aoeblk.c ++++ b/drivers/block/aoe/aoeblk.c +@@ -333,6 +333,7 @@ aoeblk_gdalloc(void *vp) + struct gendisk *gd; + mempool_t *mp; + struct blk_mq_tag_set *set; ++ sector_t ssize; + ulong flags; + int late = 0; + int err; +@@ -395,7 +396,7 @@ aoeblk_gdalloc(void *vp) + gd->minors = AOE_PARTITIONS; + gd->fops = &aoe_bdops; + gd->private_data = d; +- set_capacity(gd, d->ssize); ++ ssize = d->ssize; + snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%d", + d->aoemajor, d->aoeminor); + +@@ -404,6 +405,8 @@ aoeblk_gdalloc(void *vp) + + spin_unlock_irqrestore(&d->lock, flags); + ++ set_capacity(gd, ssize); ++ + err = device_add_disk(NULL, gd, aoe_attr_groups); + if (err) + goto out_disk_cleanup; +diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c +index d7317425be510d..d1f4ddc576451a 100644 +--- a/drivers/block/aoe/aoecmd.c ++++ b/drivers/block/aoe/aoecmd.c +@@ -361,6 +361,7 @@ ata_rw_frameinit(struct frame *f) + } + + ah->cmdstat = ATA_CMD_PIO_READ | writebit | extbit; ++ dev_hold(t->ifp->nd); + skb->dev = t->ifp->nd; + } + +@@ -401,6 +402,8 @@ aoecmd_ata_rw(struct aoedev *d) + __skb_queue_head_init(&queue); + __skb_queue_tail(&queue, skb); + aoenet_xmit(&queue); ++ } else { ++ dev_put(f->t->ifp->nd); + } + return 1; + } +@@ -419,13 +422,16 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *qu + rcu_read_lock(); + for_each_netdev_rcu(&init_net, ifp) { + dev_hold(ifp); +- if (!is_aoe_netif(ifp)) +- goto cont; ++ if (!is_aoe_netif(ifp)) { ++ dev_put(ifp); ++ continue; ++ } + + skb = new_skb(sizeof *h + sizeof *ch); + if (skb == NULL) { + printk(KERN_INFO "aoe: skb alloc failure\n"); +- goto cont; ++ dev_put(ifp); ++ continue; + } + skb_put(skb, sizeof *h + sizeof *ch); + skb->dev = ifp; +@@ -440,9 +446,6 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *qu + h->major = cpu_to_be16(aoemajor); + h->minor = aoeminor; + h->cmd = AOECMD_CFG; +- +-cont: +- dev_put(ifp); + } + rcu_read_unlock(); + } +@@ -483,10 +486,13 @@ resend(struct aoedev *d, struct frame *f) + memcpy(h->dst, t->addr, sizeof h->dst); + memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); + ++ dev_hold(t->ifp->nd); + skb->dev = t->ifp->nd; + skb = skb_clone(skb, GFP_ATOMIC); +- if (skb == NULL) ++ if (skb == NULL) { ++ dev_put(t->ifp->nd); + return; ++ } + f->sent = ktime_get(); + __skb_queue_head_init(&queue); + __skb_queue_tail(&queue, skb); +@@ -617,6 +623,8 @@ probe(struct aoetgt *t) + __skb_queue_head_init(&queue); + __skb_queue_tail(&queue, skb); + aoenet_xmit(&queue); ++ } else { ++ dev_put(f->t->ifp->nd); + } + } + +@@ -1395,6 +1403,7 @@ aoecmd_ata_id(struct aoedev *d) + ah->cmdstat = ATA_CMD_ID_ATA; + ah->lba3 = 0xa0; + ++ dev_hold(t->ifp->nd); + skb->dev = t->ifp->nd; + + d->rttavg = RTTAVG_INIT; +@@ -1404,6 +1413,8 @@ aoecmd_ata_id(struct aoedev *d) + skb = skb_clone(skb, GFP_ATOMIC); + if (skb) + f->sent = ktime_get(); ++ else ++ dev_put(t->ifp->nd); + + return skb; + } +diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c +index 63773a90581dd3..1e66c7a188a121 100644 +--- a/drivers/block/aoe/aoenet.c ++++ b/drivers/block/aoe/aoenet.c +@@ -64,6 +64,7 @@ tx(int id) __must_hold(&txlock) + pr_warn("aoe: packet could not be sent on %s. %s\n", + ifp ? ifp->name : "netif", + "consider increasing tx_queue_len"); ++ dev_put(ifp); + spin_lock_irq(&txlock); + } + return 0; +diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c +index 6bc86106c7b2ab..102cc3034412d9 100644 +--- a/drivers/block/drbd/drbd_main.c ++++ b/drivers/block/drbd/drbd_main.c +@@ -3392,10 +3392,12 @@ void drbd_uuid_new_current(struct drbd_device *device) __must_hold(local) + void drbd_uuid_set_bm(struct drbd_device *device, u64 val) __must_hold(local) + { + unsigned long flags; +- if (device->ldev->md.uuid[UI_BITMAP] == 0 && val == 0) ++ spin_lock_irqsave(&device->ldev->md.uuid_lock, flags); ++ if (device->ldev->md.uuid[UI_BITMAP] == 0 && val == 0) { ++ spin_unlock_irqrestore(&device->ldev->md.uuid_lock, flags); + return; ++ } + +- spin_lock_irqsave(&device->ldev->md.uuid_lock, flags); + if (val == 0) { + drbd_uuid_move_history(device); + device->ldev->md.uuid[UI_HISTORY_START] = device->ldev->md.uuid[UI_BITMAP]; +diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c +index 287a8d1d3f707f..87cf5883078f5b 100644 +--- a/drivers/block/drbd/drbd_state.c ++++ b/drivers/block/drbd/drbd_state.c +@@ -876,7 +876,7 @@ is_valid_state(struct drbd_device *device, union drbd_state ns) + ns.disk == D_OUTDATED) + rv = SS_CONNECTED_OUTDATES; + +- else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && ++ else if (nc && (ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && + (nc->verify_alg[0] == 0)) + rv = SS_NO_VERIFY_ALG; + +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index 9f2d412fc560e1..886c6359903779 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -165,39 +165,37 @@ static loff_t get_loop_size(struct loop_device *lo, struct file *file) + return get_size(lo->lo_offset, lo->lo_sizelimit, file); + } + ++/* ++ * We support direct I/O only if lo_offset is aligned with the logical I/O size ++ * of backing device, and the logical block size of loop is bigger than that of ++ * the backing device. ++ */ ++static bool lo_bdev_can_use_dio(struct loop_device *lo, ++ struct block_device *backing_bdev) ++{ ++ unsigned short sb_bsize = bdev_logical_block_size(backing_bdev); ++ ++ if (queue_logical_block_size(lo->lo_queue) < sb_bsize) ++ return false; ++ if (lo->lo_offset & (sb_bsize - 1)) ++ return false; ++ return true; ++} ++ + static void __loop_update_dio(struct loop_device *lo, bool dio) + { + struct file *file = lo->lo_backing_file; +- struct address_space *mapping = file->f_mapping; +- struct inode *inode = mapping->host; +- unsigned short sb_bsize = 0; +- unsigned dio_align = 0; ++ struct inode *inode = file->f_mapping->host; ++ struct block_device *backing_bdev = NULL; + bool use_dio; + +- if (inode->i_sb->s_bdev) { +- sb_bsize = bdev_logical_block_size(inode->i_sb->s_bdev); +- dio_align = sb_bsize - 1; +- } ++ if (S_ISBLK(inode->i_mode)) ++ backing_bdev = I_BDEV(inode); ++ else if (inode->i_sb->s_bdev) ++ backing_bdev = inode->i_sb->s_bdev; + +- /* +- * We support direct I/O only if lo_offset is aligned with the +- * logical I/O size of backing device, and the logical block +- * size of loop is bigger than the backing device's. +- * +- * TODO: the above condition may be loosed in the future, and +- * direct I/O may be switched runtime at that time because most +- * of requests in sane applications should be PAGE_SIZE aligned +- */ +- if (dio) { +- if (queue_logical_block_size(lo->lo_queue) >= sb_bsize && +- !(lo->lo_offset & dio_align) && +- (file->f_mode & FMODE_CAN_ODIRECT)) +- use_dio = true; +- else +- use_dio = false; +- } else { +- use_dio = false; +- } ++ use_dio = dio && (file->f_mode & FMODE_CAN_ODIRECT) && ++ (!backing_bdev || lo_bdev_can_use_dio(lo, backing_bdev)); + + if (lo->use_dio == use_dio) + return; +@@ -213,13 +211,10 @@ static void __loop_update_dio(struct loop_device *lo, bool dio) + if (lo->lo_state == Lo_bound) + blk_mq_freeze_queue(lo->lo_queue); + lo->use_dio = use_dio; +- if (use_dio) { +- blk_queue_flag_clear(QUEUE_FLAG_NOMERGES, lo->lo_queue); ++ if (use_dio) + lo->lo_flags |= LO_FLAGS_DIRECT_IO; +- } else { +- blk_queue_flag_set(QUEUE_FLAG_NOMERGES, lo->lo_queue); ++ else + lo->lo_flags &= ~LO_FLAGS_DIRECT_IO; +- } + if (lo->lo_state == Lo_bound) + blk_mq_unfreeze_queue(lo->lo_queue); + } +@@ -2040,14 +2035,6 @@ static int loop_add(int i) + + blk_queue_max_hw_sectors(lo->lo_queue, BLK_DEF_MAX_SECTORS); + +- /* +- * By default, we do buffer IO, so it doesn't make sense to enable +- * merge because the I/O submitted to backing file is handled page by +- * page. For directio mode, merge does help to dispatch bigger request +- * to underlayer disk. We will enable merge once directio is enabled. +- */ +- blk_queue_flag_set(QUEUE_FLAG_NOMERGES, lo->lo_queue); +- + /* + * Disable partition scanning by default. The in-kernel partition + * scanning can be requested individually per-device during its +diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c +index 800f131222fc8f..96b349148e5788 100644 +--- a/drivers/block/nbd.c ++++ b/drivers/block/nbd.c +@@ -67,6 +67,7 @@ struct nbd_sock { + struct recv_thread_args { + struct work_struct work; + struct nbd_device *nbd; ++ struct nbd_sock *nsock; + int index; + }; + +@@ -180,6 +181,17 @@ static void nbd_requeue_cmd(struct nbd_cmd *cmd) + { + struct request *req = blk_mq_rq_from_pdu(cmd); + ++ lockdep_assert_held(&cmd->lock); ++ ++ /* ++ * Clear INFLIGHT flag so that this cmd won't be completed in ++ * normal completion path ++ * ++ * INFLIGHT flag will be set when the cmd is queued to nbd next ++ * time. ++ */ ++ __clear_bit(NBD_CMD_INFLIGHT, &cmd->flags); ++ + if (!test_and_set_bit(NBD_CMD_REQUEUED, &cmd->flags)) + blk_mq_requeue_request(req, true); + } +@@ -250,7 +262,6 @@ static void nbd_dev_remove(struct nbd_device *nbd) + struct gendisk *disk = nbd->disk; + + del_gendisk(disk); +- put_disk(disk); + blk_mq_free_tag_set(&nbd->tag_set); + + /* +@@ -261,7 +272,7 @@ static void nbd_dev_remove(struct nbd_device *nbd) + idr_remove(&nbd_index_idr, nbd->index); + mutex_unlock(&nbd_index_mutex); + destroy_workqueue(nbd->recv_workq); +- kfree(nbd); ++ put_disk(disk); + } + + static void nbd_dev_remove_work(struct work_struct *work) +@@ -396,6 +407,22 @@ static u32 req_to_nbd_cmd_type(struct request *req) + } + } + ++static struct nbd_config *nbd_get_config_unlocked(struct nbd_device *nbd) ++{ ++ if (refcount_inc_not_zero(&nbd->config_refs)) { ++ /* ++ * Add smp_mb__after_atomic to ensure that reading nbd->config_refs ++ * and reading nbd->config is ordered. The pair is the barrier in ++ * nbd_alloc_and_init_config(), avoid nbd->config_refs is set ++ * before nbd->config. ++ */ ++ smp_mb__after_atomic(); ++ return nbd->config; ++ } ++ ++ return NULL; ++} ++ + static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req) + { + struct nbd_cmd *cmd = blk_mq_rq_to_pdu(req); +@@ -410,13 +437,13 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req) + return BLK_EH_DONE; + } + +- if (!refcount_inc_not_zero(&nbd->config_refs)) { ++ config = nbd_get_config_unlocked(nbd); ++ if (!config) { + cmd->status = BLK_STS_TIMEOUT; + __clear_bit(NBD_CMD_INFLIGHT, &cmd->flags); + mutex_unlock(&cmd->lock); + goto done; + } +- config = nbd->config; + + if (config->num_connections > 1 || + (config->num_connections == 1 && nbd->tag_set.timeout)) { +@@ -445,8 +472,8 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req) + nbd_mark_nsock_dead(nbd, nsock, 1); + mutex_unlock(&nsock->tx_lock); + } +- mutex_unlock(&cmd->lock); + nbd_requeue_cmd(cmd); ++ mutex_unlock(&cmd->lock); + nbd_config_put(nbd); + return BLK_EH_DONE; + } +@@ -490,17 +517,11 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req) + return BLK_EH_DONE; + } + +-/* +- * Send or receive packet. Return a positive value on success and +- * negtive value on failue, and never return 0. +- */ +-static int sock_xmit(struct nbd_device *nbd, int index, int send, +- struct iov_iter *iter, int msg_flags, int *sent) ++static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send, ++ struct iov_iter *iter, int msg_flags, int *sent) + { +- struct nbd_config *config = nbd->config; +- struct socket *sock = config->socks[index]->sock; + int result; +- struct msghdr msg; ++ struct msghdr msg = {} ; + unsigned int noreclaim_flag; + + if (unlikely(!sock)) { +@@ -516,10 +537,6 @@ static int sock_xmit(struct nbd_device *nbd, int index, int send, + do { + sock->sk->sk_allocation = GFP_NOIO | __GFP_MEMALLOC; + sock->sk->sk_use_task_frag = false; +- msg.msg_name = NULL; +- msg.msg_namelen = 0; +- msg.msg_control = NULL; +- msg.msg_controllen = 0; + msg.msg_flags = msg_flags | MSG_NOSIGNAL; + + if (send) +@@ -541,6 +558,19 @@ static int sock_xmit(struct nbd_device *nbd, int index, int send, + return result; + } + ++/* ++ * Send or receive packet. Return a positive value on success and ++ * negtive value on failure, and never return 0. ++ */ ++static int sock_xmit(struct nbd_device *nbd, int index, int send, ++ struct iov_iter *iter, int msg_flags, int *sent) ++{ ++ struct nbd_config *config = nbd->config; ++ struct socket *sock = config->socks[index]->sock; ++ ++ return __sock_xmit(nbd, sock, send, iter, msg_flags, sent); ++} ++ + /* + * Different settings for sk->sk_sndtimeo can result in different return values + * if there is a signal pending when we enter sendmsg, because reasons? +@@ -550,7 +580,10 @@ static inline int was_interrupted(int result) + return result == -ERESTARTSYS || result == -EINTR; + } + +-/* always call with the tx_lock held */ ++/* ++ * Returns BLK_STS_RESOURCE if the caller should retry after a delay. Returns ++ * -EAGAIN if the caller should requeue @cmd. Returns -EIO if sending failed. ++ */ + static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) + { + struct request *req = blk_mq_rq_from_pdu(cmd); +@@ -567,6 +600,9 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) + u32 nbd_cmd_flags = 0; + int sent = nsock->sent, skip = 0; + ++ lockdep_assert_held(&cmd->lock); ++ lockdep_assert_held(&nsock->tx_lock); ++ + iov_iter_kvec(&from, ITER_SOURCE, &iov, 1, sizeof(request)); + + type = req_to_nbd_cmd_type(req); +@@ -631,7 +667,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) + nsock->sent = sent; + } + set_bit(NBD_CMD_REQUEUED, &cmd->flags); +- return BLK_STS_RESOURCE; ++ return (__force int)BLK_STS_RESOURCE; + } + dev_err_ratelimited(disk_to_dev(nbd->disk), + "Send control failed (result %d)\n", result); +@@ -672,7 +708,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) + nsock->pending = req; + nsock->sent = sent; + set_bit(NBD_CMD_REQUEUED, &cmd->flags); +- return BLK_STS_RESOURCE; ++ return (__force int)BLK_STS_RESOURCE; + } + dev_err(disk_to_dev(nbd->disk), + "Send data failed (result %d)\n", +@@ -697,7 +733,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) + return 0; + } + +-static int nbd_read_reply(struct nbd_device *nbd, int index, ++static int nbd_read_reply(struct nbd_device *nbd, struct socket *sock, + struct nbd_reply *reply) + { + struct kvec iov = {.iov_base = reply, .iov_len = sizeof(*reply)}; +@@ -706,7 +742,7 @@ static int nbd_read_reply(struct nbd_device *nbd, int index, + + reply->magic = 0; + iov_iter_kvec(&to, ITER_DEST, &iov, 1, sizeof(*reply)); +- result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL); ++ result = __sock_xmit(nbd, sock, 0, &to, MSG_WAITALL, NULL); + if (result < 0) { + if (!nbd_disconnected(nbd->config)) + dev_err(disk_to_dev(nbd->disk), +@@ -830,14 +866,14 @@ static void recv_work(struct work_struct *work) + struct nbd_device *nbd = args->nbd; + struct nbd_config *config = nbd->config; + struct request_queue *q = nbd->disk->queue; +- struct nbd_sock *nsock; ++ struct nbd_sock *nsock = args->nsock; + struct nbd_cmd *cmd; + struct request *rq; + + while (1) { + struct nbd_reply reply; + +- if (nbd_read_reply(nbd, args->index, &reply)) ++ if (nbd_read_reply(nbd, nsock->sock, &reply)) + break; + + /* +@@ -872,7 +908,6 @@ static void recv_work(struct work_struct *work) + percpu_ref_put(&q->q_usage_counter); + } + +- nsock = config->socks[args->index]; + mutex_lock(&nsock->tx_lock); + nbd_mark_nsock_dead(nbd, nsock, 1); + mutex_unlock(&nsock->tx_lock); +@@ -970,7 +1005,7 @@ static int wait_for_reconnect(struct nbd_device *nbd) + return !test_bit(NBD_RT_DISCONNECTED, &config->runtime_flags); + } + +-static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) ++static blk_status_t nbd_handle_cmd(struct nbd_cmd *cmd, int index) + { + struct request *req = blk_mq_rq_from_pdu(cmd); + struct nbd_device *nbd = cmd->nbd; +@@ -978,18 +1013,20 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) + struct nbd_sock *nsock; + int ret; + +- if (!refcount_inc_not_zero(&nbd->config_refs)) { ++ lockdep_assert_held(&cmd->lock); ++ ++ config = nbd_get_config_unlocked(nbd); ++ if (!config) { + dev_err_ratelimited(disk_to_dev(nbd->disk), + "Socks array is empty\n"); +- return -EINVAL; ++ return BLK_STS_IOERR; + } +- config = nbd->config; + + if (index >= config->num_connections) { + dev_err_ratelimited(disk_to_dev(nbd->disk), + "Attempted send on invalid socket\n"); + nbd_config_put(nbd); +- return -EINVAL; ++ return BLK_STS_IOERR; + } + cmd->status = BLK_STS_OK; + again: +@@ -1012,7 +1049,7 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) + */ + sock_shutdown(nbd); + nbd_config_put(nbd); +- return -EIO; ++ return BLK_STS_IOERR; + } + goto again; + } +@@ -1025,7 +1062,7 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) + blk_mq_start_request(req); + if (unlikely(nsock->pending && nsock->pending != req)) { + nbd_requeue_cmd(cmd); +- ret = 0; ++ ret = BLK_STS_OK; + goto out; + } + /* +@@ -1044,19 +1081,19 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) + "Request send failed, requeueing\n"); + nbd_mark_nsock_dead(nbd, nsock, 1); + nbd_requeue_cmd(cmd); +- ret = 0; ++ ret = BLK_STS_OK; + } + out: + mutex_unlock(&nsock->tx_lock); + nbd_config_put(nbd); +- return ret; ++ return ret < 0 ? BLK_STS_IOERR : (__force blk_status_t)ret; + } + + static blk_status_t nbd_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) + { + struct nbd_cmd *cmd = blk_mq_rq_to_pdu(bd->rq); +- int ret; ++ blk_status_t ret; + + /* + * Since we look at the bio's to send the request over the network we +@@ -1076,10 +1113,6 @@ static blk_status_t nbd_queue_rq(struct blk_mq_hw_ctx *hctx, + * appropriate. + */ + ret = nbd_handle_cmd(cmd, hctx->queue_num); +- if (ret < 0) +- ret = BLK_STS_IOERR; +- else if (!ret) +- ret = BLK_STS_OK; + mutex_unlock(&cmd->lock); + + return ret; +@@ -1216,6 +1249,7 @@ static int nbd_reconnect_socket(struct nbd_device *nbd, unsigned long arg) + INIT_WORK(&args->work, recv_work); + args->index = i; + args->nbd = nbd; ++ args->nsock = nsock; + nsock->cookie++; + mutex_unlock(&nsock->tx_lock); + sockfd_put(old); +@@ -1398,6 +1432,7 @@ static int nbd_start_device(struct nbd_device *nbd) + refcount_inc(&nbd->config_refs); + INIT_WORK(&args->work, recv_work); + args->nbd = nbd; ++ args->nsock = config->socks[i]; + args->index = i; + queue_work(nbd->recv_workq, &args->work); + } +@@ -1531,17 +1566,20 @@ static int nbd_ioctl(struct block_device *bdev, blk_mode_t mode, + return error; + } + +-static struct nbd_config *nbd_alloc_config(void) ++static int nbd_alloc_and_init_config(struct nbd_device *nbd) + { + struct nbd_config *config; + ++ if (WARN_ON(nbd->config)) ++ return -EINVAL; ++ + if (!try_module_get(THIS_MODULE)) +- return ERR_PTR(-ENODEV); ++ return -ENODEV; + + config = kzalloc(sizeof(struct nbd_config), GFP_NOFS); + if (!config) { + module_put(THIS_MODULE); +- return ERR_PTR(-ENOMEM); ++ return -ENOMEM; + } + + atomic_set(&config->recv_threads, 0); +@@ -1549,12 +1587,24 @@ static struct nbd_config *nbd_alloc_config(void) + init_waitqueue_head(&config->conn_wait); + config->blksize_bits = NBD_DEF_BLKSIZE_BITS; + atomic_set(&config->live_connections, 0); +- return config; ++ ++ nbd->config = config; ++ /* ++ * Order refcount_set(&nbd->config_refs, 1) and nbd->config assignment, ++ * its pair is the barrier in nbd_get_config_unlocked(). ++ * So nbd_get_config_unlocked() won't see nbd->config as null after ++ * refcount_inc_not_zero() succeed. ++ */ ++ smp_mb__before_atomic(); ++ refcount_set(&nbd->config_refs, 1); ++ ++ return 0; + } + + static int nbd_open(struct gendisk *disk, blk_mode_t mode) + { + struct nbd_device *nbd; ++ struct nbd_config *config; + int ret = 0; + + mutex_lock(&nbd_index_mutex); +@@ -1567,27 +1617,25 @@ static int nbd_open(struct gendisk *disk, blk_mode_t mode) + ret = -ENXIO; + goto out; + } +- if (!refcount_inc_not_zero(&nbd->config_refs)) { +- struct nbd_config *config; + ++ config = nbd_get_config_unlocked(nbd); ++ if (!config) { + mutex_lock(&nbd->config_lock); + if (refcount_inc_not_zero(&nbd->config_refs)) { + mutex_unlock(&nbd->config_lock); + goto out; + } +- config = nbd_alloc_config(); +- if (IS_ERR(config)) { +- ret = PTR_ERR(config); ++ ret = nbd_alloc_and_init_config(nbd); ++ if (ret) { + mutex_unlock(&nbd->config_lock); + goto out; + } +- nbd->config = config; +- refcount_set(&nbd->config_refs, 1); ++ + refcount_inc(&nbd->refs); + mutex_unlock(&nbd->config_lock); + if (max_part) + set_bit(GD_NEED_PART_SCAN, &disk->state); +- } else if (nbd_disconnected(nbd->config)) { ++ } else if (nbd_disconnected(config)) { + if (max_part) + set_bit(GD_NEED_PART_SCAN, &disk->state); + } +@@ -1608,6 +1656,13 @@ static void nbd_release(struct gendisk *disk) + nbd_put(nbd); + } + ++static void nbd_free_disk(struct gendisk *disk) ++{ ++ struct nbd_device *nbd = disk->private_data; ++ ++ kfree(nbd); ++} ++ + static const struct block_device_operations nbd_fops = + { + .owner = THIS_MODULE, +@@ -1615,6 +1670,7 @@ static const struct block_device_operations nbd_fops = + .release = nbd_release, + .ioctl = nbd_ioctl, + .compat_ioctl = nbd_ioctl, ++ .free_disk = nbd_free_disk, + }; + + #if IS_ENABLED(CONFIG_DEBUG_FS) +@@ -1983,22 +2039,17 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) + pr_err("nbd%d already in use\n", index); + return -EBUSY; + } +- if (WARN_ON(nbd->config)) { +- mutex_unlock(&nbd->config_lock); +- nbd_put(nbd); +- return -EINVAL; +- } +- config = nbd_alloc_config(); +- if (IS_ERR(config)) { ++ ++ ret = nbd_alloc_and_init_config(nbd); ++ if (ret) { + mutex_unlock(&nbd->config_lock); + nbd_put(nbd); + pr_err("couldn't allocate config\n"); +- return PTR_ERR(config); ++ return ret; + } +- nbd->config = config; +- refcount_set(&nbd->config_refs, 1); +- set_bit(NBD_RT_BOUND, &config->runtime_flags); + ++ config = nbd->config; ++ set_bit(NBD_RT_BOUND, &config->runtime_flags); + ret = nbd_genl_size_set(info, nbd); + if (ret) + goto out; +@@ -2201,7 +2252,8 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info) + } + mutex_unlock(&nbd_index_mutex); + +- if (!refcount_inc_not_zero(&nbd->config_refs)) { ++ config = nbd_get_config_unlocked(nbd); ++ if (!config) { + dev_err(nbd_to_dev(nbd), + "not configured, cannot reconfigure\n"); + nbd_put(nbd); +@@ -2209,7 +2261,6 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info) + } + + mutex_lock(&nbd->config_lock); +- config = nbd->config; + if (!test_bit(NBD_RT_BOUND, &config->runtime_flags) || + !nbd->pid) { + dev_err(nbd_to_dev(nbd), +@@ -2401,6 +2452,12 @@ static int nbd_genl_status(struct sk_buff *skb, struct genl_info *info) + } + + dev_list = nla_nest_start_noflag(reply, NBD_ATTR_DEVICE_LIST); ++ if (!dev_list) { ++ nlmsg_free(reply); ++ ret = -EMSGSIZE; ++ goto out; ++ } ++ + if (index == -1) { + ret = idr_for_each(&nbd_index_idr, &status_cb, reply); + if (ret) { +diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c +index 968090935eb23f..97ed3bd9707f41 100644 +--- a/drivers/block/null_blk/main.c ++++ b/drivers/block/null_blk/main.c +@@ -392,13 +392,25 @@ static int nullb_update_nr_hw_queues(struct nullb_device *dev, + static int nullb_apply_submit_queues(struct nullb_device *dev, + unsigned int submit_queues) + { +- return nullb_update_nr_hw_queues(dev, submit_queues, dev->poll_queues); ++ int ret; ++ ++ mutex_lock(&lock); ++ ret = nullb_update_nr_hw_queues(dev, submit_queues, dev->poll_queues); ++ mutex_unlock(&lock); ++ ++ return ret; + } + + static int nullb_apply_poll_queues(struct nullb_device *dev, + unsigned int poll_queues) + { +- return nullb_update_nr_hw_queues(dev, dev->submit_queues, poll_queues); ++ int ret; ++ ++ mutex_lock(&lock); ++ ret = nullb_update_nr_hw_queues(dev, dev->submit_queues, poll_queues); ++ mutex_unlock(&lock); ++ ++ return ret; + } + + NULLB_DEVICE_ATTR(size, ulong, NULL); +@@ -444,28 +456,32 @@ static ssize_t nullb_device_power_store(struct config_item *item, + if (ret < 0) + return ret; + ++ ret = count; ++ mutex_lock(&lock); + if (!dev->power && newp) { + if (test_and_set_bit(NULLB_DEV_FL_UP, &dev->flags)) +- return count; ++ goto out; ++ + ret = null_add_dev(dev); + if (ret) { + clear_bit(NULLB_DEV_FL_UP, &dev->flags); +- return ret; ++ goto out; + } + + set_bit(NULLB_DEV_FL_CONFIGURED, &dev->flags); + dev->power = newp; ++ ret = count; + } else if (dev->power && !newp) { + if (test_and_clear_bit(NULLB_DEV_FL_UP, &dev->flags)) { +- mutex_lock(&lock); + dev->power = newp; + null_del_dev(dev->nullb); +- mutex_unlock(&lock); + } + clear_bit(NULLB_DEV_FL_CONFIGURED, &dev->flags); + } + +- return count; ++out: ++ mutex_unlock(&lock); ++ return ret; + } + + CONFIGFS_ATTR(nullb_device_, power); +@@ -1819,7 +1835,7 @@ static void null_del_dev(struct nullb *nullb) + + dev = nullb->dev; + +- ida_simple_remove(&nullb_indexes, nullb->index); ++ ida_free(&nullb_indexes, nullb->index); + + list_del_init(&nullb->list); + +@@ -2013,8 +2029,8 @@ static int null_validate_conf(struct nullb_device *dev) + return -EINVAL; + } + +- dev->blocksize = round_down(dev->blocksize, 512); +- dev->blocksize = clamp_t(unsigned int, dev->blocksize, 512, 4096); ++ if (blk_validate_block_size(dev->blocksize)) ++ return -EINVAL; + + if (dev->queue_mode == NULL_Q_MQ && dev->use_per_node_hctx) { + if (dev->submit_queues != nr_online_nodes) +@@ -2153,22 +2169,17 @@ static int null_add_dev(struct nullb_device *dev) + nullb->q->queuedata = nullb; + blk_queue_flag_set(QUEUE_FLAG_NONROT, nullb->q); + +- mutex_lock(&lock); +- rv = ida_simple_get(&nullb_indexes, 0, 0, GFP_KERNEL); +- if (rv < 0) { +- mutex_unlock(&lock); ++ rv = ida_alloc(&nullb_indexes, GFP_KERNEL); ++ if (rv < 0) + goto out_cleanup_zone; +- } ++ + nullb->index = rv; + dev->index = rv; +- mutex_unlock(&lock); + + blk_queue_logical_block_size(nullb->q, dev->blocksize); + blk_queue_physical_block_size(nullb->q, dev->blocksize); +- if (!dev->max_sectors) +- dev->max_sectors = queue_max_hw_sectors(nullb->q); +- dev->max_sectors = min(dev->max_sectors, BLK_DEF_MAX_SECTORS); +- blk_queue_max_hw_sectors(nullb->q, dev->max_sectors); ++ if (dev->max_sectors) ++ blk_queue_max_hw_sectors(nullb->q, dev->max_sectors); + + if (dev->virt_boundary) + blk_queue_virt_boundary(nullb->q, PAGE_SIZE - 1); +@@ -2187,9 +2198,7 @@ static int null_add_dev(struct nullb_device *dev) + if (rv) + goto out_ida_free; + +- mutex_lock(&lock); + list_add_tail(&nullb->list, &nullb_list); +- mutex_unlock(&lock); + + pr_info("disk %s created\n", nullb->disk_name); + +@@ -2238,7 +2247,9 @@ static int null_create_dev(void) + if (!dev) + return -ENOMEM; + ++ mutex_lock(&lock); + ret = null_add_dev(dev); ++ mutex_unlock(&lock); + if (ret) { + null_free_dev(dev); + return ret; +@@ -2268,12 +2279,6 @@ static int __init null_init(void) + g_bs = PAGE_SIZE; + } + +- if (g_max_sectors > BLK_DEF_MAX_SECTORS) { +- pr_warn("invalid max sectors\n"); +- pr_warn("defaults max sectors to %u\n", BLK_DEF_MAX_SECTORS); +- g_max_sectors = BLK_DEF_MAX_SECTORS; +- } +- + if (g_home_node != NUMA_NO_NODE && g_home_node >= nr_online_nodes) { + pr_err("invalid home_node value\n"); + g_home_node = NUMA_NO_NODE; +@@ -2360,10 +2365,13 @@ static void __exit null_exit(void) + + if (g_queue_mode == NULL_Q_MQ && shared_tags) + blk_mq_free_tag_set(&tag_set); ++ ++ mutex_destroy(&lock); + } + + module_init(null_init); + module_exit(null_exit); + + MODULE_AUTHOR("Jens Axboe "); ++MODULE_DESCRIPTION("multi queue aware block test driver"); + MODULE_LICENSE("GPL"); +diff --git a/drivers/block/null_blk/zoned.c b/drivers/block/null_blk/zoned.c +index 55c5b48bc276fe..d057f7099e7f7e 100644 +--- a/drivers/block/null_blk/zoned.c ++++ b/drivers/block/null_blk/zoned.c +@@ -83,6 +83,17 @@ int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q) + return -EINVAL; + } + ++ /* ++ * If a smaller zone capacity was requested, do not allow a smaller last ++ * zone at the same time as such zone configuration does not correspond ++ * to any real zoned device. ++ */ ++ if (dev->zone_capacity != dev->zone_size && ++ dev->size & (dev->zone_size - 1)) { ++ pr_err("A smaller last zone is not allowed with zone capacity smaller than zone size.\n"); ++ return -EINVAL; ++ } ++ + zone_capacity_sects = mb_to_sects(dev->zone_capacity); + dev_capacity_sects = mb_to_sects(dev->size); + dev->zone_size_sects = mb_to_sects(dev->zone_size); +@@ -112,7 +123,7 @@ int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q) + if (dev->zone_max_active && dev->zone_max_open > dev->zone_max_active) { + dev->zone_max_open = dev->zone_max_active; + pr_info("changed the maximum number of open zones to %u\n", +- dev->nr_zones); ++ dev->zone_max_open); + } else if (dev->zone_max_open >= dev->nr_zones - dev->zone_nr_conv) { + dev->zone_max_open = 0; + pr_info("zone_max_open limit disabled, limit >= zone count\n"); +diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c +index a999b698b131f7..6fcd7f0fe4f03e 100644 +--- a/drivers/block/rbd.c ++++ b/drivers/block/rbd.c +@@ -362,7 +362,7 @@ enum rbd_watch_state { + enum rbd_lock_state { + RBD_LOCK_STATE_UNLOCKED, + RBD_LOCK_STATE_LOCKED, +- RBD_LOCK_STATE_RELEASING, ++ RBD_LOCK_STATE_QUIESCING, + }; + + /* WatchNotify::ClientId */ +@@ -422,7 +422,7 @@ struct rbd_device { + struct list_head running_list; + struct completion acquire_wait; + int acquire_err; +- struct completion releasing_wait; ++ struct completion quiescing_wait; + + spinlock_t object_map_lock; + u8 *object_map; +@@ -525,7 +525,7 @@ static bool __rbd_is_lock_owner(struct rbd_device *rbd_dev) + lockdep_assert_held(&rbd_dev->lock_rwsem); + + return rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED || +- rbd_dev->lock_state == RBD_LOCK_STATE_RELEASING; ++ rbd_dev->lock_state == RBD_LOCK_STATE_QUIESCING; + } + + static bool rbd_is_lock_owner(struct rbd_device *rbd_dev) +@@ -3452,17 +3452,19 @@ static bool rbd_lock_add_request(struct rbd_img_request *img_req) + static void rbd_lock_del_request(struct rbd_img_request *img_req) + { + struct rbd_device *rbd_dev = img_req->rbd_dev; +- bool need_wakeup; ++ bool need_wakeup = false; + + lockdep_assert_held(&rbd_dev->lock_rwsem); + spin_lock(&rbd_dev->lock_lists_lock); +- rbd_assert(!list_empty(&img_req->lock_item)); +- list_del_init(&img_req->lock_item); +- need_wakeup = (rbd_dev->lock_state == RBD_LOCK_STATE_RELEASING && +- list_empty(&rbd_dev->running_list)); ++ if (!list_empty(&img_req->lock_item)) { ++ rbd_assert(!list_empty(&rbd_dev->running_list)); ++ list_del_init(&img_req->lock_item); ++ need_wakeup = (rbd_dev->lock_state == RBD_LOCK_STATE_QUIESCING && ++ list_empty(&rbd_dev->running_list)); ++ } + spin_unlock(&rbd_dev->lock_lists_lock); + if (need_wakeup) +- complete(&rbd_dev->releasing_wait); ++ complete(&rbd_dev->quiescing_wait); + } + + static int rbd_img_exclusive_lock(struct rbd_img_request *img_req) +@@ -3475,11 +3477,6 @@ static int rbd_img_exclusive_lock(struct rbd_img_request *img_req) + if (rbd_lock_add_request(img_req)) + return 1; + +- if (rbd_dev->opts->exclusive) { +- WARN_ON(1); /* lock got released? */ +- return -EROFS; +- } +- + /* + * Note the use of mod_delayed_work() in rbd_acquire_lock() + * and cancel_delayed_work() in wake_lock_waiters(). +@@ -3842,14 +3839,19 @@ static void wake_lock_waiters(struct rbd_device *rbd_dev, int result) + return; + } + +- list_for_each_entry(img_req, &rbd_dev->acquiring_list, lock_item) { ++ while (!list_empty(&rbd_dev->acquiring_list)) { ++ img_req = list_first_entry(&rbd_dev->acquiring_list, ++ struct rbd_img_request, lock_item); + mutex_lock(&img_req->state_mutex); + rbd_assert(img_req->state == RBD_IMG_EXCLUSIVE_LOCK); ++ if (!result) ++ list_move_tail(&img_req->lock_item, ++ &rbd_dev->running_list); ++ else ++ list_del_init(&img_req->lock_item); + rbd_img_schedule(img_req, result); + mutex_unlock(&img_req->state_mutex); + } +- +- list_splice_tail_init(&rbd_dev->acquiring_list, &rbd_dev->running_list); + } + + static bool locker_equal(const struct ceph_locker *lhs, +@@ -4175,16 +4177,16 @@ static bool rbd_quiesce_lock(struct rbd_device *rbd_dev) + /* + * Ensure that all in-flight IO is flushed. + */ +- rbd_dev->lock_state = RBD_LOCK_STATE_RELEASING; +- rbd_assert(!completion_done(&rbd_dev->releasing_wait)); ++ rbd_dev->lock_state = RBD_LOCK_STATE_QUIESCING; ++ rbd_assert(!completion_done(&rbd_dev->quiescing_wait)); + if (list_empty(&rbd_dev->running_list)) + return true; + + up_write(&rbd_dev->lock_rwsem); +- wait_for_completion(&rbd_dev->releasing_wait); ++ wait_for_completion(&rbd_dev->quiescing_wait); + + down_write(&rbd_dev->lock_rwsem); +- if (rbd_dev->lock_state != RBD_LOCK_STATE_RELEASING) ++ if (rbd_dev->lock_state != RBD_LOCK_STATE_QUIESCING) + return false; + + rbd_assert(list_empty(&rbd_dev->running_list)); +@@ -4595,6 +4597,10 @@ static void rbd_reacquire_lock(struct rbd_device *rbd_dev) + rbd_warn(rbd_dev, "failed to update lock cookie: %d", + ret); + ++ if (rbd_dev->opts->exclusive) ++ rbd_warn(rbd_dev, ++ "temporarily releasing lock on exclusive mapping"); ++ + /* + * Lock cookie cannot be updated on older OSDs, so do + * a manual release and queue an acquire. +@@ -5376,7 +5382,7 @@ static struct rbd_device *__rbd_dev_create(struct rbd_spec *spec) + INIT_LIST_HEAD(&rbd_dev->acquiring_list); + INIT_LIST_HEAD(&rbd_dev->running_list); + init_completion(&rbd_dev->acquire_wait); +- init_completion(&rbd_dev->releasing_wait); ++ init_completion(&rbd_dev->quiescing_wait); + + spin_lock_init(&rbd_dev->object_map_lock); + +@@ -6582,11 +6588,6 @@ static int rbd_add_acquire_lock(struct rbd_device *rbd_dev) + if (ret) + return ret; + +- /* +- * The lock may have been released by now, unless automatic lock +- * transitions are disabled. +- */ +- rbd_assert(!rbd_dev->opts->exclusive || rbd_is_lock_owner(rbd_dev)); + return 0; + } + +diff --git a/drivers/block/rnbd/rnbd-srv.c b/drivers/block/rnbd/rnbd-srv.c +index c186df0ec641c8..b67e39a34010b1 100644 +--- a/drivers/block/rnbd/rnbd-srv.c ++++ b/drivers/block/rnbd/rnbd-srv.c +@@ -585,6 +585,7 @@ static char *rnbd_srv_get_full_path(struct rnbd_srv_session *srv_sess, + { + char *full_path; + char *a, *b; ++ int len; + + full_path = kmalloc(PATH_MAX, GFP_KERNEL); + if (!full_path) +@@ -596,19 +597,19 @@ static char *rnbd_srv_get_full_path(struct rnbd_srv_session *srv_sess, + */ + a = strnstr(dev_search_path, "%SESSNAME%", sizeof(dev_search_path)); + if (a) { +- int len = a - dev_search_path; ++ len = a - dev_search_path; + + len = snprintf(full_path, PATH_MAX, "%.*s/%s/%s", len, + dev_search_path, srv_sess->sessname, dev_name); +- if (len >= PATH_MAX) { +- pr_err("Too long path: %s, %s, %s\n", +- dev_search_path, srv_sess->sessname, dev_name); +- kfree(full_path); +- return ERR_PTR(-EINVAL); +- } + } else { +- snprintf(full_path, PATH_MAX, "%s/%s", +- dev_search_path, dev_name); ++ len = snprintf(full_path, PATH_MAX, "%s/%s", ++ dev_search_path, dev_name); ++ } ++ if (len >= PATH_MAX) { ++ pr_err("Too long path: %s, %s, %s\n", ++ dev_search_path, srv_sess->sessname, dev_name); ++ kfree(full_path); ++ return ERR_PTR(-EINVAL); + } + + /* eliminitate duplicated slashes */ +diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c +index 630ddfe6657bc9..f31607a24f5735 100644 +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -68,9 +68,6 @@ struct ublk_rq_data { + struct llist_node node; + + struct kref ref; +- __u64 sector; +- __u32 operation; +- __u32 nr_zones; + }; + + struct ublk_uring_cmd_pdu { +@@ -115,6 +112,9 @@ struct ublk_uring_cmd_pdu { + */ + #define UBLK_IO_FLAG_NEED_GET_DATA 0x08 + ++/* atomic RW with ubq->cancel_lock */ ++#define UBLK_IO_FLAG_CANCELED 0x80000000 ++ + struct ublk_io { + /* userspace buffer address from io cmd */ + __u64 addr; +@@ -139,6 +139,7 @@ struct ublk_queue { + bool force_abort; + bool timeout; + unsigned short nr_io_ready; /* how many ios setup */ ++ spinlock_t cancel_lock; + struct ublk_device *dev; + struct ublk_io ios[]; + }; +@@ -211,6 +212,33 @@ static inline bool ublk_queue_is_zoned(struct ublk_queue *ubq) + + #ifdef CONFIG_BLK_DEV_ZONED + ++struct ublk_zoned_report_desc { ++ __u64 sector; ++ __u32 operation; ++ __u32 nr_zones; ++}; ++ ++static DEFINE_XARRAY(ublk_zoned_report_descs); ++ ++static int ublk_zoned_insert_report_desc(const struct request *req, ++ struct ublk_zoned_report_desc *desc) ++{ ++ return xa_insert(&ublk_zoned_report_descs, (unsigned long)req, ++ desc, GFP_KERNEL); ++} ++ ++static struct ublk_zoned_report_desc *ublk_zoned_erase_report_desc( ++ const struct request *req) ++{ ++ return xa_erase(&ublk_zoned_report_descs, (unsigned long)req); ++} ++ ++static struct ublk_zoned_report_desc *ublk_zoned_get_report_desc( ++ const struct request *req) ++{ ++ return xa_load(&ublk_zoned_report_descs, (unsigned long)req); ++} ++ + static int ublk_get_nr_zones(const struct ublk_device *ub) + { + const struct ublk_param_basic *p = &ub->params.basic; +@@ -317,7 +345,7 @@ static int ublk_report_zones(struct gendisk *disk, sector_t sector, + unsigned int zones_in_request = + min_t(unsigned int, remaining_zones, max_zones_per_request); + struct request *req; +- struct ublk_rq_data *pdu; ++ struct ublk_zoned_report_desc desc; + blk_status_t status; + + memset(buffer, 0, buffer_length); +@@ -328,20 +356,23 @@ static int ublk_report_zones(struct gendisk *disk, sector_t sector, + goto out; + } + +- pdu = blk_mq_rq_to_pdu(req); +- pdu->operation = UBLK_IO_OP_REPORT_ZONES; +- pdu->sector = sector; +- pdu->nr_zones = zones_in_request; ++ desc.operation = UBLK_IO_OP_REPORT_ZONES; ++ desc.sector = sector; ++ desc.nr_zones = zones_in_request; ++ ret = ublk_zoned_insert_report_desc(req, &desc); ++ if (ret) ++ goto free_req; + + ret = blk_rq_map_kern(disk->queue, req, buffer, buffer_length, + GFP_KERNEL); +- if (ret) { +- blk_mq_free_request(req); +- goto out; +- } ++ if (ret) ++ goto erase_desc; + + status = blk_execute_rq(req, 0); + ret = blk_status_to_errno(status); ++erase_desc: ++ ublk_zoned_erase_report_desc(req); ++free_req: + blk_mq_free_request(req); + if (ret) + goto out; +@@ -375,7 +406,7 @@ static blk_status_t ublk_setup_iod_zoned(struct ublk_queue *ubq, + { + struct ublksrv_io_desc *iod = ublk_get_iod(ubq, req->tag); + struct ublk_io *io = &ubq->ios[req->tag]; +- struct ublk_rq_data *pdu = blk_mq_rq_to_pdu(req); ++ struct ublk_zoned_report_desc *desc; + u32 ublk_op; + + switch (req_op(req)) { +@@ -398,12 +429,15 @@ static blk_status_t ublk_setup_iod_zoned(struct ublk_queue *ubq, + ublk_op = UBLK_IO_OP_ZONE_RESET_ALL; + break; + case REQ_OP_DRV_IN: +- ublk_op = pdu->operation; ++ desc = ublk_zoned_get_report_desc(req); ++ if (!desc) ++ return BLK_STS_IOERR; ++ ublk_op = desc->operation; + switch (ublk_op) { + case UBLK_IO_OP_REPORT_ZONES: + iod->op_flags = ublk_op | ublk_req_build_flags(req); +- iod->nr_zones = pdu->nr_zones; +- iod->start_sector = pdu->sector; ++ iod->nr_zones = desc->nr_zones; ++ iod->start_sector = desc->sector; + return BLK_STS_OK; + default: + return BLK_STS_IOERR; +@@ -1477,28 +1511,28 @@ static inline bool ublk_queue_ready(struct ublk_queue *ubq) + return ubq->nr_io_ready == ubq->q_depth; + } + +-static void ublk_cmd_cancel_cb(struct io_uring_cmd *cmd, unsigned issue_flags) +-{ +- io_uring_cmd_done(cmd, UBLK_IO_RES_ABORT, 0, issue_flags); +-} +- + static void ublk_cancel_queue(struct ublk_queue *ubq) + { + int i; + +- if (!ublk_queue_ready(ubq)) +- return; +- + for (i = 0; i < ubq->q_depth; i++) { + struct ublk_io *io = &ubq->ios[i]; + +- if (io->flags & UBLK_IO_FLAG_ACTIVE) +- io_uring_cmd_complete_in_task(io->cmd, +- ublk_cmd_cancel_cb); +- } ++ if (io->flags & UBLK_IO_FLAG_ACTIVE) { ++ bool done; + +- /* all io commands are canceled */ +- ubq->nr_io_ready = 0; ++ spin_lock(&ubq->cancel_lock); ++ done = !!(io->flags & UBLK_IO_FLAG_CANCELED); ++ if (!done) ++ io->flags |= UBLK_IO_FLAG_CANCELED; ++ spin_unlock(&ubq->cancel_lock); ++ ++ if (!done) ++ io_uring_cmd_done(io->cmd, ++ UBLK_IO_RES_ABORT, 0, ++ IO_URING_F_UNLOCKED); ++ } ++ } + } + + /* Cancel all pending commands, must be called after del_gendisk() returns */ +@@ -1545,7 +1579,6 @@ static void __ublk_quiesce_dev(struct ublk_device *ub) + blk_mq_quiesce_queue(ub->ub_disk->queue); + ublk_wait_tagset_rqs_idle(ub); + ub->dev_info.state = UBLK_S_DEV_QUIESCED; +- ublk_cancel_dev(ub); + /* we are going to release task_struct of ubq_daemon and resets + * ->ubq_daemon to NULL. So in monitor_work, check on ubq_daemon causes UAF. + * Besides, monitor_work is not necessary in QUIESCED state since we have +@@ -1568,6 +1601,7 @@ static void ublk_quiesce_work_fn(struct work_struct *work) + __ublk_quiesce_dev(ub); + unlock: + mutex_unlock(&ub->mutex); ++ ublk_cancel_dev(ub); + } + + static void ublk_unquiesce_dev(struct ublk_device *ub) +@@ -1607,8 +1641,8 @@ static void ublk_stop_dev(struct ublk_device *ub) + put_disk(ub->ub_disk); + ub->ub_disk = NULL; + unlock: +- ublk_cancel_dev(ub); + mutex_unlock(&ub->mutex); ++ ublk_cancel_dev(ub); + cancel_delayed_work_sync(&ub->monitor_work); + } + +@@ -1962,6 +1996,7 @@ static int ublk_init_queue(struct ublk_device *ub, int q_id) + void *ptr; + int size; + ++ spin_lock_init(&ubq->cancel_lock); + ubq->flags = ub->dev_info.flags; + ubq->q_id = q_id; + ubq->q_depth = ub->dev_info.queue_depth; +@@ -2292,10 +2327,19 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd) + * TODO: provide forward progress for RECOVERY handler, so that + * unprivileged device can benefit from it + */ +- if (info.flags & UBLK_F_UNPRIVILEGED_DEV) ++ if (info.flags & UBLK_F_UNPRIVILEGED_DEV) { + info.flags &= ~(UBLK_F_USER_RECOVERY_REISSUE | + UBLK_F_USER_RECOVERY); + ++ /* ++ * For USER_COPY, we depends on userspace to fill request ++ * buffer by pwrite() to ublk char device, which can't be ++ * used for unprivileged device ++ */ ++ if (info.flags & UBLK_F_USER_COPY) ++ return -EINVAL; ++ } ++ + /* the created device is always owned by current user */ + ublk_store_owner_uid_gid(&info.owner_uid, &info.owner_gid); + +@@ -2569,8 +2613,9 @@ static void ublk_queue_reinit(struct ublk_device *ub, struct ublk_queue *ubq) + int i; + + WARN_ON_ONCE(!(ubq->ubq_daemon && ubq_daemon_is_dying(ubq))); ++ + /* All old ioucmds have to be completed */ +- WARN_ON_ONCE(ubq->nr_io_ready); ++ ubq->nr_io_ready = 0; + /* old daemon is PF_EXITING, put it now */ + put_task_struct(ubq->ubq_daemon); + /* We have to reset it to NULL, otherwise ub won't accept new FETCH_REQ */ +@@ -2597,6 +2642,8 @@ static int ublk_ctrl_start_recovery(struct ublk_device *ub, + mutex_lock(&ub->mutex); + if (!ublk_can_use_recovery(ub)) + goto out_unlock; ++ if (!ub->nr_queues_ready) ++ goto out_unlock; + /* + * START_RECOVERY is only allowd after: + * +diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c +index 1fe011676d070e..41b2fd7e1b9e50 100644 +--- a/drivers/block/virtio_blk.c ++++ b/drivers/block/virtio_blk.c +@@ -1021,12 +1021,12 @@ static void virtblk_config_changed(struct virtio_device *vdev) + static int init_vq(struct virtio_blk *vblk) + { + int err; +- int i; ++ unsigned short i; + vq_callback_t **callbacks; + const char **names; + struct virtqueue **vqs; + unsigned short num_vqs; +- unsigned int num_poll_vqs; ++ unsigned short num_poll_vqs; + struct virtio_device *vdev = vblk->vdev; + struct irq_affinity desc = { 0, }; + +@@ -1070,13 +1070,13 @@ static int init_vq(struct virtio_blk *vblk) + + for (i = 0; i < num_vqs - num_poll_vqs; i++) { + callbacks[i] = virtblk_done; +- snprintf(vblk->vqs[i].name, VQ_NAME_LEN, "req.%d", i); ++ snprintf(vblk->vqs[i].name, VQ_NAME_LEN, "req.%u", i); + names[i] = vblk->vqs[i].name; + } + + for (; i < num_vqs; i++) { + callbacks[i] = NULL; +- snprintf(vblk->vqs[i].name, VQ_NAME_LEN, "req_poll.%d", i); ++ snprintf(vblk->vqs[i].name, VQ_NAME_LEN, "req_poll.%u", i); + names[i] = vblk->vqs[i].name; + } + +@@ -1313,6 +1313,7 @@ static int virtblk_probe(struct virtio_device *vdev) + u16 min_io_size; + u8 physical_block_exp, alignment_offset; + unsigned int queue_depth; ++ size_t max_dma_size; + + if (!vdev->config->get) { + dev_err(&vdev->dev, "%s failure: config access disabled\n", +@@ -1411,7 +1412,8 @@ static int virtblk_probe(struct virtio_device *vdev) + /* No real sector limit. */ + blk_queue_max_hw_sectors(q, UINT_MAX); + +- max_size = virtio_max_dma_size(vdev); ++ max_dma_size = virtio_max_dma_size(vdev); ++ max_size = max_dma_size > U32_MAX ? U32_MAX : max_dma_size; + + /* Host can optionally specify maximum segment size and number of + * segments. */ +@@ -1627,14 +1629,15 @@ static int virtblk_freeze(struct virtio_device *vdev) + { + struct virtio_blk *vblk = vdev->priv; + ++ /* Ensure no requests in virtqueues before deleting vqs. */ ++ blk_mq_freeze_queue(vblk->disk->queue); ++ + /* Ensure we don't receive any more interrupts */ + virtio_reset_device(vdev); + + /* Make sure no work handler is accessing the device. */ + flush_work(&vblk->config_work); + +- blk_mq_quiesce_queue(vblk->disk->queue); +- + vdev->config->del_vqs(vdev); + kfree(vblk->vqs); + +@@ -1652,7 +1655,7 @@ static int virtblk_restore(struct virtio_device *vdev) + + virtio_device_ready(vdev); + +- blk_mq_unquiesce_queue(vblk->disk->queue); ++ blk_mq_unfreeze_queue(vblk->disk->queue); + return 0; + } + #endif +diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c +index 06673c6ca25555..606f388c7a5716 100644 +--- a/drivers/block/zram/zram_drv.c ++++ b/drivers/block/zram/zram_drv.c +@@ -1983,6 +1983,13 @@ static void zram_destroy_comps(struct zram *zram) + zcomp_destroy(comp); + zram->num_active_comps--; + } ++ ++ for (prio = ZRAM_PRIMARY_COMP; prio < ZRAM_MAX_COMPS; prio++) { ++ /* Do not free statically defined compression algorithms */ ++ if (zram->comp_algs[prio] != default_compressor) ++ kfree(zram->comp_algs[prio]); ++ zram->comp_algs[prio] = NULL; ++ } + } + + static void zram_reset_device(struct zram *zram) +diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c +index 88262d3a93923a..ce97b336fbfb8a 100644 +--- a/drivers/bluetooth/ath3k.c ++++ b/drivers/bluetooth/ath3k.c +@@ -3,7 +3,6 @@ + * Copyright (c) 2008-2009 Atheros Communications Inc. + */ + +- + #include + #include + #include +@@ -128,7 +127,6 @@ MODULE_DEVICE_TABLE(usb, ath3k_table); + * for AR3012 + */ + static const struct usb_device_id ath3k_blist_tbl[] = { +- + /* Atheros AR3012 with sflash firmware*/ + { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, +@@ -202,7 +200,7 @@ static inline void ath3k_log_failed_loading(int err, int len, int size, + #define TIMEGAP_USEC_MAX 100 + + static int ath3k_load_firmware(struct usb_device *udev, +- const struct firmware *firmware) ++ const struct firmware *firmware) + { + u8 *send_buf; + int len = 0; +@@ -237,9 +235,9 @@ static int ath3k_load_firmware(struct usb_device *udev, + memcpy(send_buf, firmware->data + sent, size); + + err = usb_bulk_msg(udev, pipe, send_buf, size, +- &len, 3000); ++ &len, 3000); + +- if (err || (len != size)) { ++ if (err || len != size) { + ath3k_log_failed_loading(err, len, size, count); + goto error; + } +@@ -262,7 +260,7 @@ static int ath3k_get_state(struct usb_device *udev, unsigned char *state) + } + + static int ath3k_get_version(struct usb_device *udev, +- struct ath3k_version *version) ++ struct ath3k_version *version) + { + return usb_control_msg_recv(udev, 0, ATH3K_GETVERSION, + USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, +@@ -271,7 +269,7 @@ static int ath3k_get_version(struct usb_device *udev, + } + + static int ath3k_load_fwfile(struct usb_device *udev, +- const struct firmware *firmware) ++ const struct firmware *firmware) + { + u8 *send_buf; + int len = 0; +@@ -310,8 +308,8 @@ static int ath3k_load_fwfile(struct usb_device *udev, + memcpy(send_buf, firmware->data + sent, size); + + err = usb_bulk_msg(udev, pipe, send_buf, size, +- &len, 3000); +- if (err || (len != size)) { ++ &len, 3000); ++ if (err || len != size) { + ath3k_log_failed_loading(err, len, size, count); + kfree(send_buf); + return err; +@@ -425,7 +423,6 @@ static int ath3k_load_syscfg(struct usb_device *udev) + } + + switch (fw_version.ref_clock) { +- + case ATH3K_XTAL_FREQ_26M: + clk_value = 26; + break; +@@ -441,7 +438,7 @@ static int ath3k_load_syscfg(struct usb_device *udev) + } + + snprintf(filename, ATH3K_NAME_LEN, "ar3k/ramps_0x%08x_%d%s", +- le32_to_cpu(fw_version.rom_version), clk_value, ".dfu"); ++ le32_to_cpu(fw_version.rom_version), clk_value, ".dfu"); + + ret = request_firmware(&firmware, filename, &udev->dev); + if (ret < 0) { +@@ -456,7 +453,7 @@ static int ath3k_load_syscfg(struct usb_device *udev) + } + + static int ath3k_probe(struct usb_interface *intf, +- const struct usb_device_id *id) ++ const struct usb_device_id *id) + { + const struct firmware *firmware; + struct usb_device *udev = interface_to_usbdev(intf); +@@ -505,10 +502,10 @@ static int ath3k_probe(struct usb_interface *intf, + if (ret < 0) { + if (ret == -ENOENT) + BT_ERR("Firmware file \"%s\" not found", +- ATH3K_FIRMWARE); ++ ATH3K_FIRMWARE); + else + BT_ERR("Firmware file \"%s\" request failed (err=%d)", +- ATH3K_FIRMWARE, ret); ++ ATH3K_FIRMWARE, ret); + return ret; + } + +diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c +index 2462796a512a5f..a936219aebb81a 100644 +--- a/drivers/bluetooth/btintel.c ++++ b/drivers/bluetooth/btintel.c +@@ -26,21 +26,11 @@ + #define ECDSA_OFFSET 644 + #define ECDSA_HEADER_LEN 320 + +-#define BTINTEL_PPAG_NAME "PPAG" +- + enum { + DSM_SET_WDISABLE2_DELAY = 1, + DSM_SET_RESET_METHOD = 3, + }; + +-/* structure to store the PPAG data read from ACPI table */ +-struct btintel_ppag { +- u32 domain; +- u32 mode; +- acpi_status status; +- struct hci_dev *hdev; +-}; +- + #define CMD_WRITE_BOOT_PARAMS 0xfc0e + struct cmd_write_boot_params { + __le32 boot_addr; +@@ -441,7 +431,7 @@ int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver) + return PTR_ERR(skb); + } + +- if (skb->len != sizeof(*ver)) { ++ if (!skb || skb->len != sizeof(*ver)) { + bt_dev_err(hdev, "Intel version event size mismatch"); + kfree_skb(skb); + return -EILSEQ; +@@ -1312,65 +1302,6 @@ static int btintel_read_debug_features(struct hci_dev *hdev, + return 0; + } + +-static acpi_status btintel_ppag_callback(acpi_handle handle, u32 lvl, void *data, +- void **ret) +-{ +- acpi_status status; +- size_t len; +- struct btintel_ppag *ppag = data; +- union acpi_object *p, *elements; +- struct acpi_buffer string = {ACPI_ALLOCATE_BUFFER, NULL}; +- struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; +- struct hci_dev *hdev = ppag->hdev; +- +- status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); +- if (ACPI_FAILURE(status)) { +- bt_dev_warn(hdev, "PPAG-BT: ACPI Failure: %s", acpi_format_exception(status)); +- return status; +- } +- +- len = strlen(string.pointer); +- if (len < strlen(BTINTEL_PPAG_NAME)) { +- kfree(string.pointer); +- return AE_OK; +- } +- +- if (strncmp((char *)string.pointer + len - 4, BTINTEL_PPAG_NAME, 4)) { +- kfree(string.pointer); +- return AE_OK; +- } +- kfree(string.pointer); +- +- status = acpi_evaluate_object(handle, NULL, NULL, &buffer); +- if (ACPI_FAILURE(status)) { +- ppag->status = status; +- bt_dev_warn(hdev, "PPAG-BT: ACPI Failure: %s", acpi_format_exception(status)); +- return status; +- } +- +- p = buffer.pointer; +- ppag = (struct btintel_ppag *)data; +- +- if (p->type != ACPI_TYPE_PACKAGE || p->package.count != 2) { +- kfree(buffer.pointer); +- bt_dev_warn(hdev, "PPAG-BT: Invalid object type: %d or package count: %d", +- p->type, p->package.count); +- ppag->status = AE_ERROR; +- return AE_ERROR; +- } +- +- elements = p->package.elements; +- +- /* PPAG table is located at element[1] */ +- p = &elements[1]; +- +- ppag->domain = (u32)p->package.elements[0].integer.value; +- ppag->mode = (u32)p->package.elements[1].integer.value; +- ppag->status = AE_OK; +- kfree(buffer.pointer); +- return AE_CTRL_TERMINATE; +-} +- + static int btintel_set_debug_features(struct hci_dev *hdev, + const struct intel_debug_features *features) + { +@@ -2399,10 +2330,13 @@ static int btintel_configure_offload(struct hci_dev *hdev) + + static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver) + { +- struct btintel_ppag ppag; + struct sk_buff *skb; + struct hci_ppag_enable_cmd ppag_cmd; + acpi_handle handle; ++ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; ++ union acpi_object *p, *elements; ++ u32 domain, mode; ++ acpi_status status; + + /* PPAG is not supported if CRF is HrP2, Jfp2, JfP1 */ + switch (ver->cnvr_top & 0xFFF) { +@@ -2420,22 +2354,34 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver + return; + } + +- memset(&ppag, 0, sizeof(ppag)); +- +- ppag.hdev = hdev; +- ppag.status = AE_NOT_FOUND; +- acpi_walk_namespace(ACPI_TYPE_PACKAGE, handle, 1, NULL, +- btintel_ppag_callback, &ppag, NULL); +- +- if (ACPI_FAILURE(ppag.status)) { +- if (ppag.status == AE_NOT_FOUND) { ++ status = acpi_evaluate_object(handle, "PPAG", NULL, &buffer); ++ if (ACPI_FAILURE(status)) { ++ if (status == AE_NOT_FOUND) { + bt_dev_dbg(hdev, "PPAG-BT: ACPI entry not found"); + return; + } ++ bt_dev_warn(hdev, "PPAG-BT: ACPI Failure: %s", acpi_format_exception(status)); + return; + } + +- if (ppag.domain != 0x12) { ++ p = buffer.pointer; ++ if (p->type != ACPI_TYPE_PACKAGE || p->package.count != 2) { ++ bt_dev_warn(hdev, "PPAG-BT: Invalid object type: %d or package count: %d", ++ p->type, p->package.count); ++ kfree(buffer.pointer); ++ return; ++ } ++ ++ elements = p->package.elements; ++ ++ /* PPAG table is located at element[1] */ ++ p = &elements[1]; ++ ++ domain = (u32)p->package.elements[0].integer.value; ++ mode = (u32)p->package.elements[1].integer.value; ++ kfree(buffer.pointer); ++ ++ if (domain != 0x12) { + bt_dev_dbg(hdev, "PPAG-BT: Bluetooth domain is disabled in ACPI firmware"); + return; + } +@@ -2446,19 +2392,22 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver + * BIT 1 : 0 Disabled in China + * 1 Enabled in China + */ +- if ((ppag.mode & 0x01) != BIT(0) && (ppag.mode & 0x02) != BIT(1)) { +- bt_dev_dbg(hdev, "PPAG-BT: EU, China mode are disabled in CB/BIOS"); ++ mode &= 0x03; ++ ++ if (!mode) { ++ bt_dev_dbg(hdev, "PPAG-BT: EU, China mode are disabled in BIOS"); + return; + } + +- ppag_cmd.ppag_enable_flags = cpu_to_le32(ppag.mode); ++ ppag_cmd.ppag_enable_flags = cpu_to_le32(mode); + +- skb = __hci_cmd_sync(hdev, INTEL_OP_PPAG_CMD, sizeof(ppag_cmd), &ppag_cmd, HCI_CMD_TIMEOUT); ++ skb = __hci_cmd_sync(hdev, INTEL_OP_PPAG_CMD, sizeof(ppag_cmd), ++ &ppag_cmd, HCI_CMD_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_warn(hdev, "Failed to send PPAG Enable (%ld)", PTR_ERR(skb)); + return; + } +- bt_dev_info(hdev, "PPAG-BT: Enabled (Mode %d)", ppag.mode); ++ bt_dev_info(hdev, "PPAG-BT: Enabled (Mode %d)", mode); + kfree_skb(skb); + } + +@@ -2896,6 +2845,9 @@ static int btintel_setup_combined(struct hci_dev *hdev) + btintel_set_dsm_reset_method(hdev, &ver_tlv); + + err = btintel_bootloader_setup_tlv(hdev, &ver_tlv); ++ if (err) ++ goto exit_error; ++ + btintel_register_devcoredump_support(hdev); + break; + default: +diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c +index 9658b33c824a70..18f34998a1204a 100644 +--- a/drivers/bluetooth/btmrvl_main.c ++++ b/drivers/bluetooth/btmrvl_main.c +@@ -121,13 +121,6 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) + ((event->data[2] == MODULE_BROUGHT_UP) || + (event->data[2] == MODULE_ALREADY_UP)) ? + "Bring-up succeed" : "Bring-up failed"); +- +- if (event->length > 3 && event->data[3]) +- priv->btmrvl_dev.dev_type = HCI_AMP; +- else +- priv->btmrvl_dev.dev_type = HCI_PRIMARY; +- +- BT_DBG("dev_type: %d", priv->btmrvl_dev.dev_type); + } else if (priv->btmrvl_dev.sendcmdflag && + event->data[1] == MODULE_SHUTDOWN_REQ) { + BT_DBG("EVENT:%s", (event->data[2]) ? +@@ -686,8 +679,6 @@ int btmrvl_register_hdev(struct btmrvl_private *priv) + hdev->wakeup = btmrvl_wakeup; + SET_HCIDEV_DEV(hdev, &card->func->dev); + +- hdev->dev_type = priv->btmrvl_dev.dev_type; +- + ret = hci_register_dev(hdev); + if (ret < 0) { + BT_ERR("Can not register HCI device"); +diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c +index d76c799553aaa1..468e4165c7cc0e 100644 +--- a/drivers/bluetooth/btmrvl_sdio.c ++++ b/drivers/bluetooth/btmrvl_sdio.c +@@ -92,7 +92,7 @@ static int btmrvl_sdio_probe_of(struct device *dev, + } else { + ret = devm_request_irq(dev, cfg->irq_bt, + btmrvl_wake_irq_bt, +- 0, "bt_wake", card); ++ IRQF_NO_AUTOEN, "bt_wake", card); + if (ret) { + dev_err(dev, + "Failed to request irq_bt %d (%d)\n", +@@ -101,7 +101,6 @@ static int btmrvl_sdio_probe_of(struct device *dev, + + /* Configure wakeup (enabled by default) */ + device_init_wakeup(dev, true); +- disable_irq(cfg->irq_bt); + } + } + +diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c +index aaabb732082cd8..812fd2a8f853e1 100644 +--- a/drivers/bluetooth/btmtk.c ++++ b/drivers/bluetooth/btmtk.c +@@ -372,14 +372,18 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb) + struct btmediatek_data *data = hci_get_priv(hdev); + int err; + +- if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) ++ if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) { ++ kfree_skb(skb); + return 0; ++ } + + switch (data->cd_info.state) { + case HCI_DEVCOREDUMP_IDLE: + err = hci_devcd_init(hdev, MTK_COREDUMP_SIZE); +- if (err < 0) ++ if (err < 0) { ++ kfree_skb(skb); + break; ++ } + data->cd_info.cnt = 0; + + /* It is supposed coredump can be done within 5 seconds */ +@@ -405,9 +409,6 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb) + break; + } + +- if (err < 0) +- kfree_skb(skb); +- + return err; + } + EXPORT_SYMBOL_GPL(btmtk_process_coredump); +@@ -420,5 +421,6 @@ MODULE_LICENSE("GPL"); + MODULE_FIRMWARE(FIRMWARE_MT7622); + MODULE_FIRMWARE(FIRMWARE_MT7663); + MODULE_FIRMWARE(FIRMWARE_MT7668); ++MODULE_FIRMWARE(FIRMWARE_MT7922); + MODULE_FIRMWARE(FIRMWARE_MT7961); + MODULE_FIRMWARE(FIRMWARE_MT7925); +diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h +index 56f5502baadf9f..cbcdb99a22e6dd 100644 +--- a/drivers/bluetooth/btmtk.h ++++ b/drivers/bluetooth/btmtk.h +@@ -4,6 +4,7 @@ + #define FIRMWARE_MT7622 "mediatek/mt7622pr2h.bin" + #define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin" + #define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin" ++#define FIRMWARE_MT7922 "mediatek/BT_RAM_CODE_MT7922_1_1_hdr.bin" + #define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin" + #define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin" + +diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c +index 935feab815d973..203a000a84e341 100644 +--- a/drivers/bluetooth/btmtkuart.c ++++ b/drivers/bluetooth/btmtkuart.c +@@ -336,7 +336,7 @@ mtk_stp_split(struct btmtkuart_dev *bdev, const unsigned char *data, int count, + return data; + } + +-static int btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count) ++static void btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count) + { + struct btmtkuart_dev *bdev = hci_get_drvdata(hdev); + const unsigned char *p_left = data, *p_h4; +@@ -375,25 +375,20 @@ static int btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count) + bt_dev_err(bdev->hdev, + "Frame reassembly failed (%d)", err); + bdev->rx_skb = NULL; +- return err; ++ return; + } + + sz_left -= sz_h4; + p_left += sz_h4; + } +- +- return 0; + } + + static int btmtkuart_receive_buf(struct serdev_device *serdev, const u8 *data, + size_t count) + { + struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev); +- int err; + +- err = btmtkuart_recv(bdev->hdev, data, count); +- if (err < 0) +- return err; ++ btmtkuart_recv(bdev->hdev, data, count); + + bdev->hdev->stat.byte_rx += count; + +diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c +index b7e66b7ac57022..5ee9a8b8dcfdb8 100644 +--- a/drivers/bluetooth/btnxpuart.c ++++ b/drivers/bluetooth/btnxpuart.c +@@ -29,6 +29,7 @@ + #define BTNXPUART_CHECK_BOOT_SIGNATURE 3 + #define BTNXPUART_SERDEV_OPEN 4 + #define BTNXPUART_IR_IN_PROGRESS 5 ++#define BTNXPUART_FW_DOWNLOAD_ABORT 6 + + /* NXP HW err codes */ + #define BTNXPUART_IR_HW_ERR 0xb0 +@@ -126,6 +127,7 @@ struct ps_data { + struct hci_dev *hdev; + struct work_struct work; + struct timer_list ps_timer; ++ struct mutex ps_lock; + }; + + struct wakeup_cmd_payload { +@@ -158,6 +160,7 @@ struct btnxpuart_dev { + u8 fw_name[MAX_FW_FILE_NAME_LEN]; + u32 fw_dnld_v1_offset; + u32 fw_v1_sent_bytes; ++ u32 fw_dnld_v3_offset; + u32 fw_v3_offset_correction; + u32 fw_v1_expected_len; + u32 boot_reg_offset; +@@ -186,6 +189,11 @@ struct btnxpuart_dev { + #define NXP_NAK_V3 0x7b + #define NXP_CRC_ERROR_V3 0x7c + ++/* Bootloader signature error codes */ ++#define NXP_ACK_RX_TIMEOUT 0x0002 /* ACK not received from host */ ++#define NXP_HDR_RX_TIMEOUT 0x0003 /* FW Header chunk not received */ ++#define NXP_DATA_RX_TIMEOUT 0x0004 /* FW Data chunk not received */ ++ + #define HDR_LEN 16 + + #define NXP_RECV_CHIP_VER_V1 \ +@@ -276,11 +284,22 @@ struct nxp_bootloader_cmd { + __be32 crc; + } __packed; + ++struct nxp_v3_rx_timeout_nak { ++ u8 nak; ++ __le32 offset; ++ u8 crc; ++} __packed; ++ ++union nxp_v3_rx_timeout_nak_u { ++ struct nxp_v3_rx_timeout_nak pkt; ++ u8 buf[6]; ++}; ++ + static u8 crc8_table[CRC8_TABLE_SIZE]; + + /* Default configurations */ + #define DEFAULT_H2C_WAKEUP_MODE WAKEUP_METHOD_BREAK +-#define DEFAULT_PS_MODE PS_MODE_DISABLE ++#define DEFAULT_PS_MODE PS_MODE_ENABLE + #define FW_INIT_BAUDRATE HCI_NXP_PRI_BAUDRATE + + static struct sk_buff *nxp_drv_send_cmd(struct hci_dev *hdev, u16 opcode, +@@ -317,6 +336,9 @@ static void ps_start_timer(struct btnxpuart_dev *nxpdev) + + if (psdata->cur_psmode == PS_MODE_ENABLE) + mod_timer(&psdata->ps_timer, jiffies + msecs_to_jiffies(psdata->h2c_ps_interval)); ++ ++ if (psdata->ps_state == PS_STATE_AWAKE && psdata->ps_cmd == PS_CMD_ENTER_PS) ++ cancel_work_sync(&psdata->work); + } + + static void ps_cancel_timer(struct btnxpuart_dev *nxpdev) +@@ -324,7 +346,7 @@ static void ps_cancel_timer(struct btnxpuart_dev *nxpdev) + struct ps_data *psdata = &nxpdev->psdata; + + flush_work(&psdata->work); +- del_timer_sync(&psdata->ps_timer); ++ timer_shutdown_sync(&psdata->ps_timer); + } + + static void ps_control(struct hci_dev *hdev, u8 ps_state) +@@ -337,6 +359,7 @@ static void ps_control(struct hci_dev *hdev, u8 ps_state) + !test_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state)) + return; + ++ mutex_lock(&psdata->ps_lock); + switch (psdata->cur_h2c_wakeupmode) { + case WAKEUP_METHOD_DTR: + if (ps_state == PS_STATE_AWAKE) +@@ -350,12 +373,15 @@ static void ps_control(struct hci_dev *hdev, u8 ps_state) + status = serdev_device_break_ctl(nxpdev->serdev, 0); + else + status = serdev_device_break_ctl(nxpdev->serdev, -1); ++ msleep(20); /* Allow chip to detect UART-break and enter sleep */ + bt_dev_dbg(hdev, "Set UART break: %s, status=%d", + str_on_off(ps_state == PS_STATE_SLEEP), status); + break; + } + if (!status) + psdata->ps_state = ps_state; ++ mutex_unlock(&psdata->ps_lock); ++ + if (ps_state == PS_STATE_AWAKE) + btnxpuart_tx_wakeup(nxpdev); + } +@@ -391,17 +417,42 @@ static void ps_setup(struct hci_dev *hdev) + + psdata->hdev = hdev; + INIT_WORK(&psdata->work, ps_work_func); ++ mutex_init(&psdata->ps_lock); + timer_setup(&psdata->ps_timer, ps_timeout_func, 0); + } + +-static void ps_wakeup(struct btnxpuart_dev *nxpdev) ++static bool ps_wakeup(struct btnxpuart_dev *nxpdev) + { + struct ps_data *psdata = &nxpdev->psdata; ++ u8 ps_state; ++ ++ mutex_lock(&psdata->ps_lock); ++ ps_state = psdata->ps_state; ++ mutex_unlock(&psdata->ps_lock); + +- if (psdata->ps_state != PS_STATE_AWAKE) { ++ if (ps_state != PS_STATE_AWAKE) { + psdata->ps_cmd = PS_CMD_EXIT_PS; + schedule_work(&psdata->work); ++ return true; + } ++ return false; ++} ++ ++static void ps_cleanup(struct btnxpuart_dev *nxpdev) ++{ ++ struct ps_data *psdata = &nxpdev->psdata; ++ u8 ps_state; ++ ++ mutex_lock(&psdata->ps_lock); ++ ps_state = psdata->ps_state; ++ mutex_unlock(&psdata->ps_lock); ++ ++ if (ps_state != PS_STATE_AWAKE) ++ ps_control(psdata->hdev, PS_STATE_AWAKE); ++ ++ ps_cancel_timer(nxpdev); ++ cancel_work_sync(&psdata->work); ++ mutex_destroy(&psdata->ps_lock); + } + + static int send_ps_cmd(struct hci_dev *hdev, void *data) +@@ -534,6 +585,7 @@ static int nxp_download_firmware(struct hci_dev *hdev) + nxpdev->fw_v1_sent_bytes = 0; + nxpdev->fw_v1_expected_len = HDR_LEN; + nxpdev->boot_reg_offset = 0; ++ nxpdev->fw_dnld_v3_offset = 0; + nxpdev->fw_v3_offset_correction = 0; + nxpdev->baudrate_changed = false; + nxpdev->timeout_changed = false; +@@ -548,14 +600,23 @@ static int nxp_download_firmware(struct hci_dev *hdev) + !test_bit(BTNXPUART_FW_DOWNLOADING, + &nxpdev->tx_state), + msecs_to_jiffies(60000)); ++ ++ release_firmware(nxpdev->fw); ++ memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name)); ++ + if (err == 0) { +- bt_dev_err(hdev, "FW Download Timeout."); ++ bt_dev_err(hdev, "FW Download Timeout. offset: %d", ++ nxpdev->fw_dnld_v1_offset ? ++ nxpdev->fw_dnld_v1_offset : ++ nxpdev->fw_dnld_v3_offset); + return -ETIMEDOUT; + } ++ if (test_bit(BTNXPUART_FW_DOWNLOAD_ABORT, &nxpdev->tx_state)) { ++ bt_dev_err(hdev, "FW Download Aborted"); ++ return -EINTR; ++ } + + serdev_device_set_flow_control(nxpdev->serdev, true); +- release_firmware(nxpdev->fw); +- memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name)); + + /* Allow the downloaded FW to initialize */ + msleep(1200); +@@ -883,6 +944,32 @@ static int nxp_recv_chip_ver_v3(struct hci_dev *hdev, struct sk_buff *skb) + return 0; + } + ++static void nxp_handle_fw_download_error(struct hci_dev *hdev, struct v3_data_req *req) ++{ ++ struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); ++ __u32 offset = __le32_to_cpu(req->offset); ++ __u16 err = __le16_to_cpu(req->error); ++ union nxp_v3_rx_timeout_nak_u nak_tx_buf; ++ ++ switch (err) { ++ case NXP_ACK_RX_TIMEOUT: ++ case NXP_HDR_RX_TIMEOUT: ++ case NXP_DATA_RX_TIMEOUT: ++ nak_tx_buf.pkt.nak = NXP_NAK_V3; ++ nak_tx_buf.pkt.offset = __cpu_to_le32(offset); ++ nak_tx_buf.pkt.crc = crc8(crc8_table, nak_tx_buf.buf, ++ sizeof(nak_tx_buf) - 1, 0xff); ++ serdev_device_write_buf(nxpdev->serdev, nak_tx_buf.buf, ++ sizeof(nak_tx_buf)); ++ break; ++ default: ++ bt_dev_dbg(hdev, "Unknown bootloader error code: %d", err); ++ break; ++ ++ } ++ ++} ++ + static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb) + { + struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); +@@ -897,7 +984,12 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb) + if (!req || !nxpdev->fw) + goto free_skb; + +- nxp_send_ack(NXP_ACK_V3, hdev); ++ if (!req->error) { ++ nxp_send_ack(NXP_ACK_V3, hdev); ++ } else { ++ nxp_handle_fw_download_error(hdev, req); ++ goto free_skb; ++ } + + len = __le16_to_cpu(req->len); + +@@ -924,9 +1016,6 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb) + wake_up_interruptible(&nxpdev->fw_dnld_done_wait_q); + goto free_skb; + } +- if (req->error) +- bt_dev_dbg(hdev, "FW Download received err 0x%02x from chip", +- req->error); + + offset = __le32_to_cpu(req->offset); + if (offset < nxpdev->fw_v3_offset_correction) { +@@ -938,8 +1027,9 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb) + goto free_skb; + } + +- serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data + offset - +- nxpdev->fw_v3_offset_correction, len); ++ nxpdev->fw_dnld_v3_offset = offset - nxpdev->fw_v3_offset_correction; ++ serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data + ++ nxpdev->fw_dnld_v3_offset, len); + + free_skb: + kfree_skb(skb); +@@ -1171,7 +1261,6 @@ static struct sk_buff *nxp_dequeue(void *data) + { + struct btnxpuart_dev *nxpdev = (struct btnxpuart_dev *)data; + +- ps_wakeup(nxpdev); + ps_start_timer(nxpdev); + return skb_dequeue(&nxpdev->txq); + } +@@ -1186,6 +1275,9 @@ static void btnxpuart_tx_work(struct work_struct *work) + struct sk_buff *skb; + int len; + ++ if (ps_wakeup(nxpdev)) ++ return; ++ + while ((skb = nxp_dequeue(nxpdev))) { + len = serdev_device_write_buf(serdev, skb->data, skb->len); + hdev->stat.byte_tx += len; +@@ -1232,8 +1324,12 @@ static int btnxpuart_close(struct hci_dev *hdev) + { + struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); + +- ps_wakeup(nxpdev); + serdev_device_close(nxpdev->serdev); ++ skb_queue_purge(&nxpdev->txq); ++ if (!IS_ERR_OR_NULL(nxpdev->rx_skb)) { ++ kfree_skb(nxpdev->rx_skb); ++ nxpdev->rx_skb = NULL; ++ } + clear_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state); + return 0; + } +@@ -1248,8 +1344,10 @@ static int btnxpuart_flush(struct hci_dev *hdev) + + cancel_work_sync(&nxpdev->tx_work); + +- kfree_skb(nxpdev->rx_skb); +- nxpdev->rx_skb = NULL; ++ if (!IS_ERR_OR_NULL(nxpdev->rx_skb)) { ++ kfree_skb(nxpdev->rx_skb); ++ nxpdev->rx_skb = NULL; ++ } + + return 0; + } +@@ -1276,11 +1374,10 @@ static int btnxpuart_receive_buf(struct serdev_device *serdev, const u8 *data, + if (IS_ERR(nxpdev->rx_skb)) { + int err = PTR_ERR(nxpdev->rx_skb); + /* Safe to ignore out-of-sync bootloader signatures */ +- if (is_fw_downloading(nxpdev)) +- return count; +- bt_dev_err(nxpdev->hdev, "Frame reassembly failed (%d)", err); ++ if (!is_fw_downloading(nxpdev)) ++ bt_dev_err(nxpdev->hdev, "Frame reassembly failed (%d)", err); + nxpdev->rx_skb = NULL; +- return err; ++ return count; + } + if (!is_fw_downloading(nxpdev)) + nxpdev->hdev->stat.byte_rx += count; +@@ -1366,16 +1463,22 @@ static void nxp_serdev_remove(struct serdev_device *serdev) + struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev); + struct hci_dev *hdev = nxpdev->hdev; + +- /* Restore FW baudrate to fw_init_baudrate if changed. +- * This will ensure FW baudrate is in sync with +- * driver baudrate in case this driver is re-inserted. +- */ +- if (nxpdev->current_baudrate != nxpdev->fw_init_baudrate) { +- nxpdev->new_baudrate = nxpdev->fw_init_baudrate; +- nxp_set_baudrate_cmd(hdev, NULL); ++ if (is_fw_downloading(nxpdev)) { ++ set_bit(BTNXPUART_FW_DOWNLOAD_ABORT, &nxpdev->tx_state); ++ clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); ++ wake_up_interruptible(&nxpdev->check_boot_sign_wait_q); ++ wake_up_interruptible(&nxpdev->fw_dnld_done_wait_q); ++ } else { ++ /* Restore FW baudrate to fw_init_baudrate if changed. ++ * This will ensure FW baudrate is in sync with ++ * driver baudrate in case this driver is re-inserted. ++ */ ++ if (nxpdev->current_baudrate != nxpdev->fw_init_baudrate) { ++ nxpdev->new_baudrate = nxpdev->fw_init_baudrate; ++ nxp_set_baudrate_cmd(hdev, NULL); ++ } + } +- +- ps_cancel_timer(nxpdev); ++ ps_cleanup(nxpdev); + hci_unregister_dev(hdev); + hci_free_dev(hdev); + } +diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c +index 5a35ac4138c6cf..35fb26cbf22941 100644 +--- a/drivers/bluetooth/btqca.c ++++ b/drivers/bluetooth/btqca.c +@@ -99,7 +99,8 @@ static int qca_read_fw_build_info(struct hci_dev *hdev) + { + struct sk_buff *skb; + struct edl_event_hdr *edl; +- char cmd, build_label[QCA_FW_BUILD_VER_LEN]; ++ char *build_label; ++ char cmd; + int build_lbl_len, err = 0; + + bt_dev_dbg(hdev, "QCA read fw build info"); +@@ -114,6 +115,11 @@ static int qca_read_fw_build_info(struct hci_dev *hdev) + return err; + } + ++ if (skb->len < sizeof(*edl)) { ++ err = -EILSEQ; ++ goto out; ++ } ++ + edl = (struct edl_event_hdr *)(skb->data); + if (!edl) { + bt_dev_err(hdev, "QCA read fw build info with no header"); +@@ -129,14 +135,27 @@ static int qca_read_fw_build_info(struct hci_dev *hdev) + goto out; + } + ++ if (skb->len < sizeof(*edl) + 1) { ++ err = -EILSEQ; ++ goto out; ++ } ++ + build_lbl_len = edl->data[0]; +- if (build_lbl_len <= QCA_FW_BUILD_VER_LEN - 1) { +- memcpy(build_label, edl->data + 1, build_lbl_len); +- *(build_label + build_lbl_len) = '\0'; ++ ++ if (skb->len < sizeof(*edl) + 1 + build_lbl_len) { ++ err = -EILSEQ; ++ goto out; ++ } ++ ++ build_label = kstrndup(&edl->data[1], build_lbl_len, GFP_KERNEL); ++ if (!build_label) { ++ err = -ENOMEM; ++ goto out; + } + + hci_set_fw_info(hdev, "%s", build_label); + ++ kfree(build_label); + out: + kfree_skb(skb); + return err; +@@ -152,7 +171,7 @@ static int qca_send_patch_config_cmd(struct hci_dev *hdev) + bt_dev_dbg(hdev, "QCA Patch config"); + + skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, sizeof(cmd), +- cmd, HCI_EV_VENDOR, HCI_INIT_TIMEOUT); ++ cmd, 0, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + bt_dev_err(hdev, "Sending QCA Patch config failed (%d)", err); +@@ -205,6 +224,49 @@ static int qca_send_reset(struct hci_dev *hdev) + return 0; + } + ++static int qca_read_fw_board_id(struct hci_dev *hdev, u16 *bid) ++{ ++ u8 cmd; ++ struct sk_buff *skb; ++ struct edl_event_hdr *edl; ++ int err = 0; ++ ++ cmd = EDL_GET_BID_REQ_CMD; ++ skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN, ++ &cmd, 0, HCI_INIT_TIMEOUT); ++ if (IS_ERR(skb)) { ++ err = PTR_ERR(skb); ++ bt_dev_err(hdev, "Reading QCA board ID failed (%d)", err); ++ return err; ++ } ++ ++ edl = skb_pull_data(skb, sizeof(*edl)); ++ if (!edl) { ++ bt_dev_err(hdev, "QCA read board ID with no header"); ++ err = -EILSEQ; ++ goto out; ++ } ++ ++ if (edl->cresp != EDL_CMD_REQ_RES_EVT || ++ edl->rtype != EDL_GET_BID_REQ_CMD) { ++ bt_dev_err(hdev, "QCA Wrong packet: %d %d", edl->cresp, edl->rtype); ++ err = -EIO; ++ goto out; ++ } ++ ++ if (skb->len < 3) { ++ err = -EILSEQ; ++ goto out; ++ } ++ ++ *bid = (edl->data[1] << 8) + edl->data[2]; ++ bt_dev_dbg(hdev, "%s: bid = %x", __func__, *bid); ++ ++out: ++ kfree_skb(skb); ++ return err; ++} ++ + int qca_send_pre_shutdown_cmd(struct hci_dev *hdev) + { + struct sk_buff *skb; +@@ -227,9 +289,10 @@ int qca_send_pre_shutdown_cmd(struct hci_dev *hdev) + } + EXPORT_SYMBOL_GPL(qca_send_pre_shutdown_cmd); + +-static void qca_tlv_check_data(struct hci_dev *hdev, ++static int qca_tlv_check_data(struct hci_dev *hdev, + struct qca_fw_config *config, +- u8 *fw_data, enum qca_btsoc_type soc_type) ++ u8 *fw_data, size_t fw_size, ++ enum qca_btsoc_type soc_type) + { + const u8 *data; + u32 type_len; +@@ -239,12 +302,16 @@ static void qca_tlv_check_data(struct hci_dev *hdev, + struct tlv_type_patch *tlv_patch; + struct tlv_type_nvm *tlv_nvm; + uint8_t nvm_baud_rate = config->user_baud_rate; ++ u8 type; + + config->dnld_mode = QCA_SKIP_EVT_NONE; + config->dnld_type = QCA_SKIP_EVT_NONE; + + switch (config->type) { + case ELF_TYPE_PATCH: ++ if (fw_size < 7) ++ return -EINVAL; ++ + config->dnld_mode = QCA_SKIP_EVT_VSE_CC; + config->dnld_type = QCA_SKIP_EVT_VSE_CC; + +@@ -253,6 +320,9 @@ static void qca_tlv_check_data(struct hci_dev *hdev, + bt_dev_dbg(hdev, "File version : 0x%x", fw_data[6]); + break; + case TLV_TYPE_PATCH: ++ if (fw_size < sizeof(struct tlv_type_hdr) + sizeof(struct tlv_type_patch)) ++ return -EINVAL; ++ + tlv = (struct tlv_type_hdr *)fw_data; + type_len = le32_to_cpu(tlv->type_len); + tlv_patch = (struct tlv_type_patch *)tlv->data; +@@ -292,25 +362,64 @@ static void qca_tlv_check_data(struct hci_dev *hdev, + break; + + case TLV_TYPE_NVM: ++ if (fw_size < sizeof(struct tlv_type_hdr)) ++ return -EINVAL; ++ + tlv = (struct tlv_type_hdr *)fw_data; + + type_len = le32_to_cpu(tlv->type_len); +- length = (type_len >> 8) & 0x00ffffff; ++ length = type_len >> 8; ++ type = type_len & 0xff; + +- BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff); ++ /* Some NVM files have more than one set of tags, only parse ++ * the first set when it has type 2 for now. When there is ++ * more than one set there is an enclosing header of type 4. ++ */ ++ if (type == 4) { ++ if (fw_size < 2 * sizeof(struct tlv_type_hdr)) ++ return -EINVAL; ++ ++ tlv++; ++ ++ type_len = le32_to_cpu(tlv->type_len); ++ length = type_len >> 8; ++ type = type_len & 0xff; ++ } ++ ++ BT_DBG("TLV Type\t\t : 0x%x", type); + BT_DBG("Length\t\t : %d bytes", length); + ++ if (type != 2) ++ break; ++ ++ if (fw_size < length + (tlv->data - fw_data)) ++ return -EINVAL; ++ + idx = 0; + data = tlv->data; +- while (idx < length) { ++ while (idx < length - sizeof(struct tlv_type_nvm)) { + tlv_nvm = (struct tlv_type_nvm *)(data + idx); + + tag_id = le16_to_cpu(tlv_nvm->tag_id); + tag_len = le16_to_cpu(tlv_nvm->tag_len); + ++ if (length < idx + sizeof(struct tlv_type_nvm) + tag_len) ++ return -EINVAL; ++ + /* Update NVM tags as needed */ + switch (tag_id) { ++ case EDL_TAG_ID_BD_ADDR: ++ if (tag_len != sizeof(bdaddr_t)) ++ return -EINVAL; ++ ++ memcpy(&config->bdaddr, tlv_nvm->data, sizeof(bdaddr_t)); ++ ++ break; ++ + case EDL_TAG_ID_HCI: ++ if (tag_len < 3) ++ return -EINVAL; ++ + /* HCI transport layer parameters + * enabling software inband sleep + * onto controller side. +@@ -326,6 +435,9 @@ static void qca_tlv_check_data(struct hci_dev *hdev, + break; + + case EDL_TAG_ID_DEEP_SLEEP: ++ if (tag_len < 1) ++ return -EINVAL; ++ + /* Sleep enable mask + * enabling deep sleep feature on controller. + */ +@@ -334,14 +446,16 @@ static void qca_tlv_check_data(struct hci_dev *hdev, + break; + } + +- idx += (sizeof(u16) + sizeof(u16) + 8 + tag_len); ++ idx += sizeof(struct tlv_type_nvm) + tag_len; + } + break; + + default: + BT_ERR("Unknown TLV type %d", config->type); +- break; ++ return -EINVAL; + } ++ ++ return 0; + } + + static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size, +@@ -491,7 +605,9 @@ static int qca_download_firmware(struct hci_dev *hdev, + memcpy(data, fw->data, size); + release_firmware(fw); + +- qca_tlv_check_data(hdev, config, data, soc_type); ++ ret = qca_tlv_check_data(hdev, config, data, size, soc_type); ++ if (ret) ++ goto out; + + segment = data; + remain = size; +@@ -574,14 +690,64 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) + } + EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome); + ++static int qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *config) ++{ ++ struct hci_rp_read_bd_addr *bda; ++ struct sk_buff *skb; ++ int err; ++ ++ if (bacmp(&hdev->public_addr, BDADDR_ANY)) ++ return 0; ++ ++ skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, ++ HCI_INIT_TIMEOUT); ++ if (IS_ERR(skb)) { ++ err = PTR_ERR(skb); ++ bt_dev_err(hdev, "Failed to read device address (%d)", err); ++ return err; ++ } ++ ++ if (skb->len != sizeof(*bda)) { ++ bt_dev_err(hdev, "Device address length mismatch"); ++ kfree_skb(skb); ++ return -EIO; ++ } ++ ++ bda = (struct hci_rp_read_bd_addr *)skb->data; ++ if (!bacmp(&bda->bdaddr, &config->bdaddr)) ++ set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); ++ ++ kfree_skb(skb); ++ ++ return 0; ++} ++ ++static void qca_generate_hsp_nvm_name(char *fwname, size_t max_size, ++ struct qca_btsoc_version ver, u8 rom_ver, u16 bid) ++{ ++ const char *variant; ++ ++ /* hsp gf chip */ ++ if ((le32_to_cpu(ver.soc_id) & QCA_HSP_GF_SOC_MASK) == QCA_HSP_GF_SOC_ID) ++ variant = "g"; ++ else ++ variant = ""; ++ ++ if (bid == 0x0) ++ snprintf(fwname, max_size, "qca/hpnv%02x%s.bin", rom_ver, variant); ++ else ++ snprintf(fwname, max_size, "qca/hpnv%02x%s.%x", rom_ver, variant, bid); ++} ++ + int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, + enum qca_btsoc_type soc_type, struct qca_btsoc_version ver, + const char *firmware_name) + { +- struct qca_fw_config config; ++ struct qca_fw_config config = {}; + int err; + u8 rom_ver = 0; + u32 soc_ver; ++ u16 boardid = 0; + + bt_dev_dbg(hdev, "QCA setup on UART"); + +@@ -615,6 +781,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, + snprintf(config.fwname, sizeof(config.fwname), + "qca/apbtfw%02x.tlv", rom_ver); + break; ++ case QCA_QCA2066: ++ snprintf(config.fwname, sizeof(config.fwname), ++ "qca/hpbtfw%02x.tlv", rom_ver); ++ break; + case QCA_QCA6390: + snprintf(config.fwname, sizeof(config.fwname), + "qca/htbtfw%02x.tlv", rom_ver); +@@ -649,6 +819,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, + /* Give the controller some time to get ready to receive the NVM */ + msleep(10); + ++ if (soc_type == QCA_QCA2066) ++ qca_read_fw_board_id(hdev, &boardid); ++ + /* Download NVM configuration */ + config.type = TLV_TYPE_NVM; + if (firmware_name) { +@@ -671,6 +844,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, + snprintf(config.fwname, sizeof(config.fwname), + "qca/apnv%02x.bin", rom_ver); + break; ++ case QCA_QCA2066: ++ qca_generate_hsp_nvm_name(config.fwname, ++ sizeof(config.fwname), ver, rom_ver, boardid); ++ break; + case QCA_QCA6390: + snprintf(config.fwname, sizeof(config.fwname), + "qca/htnv%02x.bin", rom_ver); +@@ -702,6 +879,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, + + switch (soc_type) { + case QCA_WCN3991: ++ case QCA_QCA2066: + case QCA_QCA6390: + case QCA_WCN6750: + case QCA_WCN6855: +@@ -750,6 +928,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, + break; + } + ++ err = qca_check_bdaddr(hdev, &config); ++ if (err) ++ return err; ++ + bt_dev_info(hdev, "QCA setup on UART is completed"); + + return 0; +@@ -758,11 +940,15 @@ EXPORT_SYMBOL_GPL(qca_uart_setup); + + int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) + { ++ bdaddr_t bdaddr_swapped; + struct sk_buff *skb; + int err; + +- skb = __hci_cmd_sync_ev(hdev, EDL_WRITE_BD_ADDR_OPCODE, 6, bdaddr, +- HCI_EV_VENDOR, HCI_INIT_TIMEOUT); ++ baswap(&bdaddr_swapped, bdaddr); ++ ++ skb = __hci_cmd_sync_ev(hdev, EDL_WRITE_BD_ADDR_OPCODE, 6, ++ &bdaddr_swapped, HCI_EV_VENDOR, ++ HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + bt_dev_err(hdev, "QCA Change address cmd failed (%d)", err); +diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h +index 03bff5c0059def..215433fd76a106 100644 +--- a/drivers/bluetooth/btqca.h ++++ b/drivers/bluetooth/btqca.h +@@ -12,6 +12,7 @@ + #define EDL_PATCH_VER_REQ_CMD (0x19) + #define EDL_PATCH_TLV_REQ_CMD (0x1E) + #define EDL_GET_BUILD_INFO_CMD (0x20) ++#define EDL_GET_BID_REQ_CMD (0x23) + #define EDL_NVM_ACCESS_SET_REQ_CMD (0x01) + #define EDL_PATCH_CONFIG_CMD (0x28) + #define MAX_SIZE_PER_TLV_SEGMENT (243) +@@ -28,6 +29,7 @@ + #define EDL_PATCH_CONFIG_RES_EVT (0x00) + #define QCA_DISABLE_LOGGING_SUB_OP (0x14) + ++#define EDL_TAG_ID_BD_ADDR 2 + #define EDL_TAG_ID_HCI (17) + #define EDL_TAG_ID_DEEP_SLEEP (27) + +@@ -46,8 +48,8 @@ + #define get_soc_ver(soc_id, rom_ver) \ + ((le32_to_cpu(soc_id) << 16) | (le16_to_cpu(rom_ver))) + +-#define QCA_FW_BUILD_VER_LEN 255 +- ++#define QCA_HSP_GF_SOC_ID 0x1200 ++#define QCA_HSP_GF_SOC_MASK 0x0000ff00 + + enum qca_baudrate { + QCA_BAUDRATE_115200 = 0, +@@ -92,6 +94,7 @@ struct qca_fw_config { + uint8_t user_baud_rate; + enum qca_tlv_dnld_mode dnld_mode; + enum qca_tlv_dnld_mode dnld_type; ++ bdaddr_t bdaddr; + }; + + struct edl_event_hdr { +@@ -146,6 +149,7 @@ enum qca_btsoc_type { + QCA_WCN3990, + QCA_WCN3998, + QCA_WCN3991, ++ QCA_QCA2066, + QCA_QCA6390, + QCA_WCN6750, + QCA_WCN6855, +diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c +index 634cf8f5ed2dbd..0c91d7635ac39e 100644 +--- a/drivers/bluetooth/btrsi.c ++++ b/drivers/bluetooth/btrsi.c +@@ -134,7 +134,6 @@ static int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops) + hdev->bus = HCI_USB; + + hci_set_drvdata(hdev, h_adapter); +- hdev->dev_type = HCI_PRIMARY; + hdev->open = rsi_hci_open; + hdev->close = rsi_hci_close; + hdev->flush = rsi_hci_flush; +diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c +index 277d039ecbb429..1e7c1f9db9e4b9 100644 +--- a/drivers/bluetooth/btrtl.c ++++ b/drivers/bluetooth/btrtl.c +@@ -1285,6 +1285,7 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev) + btrealtek_set_flag(hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP); + + if (btrtl_dev->project_id == CHIP_ID_8852A || ++ btrtl_dev->project_id == CHIP_ID_8852B || + btrtl_dev->project_id == CHIP_ID_8852C) + set_bit(HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER, &hdev->quirks); + +diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c +index f19d31ee37ea89..fdcfe9c50313ea 100644 +--- a/drivers/bluetooth/btsdio.c ++++ b/drivers/bluetooth/btsdio.c +@@ -32,9 +32,6 @@ static const struct sdio_device_id btsdio_table[] = { + /* Generic Bluetooth Type-B SDIO device */ + { SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) }, + +- /* Generic Bluetooth AMP controller */ +- { SDIO_DEVICE_CLASS(SDIO_CLASS_BT_AMP) }, +- + { } /* Terminating entry */ + }; + +@@ -319,11 +316,6 @@ static int btsdio_probe(struct sdio_func *func, + hdev->bus = HCI_SDIO; + hci_set_drvdata(hdev, data); + +- if (id->class == SDIO_CLASS_BT_AMP) +- hdev->dev_type = HCI_AMP; +- else +- hdev->dev_type = HCI_PRIMARY; +- + data->hdev = hdev; + + SET_HCIDEV_DEV(hdev, &func->dev); +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 499f4809fcdf3d..b3a9b93f027a90 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -537,14 +537,26 @@ static const struct usb_device_id quirks_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3592), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x0489, 0xe122), .driver_info = BTUSB_REALTEK | ++ BTUSB_WIDEBAND_SPEECH }, + + /* Realtek 8852BE Bluetooth devices */ + { USB_DEVICE(0x0cb8, 0xc559), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x0bda, 0x4853), .driver_info = BTUSB_REALTEK | ++ BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0bda, 0x887b), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x0bda, 0xb85b), .driver_info = BTUSB_REALTEK | ++ BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x13d3, 0x3570), .driver_info = BTUSB_REALTEK | ++ BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3571), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x13d3, 0x3591), .driver_info = BTUSB_REALTEK | ++ BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x0489, 0xe125), .driver_info = BTUSB_REALTEK | ++ BTUSB_WIDEBAND_SPEECH }, + + /* Realtek Bluetooth devices */ + { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01), +@@ -1342,7 +1354,15 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags) + if (!urb) + return -ENOMEM; + +- size = le16_to_cpu(data->intr_ep->wMaxPacketSize); ++ if (le16_to_cpu(data->udev->descriptor.idVendor) == 0x0a12 && ++ le16_to_cpu(data->udev->descriptor.idProduct) == 0x0001) ++ /* Fake CSR devices don't seem to support sort-transter */ ++ size = le16_to_cpu(data->intr_ep->wMaxPacketSize); ++ else ++ /* Use maximum HCI Event size so the USB stack handles ++ * ZPL/short-transfer automatically. ++ */ ++ size = HCI_MAX_EVENT_SIZE; + + buf = kmalloc(size, mem_flags); + if (!buf) { +@@ -2818,6 +2838,9 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev, + goto err_free_wc; + } + ++ if (data->evt_skb == NULL) ++ goto err_free_wc; ++ + /* Parse and handle the return WMT event */ + wmt_evt = (struct btmtk_hci_wmt_evt *)data->evt_skb->data; + if (wmt_evt->whdr.op != hdr->op) { +@@ -3260,7 +3283,6 @@ static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb) + { + struct btusb_data *data = hci_get_drvdata(hdev); + u16 handle = le16_to_cpu(hci_acl_hdr(skb)->handle); +- struct sk_buff *skb_cd; + + switch (handle) { + case 0xfc6f: /* Firmware dump from device */ +@@ -3273,9 +3295,12 @@ static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb) + * for backward compatibility, so we have to clone the packet + * extraly for the in-kernel coredump support. + */ +- skb_cd = skb_clone(skb, GFP_ATOMIC); +- if (skb_cd) +- btmtk_process_coredump(hdev, skb_cd); ++ if (IS_ENABLED(CONFIG_DEV_COREDUMP)) { ++ struct sk_buff *skb_cd = skb_clone(skb, GFP_ATOMIC); ++ ++ if (skb_cd) ++ btmtk_process_coredump(hdev, skb_cd); ++ } + + fallthrough; + case 0x05ff: /* Firmware debug logging 1 */ +@@ -3448,13 +3473,12 @@ static void btusb_dump_hdr_qca(struct hci_dev *hdev, struct sk_buff *skb) + + static void btusb_coredump_qca(struct hci_dev *hdev) + { ++ int err; + static const u8 param[] = { 0x26 }; +- struct sk_buff *skb; + +- skb = __hci_cmd_sync(hdev, 0xfc0c, 1, param, HCI_CMD_TIMEOUT); +- if (IS_ERR(skb)) +- bt_dev_err(hdev, "%s: triggle crash failed (%ld)", __func__, PTR_ERR(skb)); +- kfree_skb(skb); ++ err = __hci_cmd_send(hdev, 0xfc0c, 1, param); ++ if (err < 0) ++ bt_dev_err(hdev, "%s: triggle crash failed (%d)", __func__, err); + } + + /* +@@ -4298,11 +4322,6 @@ static int btusb_probe(struct usb_interface *intf, + hdev->bus = HCI_USB; + hci_set_drvdata(hdev, data); + +- if (id->driver_info & BTUSB_AMP) +- hdev->dev_type = HCI_AMP; +- else +- hdev->dev_type = HCI_PRIMARY; +- + data->hdev = hdev; + + SET_HCIDEV_DEV(hdev, &intf->dev); +@@ -4468,6 +4487,7 @@ static int btusb_probe(struct usb_interface *intf, + set_bit(HCI_QUIRK_BROKEN_READ_TRANSMIT_POWER, &hdev->quirks); + set_bit(HCI_QUIRK_BROKEN_SET_RPA_TIMEOUT, &hdev->quirks); + set_bit(HCI_QUIRK_BROKEN_EXT_SCAN, &hdev->quirks); ++ set_bit(HCI_QUIRK_BROKEN_READ_ENC_KEY_SIZE, &hdev->quirks); + } + + if (!reset) +diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c +index 19ad0e78864629..0dc3ca3d410736 100644 +--- a/drivers/bluetooth/hci_bcm4377.c ++++ b/drivers/bluetooth/hci_bcm4377.c +@@ -32,7 +32,7 @@ enum bcm4377_chip { + #define BCM4378_DEVICE_ID 0x5f69 + #define BCM4387_DEVICE_ID 0x5f71 + +-#define BCM4377_TIMEOUT 1000 ++#define BCM4377_TIMEOUT msecs_to_jiffies(1000) + + /* + * These devices only support DMA transactions inside a 32bit window +@@ -512,6 +512,7 @@ struct bcm4377_hw { + unsigned long disable_aspm : 1; + unsigned long broken_ext_scan : 1; + unsigned long broken_mws_transport_config : 1; ++ unsigned long broken_le_coded : 1; + + int (*send_calibration)(struct bcm4377_data *bcm4377); + int (*send_ptb)(struct bcm4377_data *bcm4377, +@@ -715,7 +716,7 @@ static void bcm4377_handle_ack(struct bcm4377_data *bcm4377, + ring->events[msgid] = NULL; + } + +- bitmap_release_region(ring->msgids, msgid, ring->n_entries); ++ bitmap_release_region(ring->msgids, msgid, 0); + + unlock: + spin_unlock_irqrestore(&ring->lock, flags); +@@ -1416,7 +1417,7 @@ static int bcm4377_check_bdaddr(struct bcm4377_data *bcm4377) + + bda = (struct hci_rp_read_bd_addr *)skb->data; + if (!bcm4377_is_valid_bdaddr(bcm4377, &bda->bdaddr)) +- set_bit(HCI_QUIRK_INVALID_BDADDR, &bcm4377->hdev->quirks); ++ set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &bcm4377->hdev->quirks); + + kfree_skb(skb); + return 0; +@@ -2360,18 +2361,18 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id) + bcm4377->hdev = hdev; + + hdev->bus = HCI_PCI; +- hdev->dev_type = HCI_PRIMARY; + hdev->open = bcm4377_hci_open; + hdev->close = bcm4377_hci_close; + hdev->send = bcm4377_hci_send_frame; + hdev->set_bdaddr = bcm4377_hci_set_bdaddr; + hdev->setup = bcm4377_hci_setup; + +- set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); + if (bcm4377->hw->broken_mws_transport_config) + set_bit(HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG, &hdev->quirks); + if (bcm4377->hw->broken_ext_scan) + set_bit(HCI_QUIRK_BROKEN_EXT_SCAN, &hdev->quirks); ++ if (bcm4377->hw->broken_le_coded) ++ set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks); + + pci_set_drvdata(pdev, bcm4377); + hci_set_drvdata(hdev, bcm4377); +@@ -2461,6 +2462,7 @@ static const struct bcm4377_hw bcm4377_hw_variants[] = { + .bar0_core2_window2 = 0x18107000, + .has_bar0_core2_window2 = true, + .broken_mws_transport_config = true, ++ .broken_le_coded = true, + .send_calibration = bcm4378_send_calibration, + .send_ptb = bcm4378_send_ptb, + }, +@@ -2474,6 +2476,7 @@ static const struct bcm4377_hw bcm4377_hw_variants[] = { + .has_bar0_core2_window2 = true, + .clear_pciecfg_subsystem_ctrl_bit19 = true, + .broken_mws_transport_config = true, ++ .broken_le_coded = true, + .send_calibration = bcm4387_send_calibration, + .send_ptb = bcm4378_send_ptb, + }, +diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c +index 71e748a9477e44..c0436881a533c5 100644 +--- a/drivers/bluetooth/hci_h5.c ++++ b/drivers/bluetooth/hci_h5.c +@@ -113,6 +113,7 @@ struct h5_vnd { + int (*suspend)(struct h5 *h5); + int (*resume)(struct h5 *h5); + const struct acpi_gpio_mapping *acpi_gpio_map; ++ int sizeof_priv; + }; + + struct h5_device_data { +@@ -863,7 +864,8 @@ static int h5_serdev_probe(struct serdev_device *serdev) + if (IS_ERR(h5->device_wake_gpio)) + return PTR_ERR(h5->device_wake_gpio); + +- return hci_uart_register_device(&h5->serdev_hu, &h5p); ++ return hci_uart_register_device_priv(&h5->serdev_hu, &h5p, ++ h5->vnd->sizeof_priv); + } + + static void h5_serdev_remove(struct serdev_device *serdev) +@@ -1070,6 +1072,7 @@ static struct h5_vnd rtl_vnd = { + .suspend = h5_btrtl_suspend, + .resume = h5_btrtl_resume, + .acpi_gpio_map = acpi_btrtl_gpios, ++ .sizeof_priv = sizeof(struct btrealtek_data), + }; + + static const struct h5_device_data h5_data_rtl8822cs = { +diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c +index a26367e9fb197c..17a2f158a0dfab 100644 +--- a/drivers/bluetooth/hci_ldisc.c ++++ b/drivers/bluetooth/hci_ldisc.c +@@ -667,11 +667,6 @@ static int hci_uart_register_dev(struct hci_uart *hu) + if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags)) + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); + +- if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags)) +- hdev->dev_type = HCI_AMP; +- else +- hdev->dev_type = HCI_PRIMARY; +- + /* Only call open() for the protocol after hdev is fully initialized as + * open() (or a timer/workqueue it starts) may attempt to reference it. + */ +@@ -722,7 +717,6 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags) + { + unsigned long valid_flags = BIT(HCI_UART_RAW_DEVICE) | + BIT(HCI_UART_RESET_ON_INIT) | +- BIT(HCI_UART_CREATE_AMP) | + BIT(HCI_UART_INIT_PENDING) | + BIT(HCI_UART_EXT_CONFIG) | + BIT(HCI_UART_VND_DETECT); +diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c +index 4b57e15f9c7a7a..7a552387129ef0 100644 +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -225,6 +225,7 @@ struct qca_serdev { + struct qca_power *bt_power; + u32 init_speed; + u32 oper_speed; ++ bool bdaddr_property_broken; + const char *firmware_name; + }; + +@@ -1089,6 +1090,7 @@ static void qca_controller_memdump(struct work_struct *work) + qca->memdump_state = QCA_MEMDUMP_COLLECTED; + cancel_delayed_work(&qca->ctrl_memdump_timeout); + clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); ++ clear_bit(QCA_IBS_DISABLED, &qca->flags); + mutex_unlock(&qca->hci_memdump_lock); + return; + } +@@ -1671,6 +1673,9 @@ static bool qca_wakeup(struct hci_dev *hdev) + struct hci_uart *hu = hci_get_drvdata(hdev); + bool wakeup; + ++ if (!hu->serdev) ++ return true; ++ + /* BT SoC attached through the serial bus is handled by the serdev driver. + * So we need to use the device handle of the serdev driver to get the + * status of device may wakeup. +@@ -1806,13 +1811,12 @@ static int qca_power_on(struct hci_dev *hdev) + + static void hci_coredump_qca(struct hci_dev *hdev) + { ++ int err; + static const u8 param[] = { 0x26 }; +- struct sk_buff *skb; + +- skb = __hci_cmd_sync(hdev, 0xfc0c, 1, param, HCI_CMD_TIMEOUT); +- if (IS_ERR(skb)) +- bt_dev_err(hdev, "%s: trigger crash failed (%ld)", __func__, PTR_ERR(skb)); +- kfree_skb(skb); ++ err = __hci_cmd_send(hdev, 0xfc0c, 1, param); ++ if (err < 0) ++ bt_dev_err(hdev, "%s: trigger crash failed (%d)", __func__, err); + } + + static int qca_setup(struct hci_uart *hu) +@@ -1825,6 +1829,7 @@ static int qca_setup(struct hci_uart *hu) + const char *firmware_name = qca_get_firmware_name(hu); + int ret; + struct qca_btsoc_version ver; ++ struct qca_serdev *qcadev; + const char *soc_name; + + ret = qca_check_speeds(hu); +@@ -1841,6 +1846,10 @@ static int qca_setup(struct hci_uart *hu) + set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); + + switch (soc_type) { ++ case QCA_QCA2066: ++ soc_name = "qca2066"; ++ break; ++ + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: +@@ -1882,7 +1891,10 @@ static int qca_setup(struct hci_uart *hu) + case QCA_WCN6750: + case QCA_WCN6855: + case QCA_WCN7850: +- set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); ++ qcadev = serdev_device_get_drvdata(hu->serdev); ++ if (qcadev->bdaddr_property_broken) ++ set_bit(HCI_QUIRK_BDADDR_PROPERTY_BROKEN, &hdev->quirks); ++ + hci_set_aosp_capable(hdev); + + ret = qca_read_soc_version(hdev, &ver, soc_type); +@@ -1929,8 +1941,10 @@ static int qca_setup(struct hci_uart *hu) + qca_debugfs_init(hdev); + hu->hdev->hw_error = qca_hw_error; + hu->hdev->cmd_timeout = qca_cmd_timeout; +- if (device_can_wakeup(hu->serdev->ctrl->dev.parent)) +- hu->hdev->wakeup = qca_wakeup; ++ if (hu->serdev) { ++ if (device_can_wakeup(hu->serdev->ctrl->dev.parent)) ++ hu->hdev->wakeup = qca_wakeup; ++ } + } else if (ret == -ENOENT) { + /* No patch/nvm-config found, run with original fw/config */ + set_bit(QCA_ROM_FW, &qca->flags); +@@ -2032,9 +2046,15 @@ static const struct qca_device_data qca_soc_data_wcn3998 __maybe_unused = { + .num_vregs = 4, + }; + ++static const struct qca_device_data qca_soc_data_qca2066 __maybe_unused = { ++ .soc_type = QCA_QCA2066, ++ .num_vregs = 0, ++}; ++ + static const struct qca_device_data qca_soc_data_qca6390 __maybe_unused = { + .soc_type = QCA_QCA6390, + .num_vregs = 0, ++ .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES, + }; + + static const struct qca_device_data qca_soc_data_wcn6750 __maybe_unused = { +@@ -2253,6 +2273,9 @@ static int qca_serdev_probe(struct serdev_device *serdev) + if (!qcadev->oper_speed) + BT_DBG("UART will pick default operating speed"); + ++ qcadev->bdaddr_property_broken = device_property_read_bool(&serdev->dev, ++ "qcom,local-bd-address-broken"); ++ + if (data) + qcadev->btsoc_type = data->soc_type; + else +@@ -2284,20 +2307,25 @@ static int qca_serdev_probe(struct serdev_device *serdev) + + qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable", + GPIOD_OUT_LOW); +- if (IS_ERR_OR_NULL(qcadev->bt_en) && ++ if (IS_ERR(qcadev->bt_en) && + (data->soc_type == QCA_WCN6750 || + data->soc_type == QCA_WCN6855)) { + dev_err(&serdev->dev, "failed to acquire BT_EN gpio\n"); +- power_ctrl_enabled = false; ++ return PTR_ERR(qcadev->bt_en); + } + ++ if (!qcadev->bt_en) ++ power_ctrl_enabled = false; ++ + qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl", + GPIOD_IN); +- if (IS_ERR_OR_NULL(qcadev->sw_ctrl) && ++ if (IS_ERR(qcadev->sw_ctrl) && + (data->soc_type == QCA_WCN6750 || + data->soc_type == QCA_WCN6855 || +- data->soc_type == QCA_WCN7850)) +- dev_warn(&serdev->dev, "failed to acquire SW_CTRL gpio\n"); ++ data->soc_type == QCA_WCN7850)) { ++ dev_err(&serdev->dev, "failed to acquire SW_CTRL gpio\n"); ++ return PTR_ERR(qcadev->sw_ctrl); ++ } + + qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL); + if (IS_ERR(qcadev->susclk)) { +@@ -2315,11 +2343,14 @@ static int qca_serdev_probe(struct serdev_device *serdev) + default: + qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable", + GPIOD_OUT_LOW); +- if (IS_ERR_OR_NULL(qcadev->bt_en)) { +- dev_warn(&serdev->dev, "failed to acquire enable gpio\n"); +- power_ctrl_enabled = false; ++ if (IS_ERR(qcadev->bt_en)) { ++ dev_err(&serdev->dev, "failed to acquire enable gpio\n"); ++ return PTR_ERR(qcadev->bt_en); + } + ++ if (!qcadev->bt_en) ++ power_ctrl_enabled = false; ++ + qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL); + if (IS_ERR(qcadev->susclk)) { + dev_warn(&serdev->dev, "failed to acquire clk\n"); +@@ -2398,15 +2429,27 @@ static void qca_serdev_shutdown(struct device *dev) + struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); + struct hci_uart *hu = &qcadev->serdev_hu; + struct hci_dev *hdev = hu->hdev; +- struct qca_data *qca = hu->priv; + const u8 ibs_wake_cmd[] = { 0xFD }; + const u8 edl_reset_soc_cmd[] = { 0x01, 0x00, 0xFC, 0x01, 0x05 }; + + if (qcadev->btsoc_type == QCA_QCA6390) { +- if (test_bit(QCA_BT_OFF, &qca->flags) || +- !test_bit(HCI_RUNNING, &hdev->flags)) ++ /* The purpose of sending the VSC is to reset SOC into a initial ++ * state and the state will ensure next hdev->setup() success. ++ * if HCI_QUIRK_NON_PERSISTENT_SETUP is set, it means that ++ * hdev->setup() can do its job regardless of SoC state, so ++ * don't need to send the VSC. ++ * if HCI_SETUP is set, it means that hdev->setup() was never ++ * invoked and the SOC is already in the initial state, so ++ * don't also need to send the VSC. ++ */ ++ if (test_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks) || ++ hci_dev_test_flag(hdev, HCI_SETUP)) + return; + ++ /* The serdev must be in open state when conrol logic arrives ++ * here, so also fix the use-after-free issue caused by that ++ * the serdev is flushed or wrote after it is closed. ++ */ + serdev_device_write_flush(serdev); + ret = serdev_device_write_buf(serdev, ibs_wake_cmd, + sizeof(ibs_wake_cmd)); +@@ -2559,6 +2602,7 @@ static SIMPLE_DEV_PM_OPS(qca_pm_ops, qca_suspend, qca_resume); + + #ifdef CONFIG_OF + static const struct of_device_id qca_bluetooth_of_match[] = { ++ { .compatible = "qcom,qca2066-bt", .data = &qca_soc_data_qca2066}, + { .compatible = "qcom,qca6174-bt" }, + { .compatible = "qcom,qca6390-bt", .data = &qca_soc_data_qca6390}, + { .compatible = "qcom,qca9377-bt" }, +@@ -2576,6 +2620,7 @@ MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match); + + #ifdef CONFIG_ACPI + static const struct acpi_device_id qca_bluetooth_acpi_match[] = { ++ { "QCOM2066", (kernel_ulong_t)&qca_soc_data_qca2066 }, + { "QCOM6390", (kernel_ulong_t)&qca_soc_data_qca6390 }, + { "DLA16390", (kernel_ulong_t)&qca_soc_data_qca6390 }, + { "DLB16390", (kernel_ulong_t)&qca_soc_data_qca6390 }, +diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c +index f16fd79bc02b8a..1165831570e3c4 100644 +--- a/drivers/bluetooth/hci_serdev.c ++++ b/drivers/bluetooth/hci_serdev.c +@@ -300,8 +300,9 @@ static const struct serdev_device_ops hci_serdev_client_ops = { + .write_wakeup = hci_uart_write_wakeup, + }; + +-int hci_uart_register_device(struct hci_uart *hu, +- const struct hci_uart_proto *p) ++int hci_uart_register_device_priv(struct hci_uart *hu, ++ const struct hci_uart_proto *p, ++ int sizeof_priv) + { + int err; + struct hci_dev *hdev; +@@ -325,7 +326,7 @@ int hci_uart_register_device(struct hci_uart *hu, + set_bit(HCI_UART_PROTO_READY, &hu->flags); + + /* Initialize and register HCI device */ +- hdev = hci_alloc_dev(); ++ hdev = hci_alloc_dev_priv(sizeof_priv); + if (!hdev) { + BT_ERR("Can't allocate HCI device"); + err = -ENOMEM; +@@ -365,11 +366,6 @@ int hci_uart_register_device(struct hci_uart *hu, + if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags)) + set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks); + +- if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags)) +- hdev->dev_type = HCI_AMP; +- else +- hdev->dev_type = HCI_PRIMARY; +- + if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) + return 0; + +@@ -394,7 +390,7 @@ int hci_uart_register_device(struct hci_uart *hu, + percpu_free_rwsem(&hu->proto_lock); + return err; + } +-EXPORT_SYMBOL_GPL(hci_uart_register_device); ++EXPORT_SYMBOL_GPL(hci_uart_register_device_priv); + + void hci_uart_unregister_device(struct hci_uart *hu) + { +diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h +index fb4a2d0d8cc802..00bf7ae82c5b72 100644 +--- a/drivers/bluetooth/hci_uart.h ++++ b/drivers/bluetooth/hci_uart.h +@@ -37,7 +37,6 @@ + + #define HCI_UART_RAW_DEVICE 0 + #define HCI_UART_RESET_ON_INIT 1 +-#define HCI_UART_CREATE_AMP 2 + #define HCI_UART_INIT_PENDING 3 + #define HCI_UART_EXT_CONFIG 4 + #define HCI_UART_VND_DETECT 5 +@@ -97,7 +96,17 @@ struct hci_uart { + + int hci_uart_register_proto(const struct hci_uart_proto *p); + int hci_uart_unregister_proto(const struct hci_uart_proto *p); +-int hci_uart_register_device(struct hci_uart *hu, const struct hci_uart_proto *p); ++ ++int hci_uart_register_device_priv(struct hci_uart *hu, ++ const struct hci_uart_proto *p, ++ int sizeof_priv); ++ ++static inline int hci_uart_register_device(struct hci_uart *hu, ++ const struct hci_uart_proto *p) ++{ ++ return hci_uart_register_device_priv(hu, p, 0); ++} ++ + void hci_uart_unregister_device(struct hci_uart *hu); + + int hci_uart_tx_wakeup(struct hci_uart *hu); +diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c +index f3892e9ce800ff..28750a40f0ed52 100644 +--- a/drivers/bluetooth/hci_vhci.c ++++ b/drivers/bluetooth/hci_vhci.c +@@ -11,6 +11,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -44,6 +45,7 @@ struct vhci_data { + bool wakeup; + __u16 msft_opcode; + bool aosp_capable; ++ atomic_t initialized; + }; + + static int vhci_open_dev(struct hci_dev *hdev) +@@ -75,11 +77,10 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) + + memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1); + +- mutex_lock(&data->open_mutex); + skb_queue_tail(&data->readq, skb); +- mutex_unlock(&data->open_mutex); + +- wake_up_interruptible(&data->read_wait); ++ if (atomic_read(&data->initialized)) ++ wake_up_interruptible(&data->read_wait); + return 0; + } + +@@ -383,17 +384,10 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode) + { + struct hci_dev *hdev; + struct sk_buff *skb; +- __u8 dev_type; + + if (data->hdev) + return -EBADFD; + +- /* bits 0-1 are dev_type (Primary or AMP) */ +- dev_type = opcode & 0x03; +- +- if (dev_type != HCI_PRIMARY && dev_type != HCI_AMP) +- return -EINVAL; +- + /* bits 2-5 are reserved (must be zero) */ + if (opcode & 0x3c) + return -EINVAL; +@@ -411,7 +405,6 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode) + data->hdev = hdev; + + hdev->bus = HCI_VIRTUAL; +- hdev->dev_type = dev_type; + hci_set_drvdata(hdev, data); + + hdev->open = vhci_open_dev; +@@ -464,7 +457,8 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode) + skb_put_u8(skb, 0xff); + skb_put_u8(skb, opcode); + put_unaligned_le16(hdev->id, skb_put(skb, 2)); +- skb_queue_tail(&data->readq, skb); ++ skb_queue_head(&data->readq, skb); ++ atomic_inc(&data->initialized); + + wake_up_interruptible(&data->read_wait); + return 0; +@@ -632,7 +626,7 @@ static void vhci_open_timeout(struct work_struct *work) + struct vhci_data *data = container_of(work, struct vhci_data, + open_timeout.work); + +- vhci_create_device(data, amp ? HCI_AMP : HCI_PRIMARY); ++ vhci_create_device(data, 0x00); + } + + static int vhci_open(struct inode *inode, struct file *file) +diff --git a/drivers/bluetooth/virtio_bt.c b/drivers/bluetooth/virtio_bt.c +index 2ac70b560c46db..18208e152a3675 100644 +--- a/drivers/bluetooth/virtio_bt.c ++++ b/drivers/bluetooth/virtio_bt.c +@@ -274,7 +274,6 @@ static int virtbt_probe(struct virtio_device *vdev) + + switch (type) { + case VIRTIO_BT_CONFIG_TYPE_PRIMARY: +- case VIRTIO_BT_CONFIG_TYPE_AMP: + break; + default: + return -EINVAL; +@@ -303,7 +302,6 @@ static int virtbt_probe(struct virtio_device *vdev) + vbt->hdev = hdev; + + hdev->bus = HCI_VIRTIO; +- hdev->dev_type = type; + hci_set_drvdata(hdev, vbt); + + hdev->open = virtbt_open; +diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig +index c98dd6ca26297f..fab27506d945e9 100644 +--- a/drivers/bus/Kconfig ++++ b/drivers/bus/Kconfig +@@ -186,11 +186,12 @@ config SUNXI_RSB + + config TEGRA_ACONNECT + tristate "Tegra ACONNECT Bus Driver" +- depends on ARCH_TEGRA_210_SOC ++ depends on ARCH_TEGRA + depends on OF && PM + help + Driver for the Tegra ACONNECT bus which is used to interface with +- the devices inside the Audio Processing Engine (APE) for Tegra210. ++ the devices inside the Audio Processing Engine (APE) for ++ Tegra210 and later. + + config TEGRA_GMI + tristate "Tegra Generic Memory Interface bus driver" +diff --git a/drivers/bus/arm-integrator-lm.c b/drivers/bus/arm-integrator-lm.c +index b715c8ab36e8bd..a65c79b08804f4 100644 +--- a/drivers/bus/arm-integrator-lm.c ++++ b/drivers/bus/arm-integrator-lm.c +@@ -85,6 +85,7 @@ static int integrator_ap_lm_probe(struct platform_device *pdev) + return -ENODEV; + } + map = syscon_node_to_regmap(syscon); ++ of_node_put(syscon); + if (IS_ERR(map)) { + dev_err(dev, + "could not find Integrator/AP system controller\n"); +diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c +index 42c9386a7b423f..f9fd1582f150de 100644 +--- a/drivers/bus/imx-weim.c ++++ b/drivers/bus/imx-weim.c +@@ -117,7 +117,7 @@ static int imx_weim_gpr_setup(struct platform_device *pdev) + i++; + } + +- if (i == 0 || i % 4) ++ if (i == 0) + goto err; + + for (i = 0; i < ARRAY_SIZE(gprvals); i++) { +diff --git a/drivers/bus/mhi/ep/internal.h b/drivers/bus/mhi/ep/internal.h +index a2125fa5fe2f97..accbf3a51d0cf5 100644 +--- a/drivers/bus/mhi/ep/internal.h ++++ b/drivers/bus/mhi/ep/internal.h +@@ -159,6 +159,7 @@ struct mhi_ep_chan { + void (*xfer_cb)(struct mhi_ep_device *mhi_dev, struct mhi_result *result); + enum mhi_ch_state state; + enum dma_data_direction dir; ++ size_t rd_offset; + u64 tre_loc; + u32 tre_size; + u32 tre_bytes_left; +diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c +index 600881808982aa..c48f4d9f2c690b 100644 +--- a/drivers/bus/mhi/ep/main.c ++++ b/drivers/bus/mhi/ep/main.c +@@ -71,45 +71,77 @@ static int mhi_ep_send_event(struct mhi_ep_cntrl *mhi_cntrl, u32 ring_idx, + static int mhi_ep_send_completion_event(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring, + struct mhi_ring_element *tre, u32 len, enum mhi_ev_ccs code) + { +- struct mhi_ring_element event = {}; ++ struct mhi_ring_element *event; ++ int ret; ++ ++ event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL); ++ if (!event) ++ return -ENOMEM; ++ ++ event->ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(*tre)); ++ event->dword[0] = MHI_TRE_EV_DWORD0(code, len); ++ event->dword[1] = MHI_TRE_EV_DWORD1(ring->ch_id, MHI_PKT_TYPE_TX_EVENT); + +- event.ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(*tre)); +- event.dword[0] = MHI_TRE_EV_DWORD0(code, len); +- event.dword[1] = MHI_TRE_EV_DWORD1(ring->ch_id, MHI_PKT_TYPE_TX_EVENT); ++ ret = mhi_ep_send_event(mhi_cntrl, ring->er_index, event, MHI_TRE_DATA_GET_BEI(tre)); ++ kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event); + +- return mhi_ep_send_event(mhi_cntrl, ring->er_index, &event, MHI_TRE_DATA_GET_BEI(tre)); ++ return ret; + } + + int mhi_ep_send_state_change_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_state state) + { +- struct mhi_ring_element event = {}; ++ struct mhi_ring_element *event; ++ int ret; ++ ++ event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL); ++ if (!event) ++ return -ENOMEM; + +- event.dword[0] = MHI_SC_EV_DWORD0(state); +- event.dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_STATE_CHANGE_EVENT); ++ event->dword[0] = MHI_SC_EV_DWORD0(state); ++ event->dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_STATE_CHANGE_EVENT); + +- return mhi_ep_send_event(mhi_cntrl, 0, &event, 0); ++ ret = mhi_ep_send_event(mhi_cntrl, 0, event, 0); ++ kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event); ++ ++ return ret; + } + + int mhi_ep_send_ee_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_ee_type exec_env) + { +- struct mhi_ring_element event = {}; ++ struct mhi_ring_element *event; ++ int ret; ++ ++ event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL); ++ if (!event) ++ return -ENOMEM; ++ ++ event->dword[0] = MHI_EE_EV_DWORD0(exec_env); ++ event->dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_EE_EVENT); + +- event.dword[0] = MHI_EE_EV_DWORD0(exec_env); +- event.dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_EE_EVENT); ++ ret = mhi_ep_send_event(mhi_cntrl, 0, event, 0); ++ kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event); + +- return mhi_ep_send_event(mhi_cntrl, 0, &event, 0); ++ return ret; + } + + static int mhi_ep_send_cmd_comp_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_ev_ccs code) + { + struct mhi_ep_ring *ring = &mhi_cntrl->mhi_cmd->ring; +- struct mhi_ring_element event = {}; ++ struct mhi_ring_element *event; ++ int ret; + +- event.ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(struct mhi_ring_element)); +- event.dword[0] = MHI_CC_EV_DWORD0(code); +- event.dword[1] = MHI_CC_EV_DWORD1(MHI_PKT_TYPE_CMD_COMPLETION_EVENT); ++ event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL); ++ if (!event) ++ return -ENOMEM; ++ ++ event->ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(struct mhi_ring_element)); ++ event->dword[0] = MHI_CC_EV_DWORD0(code); ++ event->dword[1] = MHI_CC_EV_DWORD1(MHI_PKT_TYPE_CMD_COMPLETION_EVENT); + +- return mhi_ep_send_event(mhi_cntrl, 0, &event, 0); ++ ret = mhi_ep_send_event(mhi_cntrl, 0, event, 0); ++ kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event); ++ ++ return ret; + } + + static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_element *el) +@@ -151,6 +183,8 @@ static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_ele + + goto err_unlock; + } ++ ++ mhi_chan->rd_offset = ch_ring->rd_offset; + } + + /* Set channel state to RUNNING */ +@@ -280,22 +314,85 @@ bool mhi_ep_queue_is_empty(struct mhi_ep_device *mhi_dev, enum dma_data_directio + struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl; + struct mhi_ep_ring *ring = &mhi_cntrl->mhi_chan[mhi_chan->chan].ring; + +- return !!(ring->rd_offset == ring->wr_offset); ++ return !!(mhi_chan->rd_offset == ring->wr_offset); + } + EXPORT_SYMBOL_GPL(mhi_ep_queue_is_empty); + ++static void mhi_ep_read_completion(struct mhi_ep_buf_info *buf_info) ++{ ++ struct mhi_ep_device *mhi_dev = buf_info->mhi_dev; ++ struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl; ++ struct mhi_ep_chan *mhi_chan = mhi_dev->ul_chan; ++ struct mhi_ep_ring *ring = &mhi_cntrl->mhi_chan[mhi_chan->chan].ring; ++ struct mhi_ring_element *el = &ring->ring_cache[ring->rd_offset]; ++ struct mhi_result result = {}; ++ int ret; ++ ++ if (mhi_chan->xfer_cb) { ++ result.buf_addr = buf_info->cb_buf; ++ result.dir = mhi_chan->dir; ++ result.bytes_xferd = buf_info->size; ++ ++ mhi_chan->xfer_cb(mhi_dev, &result); ++ } ++ ++ /* ++ * The host will split the data packet into multiple TREs if it can't fit ++ * the packet in a single TRE. In that case, CHAIN flag will be set by the ++ * host for all TREs except the last one. ++ */ ++ if (buf_info->code != MHI_EV_CC_OVERFLOW) { ++ if (MHI_TRE_DATA_GET_CHAIN(el)) { ++ /* ++ * IEOB (Interrupt on End of Block) flag will be set by the host if ++ * it expects the completion event for all TREs of a TD. ++ */ ++ if (MHI_TRE_DATA_GET_IEOB(el)) { ++ ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, ++ MHI_TRE_DATA_GET_LEN(el), ++ MHI_EV_CC_EOB); ++ if (ret < 0) { ++ dev_err(&mhi_chan->mhi_dev->dev, ++ "Error sending transfer compl. event\n"); ++ goto err_free_tre_buf; ++ } ++ } ++ } else { ++ /* ++ * IEOT (Interrupt on End of Transfer) flag will be set by the host ++ * for the last TRE of the TD and expects the completion event for ++ * the same. ++ */ ++ if (MHI_TRE_DATA_GET_IEOT(el)) { ++ ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, ++ MHI_TRE_DATA_GET_LEN(el), ++ MHI_EV_CC_EOT); ++ if (ret < 0) { ++ dev_err(&mhi_chan->mhi_dev->dev, ++ "Error sending transfer compl. event\n"); ++ goto err_free_tre_buf; ++ } ++ } ++ } ++ } ++ ++ mhi_ep_ring_inc_index(ring); ++ ++err_free_tre_buf: ++ kmem_cache_free(mhi_cntrl->tre_buf_cache, buf_info->cb_buf); ++} ++ + static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl, +- struct mhi_ep_ring *ring, +- struct mhi_result *result, +- u32 len) ++ struct mhi_ep_ring *ring) + { + struct mhi_ep_chan *mhi_chan = &mhi_cntrl->mhi_chan[ring->ch_id]; + struct device *dev = &mhi_cntrl->mhi_dev->dev; + size_t tr_len, read_offset, write_offset; ++ struct mhi_ep_buf_info buf_info = {}; ++ u32 len = MHI_EP_DEFAULT_MTU; + struct mhi_ring_element *el; + bool tr_done = false; +- void *write_addr; +- u64 read_addr; ++ void *buf_addr; + u32 buf_left; + int ret; + +@@ -308,7 +405,7 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl, + return -ENODEV; + } + +- el = &ring->ring_cache[ring->rd_offset]; ++ el = &ring->ring_cache[mhi_chan->rd_offset]; + + /* Check if there is data pending to be read from previous read operation */ + if (mhi_chan->tre_bytes_left) { +@@ -324,81 +421,51 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl, + + read_offset = mhi_chan->tre_size - mhi_chan->tre_bytes_left; + write_offset = len - buf_left; +- read_addr = mhi_chan->tre_loc + read_offset; +- write_addr = result->buf_addr + write_offset; ++ ++ buf_addr = kmem_cache_zalloc(mhi_cntrl->tre_buf_cache, GFP_KERNEL); ++ if (!buf_addr) ++ return -ENOMEM; ++ ++ buf_info.host_addr = mhi_chan->tre_loc + read_offset; ++ buf_info.dev_addr = buf_addr + write_offset; ++ buf_info.size = tr_len; ++ buf_info.cb = mhi_ep_read_completion; ++ buf_info.cb_buf = buf_addr; ++ buf_info.mhi_dev = mhi_chan->mhi_dev; ++ ++ if (mhi_chan->tre_bytes_left - tr_len) ++ buf_info.code = MHI_EV_CC_OVERFLOW; + + dev_dbg(dev, "Reading %zd bytes from channel (%u)\n", tr_len, ring->ch_id); +- ret = mhi_cntrl->read_from_host(mhi_cntrl, read_addr, write_addr, tr_len); ++ ret = mhi_cntrl->read_async(mhi_cntrl, &buf_info); + if (ret < 0) { + dev_err(&mhi_chan->mhi_dev->dev, "Error reading from channel\n"); +- return ret; ++ goto err_free_buf_addr; + } + + buf_left -= tr_len; + mhi_chan->tre_bytes_left -= tr_len; + +- /* +- * Once the TRE (Transfer Ring Element) of a TD (Transfer Descriptor) has been +- * read completely: +- * +- * 1. Send completion event to the host based on the flags set in TRE. +- * 2. Increment the local read offset of the transfer ring. +- */ + if (!mhi_chan->tre_bytes_left) { +- /* +- * The host will split the data packet into multiple TREs if it can't fit +- * the packet in a single TRE. In that case, CHAIN flag will be set by the +- * host for all TREs except the last one. +- */ +- if (MHI_TRE_DATA_GET_CHAIN(el)) { +- /* +- * IEOB (Interrupt on End of Block) flag will be set by the host if +- * it expects the completion event for all TREs of a TD. +- */ +- if (MHI_TRE_DATA_GET_IEOB(el)) { +- ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, +- MHI_TRE_DATA_GET_LEN(el), +- MHI_EV_CC_EOB); +- if (ret < 0) { +- dev_err(&mhi_chan->mhi_dev->dev, +- "Error sending transfer compl. event\n"); +- return ret; +- } +- } +- } else { +- /* +- * IEOT (Interrupt on End of Transfer) flag will be set by the host +- * for the last TRE of the TD and expects the completion event for +- * the same. +- */ +- if (MHI_TRE_DATA_GET_IEOT(el)) { +- ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, +- MHI_TRE_DATA_GET_LEN(el), +- MHI_EV_CC_EOT); +- if (ret < 0) { +- dev_err(&mhi_chan->mhi_dev->dev, +- "Error sending transfer compl. event\n"); +- return ret; +- } +- } +- ++ if (MHI_TRE_DATA_GET_IEOT(el)) + tr_done = true; +- } + +- mhi_ep_ring_inc_index(ring); ++ mhi_chan->rd_offset = (mhi_chan->rd_offset + 1) % ring->ring_size; + } +- +- result->bytes_xferd += tr_len; + } while (buf_left && !tr_done); + + return 0; ++ ++err_free_buf_addr: ++ kmem_cache_free(mhi_cntrl->tre_buf_cache, buf_addr); ++ ++ return ret; + } + +-static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring, struct mhi_ring_element *el) ++static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring) + { + struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl; + struct mhi_result result = {}; +- u32 len = MHI_EP_DEFAULT_MTU; + struct mhi_ep_chan *mhi_chan; + int ret; + +@@ -419,44 +486,59 @@ static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring, struct mhi_ring_elem + mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result); + } else { + /* UL channel */ +- result.buf_addr = kzalloc(len, GFP_KERNEL); +- if (!result.buf_addr) +- return -ENOMEM; +- + do { +- ret = mhi_ep_read_channel(mhi_cntrl, ring, &result, len); ++ ret = mhi_ep_read_channel(mhi_cntrl, ring); + if (ret < 0) { + dev_err(&mhi_chan->mhi_dev->dev, "Failed to read channel\n"); +- kfree(result.buf_addr); + return ret; + } + +- result.dir = mhi_chan->dir; +- mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result); +- result.bytes_xferd = 0; +- memset(result.buf_addr, 0, len); +- + /* Read until the ring becomes empty */ + } while (!mhi_ep_queue_is_empty(mhi_chan->mhi_dev, DMA_TO_DEVICE)); +- +- kfree(result.buf_addr); + } + + return 0; + } + ++static void mhi_ep_skb_completion(struct mhi_ep_buf_info *buf_info) ++{ ++ struct mhi_ep_device *mhi_dev = buf_info->mhi_dev; ++ struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl; ++ struct mhi_ep_chan *mhi_chan = mhi_dev->dl_chan; ++ struct mhi_ep_ring *ring = &mhi_cntrl->mhi_chan[mhi_chan->chan].ring; ++ struct mhi_ring_element *el = &ring->ring_cache[ring->rd_offset]; ++ struct device *dev = &mhi_dev->dev; ++ struct mhi_result result = {}; ++ int ret; ++ ++ if (mhi_chan->xfer_cb) { ++ result.buf_addr = buf_info->cb_buf; ++ result.dir = mhi_chan->dir; ++ result.bytes_xferd = buf_info->size; ++ ++ mhi_chan->xfer_cb(mhi_dev, &result); ++ } ++ ++ ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, buf_info->size, ++ buf_info->code); ++ if (ret) { ++ dev_err(dev, "Error sending transfer completion event\n"); ++ return; ++ } ++ ++ mhi_ep_ring_inc_index(ring); ++} ++ + /* TODO: Handle partially formed TDs */ + int mhi_ep_queue_skb(struct mhi_ep_device *mhi_dev, struct sk_buff *skb) + { + struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl; + struct mhi_ep_chan *mhi_chan = mhi_dev->dl_chan; + struct device *dev = &mhi_chan->mhi_dev->dev; ++ struct mhi_ep_buf_info buf_info = {}; + struct mhi_ring_element *el; + u32 buf_left, read_offset; + struct mhi_ep_ring *ring; +- enum mhi_ev_ccs code; +- void *read_addr; +- u64 write_addr; + size_t tr_len; + u32 tre_len; + int ret; +@@ -480,40 +562,44 @@ int mhi_ep_queue_skb(struct mhi_ep_device *mhi_dev, struct sk_buff *skb) + goto err_exit; + } + +- el = &ring->ring_cache[ring->rd_offset]; ++ el = &ring->ring_cache[mhi_chan->rd_offset]; + tre_len = MHI_TRE_DATA_GET_LEN(el); + + tr_len = min(buf_left, tre_len); + read_offset = skb->len - buf_left; +- read_addr = skb->data + read_offset; +- write_addr = MHI_TRE_DATA_GET_PTR(el); + +- dev_dbg(dev, "Writing %zd bytes to channel (%u)\n", tr_len, ring->ch_id); +- ret = mhi_cntrl->write_to_host(mhi_cntrl, read_addr, write_addr, tr_len); +- if (ret < 0) { +- dev_err(dev, "Error writing to the channel\n"); +- goto err_exit; +- } ++ buf_info.dev_addr = skb->data + read_offset; ++ buf_info.host_addr = MHI_TRE_DATA_GET_PTR(el); ++ buf_info.size = tr_len; ++ buf_info.cb = mhi_ep_skb_completion; ++ buf_info.cb_buf = skb; ++ buf_info.mhi_dev = mhi_dev; + +- buf_left -= tr_len; + /* + * For all TREs queued by the host for DL channel, only the EOT flag will be set. + * If the packet doesn't fit into a single TRE, send the OVERFLOW event to + * the host so that the host can adjust the packet boundary to next TREs. Else send + * the EOT event to the host indicating the packet boundary. + */ +- if (buf_left) +- code = MHI_EV_CC_OVERFLOW; ++ if (buf_left - tr_len) ++ buf_info.code = MHI_EV_CC_OVERFLOW; + else +- code = MHI_EV_CC_EOT; ++ buf_info.code = MHI_EV_CC_EOT; + +- ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, tr_len, code); +- if (ret) { +- dev_err(dev, "Error sending transfer completion event\n"); ++ dev_dbg(dev, "Writing %zd bytes to channel (%u)\n", tr_len, ring->ch_id); ++ ret = mhi_cntrl->write_async(mhi_cntrl, &buf_info); ++ if (ret < 0) { ++ dev_err(dev, "Error writing to the channel\n"); + goto err_exit; + } + +- mhi_ep_ring_inc_index(ring); ++ buf_left -= tr_len; ++ ++ /* ++ * Update the read offset cached in mhi_chan. Actual read offset ++ * will be updated by the completion handler. ++ */ ++ mhi_chan->rd_offset = (mhi_chan->rd_offset + 1) % ring->ring_size; + } while (buf_left); + + mutex_unlock(&mhi_chan->lock); +@@ -714,7 +800,6 @@ static void mhi_ep_ch_ring_worker(struct work_struct *work) + struct mhi_ep_cntrl *mhi_cntrl = container_of(work, struct mhi_ep_cntrl, ch_ring_work); + struct device *dev = &mhi_cntrl->mhi_dev->dev; + struct mhi_ep_ring_item *itr, *tmp; +- struct mhi_ring_element *el; + struct mhi_ep_ring *ring; + struct mhi_ep_chan *chan; + unsigned long flags; +@@ -748,31 +833,29 @@ static void mhi_ep_ch_ring_worker(struct work_struct *work) + if (ret) { + dev_err(dev, "Error updating write offset for ring\n"); + mutex_unlock(&chan->lock); +- kfree(itr); ++ kmem_cache_free(mhi_cntrl->ring_item_cache, itr); + continue; + } + + /* Sanity check to make sure there are elements in the ring */ +- if (ring->rd_offset == ring->wr_offset) { ++ if (chan->rd_offset == ring->wr_offset) { + mutex_unlock(&chan->lock); +- kfree(itr); ++ kmem_cache_free(mhi_cntrl->ring_item_cache, itr); + continue; + } + +- el = &ring->ring_cache[ring->rd_offset]; +- + dev_dbg(dev, "Processing the ring for channel (%u)\n", ring->ch_id); +- ret = mhi_ep_process_ch_ring(ring, el); ++ ret = mhi_ep_process_ch_ring(ring); + if (ret) { + dev_err(dev, "Error processing ring for channel (%u): %d\n", + ring->ch_id, ret); + mutex_unlock(&chan->lock); +- kfree(itr); ++ kmem_cache_free(mhi_cntrl->ring_item_cache, itr); + continue; + } + + mutex_unlock(&chan->lock); +- kfree(itr); ++ kmem_cache_free(mhi_cntrl->ring_item_cache, itr); + } + } + +@@ -828,7 +911,7 @@ static void mhi_ep_queue_channel_db(struct mhi_ep_cntrl *mhi_cntrl, unsigned lon + u32 ch_id = ch_idx + i; + + ring = &mhi_cntrl->mhi_chan[ch_id].ring; +- item = kzalloc(sizeof(*item), GFP_ATOMIC); ++ item = kmem_cache_zalloc(mhi_cntrl->ring_item_cache, GFP_ATOMIC); + if (!item) + return; + +@@ -1375,6 +1458,29 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl, + goto err_free_ch; + } + ++ mhi_cntrl->ev_ring_el_cache = kmem_cache_create("mhi_ep_event_ring_el", ++ sizeof(struct mhi_ring_element), 0, ++ 0, NULL); ++ if (!mhi_cntrl->ev_ring_el_cache) { ++ ret = -ENOMEM; ++ goto err_free_cmd; ++ } ++ ++ mhi_cntrl->tre_buf_cache = kmem_cache_create("mhi_ep_tre_buf", MHI_EP_DEFAULT_MTU, 0, ++ 0, NULL); ++ if (!mhi_cntrl->tre_buf_cache) { ++ ret = -ENOMEM; ++ goto err_destroy_ev_ring_el_cache; ++ } ++ ++ mhi_cntrl->ring_item_cache = kmem_cache_create("mhi_ep_ring_item", ++ sizeof(struct mhi_ep_ring_item), 0, ++ 0, NULL); ++ if (!mhi_cntrl->ring_item_cache) { ++ ret = -ENOMEM; ++ goto err_destroy_tre_buf_cache; ++ } ++ + INIT_WORK(&mhi_cntrl->state_work, mhi_ep_state_worker); + INIT_WORK(&mhi_cntrl->reset_work, mhi_ep_reset_worker); + INIT_WORK(&mhi_cntrl->cmd_ring_work, mhi_ep_cmd_ring_worker); +@@ -1383,7 +1489,7 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl, + mhi_cntrl->wq = alloc_workqueue("mhi_ep_wq", 0, 0); + if (!mhi_cntrl->wq) { + ret = -ENOMEM; +- goto err_free_cmd; ++ goto err_destroy_ring_item_cache; + } + + INIT_LIST_HEAD(&mhi_cntrl->st_transition_list); +@@ -1442,6 +1548,12 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl, + ida_free(&mhi_ep_cntrl_ida, mhi_cntrl->index); + err_destroy_wq: + destroy_workqueue(mhi_cntrl->wq); ++err_destroy_ring_item_cache: ++ kmem_cache_destroy(mhi_cntrl->ring_item_cache); ++err_destroy_ev_ring_el_cache: ++ kmem_cache_destroy(mhi_cntrl->ev_ring_el_cache); ++err_destroy_tre_buf_cache: ++ kmem_cache_destroy(mhi_cntrl->tre_buf_cache); + err_free_cmd: + kfree(mhi_cntrl->mhi_cmd); + err_free_ch: +@@ -1463,6 +1575,9 @@ void mhi_ep_unregister_controller(struct mhi_ep_cntrl *mhi_cntrl) + + free_irq(mhi_cntrl->irq, mhi_cntrl); + ++ kmem_cache_destroy(mhi_cntrl->tre_buf_cache); ++ kmem_cache_destroy(mhi_cntrl->ev_ring_el_cache); ++ kmem_cache_destroy(mhi_cntrl->ring_item_cache); + kfree(mhi_cntrl->mhi_cmd); + kfree(mhi_cntrl->mhi_chan); + +diff --git a/drivers/bus/mhi/ep/ring.c b/drivers/bus/mhi/ep/ring.c +index 115518ec76a43a..ba9f696d1aa80e 100644 +--- a/drivers/bus/mhi/ep/ring.c ++++ b/drivers/bus/mhi/ep/ring.c +@@ -30,7 +30,8 @@ static int __mhi_ep_cache_ring(struct mhi_ep_ring *ring, size_t end) + { + struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl; + struct device *dev = &mhi_cntrl->mhi_dev->dev; +- size_t start, copy_size; ++ struct mhi_ep_buf_info buf_info = {}; ++ size_t start; + int ret; + + /* Don't proceed in the case of event ring. This happens during mhi_ep_ring_start(). */ +@@ -43,30 +44,34 @@ static int __mhi_ep_cache_ring(struct mhi_ep_ring *ring, size_t end) + + start = ring->wr_offset; + if (start < end) { +- copy_size = (end - start) * sizeof(struct mhi_ring_element); +- ret = mhi_cntrl->read_from_host(mhi_cntrl, ring->rbase + +- (start * sizeof(struct mhi_ring_element)), +- &ring->ring_cache[start], copy_size); ++ buf_info.size = (end - start) * sizeof(struct mhi_ring_element); ++ buf_info.host_addr = ring->rbase + (start * sizeof(struct mhi_ring_element)); ++ buf_info.dev_addr = &ring->ring_cache[start]; ++ ++ ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info); + if (ret < 0) + return ret; + } else { +- copy_size = (ring->ring_size - start) * sizeof(struct mhi_ring_element); +- ret = mhi_cntrl->read_from_host(mhi_cntrl, ring->rbase + +- (start * sizeof(struct mhi_ring_element)), +- &ring->ring_cache[start], copy_size); ++ buf_info.size = (ring->ring_size - start) * sizeof(struct mhi_ring_element); ++ buf_info.host_addr = ring->rbase + (start * sizeof(struct mhi_ring_element)); ++ buf_info.dev_addr = &ring->ring_cache[start]; ++ ++ ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info); + if (ret < 0) + return ret; + + if (end) { +- ret = mhi_cntrl->read_from_host(mhi_cntrl, ring->rbase, +- &ring->ring_cache[0], +- end * sizeof(struct mhi_ring_element)); ++ buf_info.host_addr = ring->rbase; ++ buf_info.dev_addr = &ring->ring_cache[0]; ++ buf_info.size = end * sizeof(struct mhi_ring_element); ++ ++ ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info); + if (ret < 0) + return ret; + } + } + +- dev_dbg(dev, "Cached ring: start %zu end %zu size %zu\n", start, end, copy_size); ++ dev_dbg(dev, "Cached ring: start %zu end %zu size %zu\n", start, end, buf_info.size); + + return 0; + } +@@ -102,6 +107,7 @@ int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *e + { + struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl; + struct device *dev = &mhi_cntrl->mhi_dev->dev; ++ struct mhi_ep_buf_info buf_info = {}; + size_t old_offset = 0; + u32 num_free_elem; + __le64 rp; +@@ -133,12 +139,11 @@ int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *e + rp = cpu_to_le64(ring->rd_offset * sizeof(*el) + ring->rbase); + memcpy_toio((void __iomem *) &ring->ring_ctx->generic.rp, &rp, sizeof(u64)); + +- ret = mhi_cntrl->write_to_host(mhi_cntrl, el, ring->rbase + (old_offset * sizeof(*el)), +- sizeof(*el)); +- if (ret < 0) +- return ret; ++ buf_info.host_addr = ring->rbase + (old_offset * sizeof(*el)); ++ buf_info.dev_addr = el; ++ buf_info.size = sizeof(*el); + +- return 0; ++ return mhi_cntrl->write_sync(mhi_cntrl, &buf_info); + } + + void mhi_ep_ring_init(struct mhi_ep_ring *ring, enum mhi_ep_ring_type type, u32 id) +diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c +index f78aefd2d7a362..cfd17c02fe20ef 100644 +--- a/drivers/bus/mhi/host/init.c ++++ b/drivers/bus/mhi/host/init.c +@@ -62,6 +62,7 @@ static const char * const mhi_pm_state_str[] = { + [MHI_PM_STATE_FW_DL_ERR] = "Firmware Download Error", + [MHI_PM_STATE_SYS_ERR_DETECT] = "SYS ERROR Detect", + [MHI_PM_STATE_SYS_ERR_PROCESS] = "SYS ERROR Process", ++ [MHI_PM_STATE_SYS_ERR_FAIL] = "SYS ERROR Failure", + [MHI_PM_STATE_SHUTDOWN_PROCESS] = "SHUTDOWN Process", + [MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "Linkdown or Error Fatal Detect", + }; +diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h +index 2e139e76de4c03..d2858236af52b1 100644 +--- a/drivers/bus/mhi/host/internal.h ++++ b/drivers/bus/mhi/host/internal.h +@@ -88,6 +88,7 @@ enum mhi_pm_state { + MHI_PM_STATE_FW_DL_ERR, + MHI_PM_STATE_SYS_ERR_DETECT, + MHI_PM_STATE_SYS_ERR_PROCESS, ++ MHI_PM_STATE_SYS_ERR_FAIL, + MHI_PM_STATE_SHUTDOWN_PROCESS, + MHI_PM_STATE_LD_ERR_FATAL_DETECT, + MHI_PM_STATE_MAX +@@ -104,14 +105,16 @@ enum mhi_pm_state { + #define MHI_PM_FW_DL_ERR BIT(7) + #define MHI_PM_SYS_ERR_DETECT BIT(8) + #define MHI_PM_SYS_ERR_PROCESS BIT(9) +-#define MHI_PM_SHUTDOWN_PROCESS BIT(10) ++#define MHI_PM_SYS_ERR_FAIL BIT(10) ++#define MHI_PM_SHUTDOWN_PROCESS BIT(11) + /* link not accessible */ +-#define MHI_PM_LD_ERR_FATAL_DETECT BIT(11) ++#define MHI_PM_LD_ERR_FATAL_DETECT BIT(12) + + #define MHI_REG_ACCESS_VALID(pm_state) ((pm_state & (MHI_PM_POR | MHI_PM_M0 | \ + MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_M3_EXIT | \ + MHI_PM_SYS_ERR_DETECT | MHI_PM_SYS_ERR_PROCESS | \ +- MHI_PM_SHUTDOWN_PROCESS | MHI_PM_FW_DL_ERR))) ++ MHI_PM_SYS_ERR_FAIL | MHI_PM_SHUTDOWN_PROCESS | \ ++ MHI_PM_FW_DL_ERR))) + #define MHI_PM_IN_ERROR_STATE(pm_state) (pm_state >= MHI_PM_FW_DL_ERR) + #define MHI_PM_IN_FATAL_STATE(pm_state) (pm_state == MHI_PM_LD_ERR_FATAL_DETECT) + #define MHI_DB_ACCESS_VALID(mhi_cntrl) (mhi_cntrl->pm_state & mhi_cntrl->db_access) +diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c +index dcf627b36e829e..d6653cbcf94a2e 100644 +--- a/drivers/bus/mhi/host/main.c ++++ b/drivers/bus/mhi/host/main.c +@@ -268,7 +268,8 @@ static void mhi_del_ring_element(struct mhi_controller *mhi_cntrl, + + static bool is_valid_ring_ptr(struct mhi_ring *ring, dma_addr_t addr) + { +- return addr >= ring->iommu_base && addr < ring->iommu_base + ring->len; ++ return addr >= ring->iommu_base && addr < ring->iommu_base + ring->len && ++ !(addr & (sizeof(struct mhi_ring_element) - 1)); + } + + int mhi_destroy_device(struct device *dev, void *data) +@@ -642,6 +643,8 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl, + mhi_del_ring_element(mhi_cntrl, tre_ring); + local_rp = tre_ring->rp; + ++ read_unlock_bh(&mhi_chan->lock); ++ + /* notify client */ + mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result); + +@@ -667,6 +670,8 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl, + kfree(buf_info->cb_buf); + } + } ++ ++ read_lock_bh(&mhi_chan->lock); + } + break; + } /* CC_EOT */ +@@ -1122,17 +1127,15 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info, + if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) + return -EIO; + +- read_lock_irqsave(&mhi_cntrl->pm_lock, flags); +- + ret = mhi_is_ring_full(mhi_cntrl, tre_ring); +- if (unlikely(ret)) { +- ret = -EAGAIN; +- goto exit_unlock; +- } ++ if (unlikely(ret)) ++ return -EAGAIN; + + ret = mhi_gen_tre(mhi_cntrl, mhi_chan, buf_info, mflags); + if (unlikely(ret)) +- goto exit_unlock; ++ return ret; ++ ++ read_lock_irqsave(&mhi_cntrl->pm_lock, flags); + + /* Packet is queued, take a usage ref to exit M3 if necessary + * for host->device buffer, balanced put is done on buffer completion +@@ -1152,7 +1155,6 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info, + if (dir == DMA_FROM_DEVICE) + mhi_cntrl->runtime_put(mhi_cntrl); + +-exit_unlock: + read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags); + + return ret; +@@ -1204,6 +1206,9 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, + int eot, eob, chain, bei; + int ret; + ++ /* Protect accesses for reading and incrementing WP */ ++ write_lock_bh(&mhi_chan->lock); ++ + buf_ring = &mhi_chan->buf_ring; + tre_ring = &mhi_chan->tre_ring; + +@@ -1221,8 +1226,10 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, + + if (!info->pre_mapped) { + ret = mhi_cntrl->map_single(mhi_cntrl, buf_info); +- if (ret) ++ if (ret) { ++ write_unlock_bh(&mhi_chan->lock); + return ret; ++ } + } + + eob = !!(flags & MHI_EOB); +@@ -1239,6 +1246,8 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, + mhi_add_ring_element(mhi_cntrl, tre_ring); + mhi_add_ring_element(mhi_cntrl, buf_ring); + ++ write_unlock_bh(&mhi_chan->lock); ++ + return 0; + } + +diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c +index 08f3f039dbddcf..154841916f5652 100644 +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -578,6 +578,15 @@ static const struct mhi_pci_dev_info mhi_telit_fn990_info = { + .mru_default = 32768, + }; + ++static const struct mhi_pci_dev_info mhi_telit_fe990a_info = { ++ .name = "telit-fe990a", ++ .config = &modem_telit_fn990_config, ++ .bar_num = MHI_PCI_DEFAULT_BAR_NUM, ++ .dma_data_width = 32, ++ .sideband_wake = false, ++ .mru_default = 32768, ++}; ++ + /* Keep the list sorted based on the PID. New VID should be added as the last entry */ + static const struct pci_device_id mhi_pci_id_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304), +@@ -595,9 +604,9 @@ static const struct pci_device_id mhi_pci_id_table[] = { + /* Telit FN990 */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, 0x1c5d, 0x2010), + .driver_data = (kernel_ulong_t) &mhi_telit_fn990_info }, +- /* Telit FE990 */ ++ /* Telit FE990A */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, 0x1c5d, 0x2015), +- .driver_data = (kernel_ulong_t) &mhi_telit_fn990_info }, ++ .driver_data = (kernel_ulong_t) &mhi_telit_fe990a_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1001), /* EM120R-GL (sdx24) */ +diff --git a/drivers/bus/mhi/host/pm.c b/drivers/bus/mhi/host/pm.c +index 8a4362d75fc437..27f8a40f288cfd 100644 +--- a/drivers/bus/mhi/host/pm.c ++++ b/drivers/bus/mhi/host/pm.c +@@ -36,7 +36,10 @@ + * M0 <--> M0 + * M0 -> FW_DL_ERR + * M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0 +- * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR ++ * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS ++ * SYS_ERR_PROCESS -> SYS_ERR_FAIL ++ * SYS_ERR_FAIL -> SYS_ERR_DETECT ++ * SYS_ERR_PROCESS --> POR + * L2: SHUTDOWN_PROCESS -> LD_ERR_FATAL_DETECT + * SHUTDOWN_PROCESS -> DISABLE + * L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT +@@ -93,7 +96,12 @@ static const struct mhi_pm_transitions dev_state_transitions[] = { + }, + { + MHI_PM_SYS_ERR_PROCESS, +- MHI_PM_POR | MHI_PM_SHUTDOWN_PROCESS | ++ MHI_PM_POR | MHI_PM_SYS_ERR_FAIL | MHI_PM_SHUTDOWN_PROCESS | ++ MHI_PM_LD_ERR_FATAL_DETECT ++ }, ++ { ++ MHI_PM_SYS_ERR_FAIL, ++ MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | + MHI_PM_LD_ERR_FATAL_DETECT + }, + /* L2 States */ +@@ -624,7 +632,13 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl) + !in_reset, timeout); + if (!ret || in_reset) { + dev_err(dev, "Device failed to exit MHI Reset state\n"); +- goto exit_sys_error_transition; ++ write_lock_irq(&mhi_cntrl->pm_lock); ++ cur_state = mhi_tryset_pm_state(mhi_cntrl, ++ MHI_PM_SYS_ERR_FAIL); ++ write_unlock_irq(&mhi_cntrl->pm_lock); ++ /* Shutdown may have occurred, otherwise cleanup now */ ++ if (cur_state != MHI_PM_SYS_ERR_FAIL) ++ goto exit_sys_error_transition; + } + + /* +diff --git a/drivers/bus/moxtet.c b/drivers/bus/moxtet.c +index 5eb0fe73ddc45b..e384fbc6c1d931 100644 +--- a/drivers/bus/moxtet.c ++++ b/drivers/bus/moxtet.c +@@ -755,7 +755,7 @@ static int moxtet_irq_setup(struct moxtet *moxtet) + moxtet->irq.masked = ~0; + + ret = request_threaded_irq(moxtet->dev_irq, NULL, moxtet_irq_thread_fn, +- IRQF_ONESHOT, "moxtet", moxtet); ++ IRQF_SHARED | IRQF_ONESHOT, "moxtet", moxtet); + if (ret < 0) + goto err_free; + +@@ -830,6 +830,12 @@ static void moxtet_remove(struct spi_device *spi) + mutex_destroy(&moxtet->lock); + } + ++static const struct spi_device_id moxtet_spi_ids[] = { ++ { "moxtet" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(spi, moxtet_spi_ids); ++ + static const struct of_device_id moxtet_dt_ids[] = { + { .compatible = "cznic,moxtet" }, + {}, +@@ -841,6 +847,7 @@ static struct spi_driver moxtet_spi_driver = { + .name = "moxtet", + .of_match_table = moxtet_dt_ids, + }, ++ .id_table = moxtet_spi_ids, + .probe = moxtet_probe, + .remove = moxtet_remove, + }; +diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c +index d57bc066dce6b4..9ed9239b1228f6 100644 +--- a/drivers/bus/ti-sysc.c ++++ b/drivers/bus/ti-sysc.c +@@ -2158,13 +2158,23 @@ static int sysc_reset(struct sysc *ddata) + sysc_val = sysc_read_sysconfig(ddata); + sysc_val |= sysc_mask; + sysc_write(ddata, sysc_offset, sysc_val); +- /* Flush posted write */ ++ ++ /* ++ * Some devices need a delay before reading registers ++ * after reset. Presumably a srst_udelay is not needed ++ * for devices that use a rstctrl register reset. ++ */ ++ if (ddata->cfg.srst_udelay) ++ fsleep(ddata->cfg.srst_udelay); ++ ++ /* ++ * Flush posted write. For devices needing srst_udelay ++ * this should trigger an interconnect error if the ++ * srst_udelay value is needed but not configured. ++ */ + sysc_val = sysc_read_sysconfig(ddata); + } + +- if (ddata->cfg.srst_udelay) +- fsleep(ddata->cfg.srst_udelay); +- + if (ddata->post_reset_quirk) + ddata->post_reset_quirk(ddata); + +diff --git a/drivers/cache/ax45mp_cache.c b/drivers/cache/ax45mp_cache.c +index 57186c58dc849c..1d7dd3d2c101cd 100644 +--- a/drivers/cache/ax45mp_cache.c ++++ b/drivers/cache/ax45mp_cache.c +@@ -129,8 +129,12 @@ static void ax45mp_dma_cache_wback(phys_addr_t paddr, size_t size) + unsigned long line_size; + unsigned long flags; + ++ if (unlikely(start == end)) ++ return; ++ + line_size = ax45mp_priv.ax45mp_cache_line_size; + start = start & (~(line_size - 1)); ++ end = ((end + line_size - 1) & (~(line_size - 1))); + local_irq_save(flags); + ax45mp_cpu_dcache_wb_range(start, end); + local_irq_restore(flags); +diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c +index cc283980598333..01f46caf1f88b7 100644 +--- a/drivers/cdrom/cdrom.c ++++ b/drivers/cdrom/cdrom.c +@@ -2358,7 +2358,7 @@ static int cdrom_ioctl_timed_media_change(struct cdrom_device_info *cdi, + return -EFAULT; + + tmp_info.media_flags = 0; +- if (tmp_info.last_media_change - cdi->last_media_change_ms < 0) ++ if (cdi->last_media_change_ms > tmp_info.last_media_change) + tmp_info.media_flags |= MEDIA_CHANGED_FLAG; + + tmp_info.last_media_change = cdi->last_media_change_ms; +diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c +index c6f181702b9a7b..edbc4d33811776 100644 +--- a/drivers/char/agp/parisc-agp.c ++++ b/drivers/char/agp/parisc-agp.c +@@ -38,7 +38,7 @@ static struct _parisc_agp_info { + + int lba_cap_offset; + +- u64 *gatt; ++ __le64 *gatt; + u64 gatt_entries; + + u64 gart_base; +@@ -104,7 +104,7 @@ parisc_agp_create_gatt_table(struct agp_bridge_data *bridge) + int i; + + for (i = 0; i < info->gatt_entries; i++) { +- info->gatt[i] = (unsigned long)agp_bridge->scratch_page; ++ info->gatt[i] = cpu_to_le64(agp_bridge->scratch_page); + } + + return 0; +@@ -158,9 +158,9 @@ parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type) + for (k = 0; + k < info->io_pages_per_kpage; + k++, j++, paddr += info->io_page_size) { +- info->gatt[j] = ++ info->gatt[j] = cpu_to_le64( + parisc_agp_mask_memory(agp_bridge, +- paddr, type); ++ paddr, type)); + asm_io_fdc(&info->gatt[j]); + } + } +@@ -184,7 +184,7 @@ parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type) + io_pg_start = info->io_pages_per_kpage * pg_start; + io_pg_count = info->io_pages_per_kpage * mem->page_count; + for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) { +- info->gatt[i] = agp_bridge->scratch_page; ++ info->gatt[i] = cpu_to_le64(agp_bridge->scratch_page); + } + + agp_bridge->driver->tlb_flush(mem); +@@ -204,7 +204,8 @@ parisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr, + pa |= (ci >> PAGE_SHIFT) & 0xff;/* move CI (8 bits) into lowest byte */ + pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */ + +- return cpu_to_le64(pa); ++ /* return native (big-endian) PDIR entry */ ++ return pa; + } + + static void +@@ -251,7 +252,8 @@ static int __init + agp_ioc_init(void __iomem *ioc_regs) + { + struct _parisc_agp_info *info = &parisc_agp_info; +- u64 iova_base, *io_pdir, io_tlb_ps; ++ u64 iova_base, io_tlb_ps; ++ __le64 *io_pdir; + int io_tlb_shift; + + printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n"); +diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c +index ee71376f174b70..3bc1d9243dbd05 100644 +--- a/drivers/char/hpet.c ++++ b/drivers/char/hpet.c +@@ -289,8 +289,13 @@ hpet_read(struct file *file, char __user *buf, size_t count, loff_t * ppos) + if (!devp->hd_ireqfreq) + return -EIO; + +- if (count < sizeof(unsigned long)) +- return -EINVAL; ++ if (in_compat_syscall()) { ++ if (count < sizeof(compat_ulong_t)) ++ return -EINVAL; ++ } else { ++ if (count < sizeof(unsigned long)) ++ return -EINVAL; ++ } + + add_wait_queue(&devp->hd_waitqueue, &wait); + +@@ -314,9 +319,16 @@ hpet_read(struct file *file, char __user *buf, size_t count, loff_t * ppos) + schedule(); + } + +- retval = put_user(data, (unsigned long __user *)buf); +- if (!retval) +- retval = sizeof(unsigned long); ++ if (in_compat_syscall()) { ++ retval = put_user(data, (compat_ulong_t __user *)buf); ++ if (!retval) ++ retval = sizeof(compat_ulong_t); ++ } else { ++ retval = put_user(data, (unsigned long __user *)buf); ++ if (!retval) ++ retval = sizeof(unsigned long); ++ } ++ + out: + __set_current_state(TASK_RUNNING); + remove_wait_queue(&devp->hd_waitqueue, &wait); +@@ -671,12 +683,24 @@ struct compat_hpet_info { + unsigned short hi_timer; + }; + ++/* 32-bit types would lead to different command codes which should be ++ * translated into 64-bit ones before passed to hpet_ioctl_common ++ */ ++#define COMPAT_HPET_INFO _IOR('h', 0x03, struct compat_hpet_info) ++#define COMPAT_HPET_IRQFREQ _IOW('h', 0x6, compat_ulong_t) ++ + static long + hpet_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + { + struct hpet_info info; + int err; + ++ if (cmd == COMPAT_HPET_INFO) ++ cmd = HPET_INFO; ++ ++ if (cmd == COMPAT_HPET_IRQFREQ) ++ cmd = HPET_IRQFREQ; ++ + mutex_lock(&hpet_mutex); + err = hpet_ioctl_common(file->private_data, cmd, arg, &info); + mutex_unlock(&hpet_mutex); +diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c +index 86162a13681e67..9a24d19236dc70 100644 +--- a/drivers/char/hw_random/amd-rng.c ++++ b/drivers/char/hw_random/amd-rng.c +@@ -143,8 +143,10 @@ static int __init amd_rng_mod_init(void) + + found: + err = pci_read_config_dword(pdev, 0x58, &pmbase); +- if (err) ++ if (err) { ++ err = pcibios_err_to_errno(err); + goto put_dev; ++ } + + pmbase &= 0x0000FF00; + if (pmbase == 0) { +diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c +index e19b0f9f48b97f..57a80ec93badac 100644 +--- a/drivers/char/hw_random/bcm2835-rng.c ++++ b/drivers/char/hw_random/bcm2835-rng.c +@@ -70,7 +70,7 @@ static int bcm2835_rng_read(struct hwrng *rng, void *buf, size_t max, + while ((rng_readl(priv, RNG_STATUS) >> 24) == 0) { + if (!wait) + return 0; +- hwrng_msleep(rng, 1000); ++ hwrng_yield(rng); + } + + num_words = rng_readl(priv, RNG_STATUS) >> 24; +@@ -94,8 +94,10 @@ static int bcm2835_rng_init(struct hwrng *rng) + return ret; + + ret = reset_control_reset(priv->reset); +- if (ret) ++ if (ret) { ++ clk_disable_unprepare(priv->clk); + return ret; ++ } + + if (priv->mask_interrupts) { + /* mask the interrupt */ +diff --git a/drivers/char/hw_random/cctrng.c b/drivers/char/hw_random/cctrng.c +index 1abbff04a015a5..a55f5f2d35dff7 100644 +--- a/drivers/char/hw_random/cctrng.c ++++ b/drivers/char/hw_random/cctrng.c +@@ -624,6 +624,7 @@ static int __maybe_unused cctrng_resume(struct device *dev) + /* wait for Cryptocell reset completion */ + if (!cctrng_wait_for_reset_completion(drvdata)) { + dev_err(dev, "Cryptocell reset not completed"); ++ clk_disable_unprepare(drvdata->clk); + return -EBUSY; + } + +diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c +index e3598ec9cfca8b..a182fe794f9855 100644 +--- a/drivers/char/hw_random/core.c ++++ b/drivers/char/hw_random/core.c +@@ -23,10 +23,13 @@ + #include + #include + #include ++#include + #include + + #define RNG_MODULE_NAME "hw_random" + ++#define RNG_BUFFER_SIZE (SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES) ++ + static struct hwrng *current_rng; + /* the current rng has been explicitly chosen by user via sysfs */ + static int cur_rng_set_by_user; +@@ -58,7 +61,7 @@ static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, + + static size_t rng_buffer_size(void) + { +- return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES; ++ return RNG_BUFFER_SIZE; + } + + static void add_early_randomness(struct hwrng *rng) +@@ -171,7 +174,6 @@ static int hwrng_init(struct hwrng *rng) + reinit_completion(&rng->cleanup_done); + + skip_init: +- rng->quality = min_t(u16, min_t(u16, default_quality, 1024), rng->quality ?: 1024); + current_quality = rng->quality; /* obsolete */ + + return 0; +@@ -209,6 +211,7 @@ static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, + static ssize_t rng_dev_read(struct file *filp, char __user *buf, + size_t size, loff_t *offp) + { ++ u8 buffer[RNG_BUFFER_SIZE]; + ssize_t ret = 0; + int err = 0; + int bytes_read, len; +@@ -236,34 +239,37 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, + if (bytes_read < 0) { + err = bytes_read; + goto out_unlock_reading; ++ } else if (bytes_read == 0 && ++ (filp->f_flags & O_NONBLOCK)) { ++ err = -EAGAIN; ++ goto out_unlock_reading; + } ++ + data_avail = bytes_read; + } + +- if (!data_avail) { +- if (filp->f_flags & O_NONBLOCK) { +- err = -EAGAIN; +- goto out_unlock_reading; +- } +- } else { +- len = data_avail; ++ len = data_avail; ++ if (len) { + if (len > size) + len = size; + + data_avail -= len; + +- if (copy_to_user(buf + ret, rng_buffer + data_avail, +- len)) { ++ memcpy(buffer, rng_buffer + data_avail, len); ++ } ++ mutex_unlock(&reading_mutex); ++ put_rng(rng); ++ ++ if (len) { ++ if (copy_to_user(buf + ret, buffer, len)) { + err = -EFAULT; +- goto out_unlock_reading; ++ goto out; + } + + size -= len; + ret += len; + } + +- mutex_unlock(&reading_mutex); +- put_rng(rng); + + if (need_resched()) + schedule_timeout_interruptible(1); +@@ -274,6 +280,7 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, + } + } + out: ++ memzero_explicit(buffer, sizeof(buffer)); + return ret ? : err; + + out_unlock_reading: +@@ -555,6 +562,9 @@ int hwrng_register(struct hwrng *rng) + complete(&rng->cleanup_done); + init_completion(&rng->dying); + ++ /* Adjust quality field to always have a proper value */ ++ rng->quality = min_t(u16, min_t(u16, default_quality, 1024), rng->quality ?: 1024); ++ + if (!current_rng || + (!cur_rng_set_by_user && rng->quality > current_rng->quality)) { + /* +@@ -678,6 +688,12 @@ long hwrng_msleep(struct hwrng *rng, unsigned int msecs) + } + EXPORT_SYMBOL_GPL(hwrng_msleep); + ++long hwrng_yield(struct hwrng *rng) ++{ ++ return wait_for_completion_interruptible_timeout(&rng->dying, 1); ++} ++EXPORT_SYMBOL_GPL(hwrng_yield); ++ + static int __init hwrng_modinit(void) + { + int ret; +diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c +index 12fbe809183190..159baf00a86755 100644 +--- a/drivers/char/hw_random/geode-rng.c ++++ b/drivers/char/hw_random/geode-rng.c +@@ -58,7 +58,8 @@ struct amd_geode_priv { + + static int geode_rng_data_read(struct hwrng *rng, u32 *data) + { +- void __iomem *mem = (void __iomem *)rng->priv; ++ struct amd_geode_priv *priv = (struct amd_geode_priv *)rng->priv; ++ void __iomem *mem = priv->membase; + + *data = readl(mem + GEODE_RNG_DATA_REG); + +@@ -67,7 +68,8 @@ static int geode_rng_data_read(struct hwrng *rng, u32 *data) + + static int geode_rng_data_present(struct hwrng *rng, int wait) + { +- void __iomem *mem = (void __iomem *)rng->priv; ++ struct amd_geode_priv *priv = (struct amd_geode_priv *)rng->priv; ++ void __iomem *mem = priv->membase; + int data, i; + + for (i = 0; i < 20; i++) { +diff --git a/drivers/char/hw_random/jh7110-trng.c b/drivers/char/hw_random/jh7110-trng.c +index 38474d48a25e16..b1f94e3c0c6a4a 100644 +--- a/drivers/char/hw_random/jh7110-trng.c ++++ b/drivers/char/hw_random/jh7110-trng.c +@@ -300,7 +300,7 @@ static int starfive_trng_probe(struct platform_device *pdev) + ret = devm_request_irq(&pdev->dev, irq, starfive_trng_irq, 0, pdev->name, + (void *)trng); + if (ret) +- return dev_err_probe(&pdev->dev, irq, ++ return dev_err_probe(&pdev->dev, ret, + "Failed to register interrupt handler\n"); + + trng->hclk = devm_clk_get(&pdev->dev, "hclk"); +diff --git a/drivers/char/hw_random/mtk-rng.c b/drivers/char/hw_random/mtk-rng.c +index aa993753ab120b..1e3048f2bb38f0 100644 +--- a/drivers/char/hw_random/mtk-rng.c ++++ b/drivers/char/hw_random/mtk-rng.c +@@ -142,7 +142,7 @@ static int mtk_rng_probe(struct platform_device *pdev) + dev_set_drvdata(&pdev->dev, priv); + pm_runtime_set_autosuspend_delay(&pdev->dev, RNG_AUTOSUSPEND_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); +- pm_runtime_enable(&pdev->dev); ++ devm_pm_runtime_enable(&pdev->dev); + + dev_info(&pdev->dev, "registered RNG driver\n"); + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index 56346fb328727e..ab4e87a99f0874 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -177,13 +177,15 @@ static ssize_t ssif_bmc_write(struct file *file, const char __user *buf, size_t + unsigned long flags; + ssize_t ret; + +- if (count > sizeof(struct ipmi_ssif_msg)) ++ if (count < sizeof(msg.len) || ++ count > sizeof(struct ipmi_ssif_msg)) + return -EINVAL; + + if (copy_from_user(&msg, buf, count)) + return -EFAULT; + +- if (!msg.len || count < sizeof_field(struct ipmi_ssif_msg, len) + msg.len) ++ if (!msg.len || msg.len > IPMI_SSIF_PAYLOAD_MAX || ++ count < sizeof_field(struct ipmi_ssif_msg, len) + msg.len) + return -EINVAL; + + spin_lock_irqsave(&ssif_bmc->lock, flags); +diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c +index 4c188e9e477cdf..58e9dcc2a30874 100644 +--- a/drivers/char/ppdev.c ++++ b/drivers/char/ppdev.c +@@ -296,28 +296,35 @@ static int register_device(int minor, struct pp_struct *pp) + if (!port) { + pr_warn("%s: no associated port!\n", name); + rc = -ENXIO; +- goto err; ++ goto err_free_name; ++ } ++ ++ index = ida_alloc(&ida_index, GFP_KERNEL); ++ if (index < 0) { ++ pr_warn("%s: failed to get index!\n", name); ++ rc = index; ++ goto err_put_port; + } + +- index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL); + memset(&ppdev_cb, 0, sizeof(ppdev_cb)); + ppdev_cb.irq_func = pp_irq; + ppdev_cb.flags = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0; + ppdev_cb.private = pp; + pdev = parport_register_dev_model(port, name, &ppdev_cb, index); +- parport_put_port(port); + + if (!pdev) { + pr_warn("%s: failed to register device!\n", name); + rc = -ENXIO; +- ida_simple_remove(&ida_index, index); +- goto err; ++ ida_free(&ida_index, index); ++ goto err_put_port; + } + + pp->pdev = pdev; + pp->index = index; + dev_dbg(&pdev->dev, "registered pardevice\n"); +-err: ++err_put_port: ++ parport_put_port(port); ++err_free_name: + kfree(name); + return rc; + } +@@ -750,7 +757,7 @@ static int pp_release(struct inode *inode, struct file *file) + + if (pp->pdev) { + parport_unregister_device(pp->pdev); +- ida_simple_remove(&ida_index, pp->index); ++ ida_free(&ida_index, pp->index); + pp->pdev = NULL; + pr_debug(CHRDEV "%x: unregistered pardevice\n", minor); + } +diff --git a/drivers/char/random.c b/drivers/char/random.c +index 3cb37760dfec23..7b5d4822fa3ae1 100644 +--- a/drivers/char/random.c ++++ b/drivers/char/random.c +@@ -702,7 +702,7 @@ static void extract_entropy(void *buf, size_t len) + + static void __cold _credit_init_bits(size_t bits) + { +- static struct execute_work set_ready; ++ static DECLARE_WORK(set_ready, crng_set_ready); + unsigned int new, orig, add; + unsigned long flags; + +@@ -718,8 +718,8 @@ static void __cold _credit_init_bits(size_t bits) + + if (orig < POOL_READY_BITS && new >= POOL_READY_BITS) { + crng_reseed(NULL); /* Sets crng_init to CRNG_READY under base_crng.lock. */ +- if (static_key_initialized) +- execute_in_process_context(crng_set_ready, &set_ready); ++ if (static_key_initialized && system_unbound_wq) ++ queue_work(system_unbound_wq, &set_ready); + atomic_notifier_call_chain(&random_ready_notifier, 0, NULL); + wake_up_interruptible(&crng_init_wait); + kill_fasync(&fasync, SIGIO, POLL_IN); +@@ -890,8 +890,8 @@ void __init random_init(void) + + /* + * If we were initialized by the cpu or bootloader before jump labels +- * are initialized, then we should enable the static branch here, where +- * it's guaranteed that jump labels have been initialized. ++ * or workqueues are initialized, then we should enable the static ++ * branch here, where it's guaranteed that these have been initialized. + */ + if (!static_branch_likely(&crng_is_ready) && crng_init >= CRNG_READY) + crng_set_ready(NULL); +diff --git a/drivers/char/tpm/eventlog/common.c b/drivers/char/tpm/eventlog/common.c +index 639c3f395a5afc..4c0bbba64ee500 100644 +--- a/drivers/char/tpm/eventlog/common.c ++++ b/drivers/char/tpm/eventlog/common.c +@@ -47,6 +47,8 @@ static int tpm_bios_measurements_open(struct inode *inode, + if (!err) { + seq = file->private_data; + seq->private = chip; ++ } else { ++ put_device(&chip->dev); + } + + return err; +diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c +index 30b4c288c1bbc3..c3fbbf4d3db79a 100644 +--- a/drivers/char/tpm/tpm-dev-common.c ++++ b/drivers/char/tpm/tpm-dev-common.c +@@ -47,6 +47,8 @@ static ssize_t tpm_dev_transmit(struct tpm_chip *chip, struct tpm_space *space, + + if (!ret) + ret = tpm2_commit_space(chip, space, buf, &len); ++ else ++ tpm2_flush_space(chip); + + out_rc: + return ret ? ret : len; +diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c +index 363afdd4d1d306..d4d1007fe8117e 100644 +--- a/drivers/char/tpm/tpm2-space.c ++++ b/drivers/char/tpm/tpm2-space.c +@@ -166,6 +166,9 @@ void tpm2_flush_space(struct tpm_chip *chip) + struct tpm_space *space = &chip->work_space; + int i; + ++ if (!space) ++ return; ++ + for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) + if (space->context_tbl[i] && ~space->context_tbl[i]) + tpm2_flush_context(chip, space->context_tbl[i]); +diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c +index 1b350412d8a6be..f6aa0dfadb93ee 100644 +--- a/drivers/char/tpm/tpm_tis_core.c ++++ b/drivers/char/tpm/tpm_tis_core.c +@@ -919,8 +919,6 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask, + int rc; + u32 int_status; + +- INIT_WORK(&priv->free_irq_work, tpm_tis_free_irq_func); +- + rc = devm_request_threaded_irq(chip->dev.parent, irq, NULL, + tis_int_handler, IRQF_ONESHOT | flags, + dev_name(&chip->dev), chip); +@@ -1022,7 +1020,8 @@ void tpm_tis_remove(struct tpm_chip *chip) + interrupt = 0; + + tpm_tis_write32(priv, reg, ~TPM_GLOBAL_INT_ENABLE & interrupt); +- flush_work(&priv->free_irq_work); ++ if (priv->free_irq_work.func) ++ flush_work(&priv->free_irq_work); + + tpm_tis_clkrun_enable(chip, false); + +@@ -1132,6 +1131,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, + priv->phy_ops = phy_ops; + priv->locality_count = 0; + mutex_init(&priv->locality_count_mutex); ++ INIT_WORK(&priv->free_irq_work, tpm_tis_free_irq_func); + + dev_set_drvdata(&chip->dev, priv); + +diff --git a/drivers/char/tpm/tpm_tis_spi_main.c b/drivers/char/tpm/tpm_tis_spi_main.c +index c5c3197ee29f04..4bdad9e3667fa5 100644 +--- a/drivers/char/tpm/tpm_tis_spi_main.c ++++ b/drivers/char/tpm/tpm_tis_spi_main.c +@@ -37,6 +37,7 @@ + #include "tpm_tis_spi.h" + + #define MAX_SPI_FRAMESIZE 64 ++#define SPI_HDRSIZE 4 + + /* + * TCG SPI flow control is documented in section 6.4 of the spec[1]. In short, +@@ -247,7 +248,7 @@ static int tpm_tis_spi_write_bytes(struct tpm_tis_data *data, u32 addr, + int tpm_tis_spi_init(struct spi_device *spi, struct tpm_tis_spi_phy *phy, + int irq, const struct tpm_tis_phy_ops *phy_ops) + { +- phy->iobuf = devm_kmalloc(&spi->dev, MAX_SPI_FRAMESIZE, GFP_KERNEL); ++ phy->iobuf = devm_kmalloc(&spi->dev, SPI_HDRSIZE + MAX_SPI_FRAMESIZE, GFP_KERNEL); + if (!phy->iobuf) + return -ENOMEM; + +diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c +index 680d1ef2a21794..796ab9a4e48fa1 100644 +--- a/drivers/char/virtio_console.c ++++ b/drivers/char/virtio_console.c +@@ -2052,25 +2052,27 @@ static int virtcons_probe(struct virtio_device *vdev) + multiport = true; + } + +- err = init_vqs(portdev); +- if (err < 0) { +- dev_err(&vdev->dev, "Error %d initializing vqs\n", err); +- goto free_chrdev; +- } +- + spin_lock_init(&portdev->ports_lock); + INIT_LIST_HEAD(&portdev->ports); + INIT_LIST_HEAD(&portdev->list); + +- virtio_device_ready(portdev->vdev); +- + INIT_WORK(&portdev->config_work, &config_work_handler); + INIT_WORK(&portdev->control_work, &control_work_handler); + + if (multiport) { + spin_lock_init(&portdev->c_ivq_lock); + spin_lock_init(&portdev->c_ovq_lock); ++ } + ++ err = init_vqs(portdev); ++ if (err < 0) { ++ dev_err(&vdev->dev, "Error %d initializing vqs\n", err); ++ goto free_chrdev; ++ } ++ ++ virtio_device_ready(portdev->vdev); ++ ++ if (multiport) { + err = fill_queue(portdev->c_ivq, &portdev->c_ivq_lock); + if (err < 0) { + dev_err(&vdev->dev, +diff --git a/drivers/char/xillybus/xillyusb.c b/drivers/char/xillybus/xillyusb.c +index 5a5afa14ca8cb8..45771b1a3716a2 100644 +--- a/drivers/char/xillybus/xillyusb.c ++++ b/drivers/char/xillybus/xillyusb.c +@@ -50,6 +50,7 @@ MODULE_LICENSE("GPL v2"); + static const char xillyname[] = "xillyusb"; + + static unsigned int fifo_buf_order; ++static struct workqueue_struct *wakeup_wq; + + #define USB_VENDOR_ID_XILINX 0x03fd + #define USB_VENDOR_ID_ALTERA 0x09fb +@@ -569,10 +570,6 @@ static void cleanup_dev(struct kref *kref) + * errors if executed. The mechanism relies on that xdev->error is assigned + * a non-zero value by report_io_error() prior to queueing wakeup_all(), + * which prevents bulk_in_work() from calling process_bulk_in(). +- * +- * The fact that wakeup_all() and bulk_in_work() are queued on the same +- * workqueue makes their concurrent execution very unlikely, however the +- * kernel's API doesn't seem to ensure this strictly. + */ + + static void wakeup_all(struct work_struct *work) +@@ -627,7 +624,7 @@ static void report_io_error(struct xillyusb_dev *xdev, + + if (do_once) { + kref_get(&xdev->kref); /* xdev is used by work item */ +- queue_work(xdev->workq, &xdev->wakeup_workitem); ++ queue_work(wakeup_wq, &xdev->wakeup_workitem); + } + } + +@@ -1906,6 +1903,13 @@ static const struct file_operations xillyusb_fops = { + + static int xillyusb_setup_base_eps(struct xillyusb_dev *xdev) + { ++ struct usb_device *udev = xdev->udev; ++ ++ /* Verify that device has the two fundamental bulk in/out endpoints */ ++ if (usb_pipe_type_check(udev, usb_sndbulkpipe(udev, MSG_EP_NUM)) || ++ usb_pipe_type_check(udev, usb_rcvbulkpipe(udev, IN_EP_NUM))) ++ return -ENODEV; ++ + xdev->msg_ep = endpoint_alloc(xdev, MSG_EP_NUM | USB_DIR_OUT, + bulk_out_work, 1, 2); + if (!xdev->msg_ep) +@@ -1935,14 +1939,15 @@ static int setup_channels(struct xillyusb_dev *xdev, + __le16 *chandesc, + int num_channels) + { +- struct xillyusb_channel *chan; ++ struct usb_device *udev = xdev->udev; ++ struct xillyusb_channel *chan, *new_channels; + int i; + + chan = kcalloc(num_channels, sizeof(*chan), GFP_KERNEL); + if (!chan) + return -ENOMEM; + +- xdev->channels = chan; ++ new_channels = chan; + + for (i = 0; i < num_channels; i++, chan++) { + unsigned int in_desc = le16_to_cpu(*chandesc++); +@@ -1971,6 +1976,15 @@ static int setup_channels(struct xillyusb_dev *xdev, + */ + + if ((out_desc & 0x80) && i < 14) { /* Entry is valid */ ++ if (usb_pipe_type_check(udev, ++ usb_sndbulkpipe(udev, i + 2))) { ++ dev_err(xdev->dev, ++ "Missing BULK OUT endpoint %d\n", ++ i + 2); ++ kfree(new_channels); ++ return -ENODEV; ++ } ++ + chan->writable = 1; + chan->out_synchronous = !!(out_desc & 0x40); + chan->out_seekable = !!(out_desc & 0x20); +@@ -1980,6 +1994,7 @@ static int setup_channels(struct xillyusb_dev *xdev, + } + } + ++ xdev->channels = new_channels; + return 0; + } + +@@ -2096,9 +2111,11 @@ static int xillyusb_discovery(struct usb_interface *interface) + * just after responding with the IDT, there is no reason for any + * work item to be running now. To be sure that xdev->channels + * is updated on anything that might run in parallel, flush the +- * workqueue, which rarely does anything. ++ * device's workqueue and the wakeup work item. This rarely ++ * does anything. + */ + flush_workqueue(xdev->workq); ++ flush_work(&xdev->wakeup_workitem); + + xdev->num_channels = num_channels; + +@@ -2258,6 +2275,10 @@ static int __init xillyusb_init(void) + { + int rc = 0; + ++ wakeup_wq = alloc_workqueue(xillyname, 0, 0); ++ if (!wakeup_wq) ++ return -ENOMEM; ++ + if (LOG2_INITIAL_FIFO_BUF_SIZE > PAGE_SHIFT) + fifo_buf_order = LOG2_INITIAL_FIFO_BUF_SIZE - PAGE_SHIFT; + else +@@ -2265,12 +2286,17 @@ static int __init xillyusb_init(void) + + rc = usb_register(&xillyusb_driver); + ++ if (rc) ++ destroy_workqueue(wakeup_wq); ++ + return rc; + } + + static void __exit xillyusb_exit(void) + { + usb_deregister(&xillyusb_driver); ++ ++ destroy_workqueue(wakeup_wq); + } + + module_init(xillyusb_init); +diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c +index 91b5c6f1481964..4e9594714b1428 100644 +--- a/drivers/clk/at91/sama7g5.c ++++ b/drivers/clk/at91/sama7g5.c +@@ -66,6 +66,7 @@ enum pll_component_id { + PLL_COMPID_FRAC, + PLL_COMPID_DIV0, + PLL_COMPID_DIV1, ++ PLL_COMPID_MAX, + }; + + /* +@@ -165,7 +166,7 @@ static struct sama7g5_pll { + u8 t; + u8 eid; + u8 safe_div; +-} sama7g5_plls[][PLL_ID_MAX] = { ++} sama7g5_plls[][PLL_COMPID_MAX] = { + [PLL_ID_CPU] = { + [PLL_COMPID_FRAC] = { + .n = "cpupll_fracck", +@@ -1038,7 +1039,7 @@ static void __init sama7g5_pmc_setup(struct device_node *np) + sama7g5_pmc->chws[PMC_MAIN] = hw; + + for (i = 0; i < PLL_ID_MAX; i++) { +- for (j = 0; j < 3; j++) { ++ for (j = 0; j < PLL_COMPID_MAX; j++) { + struct clk_hw *parent_hw; + + if (!sama7g5_plls[i][j].n) +diff --git a/drivers/clk/bcm/clk-bcm2711-dvp.c b/drivers/clk/bcm/clk-bcm2711-dvp.c +index e4fbbf3c40fe2b..3cb235df9d379f 100644 +--- a/drivers/clk/bcm/clk-bcm2711-dvp.c ++++ b/drivers/clk/bcm/clk-bcm2711-dvp.c +@@ -56,6 +56,8 @@ static int clk_dvp_probe(struct platform_device *pdev) + if (ret) + return ret; + ++ data->num = NR_CLOCKS; ++ + data->hws[0] = clk_hw_register_gate_parent_data(&pdev->dev, + "hdmi0-108MHz", + &clk_dvp_parent, 0, +@@ -76,7 +78,6 @@ static int clk_dvp_probe(struct platform_device *pdev) + goto unregister_clk0; + } + +- data->num = NR_CLOCKS; + ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get, + data); + if (ret) +diff --git a/drivers/clk/bcm/clk-bcm53573-ilp.c b/drivers/clk/bcm/clk-bcm53573-ilp.c +index 84f2af736ee8a6..83ef41d618be37 100644 +--- a/drivers/clk/bcm/clk-bcm53573-ilp.c ++++ b/drivers/clk/bcm/clk-bcm53573-ilp.c +@@ -112,7 +112,7 @@ static void bcm53573_ilp_init(struct device_node *np) + goto err_free_ilp; + } + +- ilp->regmap = syscon_node_to_regmap(of_get_parent(np)); ++ ilp->regmap = syscon_node_to_regmap(np->parent); + if (IS_ERR(ilp->regmap)) { + err = PTR_ERR(ilp->regmap); + goto err_free_ilp; +diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c +index 829406dc44a202..4d411408e4afef 100644 +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -371,8 +371,8 @@ static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi, + if (IS_ERR(hw)) + return PTR_ERR(hw); + +- data->hws[clks->id] = hw; + data->num = clks->id + 1; ++ data->hws[clks->id] = hw; + } + + clks++; +diff --git a/drivers/clk/clk-en7523.c b/drivers/clk/clk-en7523.c +index 7cde328495e2b6..7914e60f3d6c56 100644 +--- a/drivers/clk/clk-en7523.c ++++ b/drivers/clk/clk-en7523.c +@@ -40,6 +40,7 @@ struct en_clk_desc { + u8 div_shift; + u16 div_val0; + u8 div_step; ++ u8 div_offset; + }; + + struct en_clk_gate { +@@ -67,6 +68,7 @@ static const struct en_clk_desc en7523_base_clks[] = { + .div_bits = 3, + .div_shift = 0, + .div_step = 1, ++ .div_offset = 1, + }, { + .id = EN7523_CLK_EMI, + .name = "emi", +@@ -80,6 +82,7 @@ static const struct en_clk_desc en7523_base_clks[] = { + .div_bits = 3, + .div_shift = 0, + .div_step = 1, ++ .div_offset = 1, + }, { + .id = EN7523_CLK_BUS, + .name = "bus", +@@ -93,6 +96,7 @@ static const struct en_clk_desc en7523_base_clks[] = { + .div_bits = 3, + .div_shift = 0, + .div_step = 1, ++ .div_offset = 1, + }, { + .id = EN7523_CLK_SLIC, + .name = "slic", +@@ -133,13 +137,14 @@ static const struct en_clk_desc en7523_base_clks[] = { + .div_bits = 3, + .div_shift = 0, + .div_step = 1, ++ .div_offset = 1, + }, { + .id = EN7523_CLK_CRYPTO, + .name = "crypto", + + .base_reg = REG_CRYPTO_CLKSRC, + .base_bits = 1, +- .base_shift = 8, ++ .base_shift = 0, + .base_values = emi_base, + .n_base_values = ARRAY_SIZE(emi_base), + } +@@ -184,7 +189,7 @@ static u32 en7523_get_div(void __iomem *base, int i) + if (!val && desc->div_val0) + return desc->div_val0; + +- return (val + 1) * desc->div_step; ++ return (val + desc->div_offset) * desc->div_step; + } + + static int en7523_pci_is_enabled(struct clk_hw *hw) +diff --git a/drivers/clk/clk-npcm7xx.c b/drivers/clk/clk-npcm7xx.c +index e319cfa51a8a3f..030186def9c69a 100644 +--- a/drivers/clk/clk-npcm7xx.c ++++ b/drivers/clk/clk-npcm7xx.c +@@ -510,7 +510,7 @@ static void __init npcm7xx_clk_init(struct device_node *clk_np) + return; + + npcm7xx_init_fail: +- kfree(npcm7xx_clk_data->hws); ++ kfree(npcm7xx_clk_data); + npcm7xx_init_np_err: + iounmap(clk_base); + npcm7xx_init_error: +diff --git a/drivers/clk/clk-renesas-pcie.c b/drivers/clk/clk-renesas-pcie.c +index 7d7b2cb7531804..b00c38469cfadb 100644 +--- a/drivers/clk/clk-renesas-pcie.c ++++ b/drivers/clk/clk-renesas-pcie.c +@@ -24,10 +24,12 @@ + #define RS9_REG_SS_AMP_0V7 0x1 + #define RS9_REG_SS_AMP_0V8 0x2 + #define RS9_REG_SS_AMP_0V9 0x3 ++#define RS9_REG_SS_AMP_DEFAULT RS9_REG_SS_AMP_0V8 + #define RS9_REG_SS_AMP_MASK 0x3 + #define RS9_REG_SS_SSC_100 0 + #define RS9_REG_SS_SSC_M025 (1 << 3) + #define RS9_REG_SS_SSC_M050 (3 << 3) ++#define RS9_REG_SS_SSC_DEFAULT RS9_REG_SS_SSC_100 + #define RS9_REG_SS_SSC_MASK (3 << 3) + #define RS9_REG_SS_SSC_LOCK BIT(5) + #define RS9_REG_SR 0x2 +@@ -163,7 +165,7 @@ static u8 rs9_calc_dif(const struct rs9_driver_data *rs9, int idx) + enum rs9_model model = rs9->chip_info->model; + + if (model == RENESAS_9FGV0241) +- return BIT(idx) + 1; ++ return BIT(idx + 1); + else if (model == RENESAS_9FGV0441) + return BIT(idx); + +@@ -211,8 +213,8 @@ static int rs9_get_common_config(struct rs9_driver_data *rs9) + int ret; + + /* Set defaults */ +- rs9->pll_amplitude = RS9_REG_SS_AMP_0V7; +- rs9->pll_ssc = RS9_REG_SS_SSC_100; ++ rs9->pll_amplitude = RS9_REG_SS_AMP_DEFAULT; ++ rs9->pll_ssc = RS9_REG_SS_SSC_DEFAULT; + + /* Output clock amplitude */ + ret = of_property_read_u32(np, "renesas,out-amplitude-microvolt", +@@ -253,13 +255,13 @@ static void rs9_update_config(struct rs9_driver_data *rs9) + int i; + + /* If amplitude is non-default, update it. */ +- if (rs9->pll_amplitude != RS9_REG_SS_AMP_0V7) { ++ if (rs9->pll_amplitude != RS9_REG_SS_AMP_DEFAULT) { + regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_AMP_MASK, + rs9->pll_amplitude); + } + + /* If SSC is non-default, update it. */ +- if (rs9->pll_ssc != RS9_REG_SS_SSC_100) { ++ if (rs9->pll_ssc != RS9_REG_SS_SSC_DEFAULT) { + regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_SSC_MASK, + rs9->pll_ssc); + } +diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c +index 2c7a830ce3080f..fdec715c9ba9b3 100644 +--- a/drivers/clk/clk-scmi.c ++++ b/drivers/clk/clk-scmi.c +@@ -213,6 +213,7 @@ static int scmi_clocks_probe(struct scmi_device *sdev) + sclk->info = scmi_proto_clk_ops->info_get(ph, idx); + if (!sclk->info) { + dev_dbg(dev, "invalid clock info for idx %d\n", idx); ++ devm_kfree(dev, sclk); + continue; + } + +diff --git a/drivers/clk/clk-si521xx.c b/drivers/clk/clk-si521xx.c +index ef4ba467e747bc..5886bc54aa0e78 100644 +--- a/drivers/clk/clk-si521xx.c ++++ b/drivers/clk/clk-si521xx.c +@@ -282,7 +282,7 @@ static int si521xx_probe(struct i2c_client *client) + const u16 chip_info = (u16)(uintptr_t)device_get_match_data(&client->dev); + const struct clk_parent_data clk_parent_data = { .index = 0 }; + const u8 data[3] = { SI521XX_REG_BC, 1, 1 }; +- unsigned char name[6] = "DIFF0"; ++ unsigned char name[16] = "DIFF0"; + struct clk_init_data init = {}; + struct si521xx *si; + int i, ret; +@@ -316,7 +316,7 @@ static int si521xx_probe(struct i2c_client *client) + /* Register clock */ + for (i = 0; i < hweight16(chip_info); i++) { + memset(&init, 0, sizeof(init)); +- snprintf(name, 6, "DIFF%d", i); ++ snprintf(name, sizeof(name), "DIFF%d", i); + init.name = name; + init.ops = &si521xx_diff_clk_ops; + init.parent_data = &clk_parent_data; +diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c +index 9599857842c72c..2920fe2e5e8bef 100644 +--- a/drivers/clk/clk-si5341.c ++++ b/drivers/clk/clk-si5341.c +@@ -895,10 +895,8 @@ static int si5341_output_clk_set_rate(struct clk_hw *hw, unsigned long rate, + r[0] = r_div ? (r_div & 0xff) : 1; + r[1] = (r_div >> 8) & 0xff; + r[2] = (r_div >> 16) & 0xff; +- err = regmap_bulk_write(output->data->regmap, ++ return regmap_bulk_write(output->data->regmap, + SI5341_OUT_R_REG(output), r, 3); +- +- return 0; + } + + static int si5341_output_reparent(struct clk_si5341_output *output, u8 index) +diff --git a/drivers/clk/clk-sp7021.c b/drivers/clk/clk-sp7021.c +index 01d3c4c7b0b23f..7cb7d501d7a6eb 100644 +--- a/drivers/clk/clk-sp7021.c ++++ b/drivers/clk/clk-sp7021.c +@@ -604,14 +604,14 @@ static int sp7021_clk_probe(struct platform_device *pdev) + int i; + + clk_base = devm_platform_ioremap_resource(pdev, 0); +- if (!clk_base) +- return -ENXIO; ++ if (IS_ERR(clk_base)) ++ return PTR_ERR(clk_base); + pll_base = devm_platform_ioremap_resource(pdev, 1); +- if (!pll_base) +- return -ENXIO; ++ if (IS_ERR(pll_base)) ++ return PTR_ERR(pll_base); + sys_base = devm_platform_ioremap_resource(pdev, 2); +- if (!sys_base) +- return -ENXIO; ++ if (IS_ERR(sys_base)) ++ return PTR_ERR(sys_base); + + /* enable default clks */ + for (i = 0; i < ARRAY_SIZE(sp_clken); i++) +diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c +index 473563bc74960f..f8776065ad1f19 100644 +--- a/drivers/clk/clk.c ++++ b/drivers/clk/clk.c +@@ -37,6 +37,10 @@ static HLIST_HEAD(clk_root_list); + static HLIST_HEAD(clk_orphan_list); + static LIST_HEAD(clk_notifier_list); + ++/* List of registered clks that use runtime PM */ ++static HLIST_HEAD(clk_rpm_list); ++static DEFINE_MUTEX(clk_rpm_list_lock); ++ + static const struct hlist_head *all_lists[] = { + &clk_root_list, + &clk_orphan_list, +@@ -59,6 +63,7 @@ struct clk_core { + struct clk_hw *hw; + struct module *owner; + struct device *dev; ++ struct hlist_node rpm_node; + struct device_node *of_node; + struct clk_core *parent; + struct clk_parent_map *parents; +@@ -122,6 +127,89 @@ static void clk_pm_runtime_put(struct clk_core *core) + pm_runtime_put_sync(core->dev); + } + ++/** ++ * clk_pm_runtime_get_all() - Runtime "get" all clk provider devices ++ * ++ * Call clk_pm_runtime_get() on all runtime PM enabled clks in the clk tree so ++ * that disabling unused clks avoids a deadlock where a device is runtime PM ++ * resuming/suspending and the runtime PM callback is trying to grab the ++ * prepare_lock for something like clk_prepare_enable() while ++ * clk_disable_unused_subtree() holds the prepare_lock and is trying to runtime ++ * PM resume/suspend the device as well. ++ * ++ * Context: Acquires the 'clk_rpm_list_lock' and returns with the lock held on ++ * success. Otherwise the lock is released on failure. ++ * ++ * Return: 0 on success, negative errno otherwise. ++ */ ++static int clk_pm_runtime_get_all(void) ++{ ++ int ret; ++ struct clk_core *core, *failed; ++ ++ /* ++ * Grab the list lock to prevent any new clks from being registered ++ * or unregistered until clk_pm_runtime_put_all(). ++ */ ++ mutex_lock(&clk_rpm_list_lock); ++ ++ /* ++ * Runtime PM "get" all the devices that are needed for the clks ++ * currently registered. Do this without holding the prepare_lock, to ++ * avoid the deadlock. ++ */ ++ hlist_for_each_entry(core, &clk_rpm_list, rpm_node) { ++ ret = clk_pm_runtime_get(core); ++ if (ret) { ++ failed = core; ++ pr_err("clk: Failed to runtime PM get '%s' for clk '%s'\n", ++ dev_name(failed->dev), failed->name); ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ hlist_for_each_entry(core, &clk_rpm_list, rpm_node) { ++ if (core == failed) ++ break; ++ ++ clk_pm_runtime_put(core); ++ } ++ mutex_unlock(&clk_rpm_list_lock); ++ ++ return ret; ++} ++ ++/** ++ * clk_pm_runtime_put_all() - Runtime "put" all clk provider devices ++ * ++ * Put the runtime PM references taken in clk_pm_runtime_get_all() and release ++ * the 'clk_rpm_list_lock'. ++ */ ++static void clk_pm_runtime_put_all(void) ++{ ++ struct clk_core *core; ++ ++ hlist_for_each_entry(core, &clk_rpm_list, rpm_node) ++ clk_pm_runtime_put(core); ++ mutex_unlock(&clk_rpm_list_lock); ++} ++ ++static void clk_pm_runtime_init(struct clk_core *core) ++{ ++ struct device *dev = core->dev; ++ ++ if (dev && pm_runtime_enabled(dev)) { ++ core->rpm_enabled = true; ++ ++ mutex_lock(&clk_rpm_list_lock); ++ hlist_add_head(&core->rpm_node, &clk_rpm_list); ++ mutex_unlock(&clk_rpm_list_lock); ++ } ++} ++ + /*** locking ***/ + static void clk_prepare_lock(void) + { +@@ -418,6 +506,9 @@ static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index) + if (IS_ERR(hw)) + return ERR_CAST(hw); + ++ if (!hw) ++ return NULL; ++ + return hw->core; + } + +@@ -1359,9 +1450,6 @@ static void __init clk_unprepare_unused_subtree(struct clk_core *core) + if (core->flags & CLK_IGNORE_UNUSED) + return; + +- if (clk_pm_runtime_get(core)) +- return; +- + if (clk_core_is_prepared(core)) { + trace_clk_unprepare(core); + if (core->ops->unprepare_unused) +@@ -1370,8 +1458,6 @@ static void __init clk_unprepare_unused_subtree(struct clk_core *core) + core->ops->unprepare(core->hw); + trace_clk_unprepare_complete(core); + } +- +- clk_pm_runtime_put(core); + } + + static void __init clk_disable_unused_subtree(struct clk_core *core) +@@ -1387,9 +1473,6 @@ static void __init clk_disable_unused_subtree(struct clk_core *core) + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_prepare_enable(core->parent); + +- if (clk_pm_runtime_get(core)) +- goto unprepare_out; +- + flags = clk_enable_lock(); + + if (core->enable_count) +@@ -1414,8 +1497,6 @@ static void __init clk_disable_unused_subtree(struct clk_core *core) + + unlock_out: + clk_enable_unlock(flags); +- clk_pm_runtime_put(core); +-unprepare_out: + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_disable_unprepare(core->parent); + } +@@ -1431,6 +1512,7 @@ __setup("clk_ignore_unused", clk_ignore_unused_setup); + static int __init clk_disable_unused(void) + { + struct clk_core *core; ++ int ret; + + if (clk_ignore_unused) { + pr_warn("clk: Not disabling unused clocks\n"); +@@ -1439,6 +1521,13 @@ static int __init clk_disable_unused(void) + + pr_info("clk: Disabling unused clocks\n"); + ++ ret = clk_pm_runtime_get_all(); ++ if (ret) ++ return ret; ++ /* ++ * Grab the prepare lock to keep the clk topology stable while iterating ++ * over clks. ++ */ + clk_prepare_lock(); + + hlist_for_each_entry(core, &clk_root_list, child_node) +@@ -1455,6 +1544,8 @@ static int __init clk_disable_unused(void) + + clk_prepare_unlock(); + ++ clk_pm_runtime_put_all(); ++ + return 0; + } + late_initcall_sync(clk_disable_unused); +@@ -3188,28 +3279,41 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c, + int level) + { + int phase; ++ struct clk *clk_user; ++ int multi_node = 0; + +- seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu ", ++ seq_printf(s, "%*s%-*s %-7d %-8d %-8d %-11lu %-10lu ", + level * 3 + 1, "", +- 30 - level * 3, c->name, ++ 35 - level * 3, c->name, + c->enable_count, c->prepare_count, c->protect_count, + clk_core_get_rate_recalc(c), + clk_core_get_accuracy_recalc(c)); + + phase = clk_core_get_phase(c); + if (phase >= 0) +- seq_printf(s, "%5d", phase); ++ seq_printf(s, "%-5d", phase); + else + seq_puts(s, "-----"); + +- seq_printf(s, " %6d", clk_core_get_scaled_duty_cycle(c, 100000)); ++ seq_printf(s, " %-6d", clk_core_get_scaled_duty_cycle(c, 100000)); + + if (c->ops->is_enabled) +- seq_printf(s, " %9c\n", clk_core_is_enabled(c) ? 'Y' : 'N'); ++ seq_printf(s, " %5c ", clk_core_is_enabled(c) ? 'Y' : 'N'); + else if (!c->ops->enable) +- seq_printf(s, " %9c\n", 'Y'); ++ seq_printf(s, " %5c ", 'Y'); + else +- seq_printf(s, " %9c\n", '?'); ++ seq_printf(s, " %5c ", '?'); ++ ++ hlist_for_each_entry(clk_user, &c->clks, clks_node) { ++ seq_printf(s, "%*s%-*s %-25s\n", ++ level * 3 + 2 + 105 * multi_node, "", ++ 30, ++ clk_user->dev_id ? clk_user->dev_id : "deviceless", ++ clk_user->con_id ? clk_user->con_id : "no_connection_id"); ++ ++ multi_node = 1; ++ } ++ + } + + static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c, +@@ -3217,9 +3321,7 @@ static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c, + { + struct clk_core *child; + +- clk_pm_runtime_get(c); + clk_summary_show_one(s, c, level); +- clk_pm_runtime_put(c); + + hlist_for_each_entry(child, &c->children, child_node) + clk_summary_show_subtree(s, child, level + 1); +@@ -3229,10 +3331,15 @@ static int clk_summary_show(struct seq_file *s, void *data) + { + struct clk_core *c; + struct hlist_head **lists = s->private; ++ int ret; + +- seq_puts(s, " enable prepare protect duty hardware\n"); +- seq_puts(s, " clock count count count rate accuracy phase cycle enable\n"); +- seq_puts(s, "-------------------------------------------------------------------------------------------------------\n"); ++ seq_puts(s, " enable prepare protect duty hardware connection\n"); ++ seq_puts(s, " clock count count count rate accuracy phase cycle enable consumer id\n"); ++ seq_puts(s, "---------------------------------------------------------------------------------------------------------------------------------------------\n"); ++ ++ ret = clk_pm_runtime_get_all(); ++ if (ret) ++ return ret; + + clk_prepare_lock(); + +@@ -3241,6 +3348,7 @@ static int clk_summary_show(struct seq_file *s, void *data) + clk_summary_show_subtree(s, c, 0); + + clk_prepare_unlock(); ++ clk_pm_runtime_put_all(); + + return 0; + } +@@ -3288,8 +3396,14 @@ static int clk_dump_show(struct seq_file *s, void *data) + struct clk_core *c; + bool first_node = true; + struct hlist_head **lists = s->private; ++ int ret; ++ ++ ret = clk_pm_runtime_get_all(); ++ if (ret) ++ return ret; + + seq_putc(s, '{'); ++ + clk_prepare_lock(); + + for (; *lists; lists++) { +@@ -3302,6 +3416,7 @@ static int clk_dump_show(struct seq_file *s, void *data) + } + + clk_prepare_unlock(); ++ clk_pm_runtime_put_all(); + + seq_puts(s, "}\n"); + return 0; +@@ -3916,8 +4031,6 @@ static int __clk_core_init(struct clk_core *core) + } + + clk_core_reparent_orphans_nolock(); +- +- kref_init(&core->ref); + out: + clk_pm_runtime_put(core); + unlock: +@@ -4146,6 +4259,22 @@ static void clk_core_free_parent_map(struct clk_core *core) + kfree(core->parents); + } + ++/* Free memory allocated for a struct clk_core */ ++static void __clk_release(struct kref *ref) ++{ ++ struct clk_core *core = container_of(ref, struct clk_core, ref); ++ ++ if (core->rpm_enabled) { ++ mutex_lock(&clk_rpm_list_lock); ++ hlist_del(&core->rpm_node); ++ mutex_unlock(&clk_rpm_list_lock); ++ } ++ ++ clk_core_free_parent_map(core); ++ kfree_const(core->name); ++ kfree(core); ++} ++ + static struct clk * + __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw) + { +@@ -4166,6 +4295,8 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw) + goto fail_out; + } + ++ kref_init(&core->ref); ++ + core->name = kstrdup_const(init->name, GFP_KERNEL); + if (!core->name) { + ret = -ENOMEM; +@@ -4178,9 +4309,8 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw) + } + core->ops = init->ops; + +- if (dev && pm_runtime_enabled(dev)) +- core->rpm_enabled = true; + core->dev = dev; ++ clk_pm_runtime_init(core); + core->of_node = np; + if (dev && dev->driver) + core->owner = dev->driver->owner; +@@ -4220,12 +4350,10 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw) + hw->clk = NULL; + + fail_create_clk: +- clk_core_free_parent_map(core); + fail_parents: + fail_ops: +- kfree_const(core->name); + fail_name: +- kfree(core); ++ kref_put(&core->ref, __clk_release); + fail_out: + return ERR_PTR(ret); + } +@@ -4305,18 +4433,6 @@ int of_clk_hw_register(struct device_node *node, struct clk_hw *hw) + } + EXPORT_SYMBOL_GPL(of_clk_hw_register); + +-/* Free memory allocated for a clock. */ +-static void __clk_release(struct kref *ref) +-{ +- struct clk_core *core = container_of(ref, struct clk_core, ref); +- +- lockdep_assert_held(&prepare_lock); +- +- clk_core_free_parent_map(core); +- kfree_const(core->name); +- kfree(core); +-} +- + /* + * Empty clk_ops for unregistered clocks. These are used temporarily + * after clk_unregister() was called on a clock and until last clock +@@ -4407,7 +4523,8 @@ void clk_unregister(struct clk *clk) + if (ops == &clk_nodrv_ops) { + pr_err("%s: unregistered clock: %s\n", __func__, + clk->core->name); +- goto unlock; ++ clk_prepare_unlock(); ++ return; + } + /* + * Assign empty clock ops for consumers that might still hold +@@ -4441,11 +4558,10 @@ void clk_unregister(struct clk *clk) + if (clk->core->protect_count) + pr_warn("%s: unregistering protected clock: %s\n", + __func__, clk->core->name); ++ clk_prepare_unlock(); + + kref_put(&clk->core->ref, __clk_release); + free_clk(clk); +-unlock: +- clk_prepare_unlock(); + } + EXPORT_SYMBOL_GPL(clk_unregister); + +@@ -4604,13 +4720,11 @@ void __clk_put(struct clk *clk) + if (clk->min_rate > 0 || clk->max_rate < ULONG_MAX) + clk_set_rate_range_nolock(clk, 0, ULONG_MAX); + +- owner = clk->core->owner; +- kref_put(&clk->core->ref, __clk_release); +- + clk_prepare_unlock(); + ++ owner = clk->core->owner; ++ kref_put(&clk->core->ref, __clk_release); + module_put(owner); +- + free_clk(clk); + } + +diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c +index ee37d0be6877db..9cd80522ca2d77 100644 +--- a/drivers/clk/clkdev.c ++++ b/drivers/clk/clkdev.c +@@ -144,7 +144,7 @@ void clkdev_add_table(struct clk_lookup *cl, size_t num) + mutex_unlock(&clocks_mutex); + } + +-#define MAX_DEV_ID 20 ++#define MAX_DEV_ID 24 + #define MAX_CON_ID 16 + + struct clk_lookup_alloc { +diff --git a/drivers/clk/davinci/da8xx-cfgchip.c b/drivers/clk/davinci/da8xx-cfgchip.c +index e5b2cdfe88ce18..dff7ca35536cc1 100644 +--- a/drivers/clk/davinci/da8xx-cfgchip.c ++++ b/drivers/clk/davinci/da8xx-cfgchip.c +@@ -508,7 +508,7 @@ da8xx_cfgchip_register_usb0_clk48(struct device *dev, + const char * const parent_names[] = { "usb_refclkin", "pll0_auxclk" }; + struct clk *fck_clk; + struct da8xx_usb0_clk48 *usb0; +- struct clk_init_data init; ++ struct clk_init_data init = {}; + int ret; + + fck_clk = devm_clk_get(dev, "fck"); +@@ -583,7 +583,7 @@ da8xx_cfgchip_register_usb1_clk48(struct device *dev, + { + const char * const parent_names[] = { "usb0_clk48", "usb_refclkin" }; + struct da8xx_usb1_clk48 *usb1; +- struct clk_init_data init; ++ struct clk_init_data init = {}; + int ret; + + usb1 = devm_kzalloc(dev, sizeof(*usb1), GFP_KERNEL); +diff --git a/drivers/clk/hisilicon/clk-hi3519.c b/drivers/clk/hisilicon/clk-hi3519.c +index b871872d9960db..141b727ff60d64 100644 +--- a/drivers/clk/hisilicon/clk-hi3519.c ++++ b/drivers/clk/hisilicon/clk-hi3519.c +@@ -130,7 +130,7 @@ static void hi3519_clk_unregister(struct platform_device *pdev) + of_clk_del_provider(pdev->dev.of_node); + + hisi_clk_unregister_gate(hi3519_gate_clks, +- ARRAY_SIZE(hi3519_mux_clks), ++ ARRAY_SIZE(hi3519_gate_clks), + crg->clk_data); + hisi_clk_unregister_mux(hi3519_mux_clks, + ARRAY_SIZE(hi3519_mux_clks), +diff --git a/drivers/clk/hisilicon/clk-hi3559a.c b/drivers/clk/hisilicon/clk-hi3559a.c +index ff4ca0edce06a3..4623befafaec4d 100644 +--- a/drivers/clk/hisilicon/clk-hi3559a.c ++++ b/drivers/clk/hisilicon/clk-hi3559a.c +@@ -491,7 +491,6 @@ static void hisi_clk_register_pll(struct hi3559av100_pll_clock *clks, + + clk = clk_register(NULL, &p_clk->hw); + if (IS_ERR(clk)) { +- devm_kfree(dev, p_clk); + dev_err(dev, "%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; +diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c +index 2d7186905abdc0..5d0226530fdb2f 100644 +--- a/drivers/clk/hisilicon/clk-hi3620.c ++++ b/drivers/clk/hisilicon/clk-hi3620.c +@@ -466,8 +466,10 @@ static void __init hi3620_mmc_clk_init(struct device_node *node) + return; + + clk_data->clks = kcalloc(num, sizeof(*clk_data->clks), GFP_KERNEL); +- if (!clk_data->clks) ++ if (!clk_data->clks) { ++ kfree(clk_data); + return; ++ } + + for (i = 0; i < num; i++) { + struct hisi_mmc_clock *mmc_clk = &hi3620_mmc_clks[i]; +diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig +index f6b82e0b9703a7..db3bca5f4ec9c4 100644 +--- a/drivers/clk/imx/Kconfig ++++ b/drivers/clk/imx/Kconfig +@@ -96,6 +96,7 @@ config CLK_IMX8QXP + depends on (ARCH_MXC && ARM64) || COMPILE_TEST + depends on IMX_SCU && HAVE_ARM_SMCCC + select MXC_CLK_SCU ++ select MXC_CLK + help + Build the driver for IMX8QXP SCU based clocks. + +diff --git a/drivers/clk/imx/clk-composite-7ulp.c b/drivers/clk/imx/clk-composite-7ulp.c +index e208ddc511339e..db7f40b07d1abf 100644 +--- a/drivers/clk/imx/clk-composite-7ulp.c ++++ b/drivers/clk/imx/clk-composite-7ulp.c +@@ -14,6 +14,7 @@ + #include "../clk-fractional-divider.h" + #include "clk.h" + ++#define PCG_PR_MASK BIT(31) + #define PCG_PCS_SHIFT 24 + #define PCG_PCS_MASK 0x7 + #define PCG_CGC_SHIFT 30 +@@ -78,6 +79,12 @@ static struct clk_hw *imx_ulp_clk_hw_composite(const char *name, + struct clk_hw *hw; + u32 val; + ++ val = readl(reg); ++ if (!(val & PCG_PR_MASK)) { ++ pr_info("PCC PR is 0 for clk:%s, bypass\n", name); ++ return 0; ++ } ++ + if (mux_present) { + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) +diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c +index 27a08c50ac1d84..ac5e9d60acb833 100644 +--- a/drivers/clk/imx/clk-composite-8m.c ++++ b/drivers/clk/imx/clk-composite-8m.c +@@ -204,6 +204,34 @@ static const struct clk_ops imx8m_clk_composite_mux_ops = { + .determine_rate = imx8m_clk_composite_mux_determine_rate, + }; + ++static int imx8m_clk_composite_gate_enable(struct clk_hw *hw) ++{ ++ struct clk_gate *gate = to_clk_gate(hw); ++ unsigned long flags; ++ u32 val; ++ ++ spin_lock_irqsave(gate->lock, flags); ++ ++ val = readl(gate->reg); ++ val |= BIT(gate->bit_idx); ++ writel(val, gate->reg); ++ ++ spin_unlock_irqrestore(gate->lock, flags); ++ ++ return 0; ++} ++ ++static void imx8m_clk_composite_gate_disable(struct clk_hw *hw) ++{ ++ /* composite clk requires the disable hook */ ++} ++ ++static const struct clk_ops imx8m_clk_composite_gate_ops = { ++ .enable = imx8m_clk_composite_gate_enable, ++ .disable = imx8m_clk_composite_gate_disable, ++ .is_enabled = clk_gate_is_enabled, ++}; ++ + struct clk_hw *__imx8m_clk_hw_composite(const char *name, + const char * const *parent_names, + int num_parents, void __iomem *reg, +@@ -217,10 +245,11 @@ struct clk_hw *__imx8m_clk_hw_composite(const char *name, + struct clk_mux *mux = NULL; + const struct clk_ops *divider_ops; + const struct clk_ops *mux_ops; ++ const struct clk_ops *gate_ops; + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) +- goto fail; ++ return ERR_CAST(hw); + + mux_hw = &mux->hw; + mux->reg = reg; +@@ -230,7 +259,7 @@ struct clk_hw *__imx8m_clk_hw_composite(const char *name, + + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) +- goto fail; ++ goto free_mux; + + div_hw = &div->hw; + div->reg = reg; +@@ -257,28 +286,32 @@ struct clk_hw *__imx8m_clk_hw_composite(const char *name, + div->flags = CLK_DIVIDER_ROUND_CLOSEST; + + /* skip registering the gate ops if M4 is enabled */ +- if (!mcore_booted) { +- gate = kzalloc(sizeof(*gate), GFP_KERNEL); +- if (!gate) +- goto fail; +- +- gate_hw = &gate->hw; +- gate->reg = reg; +- gate->bit_idx = PCG_CGC_SHIFT; +- gate->lock = &imx_ccm_lock; +- } ++ gate = kzalloc(sizeof(*gate), GFP_KERNEL); ++ if (!gate) ++ goto free_div; ++ ++ gate_hw = &gate->hw; ++ gate->reg = reg; ++ gate->bit_idx = PCG_CGC_SHIFT; ++ gate->lock = &imx_ccm_lock; ++ if (!mcore_booted) ++ gate_ops = &clk_gate_ops; ++ else ++ gate_ops = &imx8m_clk_composite_gate_ops; + + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + mux_hw, mux_ops, div_hw, +- divider_ops, gate_hw, &clk_gate_ops, flags); ++ divider_ops, gate_hw, gate_ops, flags); + if (IS_ERR(hw)) +- goto fail; ++ goto free_gate; + + return hw; + +-fail: ++free_gate: + kfree(gate); ++free_div: + kfree(div); ++free_mux: + kfree(mux); + return ERR_CAST(hw); + } +diff --git a/drivers/clk/imx/clk-composite-93.c b/drivers/clk/imx/clk-composite-93.c +index 81164bdcd6cc9a..6c6c5a30f3282d 100644 +--- a/drivers/clk/imx/clk-composite-93.c ++++ b/drivers/clk/imx/clk-composite-93.c +@@ -76,6 +76,13 @@ static int imx93_clk_composite_gate_enable(struct clk_hw *hw) + + static void imx93_clk_composite_gate_disable(struct clk_hw *hw) + { ++ /* ++ * Skip disable the root clock gate if mcore enabled. ++ * The root clock may be used by the mcore. ++ */ ++ if (mcore_booted) ++ return; ++ + imx93_clk_composite_gate_endisable(hw, 0); + } + +@@ -222,7 +229,7 @@ struct clk_hw *imx93_clk_composite_flags(const char *name, const char * const *p + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + mux_hw, &clk_mux_ro_ops, div_hw, + &clk_divider_ro_ops, NULL, NULL, flags); +- } else if (!mcore_booted) { ++ } else { + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + goto fail; +@@ -238,12 +245,6 @@ struct clk_hw *imx93_clk_composite_flags(const char *name, const char * const *p + &imx93_clk_composite_divider_ops, gate_hw, + &imx93_clk_composite_gate_ops, + flags | CLK_SET_RATE_NO_REPARENT); +- } else { +- hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, +- mux_hw, &imx93_clk_composite_mux_ops, div_hw, +- &imx93_clk_composite_divider_ops, NULL, +- &imx93_clk_composite_gate_ops, +- flags | CLK_SET_RATE_NO_REPARENT); + } + + if (IS_ERR(hw)) +diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c +index 44462ab50e513c..1becba2b62d0be 100644 +--- a/drivers/clk/imx/clk-fracn-gppll.c ++++ b/drivers/clk/imx/clk-fracn-gppll.c +@@ -291,6 +291,10 @@ static int clk_fracn_gppll_prepare(struct clk_hw *hw) + if (val & POWERUP_MASK) + return 0; + ++ if (pll->flags & CLK_FRACN_GPPLL_FRACN) ++ writel_relaxed(readl_relaxed(pll->base + PLL_NUMERATOR), ++ pll->base + PLL_NUMERATOR); ++ + val |= CLKMUX_BYPASS; + writel_relaxed(val, pll->base + PLL_CTRL); + +diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c +index f9394e94f69d73..05c7a82b751f3c 100644 +--- a/drivers/clk/imx/clk-imx6ul.c ++++ b/drivers/clk/imx/clk-imx6ul.c +@@ -542,8 +542,8 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) + + clk_set_parent(hws[IMX6UL_CLK_ENFC_SEL]->clk, hws[IMX6UL_CLK_PLL2_PFD2]->clk); + +- clk_set_parent(hws[IMX6UL_CLK_ENET1_REF_SEL]->clk, hws[IMX6UL_CLK_ENET_REF]->clk); +- clk_set_parent(hws[IMX6UL_CLK_ENET2_REF_SEL]->clk, hws[IMX6UL_CLK_ENET2_REF]->clk); ++ clk_set_parent(hws[IMX6UL_CLK_ENET1_REF_SEL]->clk, hws[IMX6UL_CLK_ENET1_REF_125M]->clk); ++ clk_set_parent(hws[IMX6UL_CLK_ENET2_REF_SEL]->clk, hws[IMX6UL_CLK_ENET2_REF_125M]->clk); + + imx_register_uart_clocks(); + } +diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c +index 2b77d1fc7bb946..1e1296e748357b 100644 +--- a/drivers/clk/imx/clk-imx7d.c ++++ b/drivers/clk/imx/clk-imx7d.c +@@ -498,9 +498,9 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) + hws[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_hw_mux2_flags("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel), CLK_SET_PARENT_GATE); + hws[IMX7D_NAND_USDHC_BUS_ROOT_SRC] = imx_clk_hw_mux2_flags("nand_usdhc_src", base + 0x8980, 24, 3, nand_usdhc_bus_sel, ARRAY_SIZE(nand_usdhc_bus_sel), CLK_SET_PARENT_GATE); + hws[IMX7D_DRAM_PHYM_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_phym_src", base + 0x9800, 24, 1, dram_phym_sel, ARRAY_SIZE(dram_phym_sel), CLK_SET_PARENT_GATE); +- hws[IMX7D_DRAM_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel), CLK_SET_PARENT_GATE); ++ hws[IMX7D_DRAM_ROOT_SRC] = imx_clk_hw_mux2("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel)); + hws[IMX7D_DRAM_PHYM_ALT_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_phym_alt_src", base + 0xa000, 24, 3, dram_phym_alt_sel, ARRAY_SIZE(dram_phym_alt_sel), CLK_SET_PARENT_GATE); +- hws[IMX7D_DRAM_ALT_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel), CLK_SET_PARENT_GATE); ++ hws[IMX7D_DRAM_ALT_ROOT_SRC] = imx_clk_hw_mux2("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel)); + hws[IMX7D_USB_HSIC_ROOT_SRC] = imx_clk_hw_mux2_flags("usb_hsic_src", base + 0xa100, 24, 3, usb_hsic_sel, ARRAY_SIZE(usb_hsic_sel), CLK_SET_PARENT_GATE); + hws[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_hw_mux2_flags("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel), CLK_SET_PARENT_GATE); + hws[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_hw_mux2_flags("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel), CLK_SET_PARENT_GATE); +diff --git a/drivers/clk/imx/clk-imx8-acm.c b/drivers/clk/imx/clk-imx8-acm.c +index 1e82f72b75c674..1c95ae905eec82 100644 +--- a/drivers/clk/imx/clk-imx8-acm.c ++++ b/drivers/clk/imx/clk-imx8-acm.c +@@ -279,8 +279,10 @@ static int clk_imx_acm_attach_pm_domains(struct device *dev, + + for (i = 0; i < dev_pm->num_domains; i++) { + dev_pm->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i); +- if (IS_ERR(dev_pm->pd_dev[i])) +- return PTR_ERR(dev_pm->pd_dev[i]); ++ if (IS_ERR(dev_pm->pd_dev[i])) { ++ ret = PTR_ERR(dev_pm->pd_dev[i]); ++ goto detach_pm; ++ } + + dev_pm->pd_dev_link[i] = device_link_add(dev, + dev_pm->pd_dev[i], +@@ -371,7 +373,7 @@ static int imx8_acm_clk_probe(struct platform_device *pdev) + sels[i].shift, sels[i].width, + 0, NULL, NULL); + if (IS_ERR(hws[sels[i].clkid])) { +- pm_runtime_disable(&pdev->dev); ++ ret = PTR_ERR(hws[sels[i].clkid]); + goto err_clk_register; + } + } +@@ -381,12 +383,16 @@ static int imx8_acm_clk_probe(struct platform_device *pdev) + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data); + if (ret < 0) { + dev_err(dev, "failed to register hws for ACM\n"); +- pm_runtime_disable(&pdev->dev); ++ goto err_clk_register; + } + +-err_clk_register: ++ pm_runtime_put_sync(&pdev->dev); ++ return 0; + ++err_clk_register: + pm_runtime_put_sync(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ clk_imx_acm_detach_pm_domains(&pdev->dev, &priv->dev_pm); + + return ret; + } +diff --git a/drivers/clk/imx/clk-imx8mp-audiomix.c b/drivers/clk/imx/clk-imx8mp-audiomix.c +index e4300df88f1acc..ab2a028b3027d3 100644 +--- a/drivers/clk/imx/clk-imx8mp-audiomix.c ++++ b/drivers/clk/imx/clk-imx8mp-audiomix.c +@@ -18,7 +18,12 @@ + + #define CLKEN0 0x000 + #define CLKEN1 0x004 +-#define SAI_MCLK_SEL(n) (0x300 + 4 * (n)) /* n in 0..5 */ ++#define SAI1_MCLK_SEL 0x300 ++#define SAI2_MCLK_SEL 0x304 ++#define SAI3_MCLK_SEL 0x308 ++#define SAI5_MCLK_SEL 0x30C ++#define SAI6_MCLK_SEL 0x310 ++#define SAI7_MCLK_SEL 0x314 + #define PDM_SEL 0x318 + #define SAI_PLL_GNRL_CTL 0x400 + +@@ -95,13 +100,13 @@ static const struct clk_parent_data clk_imx8mp_audiomix_pll_bypass_sels[] = { + IMX8MP_CLK_AUDIOMIX_SAI##n##_MCLK1_SEL, {}, \ + clk_imx8mp_audiomix_sai##n##_mclk1_parents, \ + ARRAY_SIZE(clk_imx8mp_audiomix_sai##n##_mclk1_parents), \ +- SAI_MCLK_SEL(n), 1, 0 \ ++ SAI##n##_MCLK_SEL, 1, 0 \ + }, { \ + "sai"__stringify(n)"_mclk2_sel", \ + IMX8MP_CLK_AUDIOMIX_SAI##n##_MCLK2_SEL, {}, \ + clk_imx8mp_audiomix_sai_mclk2_parents, \ + ARRAY_SIZE(clk_imx8mp_audiomix_sai_mclk2_parents), \ +- SAI_MCLK_SEL(n), 4, 1 \ ++ SAI##n##_MCLK_SEL, 4, 1 \ + }, { \ + "sai"__stringify(n)"_ipg_cg", \ + IMX8MP_CLK_AUDIOMIX_SAI##n##_IPG, \ +@@ -141,6 +146,15 @@ static const struct clk_parent_data clk_imx8mp_audiomix_pll_bypass_sels[] = { + PDM_SEL, 2, 0 \ + } + ++#define CLK_GATE_PARENT(gname, cname, pname) \ ++ { \ ++ gname"_cg", \ ++ IMX8MP_CLK_AUDIOMIX_##cname, \ ++ { .fw_name = pname, .name = pname }, NULL, 1, \ ++ CLKEN0 + 4 * !!(IMX8MP_CLK_AUDIOMIX_##cname / 32), \ ++ 1, IMX8MP_CLK_AUDIOMIX_##cname % 32 \ ++ } ++ + struct clk_imx8mp_audiomix_sel { + const char *name; + int clkid; +@@ -158,14 +172,14 @@ static struct clk_imx8mp_audiomix_sel sels[] = { + CLK_GATE("earc", EARC_IPG), + CLK_GATE("ocrama", OCRAMA_IPG), + CLK_GATE("aud2htx", AUD2HTX_IPG), +- CLK_GATE("earc_phy", EARC_PHY), ++ CLK_GATE_PARENT("earc_phy", EARC_PHY, "sai_pll_out_div2"), + CLK_GATE("sdma2", SDMA2_ROOT), + CLK_GATE("sdma3", SDMA3_ROOT), + CLK_GATE("spba2", SPBA2_ROOT), + CLK_GATE("dsp", DSP_ROOT), + CLK_GATE("dspdbg", DSPDBG_ROOT), + CLK_GATE("edma", EDMA_ROOT), +- CLK_GATE("audpll", AUDPLL_ROOT), ++ CLK_GATE_PARENT("audpll", AUDPLL_ROOT, "osc_24m"), + CLK_GATE("mu2", MU2_ROOT), + CLK_GATE("mu3", MU3_ROOT), + CLK_PDM, +diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c +index 670aa2bab3017e..e561ff7b135fb5 100644 +--- a/drivers/clk/imx/clk-imx8mp.c ++++ b/drivers/clk/imx/clk-imx8mp.c +@@ -551,8 +551,8 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) + + hws[IMX8MP_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb_root", ccm_base + 0x9080, 0, 1); + +- hws[IMX8MP_CLK_DRAM_ALT] = imx8m_clk_hw_composite("dram_alt", imx8mp_dram_alt_sels, ccm_base + 0xa000); +- hws[IMX8MP_CLK_DRAM_APB] = imx8m_clk_hw_composite_critical("dram_apb", imx8mp_dram_apb_sels, ccm_base + 0xa080); ++ hws[IMX8MP_CLK_DRAM_ALT] = imx8m_clk_hw_fw_managed_composite("dram_alt", imx8mp_dram_alt_sels, ccm_base + 0xa000); ++ hws[IMX8MP_CLK_DRAM_APB] = imx8m_clk_hw_fw_managed_composite_critical("dram_apb", imx8mp_dram_apb_sels, ccm_base + 0xa080); + hws[IMX8MP_CLK_VPU_G1] = imx8m_clk_hw_composite("vpu_g1", imx8mp_vpu_g1_sels, ccm_base + 0xa100); + hws[IMX8MP_CLK_VPU_G2] = imx8m_clk_hw_composite("vpu_g2", imx8mp_vpu_g2_sels, ccm_base + 0xa180); + hws[IMX8MP_CLK_CAN1] = imx8m_clk_hw_composite("can1", imx8mp_can1_sels, ccm_base + 0xa200); +diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c +index 4bd65879fcd347..f70ed231b92d63 100644 +--- a/drivers/clk/imx/clk-imx8mq.c ++++ b/drivers/clk/imx/clk-imx8mq.c +@@ -288,8 +288,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) + void __iomem *base; + int err; + +- clk_hw_data = kzalloc(struct_size(clk_hw_data, hws, +- IMX8MQ_CLK_END), GFP_KERNEL); ++ clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, IMX8MQ_CLK_END), GFP_KERNEL); + if (WARN_ON(!clk_hw_data)) + return -ENOMEM; + +@@ -306,10 +305,12 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) + hws[IMX8MQ_CLK_EXT4] = imx_get_clk_hw_by_name(np, "clk_ext4"); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-anatop"); +- base = of_iomap(np, 0); ++ base = devm_of_iomap(dev, np, 0, NULL); + of_node_put(np); +- if (WARN_ON(!base)) +- return -ENOMEM; ++ if (WARN_ON(IS_ERR(base))) { ++ err = PTR_ERR(base); ++ goto unregister_hws; ++ } + + hws[IMX8MQ_ARM_PLL_REF_SEL] = imx_clk_hw_mux("arm_pll_ref_sel", base + 0x28, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + hws[IMX8MQ_GPU_PLL_REF_SEL] = imx_clk_hw_mux("gpu_pll_ref_sel", base + 0x18, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); +@@ -395,8 +396,10 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) + + np = dev->of_node; + base = devm_platform_ioremap_resource(pdev, 0); +- if (WARN_ON(IS_ERR(base))) +- return PTR_ERR(base); ++ if (WARN_ON(IS_ERR(base))) { ++ err = PTR_ERR(base); ++ goto unregister_hws; ++ } + + /* CORE */ + hws[IMX8MQ_CLK_A53_DIV] = imx8m_clk_hw_composite_core("arm_a53_div", imx8mq_a53_sels, base + 0x8000); +diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c +index cadcbb318f5cf5..6d458995f3887d 100644 +--- a/drivers/clk/imx/clk-imx8qxp.c ++++ b/drivers/clk/imx/clk-imx8qxp.c +@@ -66,6 +66,22 @@ static const char * const lcd_pxl_sels[] = { + "lcd_pxl_bypass_div_clk", + }; + ++static const char *const lvds0_sels[] = { ++ "clk_dummy", ++ "clk_dummy", ++ "clk_dummy", ++ "clk_dummy", ++ "mipi0_lvds_bypass_clk", ++}; ++ ++static const char *const lvds1_sels[] = { ++ "clk_dummy", ++ "clk_dummy", ++ "clk_dummy", ++ "clk_dummy", ++ "mipi1_lvds_bypass_clk", ++}; ++ + static const char * const mipi_sels[] = { + "clk_dummy", + "clk_dummy", +@@ -147,10 +163,10 @@ static int imx8qxp_clk_probe(struct platform_device *pdev) + imx_clk_scu("adc0_clk", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("adc1_clk", IMX_SC_R_ADC_1, IMX_SC_PM_CLK_PER); + imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER); ++ imx_clk_scu("elcdif_pll", IMX_SC_R_ELCDIF_PLL, IMX_SC_PM_CLK_PLL); + imx_clk_scu2("lcd_clk", lcd_sels, ARRAY_SIZE(lcd_sels), IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER); +- imx_clk_scu2("lcd_pxl_clk", lcd_pxl_sels, ARRAY_SIZE(lcd_pxl_sels), IMX_SC_R_LCD_0, IMX_SC_PM_CLK_MISC0); + imx_clk_scu("lcd_pxl_bypass_div_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_BYPASS); +- imx_clk_scu("elcdif_pll", IMX_SC_R_ELCDIF_PLL, IMX_SC_PM_CLK_PLL); ++ imx_clk_scu2("lcd_pxl_clk", lcd_pxl_sels, ARRAY_SIZE(lcd_pxl_sels), IMX_SC_R_LCD_0, IMX_SC_PM_CLK_MISC0); + + /* Audio SS */ + imx_clk_scu("audio_pll0_clk", IMX_SC_R_AUDIO_PLL_0, IMX_SC_PM_CLK_PLL); +@@ -183,26 +199,26 @@ static int imx8qxp_clk_probe(struct platform_device *pdev) + imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC); + + /* Display controller SS */ +- imx_clk_scu2("dc0_disp0_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0); +- imx_clk_scu2("dc0_disp1_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1); + imx_clk_scu("dc0_pll0_clk", IMX_SC_R_DC_0_PLL_0, IMX_SC_PM_CLK_PLL); + imx_clk_scu("dc0_pll1_clk", IMX_SC_R_DC_0_PLL_1, IMX_SC_PM_CLK_PLL); + imx_clk_scu("dc0_bypass0_clk", IMX_SC_R_DC_0_VIDEO0, IMX_SC_PM_CLK_BYPASS); ++ imx_clk_scu2("dc0_disp0_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0); ++ imx_clk_scu2("dc0_disp1_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1); + imx_clk_scu("dc0_bypass1_clk", IMX_SC_R_DC_0_VIDEO1, IMX_SC_PM_CLK_BYPASS); + +- imx_clk_scu2("dc1_disp0_clk", dc1_sels, ARRAY_SIZE(dc1_sels), IMX_SC_R_DC_1, IMX_SC_PM_CLK_MISC0); +- imx_clk_scu2("dc1_disp1_clk", dc1_sels, ARRAY_SIZE(dc1_sels), IMX_SC_R_DC_1, IMX_SC_PM_CLK_MISC1); + imx_clk_scu("dc1_pll0_clk", IMX_SC_R_DC_1_PLL_0, IMX_SC_PM_CLK_PLL); + imx_clk_scu("dc1_pll1_clk", IMX_SC_R_DC_1_PLL_1, IMX_SC_PM_CLK_PLL); + imx_clk_scu("dc1_bypass0_clk", IMX_SC_R_DC_1_VIDEO0, IMX_SC_PM_CLK_BYPASS); ++ imx_clk_scu2("dc1_disp0_clk", dc1_sels, ARRAY_SIZE(dc1_sels), IMX_SC_R_DC_1, IMX_SC_PM_CLK_MISC0); ++ imx_clk_scu2("dc1_disp1_clk", dc1_sels, ARRAY_SIZE(dc1_sels), IMX_SC_R_DC_1, IMX_SC_PM_CLK_MISC1); + imx_clk_scu("dc1_bypass1_clk", IMX_SC_R_DC_1_VIDEO1, IMX_SC_PM_CLK_BYPASS); + + /* MIPI-LVDS SS */ + imx_clk_scu("mipi0_bypass_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu("mipi0_pixel_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PER); +- imx_clk_scu("mipi0_lvds_pixel_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC2); + imx_clk_scu("mipi0_lvds_bypass_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_BYPASS); +- imx_clk_scu("mipi0_lvds_phy_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC3); ++ imx_clk_scu2("mipi0_lvds_pixel_clk", lvds0_sels, ARRAY_SIZE(lvds0_sels), IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC2); ++ imx_clk_scu2("mipi0_lvds_phy_clk", lvds0_sels, ARRAY_SIZE(lvds0_sels), IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC3); + imx_clk_scu2("mipi0_dsi_tx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_MST_BUS); + imx_clk_scu2("mipi0_dsi_rx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_SLV_BUS); + imx_clk_scu2("mipi0_dsi_phy_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PHY); +@@ -212,9 +228,9 @@ static int imx8qxp_clk_probe(struct platform_device *pdev) + + imx_clk_scu("mipi1_bypass_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu("mipi1_pixel_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_PER); +- imx_clk_scu("mipi1_lvds_pixel_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC2); + imx_clk_scu("mipi1_lvds_bypass_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_BYPASS); +- imx_clk_scu("mipi1_lvds_phy_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC3); ++ imx_clk_scu2("mipi1_lvds_pixel_clk", lvds1_sels, ARRAY_SIZE(lvds1_sels), IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC2); ++ imx_clk_scu2("mipi1_lvds_phy_clk", lvds1_sels, ARRAY_SIZE(lvds1_sels), IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC3); + + imx_clk_scu2("mipi1_dsi_tx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_MST_BUS); + imx_clk_scu2("mipi1_dsi_rx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_SLV_BUS); +diff --git a/drivers/clk/keystone/pll.c b/drivers/clk/keystone/pll.c +index ee5c72369334ff..6bbdd4705d71fd 100644 +--- a/drivers/clk/keystone/pll.c ++++ b/drivers/clk/keystone/pll.c +@@ -281,12 +281,13 @@ static void __init of_pll_div_clk_init(struct device_node *node) + + clk = clk_register_divider(NULL, clk_name, parent_name, 0, reg, shift, + mask, 0, NULL); +- if (clk) { +- of_clk_add_provider(node, of_clk_src_simple_get, clk); +- } else { ++ if (IS_ERR(clk)) { + pr_err("%s: error registering divider %s\n", __func__, clk_name); + iounmap(reg); ++ return; + } ++ ++ of_clk_add_provider(node, of_clk_src_simple_get, clk); + } + CLK_OF_DECLARE(pll_divider_clock, "ti,keystone,pll-divider-clock", of_pll_div_clk_init); + +@@ -328,10 +329,12 @@ static void __init of_pll_mux_clk_init(struct device_node *node) + clk = clk_register_mux(NULL, clk_name, (const char **)&parents, + ARRAY_SIZE(parents) , 0, reg, shift, mask, + 0, NULL); +- if (clk) +- of_clk_add_provider(node, of_clk_src_simple_get, clk); +- else ++ if (IS_ERR(clk)) { + pr_err("%s: error registering mux %s\n", __func__, clk_name); ++ return; ++ } ++ ++ of_clk_add_provider(node, of_clk_src_simple_get, clk); + } + CLK_OF_DECLARE(pll_mux_clock, "ti,keystone,pll-mux-clock", of_pll_mux_clk_init); + +diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c +index c81f3e33ce568f..12d9560eb4ba22 100644 +--- a/drivers/clk/mediatek/clk-mt2701.c ++++ b/drivers/clk/mediatek/clk-mt2701.c +@@ -667,6 +667,8 @@ static int mtk_topckgen_init(struct platform_device *pdev) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_TOP_NR); ++ if (!clk_data) ++ return -ENOMEM; + + mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), + clk_data); +@@ -747,6 +749,8 @@ static void __init mtk_infrasys_init_early(struct device_node *node) + + if (!infra_clk_data) { + infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR); ++ if (!infra_clk_data) ++ return; + + for (i = 0; i < CLK_INFRA_NR; i++) + infra_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER); +@@ -774,6 +778,8 @@ static int mtk_infrasys_init(struct platform_device *pdev) + + if (!infra_clk_data) { + infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR); ++ if (!infra_clk_data) ++ return -ENOMEM; + } else { + for (i = 0; i < CLK_INFRA_NR; i++) { + if (infra_clk_data->hws[i] == ERR_PTR(-EPROBE_DEFER)) +@@ -890,6 +896,8 @@ static int mtk_pericfg_init(struct platform_device *pdev) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_PERI_NR); ++ if (!clk_data) ++ return -ENOMEM; + + mtk_clk_register_gates(&pdev->dev, node, peri_clks, + ARRAY_SIZE(peri_clks), clk_data); +diff --git a/drivers/clk/mediatek/clk-mt6765.c b/drivers/clk/mediatek/clk-mt6765.c +index 1f4c8d0c041abe..9c7f7407d7980b 100644 +--- a/drivers/clk/mediatek/clk-mt6765.c ++++ b/drivers/clk/mediatek/clk-mt6765.c +@@ -737,6 +737,8 @@ static int clk_mt6765_apmixed_probe(struct platform_device *pdev) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); ++ if (!clk_data) ++ return -ENOMEM; + + mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + +@@ -769,6 +771,8 @@ static int clk_mt6765_top_probe(struct platform_device *pdev) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); ++ if (!clk_data) ++ return -ENOMEM; + + mtk_clk_register_fixed_clks(fixed_clks, ARRAY_SIZE(fixed_clks), + clk_data); +@@ -807,6 +811,8 @@ static int clk_mt6765_ifr_probe(struct platform_device *pdev) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_IFR_NR_CLK); ++ if (!clk_data) ++ return -ENOMEM; + + mtk_clk_register_gates(&pdev->dev, node, ifr_clks, + ARRAY_SIZE(ifr_clks), clk_data); +diff --git a/drivers/clk/mediatek/clk-mt6779.c b/drivers/clk/mediatek/clk-mt6779.c +index 3ee2f5a2319a0e..ffedb1fe3c672d 100644 +--- a/drivers/clk/mediatek/clk-mt6779.c ++++ b/drivers/clk/mediatek/clk-mt6779.c +@@ -1217,6 +1217,8 @@ static int clk_mt6779_apmixed_probe(struct platform_device *pdev) + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); ++ if (!clk_data) ++ return -ENOMEM; + + mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + +@@ -1237,6 +1239,8 @@ static int clk_mt6779_top_probe(struct platform_device *pdev) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); ++ if (!clk_data) ++ return -ENOMEM; + + mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), + clk_data); +diff --git a/drivers/clk/mediatek/clk-mt6797.c b/drivers/clk/mediatek/clk-mt6797.c +index 2ebd25f0ce71df..f12d4e9ff0bbaf 100644 +--- a/drivers/clk/mediatek/clk-mt6797.c ++++ b/drivers/clk/mediatek/clk-mt6797.c +@@ -390,6 +390,8 @@ static int mtk_topckgen_init(struct platform_device *pdev) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_TOP_NR); ++ if (!clk_data) ++ return -ENOMEM; + + mtk_clk_register_factors(top_fixed_divs, ARRAY_SIZE(top_fixed_divs), + clk_data); +@@ -545,6 +547,8 @@ static void mtk_infrasys_init_early(struct device_node *node) + + if (!infra_clk_data) { + infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR); ++ if (!infra_clk_data) ++ return; + + for (i = 0; i < CLK_INFRA_NR; i++) + infra_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER); +@@ -570,6 +574,8 @@ static int mtk_infrasys_init(struct platform_device *pdev) + + if (!infra_clk_data) { + infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR); ++ if (!infra_clk_data) ++ return -ENOMEM; + } else { + for (i = 0; i < CLK_INFRA_NR; i++) { + if (infra_clk_data->hws[i] == ERR_PTR(-EPROBE_DEFER)) +diff --git a/drivers/clk/mediatek/clk-mt7622-apmixedsys.c b/drivers/clk/mediatek/clk-mt7622-apmixedsys.c +index 9cffd278e9a43e..1b8f859b6b6ccd 100644 +--- a/drivers/clk/mediatek/clk-mt7622-apmixedsys.c ++++ b/drivers/clk/mediatek/clk-mt7622-apmixedsys.c +@@ -127,7 +127,6 @@ static void clk_mt7622_apmixed_remove(struct platform_device *pdev) + of_clk_del_provider(node); + mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); +- mtk_free_clk_data(clk_data); + } + + static const struct of_device_id of_match_clk_mt7622_apmixed[] = { +diff --git a/drivers/clk/mediatek/clk-mt7629-eth.c b/drivers/clk/mediatek/clk-mt7629-eth.c +index fe714debdc9ece..1bfedc988cfe89 100644 +--- a/drivers/clk/mediatek/clk-mt7629-eth.c ++++ b/drivers/clk/mediatek/clk-mt7629-eth.c +@@ -77,6 +77,8 @@ static int clk_mt7629_ethsys_init(struct platform_device *pdev) + int r; + + clk_data = mtk_alloc_clk_data(CLK_ETH_NR_CLK); ++ if (!clk_data) ++ return -ENOMEM; + + mtk_clk_register_gates(&pdev->dev, node, eth_clks, + CLK_ETH_NR_CLK, clk_data); +@@ -100,6 +102,8 @@ static int clk_mt7629_sgmiisys_init(struct platform_device *pdev) + int r; + + clk_data = mtk_alloc_clk_data(CLK_SGMII_NR_CLK); ++ if (!clk_data) ++ return -ENOMEM; + + mtk_clk_register_gates(&pdev->dev, node, sgmii_clks[id++], + CLK_SGMII_NR_CLK, clk_data); +diff --git a/drivers/clk/mediatek/clk-mt7629.c b/drivers/clk/mediatek/clk-mt7629.c +index 2882107d0f2403..b8a1f01bc974d2 100644 +--- a/drivers/clk/mediatek/clk-mt7629.c ++++ b/drivers/clk/mediatek/clk-mt7629.c +@@ -555,6 +555,8 @@ static int mtk_topckgen_init(struct platform_device *pdev) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); ++ if (!clk_data) ++ return -ENOMEM; + + mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), + clk_data); +@@ -579,6 +581,8 @@ static int mtk_infrasys_init(struct platform_device *pdev) + struct clk_hw_onecell_data *clk_data; + + clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK); ++ if (!clk_data) ++ return -ENOMEM; + + mtk_clk_register_gates(&pdev->dev, node, infra_clks, + ARRAY_SIZE(infra_clks), clk_data); +@@ -602,6 +606,8 @@ static int mtk_pericfg_init(struct platform_device *pdev) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK); ++ if (!clk_data) ++ return -ENOMEM; + + mtk_clk_register_gates(&pdev->dev, node, peri_clks, + ARRAY_SIZE(peri_clks), clk_data); +diff --git a/drivers/clk/mediatek/clk-mt7981-topckgen.c b/drivers/clk/mediatek/clk-mt7981-topckgen.c +index 682f4ca9e89ada..493aa11d3a175f 100644 +--- a/drivers/clk/mediatek/clk-mt7981-topckgen.c ++++ b/drivers/clk/mediatek/clk-mt7981-topckgen.c +@@ -357,8 +357,9 @@ static const struct mtk_mux top_muxes[] = { + MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_325M_SEL, "sgm_325m_sel", + sgm_325m_parents, 0x050, 0x054, 0x058, 8, 1, 15, + 0x1C0, 21), +- MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_REG_SEL, "sgm_reg_sel", sgm_reg_parents, +- 0x050, 0x054, 0x058, 16, 1, 23, 0x1C0, 22), ++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SGM_REG_SEL, "sgm_reg_sel", sgm_reg_parents, ++ 0x050, 0x054, 0x058, 16, 1, 23, 0x1C0, 22, ++ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT), + MUX_GATE_CLR_SET_UPD(CLK_TOP_EIP97B_SEL, "eip97b_sel", eip97b_parents, + 0x050, 0x054, 0x058, 24, 3, 31, 0x1C0, 23), + /* CLK_CFG_6 */ +diff --git a/drivers/clk/mediatek/clk-mt8135-apmixedsys.c b/drivers/clk/mediatek/clk-mt8135-apmixedsys.c +index d1239b4b3db74b..41bb2d2e2ea740 100644 +--- a/drivers/clk/mediatek/clk-mt8135-apmixedsys.c ++++ b/drivers/clk/mediatek/clk-mt8135-apmixedsys.c +@@ -59,7 +59,7 @@ static int clk_mt8135_apmixed_probe(struct platform_device *pdev) + + ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + if (ret) +- return ret; ++ goto free_clk_data; + + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (ret) +@@ -69,6 +69,8 @@ static int clk_mt8135_apmixed_probe(struct platform_device *pdev) + + unregister_plls: + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); ++free_clk_data: ++ mtk_free_clk_data(clk_data); + + return ret; + } +diff --git a/drivers/clk/mediatek/clk-mt8183-mfgcfg.c b/drivers/clk/mediatek/clk-mt8183-mfgcfg.c +index ba504e19d42031..62d876e150e117 100644 +--- a/drivers/clk/mediatek/clk-mt8183-mfgcfg.c ++++ b/drivers/clk/mediatek/clk-mt8183-mfgcfg.c +@@ -29,6 +29,7 @@ static const struct mtk_gate mfg_clks[] = { + static const struct mtk_clk_desc mfg_desc = { + .clks = mfg_clks, + .num_clks = ARRAY_SIZE(mfg_clks), ++ .need_runtime_pm = true, + }; + + static const struct of_device_id of_match_clk_mt8183_mfg[] = { +diff --git a/drivers/clk/mediatek/clk-mt8183.c b/drivers/clk/mediatek/clk-mt8183.c +index 6e23461a04559c..934d5a15acfc58 100644 +--- a/drivers/clk/mediatek/clk-mt8183.c ++++ b/drivers/clk/mediatek/clk-mt8183.c +@@ -790,7 +790,7 @@ static const struct mtk_gate infra_clks[] = { + /* infra_sspm_26m_self is main clock in co-processor, should not be closed in Linux. */ + GATE_INFRA3_FLAGS(CLK_INFRA_SSPM_26M_SELF, "infra_sspm_26m_self", "f_f26m_ck", 3, CLK_IS_CRITICAL), + /* infra_sspm_32k_self is main clock in co-processor, should not be closed in Linux. */ +- GATE_INFRA3_FLAGS(CLK_INFRA_SSPM_32K_SELF, "infra_sspm_32k_self", "f_f26m_ck", 4, CLK_IS_CRITICAL), ++ GATE_INFRA3_FLAGS(CLK_INFRA_SSPM_32K_SELF, "infra_sspm_32k_self", "clk32k", 4, CLK_IS_CRITICAL), + GATE_INFRA3(CLK_INFRA_UFS_AXI, "infra_ufs_axi", "axi_sel", 5), + GATE_INFRA3(CLK_INFRA_I2C6, "infra_i2c6", "i2c_sel", 6), + GATE_INFRA3(CLK_INFRA_AP_MSDC0, "infra_ap_msdc0", "msdc50_hclk_sel", 7), +diff --git a/drivers/clk/mediatek/clk-mt8365-mm.c b/drivers/clk/mediatek/clk-mt8365-mm.c +index 01a2ef8f594ef5..3f62ec75073367 100644 +--- a/drivers/clk/mediatek/clk-mt8365-mm.c ++++ b/drivers/clk/mediatek/clk-mt8365-mm.c +@@ -53,7 +53,7 @@ static const struct mtk_gate mm_clks[] = { + GATE_MM0(CLK_MM_MM_DSI0, "mm_dsi0", "mm_sel", 17), + GATE_MM0(CLK_MM_MM_DISP_RDMA1, "mm_disp_rdma1", "mm_sel", 18), + GATE_MM0(CLK_MM_MM_MDP_RDMA1, "mm_mdp_rdma1", "mm_sel", 19), +- GATE_MM0(CLK_MM_DPI0_DPI0, "mm_dpi0_dpi0", "vpll_dpix", 20), ++ GATE_MM0(CLK_MM_DPI0_DPI0, "mm_dpi0_dpi0", "dpi0_sel", 20), + GATE_MM0(CLK_MM_MM_FAKE, "mm_fake", "mm_sel", 21), + GATE_MM0(CLK_MM_MM_SMI_COMMON, "mm_smi_common", "mm_sel", 22), + GATE_MM0(CLK_MM_MM_SMI_LARB0, "mm_smi_larb0", "mm_sel", 23), +diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c +index 2e55368dc4d820..ba1d1c495bc2bf 100644 +--- a/drivers/clk/mediatek/clk-mtk.c ++++ b/drivers/clk/mediatek/clk-mtk.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + #include "clk-mtk.h" +@@ -494,6 +495,18 @@ static int __mtk_clk_simple_probe(struct platform_device *pdev, + return IS_ERR(base) ? PTR_ERR(base) : -ENOMEM; + } + ++ ++ if (mcd->need_runtime_pm) { ++ devm_pm_runtime_enable(&pdev->dev); ++ /* ++ * Do a pm_runtime_resume_and_get() to workaround a possible ++ * deadlock between clk_register() and the genpd framework. ++ */ ++ r = pm_runtime_resume_and_get(&pdev->dev); ++ if (r) ++ return r; ++ } ++ + /* Calculate how many clk_hw_onecell_data entries to allocate */ + num_clks = mcd->num_clks + mcd->num_composite_clks; + num_clks += mcd->num_fixed_clks + mcd->num_factor_clks; +@@ -574,6 +587,9 @@ static int __mtk_clk_simple_probe(struct platform_device *pdev, + goto unregister_clks; + } + ++ if (mcd->need_runtime_pm) ++ pm_runtime_put(&pdev->dev); ++ + return r; + + unregister_clks: +@@ -604,6 +620,9 @@ static int __mtk_clk_simple_probe(struct platform_device *pdev, + free_base: + if (mcd->shared_io && base) + iounmap(base); ++ ++ if (mcd->need_runtime_pm) ++ pm_runtime_put(&pdev->dev); + return r; + } + +diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h +index 22096501a60a7b..c17fe1c2d732da 100644 +--- a/drivers/clk/mediatek/clk-mtk.h ++++ b/drivers/clk/mediatek/clk-mtk.h +@@ -237,6 +237,8 @@ struct mtk_clk_desc { + + int (*clk_notifier_func)(struct device *dev, struct clk *clk); + unsigned int mfg_clk_idx; ++ ++ bool need_runtime_pm; + }; + + int mtk_clk_pdev_probe(struct platform_device *pdev); +diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c +index a4eca5fd539c83..513ab6b1b32292 100644 +--- a/drivers/clk/mediatek/clk-pll.c ++++ b/drivers/clk/mediatek/clk-pll.c +@@ -321,10 +321,8 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll, + + ret = clk_hw_register(NULL, &pll->hw); + +- if (ret) { +- kfree(pll); ++ if (ret) + return ERR_PTR(ret); +- } + + return &pll->hw; + } +@@ -340,6 +338,8 @@ struct clk_hw *mtk_clk_register_pll(const struct mtk_pll_data *data, + return ERR_PTR(-ENOMEM); + + hw = mtk_clk_register_pll_ops(pll, data, base, &mtk_pll_ops); ++ if (IS_ERR(hw)) ++ kfree(pll); + + return hw; + } +diff --git a/drivers/clk/mediatek/clk-pllfh.c b/drivers/clk/mediatek/clk-pllfh.c +index 3a2b3f90be25d5..094ec8a26d6683 100644 +--- a/drivers/clk/mediatek/clk-pllfh.c ++++ b/drivers/clk/mediatek/clk-pllfh.c +@@ -68,7 +68,7 @@ void fhctl_parse_dt(const u8 *compatible_node, struct mtk_pllfh_data *pllfhs, + + node = of_find_compatible_node(NULL, NULL, compatible_node); + if (!node) { +- pr_err("cannot find \"%s\"\n", compatible_node); ++ pr_warn("cannot find \"%s\"\n", compatible_node); + return; + } + +diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c +index c12f81dfa67453..5f60f2bcca592a 100644 +--- a/drivers/clk/meson/axg.c ++++ b/drivers/clk/meson/axg.c +@@ -2142,7 +2142,9 @@ static struct clk_regmap *const axg_clk_regmaps[] = { + &axg_vclk_input, + &axg_vclk2_input, + &axg_vclk_div, ++ &axg_vclk_div1, + &axg_vclk2_div, ++ &axg_vclk2_div1, + &axg_vclk_div2_en, + &axg_vclk_div4_en, + &axg_vclk_div6_en, +diff --git a/drivers/clk/mmp/clk-of-pxa168.c b/drivers/clk/mmp/clk-of-pxa168.c +index fb0df64cf053c4..c5a7ba1deaa3a1 100644 +--- a/drivers/clk/mmp/clk-of-pxa168.c ++++ b/drivers/clk/mmp/clk-of-pxa168.c +@@ -308,18 +308,21 @@ static void __init pxa168_clk_init(struct device_node *np) + pxa_unit->mpmu_base = of_iomap(np, 0); + if (!pxa_unit->mpmu_base) { + pr_err("failed to map mpmu registers\n"); ++ kfree(pxa_unit); + return; + } + + pxa_unit->apmu_base = of_iomap(np, 1); + if (!pxa_unit->apmu_base) { + pr_err("failed to map apmu registers\n"); ++ kfree(pxa_unit); + return; + } + + pxa_unit->apbc_base = of_iomap(np, 2); + if (!pxa_unit->apbc_base) { + pr_err("failed to map apbc registers\n"); ++ kfree(pxa_unit); + return; + } + +diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig +index 865db5202e4cfe..a79b837583894f 100644 +--- a/drivers/clk/qcom/Kconfig ++++ b/drivers/clk/qcom/Kconfig +@@ -131,6 +131,7 @@ config IPQ_APSS_6018 + tristate "IPQ APSS Clock Controller" + select IPQ_APSS_PLL + depends on QCOM_APCS_IPC || COMPILE_TEST ++ depends on QCOM_SMEM + help + Support for APSS clock controller on IPQ platforms. The + APSS clock controller manages the Mux and enable block that feeds the +diff --git a/drivers/clk/qcom/apss-ipq-pll.c b/drivers/clk/qcom/apss-ipq-pll.c +index e170331858cc14..41279e5437a620 100644 +--- a/drivers/clk/qcom/apss-ipq-pll.c ++++ b/drivers/clk/qcom/apss-ipq-pll.c +@@ -68,13 +68,13 @@ static struct clk_alpha_pll ipq_pll_stromer_plus = { + .fw_name = "xo", + }, + .num_parents = 1, +- .ops = &clk_alpha_pll_stromer_ops, ++ .ops = &clk_alpha_pll_stromer_plus_ops, + }, + }, + }; + + static const struct alpha_pll_config ipq5332_pll_config = { +- .l = 0x3e, ++ .l = 0x2d, + .config_ctl_val = 0x4001075b, + .config_ctl_hi_val = 0x304, + .main_output_mask = BIT(0), +diff --git a/drivers/clk/qcom/camcc-sc7280.c b/drivers/clk/qcom/camcc-sc7280.c +index 49f046ea857cbe..c1551de51d4013 100644 +--- a/drivers/clk/qcom/camcc-sc7280.c ++++ b/drivers/clk/qcom/camcc-sc7280.c +@@ -2260,6 +2260,7 @@ static struct gdsc cam_cc_bps_gdsc = { + .name = "cam_cc_bps_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .parent = &cam_cc_titan_top_gdsc.pd, + .flags = HW_CTRL | RETAIN_FF_ENABLE, + }; + +@@ -2269,6 +2270,7 @@ static struct gdsc cam_cc_ife_0_gdsc = { + .name = "cam_cc_ife_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .parent = &cam_cc_titan_top_gdsc.pd, + .flags = RETAIN_FF_ENABLE, + }; + +@@ -2278,6 +2280,7 @@ static struct gdsc cam_cc_ife_1_gdsc = { + .name = "cam_cc_ife_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .parent = &cam_cc_titan_top_gdsc.pd, + .flags = RETAIN_FF_ENABLE, + }; + +@@ -2287,6 +2290,7 @@ static struct gdsc cam_cc_ife_2_gdsc = { + .name = "cam_cc_ife_2_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .parent = &cam_cc_titan_top_gdsc.pd, + .flags = RETAIN_FF_ENABLE, + }; + +@@ -2296,6 +2300,7 @@ static struct gdsc cam_cc_ipe_0_gdsc = { + .name = "cam_cc_ipe_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .parent = &cam_cc_titan_top_gdsc.pd, + .flags = HW_CTRL | RETAIN_FF_ENABLE, + }; + +diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c +index e4ef645f65d1fd..8b3e5f84e89a77 100644 +--- a/drivers/clk/qcom/clk-alpha-pll.c ++++ b/drivers/clk/qcom/clk-alpha-pll.c +@@ -40,7 +40,7 @@ + + #define PLL_USER_CTL(p) ((p)->offset + (p)->regs[PLL_OFF_USER_CTL]) + # define PLL_POST_DIV_SHIFT 8 +-# define PLL_POST_DIV_MASK(p) GENMASK((p)->width, 0) ++# define PLL_POST_DIV_MASK(p) GENMASK((p)->width - 1, 0) + # define PLL_ALPHA_EN BIT(24) + # define PLL_ALPHA_MODE BIT(25) + # define PLL_VCO_SHIFT 20 +@@ -212,7 +212,6 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { + [PLL_OFF_USER_CTL] = 0x18, + [PLL_OFF_USER_CTL_U] = 0x1c, + [PLL_OFF_CONFIG_CTL] = 0x20, +- [PLL_OFF_CONFIG_CTL_U] = 0xff, + [PLL_OFF_TEST_CTL] = 0x30, + [PLL_OFF_TEST_CTL_U] = 0x34, + [PLL_OFF_STATUS] = 0x28, +@@ -1479,8 +1478,8 @@ clk_trion_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, + } + + return regmap_update_bits(regmap, PLL_USER_CTL(pll), +- PLL_POST_DIV_MASK(pll) << PLL_POST_DIV_SHIFT, +- val << PLL_POST_DIV_SHIFT); ++ PLL_POST_DIV_MASK(pll) << pll->post_div_shift, ++ val << pll->post_div_shift); + } + + const struct clk_ops clk_alpha_pll_postdiv_trion_ops = { +@@ -1639,7 +1638,7 @@ static int __alpha_pll_trion_set_rate(struct clk_hw *hw, unsigned long rate, + if (ret < 0) + return ret; + +- regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); ++ regmap_update_bits(pll->clkr.regmap, PLL_L_VAL(pll), LUCID_EVO_PLL_L_VAL_MASK, l); + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); + + /* Latch the PLL input */ +@@ -1758,6 +1757,58 @@ const struct clk_ops clk_alpha_pll_agera_ops = { + }; + EXPORT_SYMBOL_GPL(clk_alpha_pll_agera_ops); + ++/** ++ * clk_lucid_5lpe_pll_configure - configure the lucid 5lpe pll ++ * ++ * @pll: clk alpha pll ++ * @regmap: register map ++ * @config: configuration to apply for pll ++ */ ++void clk_lucid_5lpe_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, ++ const struct alpha_pll_config *config) ++{ ++ /* ++ * If the bootloader left the PLL enabled it's likely that there are ++ * RCGs that will lock up if we disable the PLL below. ++ */ ++ if (trion_pll_is_enabled(pll, regmap)) { ++ pr_debug("Lucid 5LPE PLL is already enabled, skipping configuration\n"); ++ return; ++ } ++ ++ clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l); ++ regmap_write(regmap, PLL_CAL_L_VAL(pll), TRION_PLL_CAL_VAL); ++ clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha); ++ clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll), ++ config->config_ctl_val); ++ clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll), ++ config->config_ctl_hi_val); ++ clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U1(pll), ++ config->config_ctl_hi1_val); ++ clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll), ++ config->user_ctl_val); ++ clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U(pll), ++ config->user_ctl_hi_val); ++ clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U1(pll), ++ config->user_ctl_hi1_val); ++ clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll), ++ config->test_ctl_val); ++ clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll), ++ config->test_ctl_hi_val); ++ clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U1(pll), ++ config->test_ctl_hi1_val); ++ ++ /* Disable PLL output */ ++ regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, 0); ++ ++ /* Set operation mode to OFF */ ++ regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY); ++ ++ /* Place the PLL in STANDBY mode */ ++ regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); ++} ++EXPORT_SYMBOL_GPL(clk_lucid_5lpe_pll_configure); ++ + static int alpha_pll_lucid_5lpe_enable(struct clk_hw *hw) + { + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); +@@ -2445,6 +2496,8 @@ static int clk_alpha_pll_stromer_set_rate(struct clk_hw *hw, unsigned long rate, + rate = alpha_pll_round_rate(rate, prate, &l, &a, ALPHA_REG_BITWIDTH); + + regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); ++ ++ a <<= ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH; + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), + a >> ALPHA_BITWIDTH); +@@ -2479,3 +2532,69 @@ const struct clk_ops clk_alpha_pll_stromer_ops = { + .set_rate = clk_alpha_pll_stromer_set_rate, + }; + EXPORT_SYMBOL_GPL(clk_alpha_pll_stromer_ops); ++ ++static int clk_alpha_pll_stromer_plus_set_rate(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long prate) ++{ ++ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); ++ u32 l, alpha_width = pll_alpha_width(pll); ++ int ret, pll_mode; ++ u64 a; ++ ++ rate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width); ++ ++ ret = regmap_read(pll->clkr.regmap, PLL_MODE(pll), &pll_mode); ++ if (ret) ++ return ret; ++ ++ regmap_write(pll->clkr.regmap, PLL_MODE(pll), 0); ++ ++ /* Delay of 2 output clock ticks required until output is disabled */ ++ udelay(1); ++ ++ regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); ++ ++ if (alpha_width > ALPHA_BITWIDTH) ++ a <<= alpha_width - ALPHA_BITWIDTH; ++ ++ regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); ++ regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), ++ a >> ALPHA_BITWIDTH); ++ ++ regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), ++ PLL_ALPHA_EN, PLL_ALPHA_EN); ++ ++ regmap_write(pll->clkr.regmap, PLL_MODE(pll), PLL_BYPASSNL); ++ ++ /* Wait five micro seconds or more */ ++ udelay(5); ++ regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_RESET_N, ++ PLL_RESET_N); ++ ++ /* The lock time should be less than 50 micro seconds worst case */ ++ usleep_range(50, 60); ++ ++ ret = wait_for_pll_enable_lock(pll); ++ if (ret) { ++ pr_err("Wait for PLL enable lock failed [%s] %d\n", ++ clk_hw_get_name(hw), ret); ++ return ret; ++ } ++ ++ if (pll_mode & PLL_OUTCTRL) ++ regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_OUTCTRL, ++ PLL_OUTCTRL); ++ ++ return 0; ++} ++ ++const struct clk_ops clk_alpha_pll_stromer_plus_ops = { ++ .prepare = clk_alpha_pll_enable, ++ .unprepare = clk_alpha_pll_disable, ++ .is_enabled = clk_alpha_pll_is_enabled, ++ .recalc_rate = clk_alpha_pll_recalc_rate, ++ .determine_rate = clk_alpha_pll_stromer_determine_rate, ++ .set_rate = clk_alpha_pll_stromer_plus_set_rate, ++}; ++EXPORT_SYMBOL_GPL(clk_alpha_pll_stromer_plus_ops); +diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h +index e4bd863027ab63..3fd0ef41c72c89 100644 +--- a/drivers/clk/qcom/clk-alpha-pll.h ++++ b/drivers/clk/qcom/clk-alpha-pll.h +@@ -152,6 +152,7 @@ extern const struct clk_ops clk_alpha_pll_postdiv_ops; + extern const struct clk_ops clk_alpha_pll_huayra_ops; + extern const struct clk_ops clk_alpha_pll_postdiv_ro_ops; + extern const struct clk_ops clk_alpha_pll_stromer_ops; ++extern const struct clk_ops clk_alpha_pll_stromer_plus_ops; + + extern const struct clk_ops clk_alpha_pll_fabia_ops; + extern const struct clk_ops clk_alpha_pll_fixed_fabia_ops; +@@ -197,6 +198,8 @@ void clk_agera_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + + void clk_zonda_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config); ++void clk_lucid_5lpe_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, ++ const struct alpha_pll_config *config); + void clk_lucid_evo_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config); + void clk_rivian_evo_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, +diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h +index e6d84c8c7989c8..84c497f361bc6b 100644 +--- a/drivers/clk/qcom/clk-rcg.h ++++ b/drivers/clk/qcom/clk-rcg.h +@@ -176,6 +176,7 @@ extern const struct clk_ops clk_byte2_ops; + extern const struct clk_ops clk_pixel_ops; + extern const struct clk_ops clk_gfx3d_ops; + extern const struct clk_ops clk_rcg2_shared_ops; ++extern const struct clk_ops clk_rcg2_shared_no_init_park_ops; + extern const struct clk_ops clk_dp_ops; + + struct clk_rcg_dfs_data { +diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c +index e22baf3a7112aa..461f54fe5e4f1f 100644 +--- a/drivers/clk/qcom/clk-rcg2.c ++++ b/drivers/clk/qcom/clk-rcg2.c +@@ -158,17 +158,11 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index) + static unsigned long + calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div) + { +- if (hid_div) { +- rate *= 2; +- rate /= hid_div + 1; +- } ++ if (hid_div) ++ rate = mult_frac(rate, 2, hid_div + 1); + +- if (mode) { +- u64 tmp = rate; +- tmp *= m; +- do_div(tmp, n); +- rate = tmp; +- } ++ if (mode) ++ rate = mult_frac(rate, m, n); + + return rate; + } +@@ -1144,7 +1138,39 @@ clk_rcg2_shared_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) + return clk_rcg2_recalc_rate(hw, parent_rate); + } + ++static int clk_rcg2_shared_init(struct clk_hw *hw) ++{ ++ /* ++ * This does a few things: ++ * ++ * 1. Sets rcg->parked_cfg to reflect the value at probe so that the ++ * proper parent is reported from clk_rcg2_shared_get_parent(). ++ * ++ * 2. Clears the force enable bit of the RCG because we rely on child ++ * clks (branches) to turn the RCG on/off with a hardware feedback ++ * mechanism and only set the force enable bit in the RCG when we ++ * want to make sure the clk stays on for parent switches or ++ * parking. ++ * ++ * 3. Parks shared RCGs on the safe source at registration because we ++ * can't be certain that the parent clk will stay on during boot, ++ * especially if the parent is shared. If this RCG is enabled at ++ * boot, and the parent is turned off, the RCG will get stuck on. A ++ * GDSC can wedge if is turned on and the RCG is stuck on because ++ * the GDSC's controller will hang waiting for the clk status to ++ * toggle on when it never does. ++ * ++ * The safest option here is to "park" the RCG at init so that the clk ++ * can never get stuck on or off. This ensures the GDSC can't get ++ * wedged. ++ */ ++ clk_rcg2_shared_disable(hw); ++ ++ return 0; ++} ++ + const struct clk_ops clk_rcg2_shared_ops = { ++ .init = clk_rcg2_shared_init, + .enable = clk_rcg2_shared_enable, + .disable = clk_rcg2_shared_disable, + .get_parent = clk_rcg2_shared_get_parent, +@@ -1156,6 +1182,36 @@ const struct clk_ops clk_rcg2_shared_ops = { + }; + EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops); + ++static int clk_rcg2_shared_no_init_park(struct clk_hw *hw) ++{ ++ struct clk_rcg2 *rcg = to_clk_rcg2(hw); ++ ++ /* ++ * Read the config register so that the parent is properly mapped at ++ * registration time. ++ */ ++ regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &rcg->parked_cfg); ++ ++ return 0; ++} ++ ++/* ++ * Like clk_rcg2_shared_ops but skip the init so that the clk frequency is left ++ * unchanged at registration time. ++ */ ++const struct clk_ops clk_rcg2_shared_no_init_park_ops = { ++ .init = clk_rcg2_shared_no_init_park, ++ .enable = clk_rcg2_shared_enable, ++ .disable = clk_rcg2_shared_disable, ++ .get_parent = clk_rcg2_shared_get_parent, ++ .set_parent = clk_rcg2_shared_set_parent, ++ .recalc_rate = clk_rcg2_shared_recalc_rate, ++ .determine_rate = clk_rcg2_determine_rate, ++ .set_rate = clk_rcg2_shared_set_rate, ++ .set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent, ++}; ++EXPORT_SYMBOL_GPL(clk_rcg2_shared_no_init_park_ops); ++ + /* Common APIs to be used for DFS based RCGR */ + static void clk_rcg2_dfs_populate_freq(struct clk_hw *hw, unsigned int l, + struct freq_tbl *f) +diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c +index 4c5b552b47b6a1..a556c9e77d192d 100644 +--- a/drivers/clk/qcom/clk-rpmh.c ++++ b/drivers/clk/qcom/clk-rpmh.c +@@ -263,6 +263,8 @@ static int clk_rpmh_bcm_send_cmd(struct clk_rpmh *c, bool enable) + cmd_state = 0; + } + ++ cmd_state = min(cmd_state, BCM_TCS_CMD_VOTE_MASK); ++ + if (c->last_sent_aggr_state != cmd_state) { + cmd.addr = c->res_addr; + cmd.data = BCM_TCS_CMD(1, enable, 0, cmd_state); +diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c +index 0191fc0dd7dac1..789903a1b3f2b3 100644 +--- a/drivers/clk/qcom/clk-smd-rpm.c ++++ b/drivers/clk/qcom/clk-smd-rpm.c +@@ -758,6 +758,7 @@ static struct clk_smd_rpm *msm8976_clks[] = { + + static const struct rpm_smd_clk_desc rpm_clk_msm8976 = { + .clks = msm8976_clks, ++ .num_clks = ARRAY_SIZE(msm8976_clks), + .icc_clks = bimc_pcnoc_snoc_smmnoc_icc_clks, + .num_icc_clks = ARRAY_SIZE(bimc_pcnoc_snoc_smmnoc_icc_clks), + }; +diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c +index 735adfefc37983..e792e0b130d333 100644 +--- a/drivers/clk/qcom/dispcc-sdm845.c ++++ b/drivers/clk/qcom/dispcc-sdm845.c +@@ -759,6 +759,8 @@ static struct clk_branch disp_cc_mdss_vsync_clk = { + + static struct gdsc mdss_gdsc = { + .gdscr = 0x3000, ++ .en_few_wait_val = 0x6, ++ .en_rest_wait_val = 0x5, + .pd = { + .name = "mdss_gdsc", + }, +diff --git a/drivers/clk/qcom/dispcc-sm6350.c b/drivers/clk/qcom/dispcc-sm6350.c +index ea6f54ed846ece..441f042f5ea459 100644 +--- a/drivers/clk/qcom/dispcc-sm6350.c ++++ b/drivers/clk/qcom/dispcc-sm6350.c +@@ -221,26 +221,17 @@ static struct clk_rcg2 disp_cc_mdss_dp_crypto_clk_src = { + }, + }; + +-static const struct freq_tbl ftbl_disp_cc_mdss_dp_link_clk_src[] = { +- F(162000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(270000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(540000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(810000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), +- { } +-}; +- + static struct clk_rcg2 disp_cc_mdss_dp_link_clk_src = { + .cmd_rcgr = 0x10f8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, +- .freq_tbl = ftbl_disp_cc_mdss_dp_link_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_link_clk_src", + .parent_data = disp_cc_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c +index e17bb8b543b51b..317a7e2b50bfbc 100644 +--- a/drivers/clk/qcom/dispcc-sm8250.c ++++ b/drivers/clk/qcom/dispcc-sm8250.c +@@ -851,6 +851,7 @@ static struct clk_branch disp_cc_mdss_dp_link1_intf_clk = { + &disp_cc_mdss_dp_link1_div_clk_src.clkr.hw, + }, + .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -886,6 +887,7 @@ static struct clk_branch disp_cc_mdss_dp_link_intf_clk = { + &disp_cc_mdss_dp_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -1011,6 +1013,7 @@ static struct clk_branch disp_cc_mdss_mdp_lut_clk = { + &disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -1359,8 +1362,13 @@ static int disp_cc_sm8250_probe(struct platform_device *pdev) + disp_cc_sm8250_clocks[DISP_CC_MDSS_EDP_GTC_CLK_SRC] = NULL; + } + +- clk_lucid_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); +- clk_lucid_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config); ++ if (of_device_is_compatible(pdev->dev.of_node, "qcom,sm8350-dispcc")) { ++ clk_lucid_5lpe_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); ++ clk_lucid_5lpe_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config); ++ } else { ++ clk_lucid_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); ++ clk_lucid_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config); ++ } + + /* Enable clock gating for MDP clocks */ + regmap_update_bits(regmap, 0x8000, 0x10, 0x10); +diff --git a/drivers/clk/qcom/dispcc-sm8450.c b/drivers/clk/qcom/dispcc-sm8450.c +index 2c4aecd75186b0..239cc726c7e296 100644 +--- a/drivers/clk/qcom/dispcc-sm8450.c ++++ b/drivers/clk/qcom/dispcc-sm8450.c +@@ -309,26 +309,17 @@ static struct clk_rcg2 disp_cc_mdss_dptx0_aux_clk_src = { + }, + }; + +-static const struct freq_tbl ftbl_disp_cc_mdss_dptx0_link_clk_src[] = { +- F(162000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(270000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(540000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(810000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- { } +-}; +- + static struct clk_rcg2 disp_cc_mdss_dptx0_link_clk_src = { + .cmd_rcgr = 0x819c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +@@ -382,13 +373,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_link_clk_src = { + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +@@ -442,13 +432,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx2_link_clk_src = { + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +@@ -502,13 +491,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx3_link_clk_src = { + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +diff --git a/drivers/clk/qcom/dispcc-sm8550.c b/drivers/clk/qcom/dispcc-sm8550.c +index aefa19f3c2c514..95b4c0548f50d6 100644 +--- a/drivers/clk/qcom/dispcc-sm8550.c ++++ b/drivers/clk/qcom/dispcc-sm8550.c +@@ -81,6 +81,10 @@ static const struct alpha_pll_config disp_cc_pll0_config = { + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, ++ .test_ctl_val = 0x00000000, ++ .test_ctl_hi_val = 0x00000003, ++ .test_ctl_hi1_val = 0x00009000, ++ .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, + }; +@@ -108,6 +112,10 @@ static const struct alpha_pll_config disp_cc_pll1_config = { + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, ++ .test_ctl_val = 0x00000000, ++ .test_ctl_hi_val = 0x00000003, ++ .test_ctl_hi1_val = 0x00009000, ++ .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, + }; +@@ -188,7 +196,7 @@ static const struct clk_parent_data disp_cc_parent_data_3[] = { + static const struct parent_map disp_cc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_DP0_PHY_PLL_LINK_CLK, 1 }, +- { P_DP1_PHY_PLL_VCO_DIV_CLK, 2 }, ++ { P_DP0_PHY_PLL_VCO_DIV_CLK, 2 }, + { P_DP3_PHY_PLL_VCO_DIV_CLK, 3 }, + { P_DP1_PHY_PLL_VCO_DIV_CLK, 4 }, + { P_DP2_PHY_PLL_VCO_DIV_CLK, 6 }, +@@ -205,7 +213,7 @@ static const struct clk_parent_data disp_cc_parent_data_4[] = { + + static const struct parent_map disp_cc_parent_map_5[] = { + { P_BI_TCXO, 0 }, +- { P_DSI0_PHY_PLL_OUT_BYTECLK, 4 }, ++ { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 4 }, + }; + +@@ -337,26 +345,17 @@ static struct clk_rcg2 disp_cc_mdss_dptx0_aux_clk_src = { + }, + }; + +-static const struct freq_tbl ftbl_disp_cc_mdss_dptx0_link_clk_src[] = { +- F(162000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(270000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(540000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- F(810000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0), +- { } +-}; +- + static struct clk_rcg2 disp_cc_mdss_dptx0_link_clk_src = { + .cmd_rcgr = 0x8170, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_7, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx0_link_clk_src", + .parent_data = disp_cc_parent_data_7, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +@@ -401,7 +400,7 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_aux_clk_src = { + .parent_data = disp_cc_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_dp_ops, ++ .ops = &clk_rcg2_ops, + }, + }; + +@@ -410,13 +409,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_link_clk_src = { + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +@@ -470,13 +468,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx2_link_clk_src = { + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx2_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +@@ -530,13 +527,12 @@ static struct clk_rcg2 disp_cc_mdss_dptx3_link_clk_src = { + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, +- .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src, + .clkr.hw.init = &(struct clk_init_data) { + .name = "disp_cc_mdss_dptx3_link_clk_src", + .parent_data = disp_cc_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_byte2_ops, + }, + }; + +@@ -566,7 +562,7 @@ static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = { + .parent_data = disp_cc_parent_data_5, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -581,7 +577,7 @@ static struct clk_rcg2 disp_cc_mdss_esc1_clk_src = { + .parent_data = disp_cc_parent_data_5, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -1615,7 +1611,7 @@ static struct gdsc mdss_gdsc = { + .name = "mdss_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = HW_CTRL | RETAIN_FF_ENABLE, ++ .flags = POLL_CFG_GDSCR | HW_CTRL | RETAIN_FF_ENABLE, + }; + + static struct gdsc mdss_int2_gdsc = { +@@ -1624,7 +1620,7 @@ static struct gdsc mdss_int2_gdsc = { + .name = "mdss_int2_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = HW_CTRL | RETAIN_FF_ENABLE, ++ .flags = POLL_CFG_GDSCR | HW_CTRL | RETAIN_FF_ENABLE, + }; + + static struct clk_regmap *disp_cc_sm8550_clocks[] = { +diff --git a/drivers/clk/qcom/gcc-ipq5018.c b/drivers/clk/qcom/gcc-ipq5018.c +index 19dc2b71cacf00..3136ba1c2a59cc 100644 +--- a/drivers/clk/qcom/gcc-ipq5018.c ++++ b/drivers/clk/qcom/gcc-ipq5018.c +@@ -128,7 +128,6 @@ static struct clk_alpha_pll_postdiv gpll0 = { + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -143,7 +142,6 @@ static struct clk_alpha_pll_postdiv gpll2 = { + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -158,7 +156,6 @@ static struct clk_alpha_pll_postdiv gpll4 = { + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -859,6 +856,7 @@ static struct clk_rcg2 lpass_sway_clk_src = { + + static const struct freq_tbl ftbl_pcie0_aux_clk_src[] = { + F(2000000, P_XO, 12, 0, 0), ++ { } + }; + + static struct clk_rcg2 pcie0_aux_clk_src = { +@@ -1101,6 +1099,7 @@ static const struct freq_tbl ftbl_qpic_io_macro_clk_src[] = { + F(100000000, P_GPLL0, 8, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + F(320000000, P_GPLL0, 2.5, 0, 0), ++ { } + }; + + static struct clk_rcg2 qpic_io_macro_clk_src = { +@@ -1196,6 +1195,7 @@ static struct clk_rcg2 ubi0_axi_clk_src = { + static const struct freq_tbl ftbl_ubi0_core_clk_src[] = { + F(850000000, P_UBI32_PLL, 1, 0, 0), + F(1000000000, P_UBI32_PLL, 1, 0, 0), ++ { } + }; + + static struct clk_rcg2 ubi0_core_clk_src = { +@@ -1756,7 +1756,7 @@ static struct clk_branch gcc_gmac0_sys_clk = { + .halt_check = BRANCH_HALT_DELAY, + .halt_bit = 31, + .clkr = { +- .enable_reg = 0x683190, ++ .enable_reg = 0x68190, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_gmac0_sys_clk", +@@ -2182,7 +2182,7 @@ static struct clk_branch gcc_pcie1_axi_s_clk = { + }; + + static struct clk_branch gcc_pcie1_pipe_clk = { +- .halt_reg = 8, ++ .halt_reg = 0x76018, + .halt_check = BRANCH_HALT_DELAY, + .halt_bit = 31, + .clkr = { +@@ -3634,7 +3634,7 @@ static const struct qcom_reset_map gcc_ipq5018_resets[] = { + [GCC_SYSTEM_NOC_BCR] = { 0x26000, 0 }, + [GCC_TCSR_BCR] = { 0x28000, 0 }, + [GCC_TLMM_BCR] = { 0x34000, 0 }, +- [GCC_UBI0_AXI_ARES] = { 0x680}, ++ [GCC_UBI0_AXI_ARES] = { 0x68010, 0 }, + [GCC_UBI0_AHB_ARES] = { 0x68010, 1 }, + [GCC_UBI0_NC_AXI_ARES] = { 0x68010, 2 }, + [GCC_UBI0_DBG_ARES] = { 0x68010, 3 }, +diff --git a/drivers/clk/qcom/gcc-ipq5332.c b/drivers/clk/qcom/gcc-ipq5332.c +index b02026f8549b2f..6a4877d8882946 100644 +--- a/drivers/clk/qcom/gcc-ipq5332.c ++++ b/drivers/clk/qcom/gcc-ipq5332.c +@@ -71,7 +71,6 @@ static struct clk_fixed_factor gpll0_div2 = { + &gpll0_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -85,7 +84,6 @@ static struct clk_alpha_pll_postdiv gpll0 = { + &gpll0_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -114,7 +112,6 @@ static struct clk_alpha_pll_postdiv gpll2 = { + &gpll2_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -154,7 +151,6 @@ static struct clk_alpha_pll_postdiv gpll4 = { + &gpll4_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -3392,6 +3388,7 @@ static struct clk_regmap *gcc_ipq5332_clocks[] = { + [GCC_QDSS_DAP_DIV_CLK_SRC] = &gcc_qdss_dap_div_clk_src.clkr, + [GCC_QDSS_ETR_USB_CLK] = &gcc_qdss_etr_usb_clk.clkr, + [GCC_QDSS_EUD_AT_CLK] = &gcc_qdss_eud_at_clk.clkr, ++ [GCC_QDSS_TSCTR_CLK_SRC] = &gcc_qdss_tsctr_clk_src.clkr, + [GCC_QPIC_AHB_CLK] = &gcc_qpic_ahb_clk.clkr, + [GCC_QPIC_CLK] = &gcc_qpic_clk.clkr, + [GCC_QPIC_IO_MACRO_CLK] = &gcc_qpic_io_macro_clk.clkr, +diff --git a/drivers/clk/qcom/gcc-ipq6018.c b/drivers/clk/qcom/gcc-ipq6018.c +index 6120fbbc5de053..2e4189e770d3ff 100644 +--- a/drivers/clk/qcom/gcc-ipq6018.c ++++ b/drivers/clk/qcom/gcc-ipq6018.c +@@ -72,7 +72,6 @@ static struct clk_fixed_factor gpll0_out_main_div2 = { + &gpll0_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -86,7 +85,6 @@ static struct clk_alpha_pll_postdiv gpll0 = { + &gpll0_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -161,7 +159,6 @@ static struct clk_alpha_pll_postdiv gpll6 = { + &gpll6_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -192,7 +189,6 @@ static struct clk_alpha_pll_postdiv gpll4 = { + &gpll4_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -243,7 +239,6 @@ static struct clk_alpha_pll_postdiv gpll2 = { + &gpll2_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -274,7 +269,6 @@ static struct clk_alpha_pll_postdiv nss_crypto_pll = { + &nss_crypto_pll_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -1560,6 +1554,7 @@ static struct clk_regmap_div nss_ubi0_div_clk_src = { + + static const struct freq_tbl ftbl_pcie_aux_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), ++ { } + }; + + static const struct clk_parent_data gcc_xo_gpll0_core_pi_sleep_clk[] = { +@@ -1740,6 +1735,7 @@ static const struct freq_tbl ftbl_sdcc_ice_core_clk_src[] = { + F(160000000, P_GPLL0, 5, 0, 0), + F(216000000, P_GPLL6, 5, 0, 0), + F(308570000, P_GPLL6, 3.5, 0, 0), ++ { } + }; + + static const struct clk_parent_data gcc_xo_gpll0_gpll6_gpll0_div2[] = { +diff --git a/drivers/clk/qcom/gcc-ipq8074.c b/drivers/clk/qcom/gcc-ipq8074.c +index 63ac2ced76bb95..7bc679871f324f 100644 +--- a/drivers/clk/qcom/gcc-ipq8074.c ++++ b/drivers/clk/qcom/gcc-ipq8074.c +@@ -75,7 +75,6 @@ static struct clk_fixed_factor gpll0_out_main_div2 = { + &gpll0_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -121,7 +120,6 @@ static struct clk_alpha_pll_postdiv gpll2 = { + &gpll2_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -154,7 +152,6 @@ static struct clk_alpha_pll_postdiv gpll4 = { + &gpll4_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -188,7 +185,6 @@ static struct clk_alpha_pll_postdiv gpll6 = { + &gpll6_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -201,7 +197,6 @@ static struct clk_fixed_factor gpll6_out_main_div2 = { + &gpll6_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -266,7 +261,6 @@ static struct clk_alpha_pll_postdiv nss_crypto_pll = { + &nss_crypto_pll_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, +- .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -650,6 +644,7 @@ static struct clk_rcg2 pcie0_axi_clk_src = { + + static const struct freq_tbl ftbl_pcie_aux_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), ++ { } + }; + + static const struct clk_parent_data gcc_xo_gpll0_sleep_clk[] = { +@@ -801,6 +796,7 @@ static const struct freq_tbl ftbl_sdcc_ice_core_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + F(308570000, P_GPLL6, 3.5, 0, 0), ++ { } + }; + + static const struct clk_parent_data gcc_xo_gpll0_gpll6_gpll0_div2[] = { +diff --git a/drivers/clk/qcom/gcc-ipq9574.c b/drivers/clk/qcom/gcc-ipq9574.c +index 8f430367299e66..cdbbf2cc9c5d19 100644 +--- a/drivers/clk/qcom/gcc-ipq9574.c ++++ b/drivers/clk/qcom/gcc-ipq9574.c +@@ -65,7 +65,7 @@ static const struct clk_parent_data gcc_sleep_clk_data[] = { + + static struct clk_alpha_pll gpll0_main = { + .offset = 0x20000, +- .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], ++ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO], + .clkr = { + .enable_reg = 0x0b000, + .enable_mask = BIT(0), +@@ -87,14 +87,13 @@ static struct clk_fixed_factor gpll0_out_main_div2 = { + &gpll0_main.clkr.hw + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, + }; + + static struct clk_alpha_pll_postdiv gpll0 = { + .offset = 0x20000, +- .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], ++ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO], + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gpll0", +@@ -102,14 +101,13 @@ static struct clk_alpha_pll_postdiv gpll0 = { + &gpll0_main.clkr.hw + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_ro_ops, + }, + }; + + static struct clk_alpha_pll gpll4_main = { + .offset = 0x22000, +- .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], ++ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO], + .clkr = { + .enable_reg = 0x0b000, + .enable_mask = BIT(2), +@@ -124,7 +122,7 @@ static struct clk_alpha_pll gpll4_main = { + + static struct clk_alpha_pll_postdiv gpll4 = { + .offset = 0x22000, +- .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], ++ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO], + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gpll4", +@@ -132,14 +130,13 @@ static struct clk_alpha_pll_postdiv gpll4 = { + &gpll4_main.clkr.hw + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_ro_ops, + }, + }; + + static struct clk_alpha_pll gpll2_main = { + .offset = 0x21000, +- .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], ++ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO], + .clkr = { + .enable_reg = 0x0b000, + .enable_mask = BIT(1), +@@ -154,7 +151,7 @@ static struct clk_alpha_pll gpll2_main = { + + static struct clk_alpha_pll_postdiv gpll2 = { + .offset = 0x21000, +- .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], ++ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO], + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gpll2", +@@ -162,7 +159,6 @@ static struct clk_alpha_pll_postdiv gpll2 = { + &gpll2_main.clkr.hw + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_ro_ops, + }, + }; +@@ -2086,6 +2082,7 @@ static struct clk_branch gcc_sdcc1_apps_clk = { + static const struct freq_tbl ftbl_sdcc_ice_core_clk_src[] = { + F(150000000, P_GPLL4, 8, 0, 0), + F(300000000, P_GPLL4, 4, 0, 0), ++ { } + }; + + static struct clk_rcg2 sdcc1_ice_core_clk_src = { +@@ -2143,9 +2140,10 @@ static struct clk_rcg2 pcnoc_bfdcd_clk_src = { + + static struct clk_branch gcc_crypto_axi_clk = { + .halt_reg = 0x16010, ++ .halt_check = BRANCH_HALT_VOTED, + .clkr = { +- .enable_reg = 0x16010, +- .enable_mask = BIT(0), ++ .enable_reg = 0xb004, ++ .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_crypto_axi_clk", + .parent_hws = (const struct clk_hw *[]) { +@@ -2159,9 +2157,10 @@ static struct clk_branch gcc_crypto_axi_clk = { + + static struct clk_branch gcc_crypto_ahb_clk = { + .halt_reg = 0x16014, ++ .halt_check = BRANCH_HALT_VOTED, + .clkr = { +- .enable_reg = 0x16014, +- .enable_mask = BIT(0), ++ .enable_reg = 0xb004, ++ .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_crypto_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { +diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c +index 14dcc3f036683c..e7b03a17514a5d 100644 +--- a/drivers/clk/qcom/gcc-msm8996.c ++++ b/drivers/clk/qcom/gcc-msm8996.c +@@ -244,71 +244,6 @@ static const struct clk_parent_data gcc_xo_gpll0_gpll4_gpll0_early_div[] = { + { .hw = &gpll0_early_div.hw } + }; + +-static const struct freq_tbl ftbl_system_noc_clk_src[] = { +- F(19200000, P_XO, 1, 0, 0), +- F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0), +- F(100000000, P_GPLL0, 6, 0, 0), +- F(150000000, P_GPLL0, 4, 0, 0), +- F(200000000, P_GPLL0, 3, 0, 0), +- F(240000000, P_GPLL0, 2.5, 0, 0), +- { } +-}; +- +-static struct clk_rcg2 system_noc_clk_src = { +- .cmd_rcgr = 0x0401c, +- .hid_width = 5, +- .parent_map = gcc_xo_gpll0_gpll0_early_div_map, +- .freq_tbl = ftbl_system_noc_clk_src, +- .clkr.hw.init = &(struct clk_init_data){ +- .name = "system_noc_clk_src", +- .parent_data = gcc_xo_gpll0_gpll0_early_div, +- .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_early_div), +- .ops = &clk_rcg2_ops, +- }, +-}; +- +-static const struct freq_tbl ftbl_config_noc_clk_src[] = { +- F(19200000, P_XO, 1, 0, 0), +- F(37500000, P_GPLL0, 16, 0, 0), +- F(75000000, P_GPLL0, 8, 0, 0), +- { } +-}; +- +-static struct clk_rcg2 config_noc_clk_src = { +- .cmd_rcgr = 0x0500c, +- .hid_width = 5, +- .parent_map = gcc_xo_gpll0_map, +- .freq_tbl = ftbl_config_noc_clk_src, +- .clkr.hw.init = &(struct clk_init_data){ +- .name = "config_noc_clk_src", +- .parent_data = gcc_xo_gpll0, +- .num_parents = ARRAY_SIZE(gcc_xo_gpll0), +- .ops = &clk_rcg2_ops, +- }, +-}; +- +-static const struct freq_tbl ftbl_periph_noc_clk_src[] = { +- F(19200000, P_XO, 1, 0, 0), +- F(37500000, P_GPLL0, 16, 0, 0), +- F(50000000, P_GPLL0, 12, 0, 0), +- F(75000000, P_GPLL0, 8, 0, 0), +- F(100000000, P_GPLL0, 6, 0, 0), +- { } +-}; +- +-static struct clk_rcg2 periph_noc_clk_src = { +- .cmd_rcgr = 0x06014, +- .hid_width = 5, +- .parent_map = gcc_xo_gpll0_map, +- .freq_tbl = ftbl_periph_noc_clk_src, +- .clkr.hw.init = &(struct clk_init_data){ +- .name = "periph_noc_clk_src", +- .parent_data = gcc_xo_gpll0, +- .num_parents = ARRAY_SIZE(gcc_xo_gpll0), +- .ops = &clk_rcg2_ops, +- }, +-}; +- + static const struct freq_tbl ftbl_usb30_master_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(120000000, P_GPLL0, 5, 0, 0), +@@ -1297,11 +1232,7 @@ static struct clk_branch gcc_mmss_noc_cfg_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mmss_noc_cfg_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &config_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, ++ .flags = CLK_IGNORE_UNUSED, + .ops = &clk_branch2_ops, + }, + }, +@@ -1464,11 +1395,6 @@ static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb_phy_cfg_ahb2phy_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &periph_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -1498,11 +1424,6 @@ static struct clk_branch gcc_sdcc1_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &periph_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -1549,11 +1470,6 @@ static struct clk_branch gcc_sdcc2_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc2_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &periph_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -1583,11 +1499,6 @@ static struct clk_branch gcc_sdcc3_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc3_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &periph_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -1617,11 +1528,6 @@ static struct clk_branch gcc_sdcc4_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc4_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &periph_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -1635,11 +1541,6 @@ static struct clk_branch gcc_blsp1_ahb_clk = { + .enable_mask = BIT(17), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &periph_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -1977,11 +1878,6 @@ static struct clk_branch gcc_blsp2_ahb_clk = { + .enable_mask = BIT(15), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp2_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &periph_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -2318,11 +2214,6 @@ static struct clk_branch gcc_pdm_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &periph_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -2353,11 +2244,6 @@ static struct clk_branch gcc_prng_ahb_clk = { + .enable_mask = BIT(13), + .hw.init = &(struct clk_init_data){ + .name = "gcc_prng_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &config_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -2370,11 +2256,6 @@ static struct clk_branch gcc_tsif_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_tsif_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &periph_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -2422,11 +2303,6 @@ static struct clk_branch gcc_boot_rom_ahb_clk = { + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "gcc_boot_rom_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &config_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -2520,11 +2396,6 @@ static struct clk_branch gcc_pcie_0_slv_axi_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_slv_axi_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &system_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -2537,11 +2408,6 @@ static struct clk_branch gcc_pcie_0_mstr_axi_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_mstr_axi_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &system_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -2554,11 +2420,6 @@ static struct clk_branch gcc_pcie_0_cfg_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_cfg_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &config_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -2606,11 +2467,6 @@ static struct clk_branch gcc_pcie_1_slv_axi_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_1_slv_axi_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &system_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -2623,11 +2479,6 @@ static struct clk_branch gcc_pcie_1_mstr_axi_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_1_mstr_axi_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &system_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -2640,11 +2491,6 @@ static struct clk_branch gcc_pcie_1_cfg_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_1_cfg_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &config_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -2692,11 +2538,6 @@ static struct clk_branch gcc_pcie_2_slv_axi_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_2_slv_axi_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &system_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -2709,11 +2550,6 @@ static struct clk_branch gcc_pcie_2_mstr_axi_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_2_mstr_axi_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &system_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -2726,11 +2562,6 @@ static struct clk_branch gcc_pcie_2_cfg_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_2_cfg_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &config_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -2778,11 +2609,6 @@ static struct clk_branch gcc_pcie_phy_cfg_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_phy_cfg_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &config_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -2829,11 +2655,6 @@ static struct clk_branch gcc_ufs_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &config_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -3060,11 +2881,7 @@ static struct clk_branch gcc_aggre0_snoc_axi_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre0_snoc_axi_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &system_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +@@ -3077,11 +2894,7 @@ static struct clk_branch gcc_aggre0_cnoc_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre0_cnoc_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &config_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +@@ -3094,11 +2907,7 @@ static struct clk_branch gcc_smmu_aggre0_axi_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_smmu_aggre0_axi_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &system_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +@@ -3111,11 +2920,7 @@ static struct clk_branch gcc_smmu_aggre0_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_smmu_aggre0_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &config_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +@@ -3162,10 +2967,6 @@ static struct clk_branch gcc_dcc_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_dcc_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &config_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +@@ -3178,10 +2979,6 @@ static struct clk_branch gcc_aggre0_noc_mpu_cfg_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre0_noc_mpu_cfg_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &config_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +@@ -3194,11 +2991,6 @@ static struct clk_branch gcc_qspi_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qspi_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &periph_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -3347,10 +3139,6 @@ static struct clk_branch gcc_mss_cfg_ahb_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mss_cfg_ahb_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &config_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +@@ -3363,10 +3151,6 @@ static struct clk_branch gcc_mss_mnoc_bimc_axi_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mss_mnoc_bimc_axi_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &system_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +@@ -3379,10 +3163,6 @@ static struct clk_branch gcc_mss_snoc_axi_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mss_snoc_axi_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &system_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +@@ -3395,10 +3175,6 @@ static struct clk_branch gcc_mss_q6_bimc_axi_clk = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mss_q6_bimc_axi_clk", +- .parent_hws = (const struct clk_hw*[]){ +- &system_noc_clk_src.clkr.hw, +- }, +- .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +@@ -3495,9 +3271,6 @@ static struct clk_regmap *gcc_msm8996_clocks[] = { + [GPLL0] = &gpll0.clkr, + [GPLL4_EARLY] = &gpll4_early.clkr, + [GPLL4] = &gpll4.clkr, +- [SYSTEM_NOC_CLK_SRC] = &system_noc_clk_src.clkr, +- [CONFIG_NOC_CLK_SRC] = &config_noc_clk_src.clkr, +- [PERIPH_NOC_CLK_SRC] = &periph_noc_clk_src.clkr, + [USB30_MASTER_CLK_SRC] = &usb30_master_clk_src.clkr, + [USB30_MOCK_UTMI_CLK_SRC] = &usb30_mock_utmi_clk_src.clkr, + [USB3_PHY_AUX_CLK_SRC] = &usb3_phy_aux_clk_src.clkr, +diff --git a/drivers/clk/qcom/gcc-sa8775p.c b/drivers/clk/qcom/gcc-sa8775p.c +index 8171d23c96e64d..a54438205698cd 100644 +--- a/drivers/clk/qcom/gcc-sa8775p.c ++++ b/drivers/clk/qcom/gcc-sa8775p.c +@@ -4305,74 +4305,114 @@ static struct clk_branch gcc_video_axi1_clk = { + + static struct gdsc pcie_0_gdsc = { + .gdscr = 0xa9004, ++ .collapse_ctrl = 0x4b104, ++ .collapse_mask = BIT(0), ++ .en_rest_wait_val = 0x2, ++ .en_few_wait_val = 0x2, ++ .clk_dis_wait_val = 0xf, + .pd = { + .name = "pcie_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE | RETAIN_FF_ENABLE | POLL_CFG_GDSCR, + }; + + static struct gdsc pcie_1_gdsc = { + .gdscr = 0x77004, ++ .collapse_ctrl = 0x4b104, ++ .collapse_mask = BIT(1), ++ .en_rest_wait_val = 0x2, ++ .en_few_wait_val = 0x2, ++ .clk_dis_wait_val = 0xf, + .pd = { + .name = "pcie_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE | RETAIN_FF_ENABLE | POLL_CFG_GDSCR, + }; + + static struct gdsc ufs_card_gdsc = { + .gdscr = 0x81004, ++ .en_rest_wait_val = 0x2, ++ .en_few_wait_val = 0x2, ++ .clk_dis_wait_val = 0xf, + .pd = { + .name = "ufs_card_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR, + }; + + static struct gdsc ufs_phy_gdsc = { + .gdscr = 0x83004, ++ .en_rest_wait_val = 0x2, ++ .en_few_wait_val = 0x2, ++ .clk_dis_wait_val = 0xf, + .pd = { + .name = "ufs_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR, + }; + + static struct gdsc usb20_prim_gdsc = { + .gdscr = 0x1c004, ++ .en_rest_wait_val = 0x2, ++ .en_few_wait_val = 0x2, ++ .clk_dis_wait_val = 0xf, + .pd = { + .name = "usb20_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR, + }; + + static struct gdsc usb30_prim_gdsc = { + .gdscr = 0x1b004, ++ .en_rest_wait_val = 0x2, ++ .en_few_wait_val = 0x2, ++ .clk_dis_wait_val = 0xf, + .pd = { + .name = "usb30_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR, + }; + + static struct gdsc usb30_sec_gdsc = { + .gdscr = 0x2f004, ++ .en_rest_wait_val = 0x2, ++ .en_few_wait_val = 0x2, ++ .clk_dis_wait_val = 0xf, + .pd = { + .name = "usb30_sec_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR, + }; + + static struct gdsc emac0_gdsc = { + .gdscr = 0xb6004, ++ .en_rest_wait_val = 0x2, ++ .en_few_wait_val = 0x2, ++ .clk_dis_wait_val = 0xf, + .pd = { + .name = "emac0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR, + }; + + static struct gdsc emac1_gdsc = { + .gdscr = 0xb4004, ++ .en_rest_wait_val = 0x2, ++ .en_few_wait_val = 0x2, ++ .clk_dis_wait_val = 0xf, + .pd = { + .name = "emac1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR, + }; + + static struct clk_regmap *gcc_sa8775p_clocks[] = { +diff --git a/drivers/clk/qcom/gcc-sc7280.c b/drivers/clk/qcom/gcc-sc7280.c +index 2b661df5de2660..bc81026292fc9b 100644 +--- a/drivers/clk/qcom/gcc-sc7280.c ++++ b/drivers/clk/qcom/gcc-sc7280.c +@@ -3467,6 +3467,9 @@ static int gcc_sc7280_probe(struct platform_device *pdev) + regmap_update_bits(regmap, 0x71004, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x7100C, BIT(13), BIT(13)); + ++ /* FORCE_MEM_CORE_ON for ufs phy ice core clocks */ ++ qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_ice_core_clk, true); ++ + ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks, + ARRAY_SIZE(gcc_dfs_clocks)); + if (ret) +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index ae21473815596d..ec0c45881c67a7 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -142,6 +142,23 @@ static struct clk_alpha_pll gpll7 = { + }, + }; + ++static struct clk_alpha_pll gpll9 = { ++ .offset = 0x1c000, ++ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TRION], ++ .clkr = { ++ .enable_reg = 0x52000, ++ .enable_mask = BIT(9), ++ .hw.init = &(const struct clk_init_data) { ++ .name = "gpll9", ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "bi_tcxo", ++ }, ++ .num_parents = 1, ++ .ops = &clk_alpha_pll_fixed_trion_ops, ++ }, ++ }, ++}; ++ + static const struct parent_map gcc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, +@@ -241,7 +258,7 @@ static const struct parent_map gcc_parent_map_7[] = { + static const struct clk_parent_data gcc_parents_7[] = { + { .fw_name = "bi_tcxo", }, + { .hw = &gpll0.clkr.hw }, +- { .name = "gppl9" }, ++ { .hw = &gpll9.clkr.hw }, + { .hw = &gpll4.clkr.hw }, + { .hw = &gpll0_out_even.clkr.hw }, + }; +@@ -260,28 +277,6 @@ static const struct clk_parent_data gcc_parents_8[] = { + { .hw = &gpll0_out_even.clkr.hw }, + }; + +-static const struct freq_tbl ftbl_gcc_cpuss_ahb_clk_src[] = { +- F(19200000, P_BI_TCXO, 1, 0, 0), +- F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), +- F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), +- { } +-}; +- +-static struct clk_rcg2 gcc_cpuss_ahb_clk_src = { +- .cmd_rcgr = 0x48014, +- .mnd_width = 0, +- .hid_width = 5, +- .parent_map = gcc_parent_map_0, +- .freq_tbl = ftbl_gcc_cpuss_ahb_clk_src, +- .clkr.hw.init = &(struct clk_init_data){ +- .name = "gcc_cpuss_ahb_clk_src", +- .parent_data = gcc_parents_0, +- .num_parents = ARRAY_SIZE(gcc_parents_0), +- .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, +- }, +-}; +- + static const struct freq_tbl ftbl_gcc_emac_ptp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), +@@ -916,7 +911,7 @@ static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(25000000, P_GPLL0_OUT_MAIN, 12, 1, 2), + F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), +- F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), ++ F(202000000, P_GPLL9_OUT_MAIN, 4, 0, 0), + { } + }; + +@@ -939,9 +934,8 @@ static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), +- F(37500000, P_GPLL0_OUT_MAIN, 16, 0, 0), + F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), +- F(75000000, P_GPLL0_OUT_MAIN, 8, 0, 0), ++ F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + { } + }; + +@@ -1599,25 +1593,6 @@ static struct clk_branch gcc_cfg_noc_usb3_sec_axi_clk = { + }, + }; + +-/* For CPUSS functionality the AHB clock needs to be left enabled */ +-static struct clk_branch gcc_cpuss_ahb_clk = { +- .halt_reg = 0x48000, +- .halt_check = BRANCH_HALT_VOTED, +- .clkr = { +- .enable_reg = 0x52004, +- .enable_mask = BIT(21), +- .hw.init = &(struct clk_init_data){ +- .name = "gcc_cpuss_ahb_clk", +- .parent_hws = (const struct clk_hw *[]){ +- &gcc_cpuss_ahb_clk_src.clkr.hw +- }, +- .num_parents = 1, +- .flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, +- .ops = &clk_branch2_ops, +- }, +- }, +-}; +- + static struct clk_branch gcc_cpuss_rbcpr_clk = { + .halt_reg = 0x48008, + .halt_check = BRANCH_HALT, +@@ -3150,25 +3125,6 @@ static struct clk_branch gcc_sdcc4_apps_clk = { + }, + }; + +-/* For CPUSS functionality the SYS NOC clock needs to be left enabled */ +-static struct clk_branch gcc_sys_noc_cpuss_ahb_clk = { +- .halt_reg = 0x4819c, +- .halt_check = BRANCH_HALT_VOTED, +- .clkr = { +- .enable_reg = 0x52004, +- .enable_mask = BIT(0), +- .hw.init = &(struct clk_init_data){ +- .name = "gcc_sys_noc_cpuss_ahb_clk", +- .parent_hws = (const struct clk_hw *[]){ +- &gcc_cpuss_ahb_clk_src.clkr.hw +- }, +- .num_parents = 1, +- .flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, +- .ops = &clk_branch2_ops, +- }, +- }, +-}; +- + static struct clk_branch gcc_tsif_ahb_clk = { + .halt_reg = 0x36004, + .halt_check = BRANCH_HALT, +@@ -4258,8 +4214,6 @@ static struct clk_regmap *gcc_sc8180x_clocks[] = { + [GCC_CFG_NOC_USB3_MP_AXI_CLK] = &gcc_cfg_noc_usb3_mp_axi_clk.clkr, + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr, + [GCC_CFG_NOC_USB3_SEC_AXI_CLK] = &gcc_cfg_noc_usb3_sec_axi_clk.clkr, +- [GCC_CPUSS_AHB_CLK] = &gcc_cpuss_ahb_clk.clkr, +- [GCC_CPUSS_AHB_CLK_SRC] = &gcc_cpuss_ahb_clk_src.clkr, + [GCC_CPUSS_RBCPR_CLK] = &gcc_cpuss_rbcpr_clk.clkr, + [GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr, + [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr, +@@ -4396,7 +4350,6 @@ static struct clk_regmap *gcc_sc8180x_clocks[] = { + [GCC_SDCC4_AHB_CLK] = &gcc_sdcc4_ahb_clk.clkr, + [GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr, + [GCC_SDCC4_APPS_CLK_SRC] = &gcc_sdcc4_apps_clk_src.clkr, +- [GCC_SYS_NOC_CPUSS_AHB_CLK] = &gcc_sys_noc_cpuss_ahb_clk.clkr, + [GCC_TSIF_AHB_CLK] = &gcc_tsif_ahb_clk.clkr, + [GCC_TSIF_INACTIVITY_TIMERS_CLK] = &gcc_tsif_inactivity_timers_clk.clkr, + [GCC_TSIF_REF_CLK] = &gcc_tsif_ref_clk.clkr, +@@ -4483,6 +4436,7 @@ static struct clk_regmap *gcc_sc8180x_clocks[] = { + [GPLL1] = &gpll1.clkr, + [GPLL4] = &gpll4.clkr, + [GPLL7] = &gpll7.clkr, ++ [GPLL9] = &gpll9.clkr, + }; + + static const struct qcom_reset_map gcc_sc8180x_resets[] = { +diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c +index 725cd52d2398ed..ea4c3bf4fb9bf7 100644 +--- a/drivers/clk/qcom/gcc-sdm845.c ++++ b/drivers/clk/qcom/gcc-sdm845.c +@@ -4037,3 +4037,4 @@ module_exit(gcc_sdm845_exit); + MODULE_DESCRIPTION("QTI GCC SDM845 Driver"); + MODULE_LICENSE("GPL v2"); + MODULE_ALIAS("platform:gcc-sdm845"); ++MODULE_SOFTDEP("pre: rpmhpd"); +diff --git a/drivers/clk/qcom/gcc-sm6350.c b/drivers/clk/qcom/gcc-sm6350.c +index cf4a7b6e0b23ad..0559a33faf00e6 100644 +--- a/drivers/clk/qcom/gcc-sm6350.c ++++ b/drivers/clk/qcom/gcc-sm6350.c +@@ -100,8 +100,8 @@ static struct clk_alpha_pll gpll6 = { + .enable_mask = BIT(6), + .hw.init = &(struct clk_init_data){ + .name = "gpll6", +- .parent_hws = (const struct clk_hw*[]){ +- &gpll0.clkr.hw, ++ .parent_data = &(const struct clk_parent_data){ ++ .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_fabia_ops, +@@ -124,7 +124,7 @@ static struct clk_alpha_pll_postdiv gpll6_out_even = { + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll6_out_even", + .parent_hws = (const struct clk_hw*[]){ +- &gpll0.clkr.hw, ++ &gpll6.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_fabia_ops, +@@ -139,8 +139,8 @@ static struct clk_alpha_pll gpll7 = { + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "gpll7", +- .parent_hws = (const struct clk_hw*[]){ +- &gpll0.clkr.hw, ++ .parent_data = &(const struct clk_parent_data){ ++ .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_fabia_ops, +diff --git a/drivers/clk/qcom/gcc-sm8150.c b/drivers/clk/qcom/gcc-sm8150.c +index 41ab210875fb24..05d115c52dfebb 100644 +--- a/drivers/clk/qcom/gcc-sm8150.c ++++ b/drivers/clk/qcom/gcc-sm8150.c +@@ -774,7 +774,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parents_6, + .num_parents = ARRAY_SIZE(gcc_parents_6), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_OPS_PARENT_ENABLE, + .ops = &clk_rcg2_floor_ops, + }, + }; +diff --git a/drivers/clk/qcom/gcc-sm8250.c b/drivers/clk/qcom/gcc-sm8250.c +index c6c5261264f118..272da807c6945d 100644 +--- a/drivers/clk/qcom/gcc-sm8250.c ++++ b/drivers/clk/qcom/gcc-sm8250.c +@@ -3226,7 +3226,7 @@ static struct gdsc pcie_0_gdsc = { + .pd = { + .name = "pcie_0_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + }; + + static struct gdsc pcie_1_gdsc = { +@@ -3234,7 +3234,7 @@ static struct gdsc pcie_1_gdsc = { + .pd = { + .name = "pcie_1_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + }; + + static struct gdsc pcie_2_gdsc = { +@@ -3242,7 +3242,7 @@ static struct gdsc pcie_2_gdsc = { + .pd = { + .name = "pcie_2_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + }; + + static struct gdsc ufs_card_gdsc = { +diff --git a/drivers/clk/qcom/gcc-sm8450.c b/drivers/clk/qcom/gcc-sm8450.c +index 56354298255160..4c55df89ddca7d 100644 +--- a/drivers/clk/qcom/gcc-sm8450.c ++++ b/drivers/clk/qcom/gcc-sm8450.c +@@ -2974,7 +2974,7 @@ static struct gdsc pcie_0_gdsc = { + .pd = { + .name = "pcie_0_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + }; + + static struct gdsc pcie_1_gdsc = { +@@ -2982,7 +2982,7 @@ static struct gdsc pcie_1_gdsc = { + .pd = { + .name = "pcie_1_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + }; + + static struct gdsc ufs_phy_gdsc = { +diff --git a/drivers/clk/qcom/gcc-sm8550.c b/drivers/clk/qcom/gcc-sm8550.c +index 586126c4dd907c..eb3765c57b6502 100644 +--- a/drivers/clk/qcom/gcc-sm8550.c ++++ b/drivers/clk/qcom/gcc-sm8550.c +@@ -401,7 +401,7 @@ static struct clk_rcg2 gcc_gp1_clk_src = { + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -416,7 +416,7 @@ static struct clk_rcg2 gcc_gp2_clk_src = { + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -431,7 +431,7 @@ static struct clk_rcg2 gcc_gp3_clk_src = { + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -451,7 +451,7 @@ static struct clk_rcg2 gcc_pcie_0_aux_clk_src = { + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -471,7 +471,7 @@ static struct clk_rcg2 gcc_pcie_0_phy_rchng_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_shared_ops, + }, + }; + +@@ -486,7 +486,7 @@ static struct clk_rcg2 gcc_pcie_1_aux_clk_src = { + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -501,7 +501,7 @@ static struct clk_rcg2 gcc_pcie_1_phy_rchng_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_shared_ops, + }, + }; + +@@ -521,7 +521,7 @@ static struct clk_rcg2 gcc_pdm2_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_shared_ops, + }, + }; + +@@ -1025,7 +1025,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -1048,7 +1048,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_shared_ops, + }, + }; + +@@ -1071,7 +1071,7 @@ static struct clk_rcg2 gcc_ufs_phy_axi_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_shared_ops, + }, + }; + +@@ -1093,7 +1093,7 @@ static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = { + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -1114,7 +1114,7 @@ static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = { + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -1136,7 +1136,7 @@ static struct clk_rcg2 gcc_ufs_phy_unipro_core_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_shared_ops, + }, + }; + +@@ -1159,7 +1159,7 @@ static struct clk_rcg2 gcc_usb30_prim_master_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_shared_no_init_park_ops, + }, + }; + +@@ -1174,7 +1174,7 @@ static struct clk_rcg2 gcc_usb30_prim_mock_utmi_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_shared_ops, + }, + }; + +@@ -1189,7 +1189,7 @@ static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = { + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -2998,38 +2998,46 @@ static struct clk_branch gcc_video_axi1_clk = { + + static struct gdsc pcie_0_gdsc = { + .gdscr = 0x6b004, ++ .collapse_ctrl = 0x52020, ++ .collapse_mask = BIT(0), + .pd = { + .name = "pcie_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = POLL_CFG_GDSCR, ++ .flags = VOTABLE | POLL_CFG_GDSCR | RETAIN_FF_ENABLE, + }; + + static struct gdsc pcie_0_phy_gdsc = { + .gdscr = 0x6c000, ++ .collapse_ctrl = 0x52020, ++ .collapse_mask = BIT(3), + .pd = { + .name = "pcie_0_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = POLL_CFG_GDSCR, ++ .flags = VOTABLE | POLL_CFG_GDSCR | RETAIN_FF_ENABLE, + }; + + static struct gdsc pcie_1_gdsc = { + .gdscr = 0x8d004, ++ .collapse_ctrl = 0x52020, ++ .collapse_mask = BIT(1), + .pd = { + .name = "pcie_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = POLL_CFG_GDSCR, ++ .flags = VOTABLE | POLL_CFG_GDSCR | RETAIN_FF_ENABLE, + }; + + static struct gdsc pcie_1_phy_gdsc = { + .gdscr = 0x8e000, ++ .collapse_ctrl = 0x52020, ++ .collapse_mask = BIT(4), + .pd = { + .name = "pcie_1_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = POLL_CFG_GDSCR, ++ .flags = VOTABLE | POLL_CFG_GDSCR | RETAIN_FF_ENABLE, + }; + + static struct gdsc ufs_phy_gdsc = { +@@ -3038,7 +3046,7 @@ static struct gdsc ufs_phy_gdsc = { + .name = "ufs_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = POLL_CFG_GDSCR, ++ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, + }; + + static struct gdsc ufs_mem_phy_gdsc = { +@@ -3047,7 +3055,7 @@ static struct gdsc ufs_mem_phy_gdsc = { + .name = "ufs_mem_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = POLL_CFG_GDSCR, ++ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, + }; + + static struct gdsc usb30_prim_gdsc = { +@@ -3056,7 +3064,7 @@ static struct gdsc usb30_prim_gdsc = { + .name = "usb30_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = POLL_CFG_GDSCR, ++ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, + }; + + static struct gdsc usb3_phy_gdsc = { +@@ -3065,7 +3073,7 @@ static struct gdsc usb3_phy_gdsc = { + .name = "usb3_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = POLL_CFG_GDSCR, ++ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, + }; + + static struct clk_regmap *gcc_sm8550_clocks[] = { +diff --git a/drivers/clk/qcom/gpucc-sa8775p.c b/drivers/clk/qcom/gpucc-sa8775p.c +index 26ecfa63be1939..0d9a8379efaa83 100644 +--- a/drivers/clk/qcom/gpucc-sa8775p.c ++++ b/drivers/clk/qcom/gpucc-sa8775p.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0-only + /* +- * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) 2021-2022, 2024, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ + +@@ -161,7 +161,7 @@ static struct clk_rcg2 gpu_cc_ff_clk_src = { + .name = "gpu_cc_ff_clk_src", + .parent_data = gpu_cc_parent_data_0, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0), +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -181,7 +181,7 @@ static struct clk_rcg2 gpu_cc_gmu_clk_src = { + .parent_data = gpu_cc_parent_data_1, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -200,7 +200,7 @@ static struct clk_rcg2 gpu_cc_hub_clk_src = { + .name = "gpu_cc_hub_clk_src", + .parent_data = gpu_cc_parent_data_2, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_2), +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -280,7 +280,7 @@ static struct clk_branch gpu_cc_ahb_clk = { + &gpu_cc_hub_ahb_div_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -294,8 +294,7 @@ static struct clk_branch gpu_cc_cb_clk = { + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_cb_clk", +- .flags = CLK_IS_CRITICAL, +- .ops = &clk_branch2_ops, ++ .ops = &clk_branch2_aon_ops, + }, + }, + }; +@@ -312,7 +311,7 @@ static struct clk_branch gpu_cc_crc_ahb_clk = { + &gpu_cc_hub_ahb_div_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -330,7 +329,7 @@ static struct clk_branch gpu_cc_cx_ff_clk = { + &gpu_cc_ff_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -348,7 +347,7 @@ static struct clk_branch gpu_cc_cx_gmu_clk = { + &gpu_cc_gmu_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_aon_ops, + }, + }, +@@ -362,7 +361,6 @@ static struct clk_branch gpu_cc_cx_snoc_dvm_clk = { + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_cx_snoc_dvm_clk", +- .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +@@ -380,7 +378,7 @@ static struct clk_branch gpu_cc_cxo_aon_clk = { + &gpu_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -398,7 +396,7 @@ static struct clk_branch gpu_cc_cxo_clk = { + &gpu_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +@@ -416,7 +414,7 @@ static struct clk_branch gpu_cc_demet_clk = { + &gpu_cc_demet_div_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_aon_ops, + }, + }, +@@ -430,7 +428,6 @@ static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = { + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_hlos1_vote_gpu_smmu_clk", +- .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +@@ -448,7 +445,7 @@ static struct clk_branch gpu_cc_hub_aon_clk = { + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_aon_ops, + }, + }, +@@ -466,7 +463,7 @@ static struct clk_branch gpu_cc_hub_cx_int_clk = { + &gpu_cc_hub_cx_int_div_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_aon_ops, + }, + }, +@@ -480,7 +477,6 @@ static struct clk_branch gpu_cc_memnoc_gfx_clk = { + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_memnoc_gfx_clk", +- .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +@@ -494,7 +490,6 @@ static struct clk_branch gpu_cc_sleep_clk = { + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_sleep_clk", +- .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +@@ -528,16 +523,22 @@ static struct clk_regmap *gpu_cc_sa8775p_clocks[] = { + + static struct gdsc cx_gdsc = { + .gdscr = 0x9108, ++ .en_rest_wait_val = 0x2, ++ .en_few_wait_val = 0x2, ++ .clk_dis_wait_val = 0xf, + .gds_hw_ctrl = 0x953c, + .pd = { + .name = "cx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = VOTABLE | RETAIN_FF_ENABLE | ALWAYS_ON, ++ .flags = VOTABLE | RETAIN_FF_ENABLE, + }; + + static struct gdsc gx_gdsc = { + .gdscr = 0x905c, ++ .en_rest_wait_val = 0x2, ++ .en_few_wait_val = 0x2, ++ .clk_dis_wait_val = 0xf, + .pd = { + .name = "gx_gdsc", + .power_on = gdsc_gx_do_nothing_enable, +diff --git a/drivers/clk/qcom/gpucc-sm8150.c b/drivers/clk/qcom/gpucc-sm8150.c +index 8422fd0474932d..c89a5b59ddb7c2 100644 +--- a/drivers/clk/qcom/gpucc-sm8150.c ++++ b/drivers/clk/qcom/gpucc-sm8150.c +@@ -37,8 +37,8 @@ static struct alpha_pll_config gpu_cc_pll1_config = { + .config_ctl_hi_val = 0x00002267, + .config_ctl_hi1_val = 0x00000024, + .test_ctl_val = 0x00000000, +- .test_ctl_hi_val = 0x00000002, +- .test_ctl_hi1_val = 0x00000000, ++ .test_ctl_hi_val = 0x00000000, ++ .test_ctl_hi1_val = 0x00000020, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x000000d0, +diff --git a/drivers/clk/qcom/gpucc-sm8350.c b/drivers/clk/qcom/gpucc-sm8350.c +index 8dc54dff983f3a..33c4fb8891caa3 100644 +--- a/drivers/clk/qcom/gpucc-sm8350.c ++++ b/drivers/clk/qcom/gpucc-sm8350.c +@@ -2,6 +2,7 @@ + /* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Linaro Limited ++ * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #include +@@ -147,7 +148,7 @@ static struct clk_rcg2 gpu_cc_gmu_clk_src = { + .parent_data = gpu_cc_parent_data_0, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +@@ -169,7 +170,7 @@ static struct clk_rcg2 gpu_cc_hub_clk_src = { + .parent_data = gpu_cc_parent_data_1, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +diff --git a/drivers/clk/qcom/kpss-xcc.c b/drivers/clk/qcom/kpss-xcc.c +index 97358c98c6c98e..d8c1f2b41eeb39 100644 +--- a/drivers/clk/qcom/kpss-xcc.c ++++ b/drivers/clk/qcom/kpss-xcc.c +@@ -63,9 +63,7 @@ static int kpss_xcc_driver_probe(struct platform_device *pdev) + if (IS_ERR(hw)) + return PTR_ERR(hw); + +- of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get, hw); +- +- return 0; ++ return of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get, hw); + } + + static struct platform_driver kpss_xcc_driver = { +diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c +index 02fc21208dd14b..c89700ab93f9c6 100644 +--- a/drivers/clk/qcom/mmcc-apq8084.c ++++ b/drivers/clk/qcom/mmcc-apq8084.c +@@ -348,6 +348,7 @@ static struct freq_tbl ftbl_mmss_axi_clk[] = { + F(333430000, P_MMPLL1, 3.5, 0, 0), + F(400000000, P_MMPLL0, 2, 0, 0), + F(466800000, P_MMPLL1, 2.5, 0, 0), ++ { } + }; + + static struct clk_rcg2 mmss_axi_clk_src = { +@@ -372,6 +373,7 @@ static struct freq_tbl ftbl_ocmemnoc_clk[] = { + F(150000000, P_GPLL0, 4, 0, 0), + F(228570000, P_MMPLL0, 3.5, 0, 0), + F(320000000, P_MMPLL0, 2.5, 0, 0), ++ { } + }; + + static struct clk_rcg2 ocmemnoc_clk_src = { +diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c +index 1f3bd302fe6ed4..6df22a67f02d3e 100644 +--- a/drivers/clk/qcom/mmcc-msm8974.c ++++ b/drivers/clk/qcom/mmcc-msm8974.c +@@ -290,6 +290,7 @@ static struct freq_tbl ftbl_mmss_axi_clk[] = { + F(291750000, P_MMPLL1, 4, 0, 0), + F(400000000, P_MMPLL0, 2, 0, 0), + F(466800000, P_MMPLL1, 2.5, 0, 0), ++ { } + }; + + static struct clk_rcg2 mmss_axi_clk_src = { +@@ -314,6 +315,7 @@ static struct freq_tbl ftbl_ocmemnoc_clk[] = { + F(150000000, P_GPLL0, 4, 0, 0), + F(291750000, P_MMPLL1, 4, 0, 0), + F(400000000, P_MMPLL0, 2, 0, 0), ++ { } + }; + + static struct clk_rcg2 ocmemnoc_clk_src = { +diff --git a/drivers/clk/qcom/mmcc-msm8998.c b/drivers/clk/qcom/mmcc-msm8998.c +index a023c4374be96a..275fb3b71ede4c 100644 +--- a/drivers/clk/qcom/mmcc-msm8998.c ++++ b/drivers/clk/qcom/mmcc-msm8998.c +@@ -2439,6 +2439,7 @@ static struct clk_branch fd_ahb_clk = { + + static struct clk_branch mnoc_ahb_clk = { + .halt_reg = 0x5024, ++ .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x5024, + .enable_mask = BIT(0), +@@ -2454,6 +2455,7 @@ static struct clk_branch mnoc_ahb_clk = { + + static struct clk_branch bimc_smmu_ahb_clk = { + .halt_reg = 0xe004, ++ .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0xe004, + .hwcg_bit = 1, + .clkr = { +@@ -2471,6 +2473,7 @@ static struct clk_branch bimc_smmu_ahb_clk = { + + static struct clk_branch bimc_smmu_axi_clk = { + .halt_reg = 0xe008, ++ .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0xe008, + .hwcg_bit = 1, + .clkr = { +@@ -2532,6 +2535,8 @@ static struct clk_branch vmem_ahb_clk = { + + static struct gdsc video_top_gdsc = { + .gdscr = 0x1024, ++ .cxcs = (unsigned int []){ 0x1028, 0x1034, 0x1038 }, ++ .cxc_count = 3, + .pd = { + .name = "video_top", + }, +@@ -2540,20 +2545,26 @@ static struct gdsc video_top_gdsc = { + + static struct gdsc video_subcore0_gdsc = { + .gdscr = 0x1040, ++ .cxcs = (unsigned int []){ 0x1048 }, ++ .cxc_count = 1, + .pd = { + .name = "video_subcore0", + }, + .parent = &video_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = HW_CTRL, + }; + + static struct gdsc video_subcore1_gdsc = { + .gdscr = 0x1044, ++ .cxcs = (unsigned int []){ 0x104c }, ++ .cxc_count = 1, + .pd = { + .name = "video_subcore1", + }, + .parent = &video_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, ++ .flags = HW_CTRL, + }; + + static struct gdsc mdss_gdsc = { +@@ -2607,11 +2618,13 @@ static struct gdsc camss_cpp_gdsc = { + static struct gdsc bimc_smmu_gdsc = { + .gdscr = 0xe020, + .gds_hw_ctrl = 0xe024, ++ .cxcs = (unsigned int []){ 0xe008 }, ++ .cxc_count = 1, + .pd = { + .name = "bimc_smmu", + }, + .pwrsts = PWRSTS_OFF_ON, +- .flags = HW_CTRL | ALWAYS_ON, ++ .flags = VOTABLE, + }; + + static struct clk_regmap *mmcc_msm8998_clocks[] = { +diff --git a/drivers/clk/qcom/reset.c b/drivers/clk/qcom/reset.c +index e45e32804d2c75..d96c96a9089f40 100644 +--- a/drivers/clk/qcom/reset.c ++++ b/drivers/clk/qcom/reset.c +@@ -22,8 +22,8 @@ static int qcom_reset(struct reset_controller_dev *rcdev, unsigned long id) + return 0; + } + +-static int +-qcom_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) ++static int qcom_reset_set_assert(struct reset_controller_dev *rcdev, ++ unsigned long id, bool assert) + { + struct qcom_reset_controller *rst; + const struct qcom_reset_map *map; +@@ -33,21 +33,22 @@ qcom_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) + map = &rst->reset_map[id]; + mask = map->bitmask ? map->bitmask : BIT(map->bit); + +- return regmap_update_bits(rst->regmap, map->reg, mask, mask); ++ regmap_update_bits(rst->regmap, map->reg, mask, assert ? mask : 0); ++ ++ /* Read back the register to ensure write completion, ignore the value */ ++ regmap_read(rst->regmap, map->reg, &mask); ++ ++ return 0; + } + +-static int +-qcom_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) ++static int qcom_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) + { +- struct qcom_reset_controller *rst; +- const struct qcom_reset_map *map; +- u32 mask; +- +- rst = to_qcom_reset_controller(rcdev); +- map = &rst->reset_map[id]; +- mask = map->bitmask ? map->bitmask : BIT(map->bit); ++ return qcom_reset_set_assert(rcdev, id, true); ++} + +- return regmap_update_bits(rst->regmap, map->reg, mask, 0); ++static int qcom_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) ++{ ++ return qcom_reset_set_assert(rcdev, id, false); + } + + const struct reset_control_ops qcom_reset_ops = { +diff --git a/drivers/clk/qcom/videocc-sm8150.c b/drivers/clk/qcom/videocc-sm8150.c +index 1afdbe4a249d62..52a9a453a14326 100644 +--- a/drivers/clk/qcom/videocc-sm8150.c ++++ b/drivers/clk/qcom/videocc-sm8150.c +@@ -33,6 +33,7 @@ static struct alpha_pll_config video_pll0_config = { + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002267, + .config_ctl_hi1_val = 0x00000024, ++ .test_ctl_hi1_val = 0x00000020, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x000000D0, +@@ -214,6 +215,10 @@ static const struct regmap_config video_cc_sm8150_regmap_config = { + + static const struct qcom_reset_map video_cc_sm8150_resets[] = { + [VIDEO_CC_MVSC_CORE_CLK_BCR] = { 0x850, 2 }, ++ [VIDEO_CC_INTERFACE_BCR] = { 0x8f0 }, ++ [VIDEO_CC_MVS0_BCR] = { 0x870 }, ++ [VIDEO_CC_MVS1_BCR] = { 0x8b0 }, ++ [VIDEO_CC_MVSC_BCR] = { 0x810 }, + }; + + static const struct qcom_cc_desc video_cc_sm8150_desc = { +diff --git a/drivers/clk/ralink/clk-mtmips.c b/drivers/clk/ralink/clk-mtmips.c +index 1e7991439527a8..50a443bf79ecd3 100644 +--- a/drivers/clk/ralink/clk-mtmips.c ++++ b/drivers/clk/ralink/clk-mtmips.c +@@ -821,6 +821,10 @@ static const struct mtmips_clk_data mt76x8_clk_data = { + }; + + static const struct of_device_id mtmips_of_match[] = { ++ { ++ .compatible = "ralink,rt2880-reset", ++ .data = NULL, ++ }, + { + .compatible = "ralink,rt2880-sysc", + .data = &rt2880_clk_data, +@@ -1088,25 +1092,11 @@ static int mtmips_clk_probe(struct platform_device *pdev) + return 0; + } + +-static const struct of_device_id mtmips_clk_of_match[] = { +- { .compatible = "ralink,rt2880-reset" }, +- { .compatible = "ralink,rt2880-sysc" }, +- { .compatible = "ralink,rt3050-sysc" }, +- { .compatible = "ralink,rt3052-sysc" }, +- { .compatible = "ralink,rt3352-sysc" }, +- { .compatible = "ralink,rt3883-sysc" }, +- { .compatible = "ralink,rt5350-sysc" }, +- { .compatible = "ralink,mt7620-sysc" }, +- { .compatible = "ralink,mt7628-sysc" }, +- { .compatible = "ralink,mt7688-sysc" }, +- {} +-}; +- + static struct platform_driver mtmips_clk_driver = { + .probe = mtmips_clk_probe, + .driver = { + .name = "mtmips-clk", +- .of_match_table = mtmips_clk_of_match, ++ .of_match_table = mtmips_of_match, + }, + }; + +diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c +index 4c2872f45387ff..ff3f85e906fe17 100644 +--- a/drivers/clk/renesas/r8a779a0-cpg-mssr.c ++++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c +@@ -139,7 +139,7 @@ static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = { + DEF_MOD("avb3", 214, R8A779A0_CLK_S3D2), + DEF_MOD("avb4", 215, R8A779A0_CLK_S3D2), + DEF_MOD("avb5", 216, R8A779A0_CLK_S3D2), +- DEF_MOD("canfd0", 328, R8A779A0_CLK_CANFD), ++ DEF_MOD("canfd0", 328, R8A779A0_CLK_S3D2), + DEF_MOD("csi40", 331, R8A779A0_CLK_CSI0), + DEF_MOD("csi41", 400, R8A779A0_CLK_CSI0), + DEF_MOD("csi42", 401, R8A779A0_CLK_CSI0), +diff --git a/drivers/clk/renesas/r8a779f0-cpg-mssr.c b/drivers/clk/renesas/r8a779f0-cpg-mssr.c +index f721835c7e2124..cc06127406ab57 100644 +--- a/drivers/clk/renesas/r8a779f0-cpg-mssr.c ++++ b/drivers/clk/renesas/r8a779f0-cpg-mssr.c +@@ -161,7 +161,7 @@ static const struct mssr_mod_clk r8a779f0_mod_clks[] __initconst = { + DEF_MOD("cmt1", 911, R8A779F0_CLK_R), + DEF_MOD("cmt2", 912, R8A779F0_CLK_R), + DEF_MOD("cmt3", 913, R8A779F0_CLK_R), +- DEF_MOD("pfc0", 915, R8A779F0_CLK_CL16M), ++ DEF_MOD("pfc0", 915, R8A779F0_CLK_CPEX), + DEF_MOD("tsc", 919, R8A779F0_CLK_CL16M), + DEF_MOD("rswitch2", 1505, R8A779F0_CLK_RSW2), + DEF_MOD("ether-serdes", 1506, R8A779F0_CLK_S0D2_HSC), +diff --git a/drivers/clk/renesas/r8a779g0-cpg-mssr.c b/drivers/clk/renesas/r8a779g0-cpg-mssr.c +index 7cc580d6736261..7999faa9a921be 100644 +--- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c ++++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c +@@ -22,7 +22,7 @@ + + enum clk_ids { + /* Core Clock Outputs exported to DT */ +- LAST_DT_CORE_CLK = R8A779G0_CLK_R, ++ LAST_DT_CORE_CLK = R8A779G0_CLK_CP, + + /* External Input Clocks */ + CLK_EXTAL, +@@ -141,6 +141,7 @@ static const struct cpg_core_clk r8a779g0_core_clks[] __initconst = { + DEF_FIXED("svd2_vip", R8A779G0_CLK_SVD2_VIP, CLK_SV_VIP, 2, 1), + DEF_FIXED("cbfusa", R8A779G0_CLK_CBFUSA, CLK_EXTAL, 2, 1), + DEF_FIXED("cpex", R8A779G0_CLK_CPEX, CLK_EXTAL, 2, 1), ++ DEF_FIXED("cp", R8A779G0_CLK_CP, CLK_EXTAL, 2, 1), + DEF_FIXED("viobus", R8A779G0_CLK_VIOBUS, CLK_VIO, 1, 1), + DEF_FIXED("viobusd2", R8A779G0_CLK_VIOBUSD2, CLK_VIO, 2, 1), + DEF_FIXED("vcbus", R8A779G0_CLK_VCBUS, CLK_VC, 1, 1), +@@ -230,10 +231,10 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = { + DEF_MOD("cmt1", 911, R8A779G0_CLK_R), + DEF_MOD("cmt2", 912, R8A779G0_CLK_R), + DEF_MOD("cmt3", 913, R8A779G0_CLK_R), +- DEF_MOD("pfc0", 915, R8A779G0_CLK_CL16M), +- DEF_MOD("pfc1", 916, R8A779G0_CLK_CL16M), +- DEF_MOD("pfc2", 917, R8A779G0_CLK_CL16M), +- DEF_MOD("pfc3", 918, R8A779G0_CLK_CL16M), ++ DEF_MOD("pfc0", 915, R8A779G0_CLK_CP), ++ DEF_MOD("pfc1", 916, R8A779G0_CLK_CP), ++ DEF_MOD("pfc2", 917, R8A779G0_CLK_CP), ++ DEF_MOD("pfc3", 918, R8A779G0_CLK_CP), + DEF_MOD("tsc", 919, R8A779G0_CLK_CL16M), + DEF_MOD("ssiu", 2926, R8A779G0_CLK_S0D6_PER), + DEF_MOD("ssi", 2927, R8A779G0_CLK_S0D6_PER), +diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c +index 1a7a6d60aca44b..6c6bc79b2e9cec 100644 +--- a/drivers/clk/renesas/r9a07g043-cpg.c ++++ b/drivers/clk/renesas/r9a07g043-cpg.c +@@ -250,6 +250,10 @@ static struct rzg2l_mod_clk r9a07g043_mod_clks[] = { + 0x5a8, 1), + DEF_MOD("tsu_pclk", R9A07G043_TSU_PCLK, R9A07G043_CLK_TSU, + 0x5ac, 0), ++#ifdef CONFIG_RISCV ++ DEF_MOD("nceplic_aclk", R9A07G043_NCEPLIC_ACLK, R9A07G043_CLK_P1, ++ 0x608, 0), ++#endif + }; + + static struct rzg2l_reset r9a07g043_resets[] = { +@@ -303,6 +307,10 @@ static struct rzg2l_reset r9a07g043_resets[] = { + DEF_RST(R9A07G043_ADC_PRESETN, 0x8a8, 0), + DEF_RST(R9A07G043_ADC_ADRST_N, 0x8a8, 1), + DEF_RST(R9A07G043_TSU_PRESETN, 0x8ac, 0), ++#ifdef CONFIG_RISCV ++ DEF_RST(R9A07G043_NCEPLIC_ARESETN, 0x908, 0), ++#endif ++ + }; + + static const unsigned int r9a07g043_crit_mod_clks[] __initconst = { +@@ -312,6 +320,7 @@ static const unsigned int r9a07g043_crit_mod_clks[] __initconst = { + #endif + #ifdef CONFIG_RISCV + MOD_CLK_BASE + R9A07G043_IAX45_CLK, ++ MOD_CLK_BASE + R9A07G043_NCEPLIC_ACLK, + #endif + MOD_CLK_BASE + R9A07G043_DMAC_ACLK, + }; +diff --git a/drivers/clk/renesas/rcar-cpg-lib.c b/drivers/clk/renesas/rcar-cpg-lib.c +index e2e0447de1901d..5a15f8788b9227 100644 +--- a/drivers/clk/renesas/rcar-cpg-lib.c ++++ b/drivers/clk/renesas/rcar-cpg-lib.c +@@ -70,8 +70,21 @@ void cpg_simple_notifier_register(struct raw_notifier_head *notifiers, + #define STPnHCK BIT(9 - SDnSRCFC_SHIFT) + + static const struct clk_div_table cpg_sdh_div_table[] = { ++ /* ++ * These values are recommended by the datasheet. Because they come ++ * first, Linux will only use these. ++ */ + { 0, 1 }, { 1, 2 }, { STPnHCK | 2, 4 }, { STPnHCK | 3, 8 }, +- { STPnHCK | 4, 16 }, { 0, 0 }, ++ { STPnHCK | 4, 16 }, ++ /* ++ * These values are not recommended because STPnHCK is wrong. But they ++ * have been seen because of broken firmware. So, we support reading ++ * them but Linux will sanitize them when initializing through ++ * recalc_rate. ++ */ ++ { STPnHCK | 0, 1 }, { STPnHCK | 1, 2 }, { 2, 4 }, { 3, 8 }, { 4, 16 }, ++ /* Sentinel */ ++ { 0, 0 } + }; + + struct clk * __init cpg_sdh_clk_register(const char *name, +diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c +index 47f488387f33a1..75f9eca020ce57 100644 +--- a/drivers/clk/renesas/rzg2l-cpg.c ++++ b/drivers/clk/renesas/rzg2l-cpg.c +@@ -11,6 +11,7 @@ + * Copyright (C) 2015 Renesas Electronics Corp. + */ + ++#include + #include + #include + #include +@@ -38,14 +39,13 @@ + #define WARN_DEBUG(x) do { } while (0) + #endif + +-#define DIV_RSMASK(v, s, m) ((v >> s) & m) + #define GET_SHIFT(val) ((val >> 12) & 0xff) + #define GET_WIDTH(val) ((val >> 8) & 0xf) + +-#define KDIV(val) DIV_RSMASK(val, 16, 0xffff) +-#define MDIV(val) DIV_RSMASK(val, 6, 0x3ff) +-#define PDIV(val) DIV_RSMASK(val, 0, 0x3f) +-#define SDIV(val) DIV_RSMASK(val, 0, 0x7) ++#define KDIV(val) ((s16)FIELD_GET(GENMASK(31, 16), val)) ++#define MDIV(val) FIELD_GET(GENMASK(15, 6), val) ++#define PDIV(val) FIELD_GET(GENMASK(5, 0), val) ++#define SDIV(val) FIELD_GET(GENMASK(2, 0), val) + + #define CLK_ON_R(reg) (reg) + #define CLK_MON_R(reg) (0x180 + (reg)) +@@ -188,7 +188,9 @@ static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) + u32 off = GET_REG_OFFSET(hwdata->conf); + u32 shift = GET_SHIFT(hwdata->conf); + const u32 clk_src_266 = 2; +- u32 bitmask; ++ u32 msk, val, bitmask; ++ unsigned long flags; ++ int ret; + + /* + * As per the HW manual, we should not directly switch from 533 MHz to +@@ -202,26 +204,30 @@ static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) + * the index to value mapping is done by adding 1 to the index. + */ + bitmask = (GENMASK(GET_WIDTH(hwdata->conf) - 1, 0) << shift) << 16; ++ msk = off ? CPG_CLKSTATUS_SELSDHI1_STS : CPG_CLKSTATUS_SELSDHI0_STS; ++ spin_lock_irqsave(&priv->rmw_lock, flags); + if (index != clk_src_266) { +- u32 msk, val; +- int ret; +- + writel(bitmask | ((clk_src_266 + 1) << shift), priv->base + off); + +- msk = off ? CPG_CLKSTATUS_SELSDHI1_STS : CPG_CLKSTATUS_SELSDHI0_STS; +- +- ret = readl_poll_timeout(priv->base + CPG_CLKSTATUS, val, +- !(val & msk), 100, +- CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); +- if (ret) { +- dev_err(priv->dev, "failed to switch clk source\n"); +- return ret; +- } ++ ret = readl_poll_timeout_atomic(priv->base + CPG_CLKSTATUS, val, ++ !(val & msk), 10, ++ CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); ++ if (ret) ++ goto unlock; + } + + writel(bitmask | ((index + 1) << shift), priv->base + off); + +- return 0; ++ ret = readl_poll_timeout_atomic(priv->base + CPG_CLKSTATUS, val, ++ !(val & msk), 10, ++ CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); ++unlock: ++ spin_unlock_irqrestore(&priv->rmw_lock, flags); ++ ++ if (ret) ++ dev_err(priv->dev, "failed to switch clk source\n"); ++ ++ return ret; + } + + static u8 rzg2l_cpg_sd_clk_mux_get_parent(struct clk_hw *hw) +@@ -232,14 +238,8 @@ static u8 rzg2l_cpg_sd_clk_mux_get_parent(struct clk_hw *hw) + + val >>= GET_SHIFT(hwdata->conf); + val &= GENMASK(GET_WIDTH(hwdata->conf) - 1, 0); +- if (val) { +- val--; +- } else { +- /* Prohibited clk source, change it to 533 MHz(reset value) */ +- rzg2l_cpg_sd_clk_mux_set_parent(hw, 0); +- } + +- return val; ++ return val ? val - 1 : 0; + } + + static const struct clk_ops rzg2l_cpg_sd_clk_mux_ops = { +@@ -695,18 +695,18 @@ static unsigned long rzg2l_cpg_pll_clk_recalc_rate(struct clk_hw *hw, + struct pll_clk *pll_clk = to_pll(hw); + struct rzg2l_cpg_priv *priv = pll_clk->priv; + unsigned int val1, val2; +- unsigned int mult = 1; +- unsigned int div = 1; ++ u64 rate; + + if (pll_clk->type != CLK_TYPE_SAM_PLL) + return parent_rate; + + val1 = readl(priv->base + GET_REG_SAMPLL_CLK1(pll_clk->conf)); + val2 = readl(priv->base + GET_REG_SAMPLL_CLK2(pll_clk->conf)); +- mult = MDIV(val1) + KDIV(val1) / 65536; +- div = PDIV(val1) << SDIV(val2); + +- return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, div); ++ rate = mul_u64_u32_shr(parent_rate, (MDIV(val1) << 16) + KDIV(val1), ++ 16 + SDIV(val2)); ++ ++ return DIV_ROUND_CLOSEST_ULL(rate, PDIV(val1)); + } + + static const struct clk_ops rzg2l_cpg_pll_ops = { +@@ -1105,41 +1105,33 @@ rzg2l_cpg_register_mod_clk(const struct rzg2l_mod_clk *mod, + + #define rcdev_to_priv(x) container_of(x, struct rzg2l_cpg_priv, rcdev) + +-static int rzg2l_cpg_reset(struct reset_controller_dev *rcdev, +- unsigned long id) +-{ +- struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev); +- const struct rzg2l_cpg_info *info = priv->info; +- unsigned int reg = info->resets[id].off; +- u32 dis = BIT(info->resets[id].bit); +- u32 we = dis << 16; +- +- dev_dbg(rcdev->dev, "reset id:%ld offset:0x%x\n", id, CLK_RST_R(reg)); +- +- /* Reset module */ +- writel(we, priv->base + CLK_RST_R(reg)); +- +- /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ +- udelay(35); +- +- /* Release module from reset state */ +- writel(we | dis, priv->base + CLK_RST_R(reg)); +- +- return 0; +-} +- + static int rzg2l_cpg_assert(struct reset_controller_dev *rcdev, + unsigned long id) + { + struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev); + const struct rzg2l_cpg_info *info = priv->info; + unsigned int reg = info->resets[id].off; +- u32 value = BIT(info->resets[id].bit) << 16; ++ u32 mask = BIT(info->resets[id].bit); ++ s8 monbit = info->resets[id].monbit; ++ u32 value = mask << 16; + + dev_dbg(rcdev->dev, "assert id:%ld offset:0x%x\n", id, CLK_RST_R(reg)); + + writel(value, priv->base + CLK_RST_R(reg)); +- return 0; ++ ++ if (info->has_clk_mon_regs) { ++ reg = CLK_MRST_R(reg); ++ } else if (monbit >= 0) { ++ reg = CPG_RST_MON; ++ mask = BIT(monbit); ++ } else { ++ /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ ++ udelay(35); ++ return 0; ++ } ++ ++ return readl_poll_timeout_atomic(priv->base + reg, value, ++ value & mask, 10, 200); + } + + static int rzg2l_cpg_deassert(struct reset_controller_dev *rcdev, +@@ -1148,14 +1140,40 @@ static int rzg2l_cpg_deassert(struct reset_controller_dev *rcdev, + struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev); + const struct rzg2l_cpg_info *info = priv->info; + unsigned int reg = info->resets[id].off; +- u32 dis = BIT(info->resets[id].bit); +- u32 value = (dis << 16) | dis; ++ u32 mask = BIT(info->resets[id].bit); ++ s8 monbit = info->resets[id].monbit; ++ u32 value = (mask << 16) | mask; + + dev_dbg(rcdev->dev, "deassert id:%ld offset:0x%x\n", id, + CLK_RST_R(reg)); + + writel(value, priv->base + CLK_RST_R(reg)); +- return 0; ++ ++ if (info->has_clk_mon_regs) { ++ reg = CLK_MRST_R(reg); ++ } else if (monbit >= 0) { ++ reg = CPG_RST_MON; ++ mask = BIT(monbit); ++ } else { ++ /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ ++ udelay(35); ++ return 0; ++ } ++ ++ return readl_poll_timeout_atomic(priv->base + reg, value, ++ !(value & mask), 10, 200); ++} ++ ++static int rzg2l_cpg_reset(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ int ret; ++ ++ ret = rzg2l_cpg_assert(rcdev, id); ++ if (ret) ++ return ret; ++ ++ return rzg2l_cpg_deassert(rcdev, id); + } + + static int rzg2l_cpg_status(struct reset_controller_dev *rcdev, +@@ -1163,18 +1181,21 @@ static int rzg2l_cpg_status(struct reset_controller_dev *rcdev, + { + struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev); + const struct rzg2l_cpg_info *info = priv->info; +- unsigned int reg = info->resets[id].off; +- u32 bitmask = BIT(info->resets[id].bit); + s8 monbit = info->resets[id].monbit; ++ unsigned int reg; ++ u32 bitmask; + + if (info->has_clk_mon_regs) { +- return !!(readl(priv->base + CLK_MRST_R(reg)) & bitmask); ++ reg = CLK_MRST_R(info->resets[id].off); ++ bitmask = BIT(info->resets[id].bit); + } else if (monbit >= 0) { +- u32 monbitmask = BIT(monbit); +- +- return !!(readl(priv->base + CPG_RST_MON) & monbitmask); ++ reg = CPG_RST_MON; ++ bitmask = BIT(monbit); ++ } else { ++ return -ENOTSUPP; + } +- return -ENOTSUPP; ++ ++ return !!(readl(priv->base + reg) & bitmask); + } + + static const struct reset_control_ops rzg2l_cpg_reset_ops = { +diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h +index 6cee9e56acc722..91e9c2569f801b 100644 +--- a/drivers/clk/renesas/rzg2l-cpg.h ++++ b/drivers/clk/renesas/rzg2l-cpg.h +@@ -43,7 +43,7 @@ + #define CPG_CLKSTATUS_SELSDHI0_STS BIT(28) + #define CPG_CLKSTATUS_SELSDHI1_STS BIT(29) + +-#define CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US 20000 ++#define CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US 200 + + /* n = 0/1/2 for PLL1/4/6 */ + #define CPG_SAMPLL_CLK1(n) (0x04 + (16 * n)) +diff --git a/drivers/clk/rockchip/clk-rk3128.c b/drivers/clk/rockchip/clk-rk3128.c +index aa53797dbfc145..75071e0cd3216e 100644 +--- a/drivers/clk/rockchip/clk-rk3128.c ++++ b/drivers/clk/rockchip/clk-rk3128.c +@@ -138,7 +138,7 @@ PNAME(mux_pll_src_5plls_p) = { "cpll", "gpll", "gpll_div2", "gpll_div3", "usb480 + PNAME(mux_pll_src_4plls_p) = { "cpll", "gpll", "gpll_div2", "usb480m" }; + PNAME(mux_pll_src_3plls_p) = { "cpll", "gpll", "gpll_div2" }; + +-PNAME(mux_aclk_peri_src_p) = { "gpll_peri", "cpll_peri", "gpll_div2_peri", "gpll_div3_peri" }; ++PNAME(mux_clk_peri_src_p) = { "gpll", "cpll", "gpll_div2", "gpll_div3" }; + PNAME(mux_mmc_src_p) = { "cpll", "gpll", "gpll_div2", "xin24m" }; + PNAME(mux_clk_cif_out_src_p) = { "clk_cif_src", "xin24m" }; + PNAME(mux_sclk_vop_src_p) = { "cpll", "gpll", "gpll_div2", "gpll_div3" }; +@@ -275,23 +275,17 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { + RK2928_CLKGATE_CON(0), 11, GFLAGS), + + /* PD_PERI */ +- GATE(0, "gpll_peri", "gpll", CLK_IGNORE_UNUSED, ++ COMPOSITE(0, "clk_peri_src", mux_clk_peri_src_p, 0, ++ RK2928_CLKSEL_CON(10), 14, 2, MFLAGS, 0, 5, DFLAGS, + RK2928_CLKGATE_CON(2), 0, GFLAGS), +- GATE(0, "cpll_peri", "cpll", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(2), 0, GFLAGS), +- GATE(0, "gpll_div2_peri", "gpll_div2", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(2), 0, GFLAGS), +- GATE(0, "gpll_div3_peri", "gpll_div3", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(2), 0, GFLAGS), +- COMPOSITE_NOGATE(0, "aclk_peri_src", mux_aclk_peri_src_p, 0, +- RK2928_CLKSEL_CON(10), 14, 2, MFLAGS, 0, 5, DFLAGS), +- COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_src", 0, ++ ++ COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "clk_peri_src", 0, + RK2928_CLKSEL_CON(10), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK2928_CLKGATE_CON(2), 3, GFLAGS), +- COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_src", 0, ++ COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "clk_peri_src", 0, + RK2928_CLKSEL_CON(10), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK2928_CLKGATE_CON(2), 2, GFLAGS), +- GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", 0, ++ GATE(ACLK_PERI, "aclk_peri", "clk_peri_src", 0, + RK2928_CLKGATE_CON(2), 1, GFLAGS), + + GATE(SCLK_TIMER0, "sclk_timer0", "xin24m", 0, +@@ -316,7 +310,7 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { + GATE(SCLK_MIPI_24M, "clk_mipi_24m", "xin24m", CLK_IGNORE_UNUSED, + RK2928_CLKGATE_CON(2), 15, GFLAGS), + +- COMPOSITE(SCLK_SDMMC, "sclk_sdmmc0", mux_mmc_src_p, 0, ++ COMPOSITE(SCLK_SDMMC, "sclk_sdmmc", mux_mmc_src_p, 0, + RK2928_CLKSEL_CON(11), 6, 2, MFLAGS, 0, 6, DFLAGS, + RK2928_CLKGATE_CON(2), 11, GFLAGS), + +@@ -490,7 +484,7 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { + GATE(HCLK_I2S_2CH, "hclk_i2s_2ch", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS), + GATE(0, "hclk_usb_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 13, GFLAGS), + GATE(HCLK_HOST2, "hclk_host2", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS), +- GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0, RK2928_CLKGATE_CON(3), 13, GFLAGS), ++ GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 13, GFLAGS), + GATE(0, "hclk_peri_ahb", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 14, GFLAGS), + GATE(HCLK_SPDIF, "hclk_spdif", "hclk_peri", 0, RK2928_CLKGATE_CON(10), 9, GFLAGS), + GATE(HCLK_TSP, "hclk_tsp", "hclk_peri", 0, RK2928_CLKGATE_CON(10), 12, GFLAGS), +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index a24a35553e1349..7343d2d7676bca 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -409,7 +409,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + RK2928_CLKSEL_CON(29), 0, 3, DFLAGS), + DIV(0, "sclk_vop_pre", "sclk_vop_src", 0, + RK2928_CLKSEL_CON(27), 8, 8, DFLAGS), +- MUX(DCLK_VOP, "dclk_vop", mux_dclk_vop_p, 0, ++ MUX(DCLK_VOP, "dclk_vop", mux_dclk_vop_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + RK2928_CLKSEL_CON(27), 1, 1, MFLAGS), + + FACTOR(0, "xin12m", "xin24m", 0, 1, 2), +diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c +index 16dabe2b9c47f4..db713e1526cdc3 100644 +--- a/drivers/clk/rockchip/clk-rk3568.c ++++ b/drivers/clk/rockchip/clk-rk3568.c +@@ -72,6 +72,7 @@ static struct rockchip_pll_rate_table rk3568_pll_rates[] = { + RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0), + RK3036_PLL_RATE(312000000, 1, 78, 6, 1, 1, 0), + RK3036_PLL_RATE(297000000, 2, 99, 4, 1, 1, 0), ++ RK3036_PLL_RATE(292500000, 1, 195, 4, 4, 1, 0), + RK3036_PLL_RATE(241500000, 2, 161, 4, 2, 1, 0), + RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0), + RK3036_PLL_RATE(200000000, 1, 100, 3, 4, 1, 0), +diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c +index 6994165e03957c..d8ffcaefa480b3 100644 +--- a/drivers/clk/rockchip/clk-rk3588.c ++++ b/drivers/clk/rockchip/clk-rk3588.c +@@ -526,7 +526,7 @@ PNAME(pmu_200m_100m_p) = { "clk_pmu1_200m_src", "clk_pmu1_100m_src" }; + PNAME(pmu_300m_24m_p) = { "clk_300m_src", "xin24m" }; + PNAME(pmu_400m_24m_p) = { "clk_400m_src", "xin24m" }; + PNAME(pmu_100m_50m_24m_src_p) = { "clk_pmu1_100m_src", "clk_pmu1_50m_src", "xin24m" }; +-PNAME(pmu_24m_32k_100m_src_p) = { "xin24m", "32k", "clk_pmu1_100m_src" }; ++PNAME(pmu_24m_32k_100m_src_p) = { "xin24m", "xin32k", "clk_pmu1_100m_src" }; + PNAME(hclk_pmu1_root_p) = { "clk_pmu1_200m_src", "clk_pmu1_100m_src", "clk_pmu1_50m_src", "xin24m" }; + PNAME(hclk_pmu_cm0_root_p) = { "clk_pmu1_400m_src", "clk_pmu1_200m_src", "clk_pmu1_100m_src", "xin24m" }; + PNAME(mclk_pdm0_p) = { "clk_pmu1_300m_src", "clk_pmu1_200m_src" }; +diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c +index 4059d9365ae642..b9d6ffcb340912 100644 +--- a/drivers/clk/rockchip/clk.c ++++ b/drivers/clk/rockchip/clk.c +@@ -433,12 +433,13 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, + struct rockchip_clk_branch *list, + unsigned int nr_clk) + { +- struct clk *clk = NULL; ++ struct clk *clk; + unsigned int idx; + unsigned long flags; + + for (idx = 0; idx < nr_clk; idx++, list++) { + flags = list->flags; ++ clk = NULL; + + /* catch simple muxes */ + switch (list->branch_type) { +diff --git a/drivers/clk/samsung/clk-exynos7885.c b/drivers/clk/samsung/clk-exynos7885.c +index f7d7427a558ba0..87387d4cbf48a2 100644 +--- a/drivers/clk/samsung/clk-exynos7885.c ++++ b/drivers/clk/samsung/clk-exynos7885.c +@@ -20,7 +20,7 @@ + #define CLKS_NR_TOP (CLK_GOUT_FSYS_USB30DRD + 1) + #define CLKS_NR_CORE (CLK_GOUT_TREX_P_CORE_PCLK_P_CORE + 1) + #define CLKS_NR_PERI (CLK_GOUT_WDT1_PCLK + 1) +-#define CLKS_NR_FSYS (CLK_GOUT_MMC_SDIO_SDCLKIN + 1) ++#define CLKS_NR_FSYS (CLK_MOUT_FSYS_USB30DRD_USER + 1) + + /* ---- CMU_TOP ------------------------------------------------------------- */ + +diff --git a/drivers/clk/samsung/clk-exynos850.c b/drivers/clk/samsung/clk-exynos850.c +index bdc1eef7d6e548..c7b0b9751307b9 100644 +--- a/drivers/clk/samsung/clk-exynos850.c ++++ b/drivers/clk/samsung/clk-exynos850.c +@@ -605,7 +605,7 @@ static const struct samsung_div_clock apm_div_clks[] __initconst = { + + static const struct samsung_gate_clock apm_gate_clks[] __initconst = { + GATE(CLK_GOUT_CLKCMU_CMGP_BUS, "gout_clkcmu_cmgp_bus", "dout_apm_bus", +- CLK_CON_GAT_CLKCMU_CMGP_BUS, 21, 0, 0), ++ CLK_CON_GAT_CLKCMU_CMGP_BUS, 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_CLKCMU_CHUB_BUS, "gout_clkcmu_chub_bus", + "mout_clkcmu_chub_bus", + CLK_CON_GAT_GATE_CLKCMU_CHUB_BUS, 21, 0, 0), +@@ -974,19 +974,19 @@ static const struct samsung_fixed_rate_clock cmgp_fixed_clks[] __initconst = { + static const struct samsung_mux_clock cmgp_mux_clks[] __initconst = { + MUX(CLK_MOUT_CMGP_ADC, "mout_cmgp_adc", mout_cmgp_adc_p, + CLK_CON_MUX_CLK_CMGP_ADC, 0, 1), +- MUX(CLK_MOUT_CMGP_USI0, "mout_cmgp_usi0", mout_cmgp_usi0_p, +- CLK_CON_MUX_MUX_CLK_CMGP_USI_CMGP0, 0, 1), +- MUX(CLK_MOUT_CMGP_USI1, "mout_cmgp_usi1", mout_cmgp_usi1_p, +- CLK_CON_MUX_MUX_CLK_CMGP_USI_CMGP1, 0, 1), ++ MUX_F(CLK_MOUT_CMGP_USI0, "mout_cmgp_usi0", mout_cmgp_usi0_p, ++ CLK_CON_MUX_MUX_CLK_CMGP_USI_CMGP0, 0, 1, CLK_SET_RATE_PARENT, 0), ++ MUX_F(CLK_MOUT_CMGP_USI1, "mout_cmgp_usi1", mout_cmgp_usi1_p, ++ CLK_CON_MUX_MUX_CLK_CMGP_USI_CMGP1, 0, 1, CLK_SET_RATE_PARENT, 0), + }; + + static const struct samsung_div_clock cmgp_div_clks[] __initconst = { + DIV(CLK_DOUT_CMGP_ADC, "dout_cmgp_adc", "gout_clkcmu_cmgp_bus", + CLK_CON_DIV_DIV_CLK_CMGP_ADC, 0, 4), +- DIV(CLK_DOUT_CMGP_USI0, "dout_cmgp_usi0", "mout_cmgp_usi0", +- CLK_CON_DIV_DIV_CLK_CMGP_USI_CMGP0, 0, 5), +- DIV(CLK_DOUT_CMGP_USI1, "dout_cmgp_usi1", "mout_cmgp_usi1", +- CLK_CON_DIV_DIV_CLK_CMGP_USI_CMGP1, 0, 5), ++ DIV_F(CLK_DOUT_CMGP_USI0, "dout_cmgp_usi0", "mout_cmgp_usi0", ++ CLK_CON_DIV_DIV_CLK_CMGP_USI_CMGP0, 0, 5, CLK_SET_RATE_PARENT, 0), ++ DIV_F(CLK_DOUT_CMGP_USI1, "dout_cmgp_usi1", "mout_cmgp_usi1", ++ CLK_CON_DIV_DIV_CLK_CMGP_USI_CMGP1, 0, 5, CLK_SET_RATE_PARENT, 0), + }; + + static const struct samsung_gate_clock cmgp_gate_clks[] __initconst = { +@@ -1001,12 +1001,12 @@ static const struct samsung_gate_clock cmgp_gate_clks[] __initconst = { + "gout_clkcmu_cmgp_bus", + CLK_CON_GAT_GOUT_CMGP_GPIO_PCLK, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_CMGP_USI0_IPCLK, "gout_cmgp_usi0_ipclk", "dout_cmgp_usi0", +- CLK_CON_GAT_GOUT_CMGP_USI_CMGP0_IPCLK, 21, 0, 0), ++ CLK_CON_GAT_GOUT_CMGP_USI_CMGP0_IPCLK, 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_CMGP_USI0_PCLK, "gout_cmgp_usi0_pclk", + "gout_clkcmu_cmgp_bus", + CLK_CON_GAT_GOUT_CMGP_USI_CMGP0_PCLK, 21, 0, 0), + GATE(CLK_GOUT_CMGP_USI1_IPCLK, "gout_cmgp_usi1_ipclk", "dout_cmgp_usi1", +- CLK_CON_GAT_GOUT_CMGP_USI_CMGP1_IPCLK, 21, 0, 0), ++ CLK_CON_GAT_GOUT_CMGP_USI_CMGP1_IPCLK, 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_CMGP_USI1_PCLK, "gout_cmgp_usi1_pclk", + "gout_clkcmu_cmgp_bus", + CLK_CON_GAT_GOUT_CMGP_USI_CMGP1_PCLK, 21, 0, 0), +@@ -1557,8 +1557,9 @@ static const struct samsung_mux_clock peri_mux_clks[] __initconst = { + mout_peri_uart_user_p, PLL_CON0_MUX_CLKCMU_PERI_UART_USER, 4, 1), + MUX(CLK_MOUT_PERI_HSI2C_USER, "mout_peri_hsi2c_user", + mout_peri_hsi2c_user_p, PLL_CON0_MUX_CLKCMU_PERI_HSI2C_USER, 4, 1), +- MUX(CLK_MOUT_PERI_SPI_USER, "mout_peri_spi_user", mout_peri_spi_user_p, +- PLL_CON0_MUX_CLKCMU_PERI_SPI_USER, 4, 1), ++ MUX_F(CLK_MOUT_PERI_SPI_USER, "mout_peri_spi_user", ++ mout_peri_spi_user_p, PLL_CON0_MUX_CLKCMU_PERI_SPI_USER, 4, 1, ++ CLK_SET_RATE_PARENT, 0), + }; + + static const struct samsung_div_clock peri_div_clks[] __initconst = { +@@ -1568,8 +1569,8 @@ static const struct samsung_div_clock peri_div_clks[] __initconst = { + CLK_CON_DIV_DIV_CLK_PERI_HSI2C_1, 0, 5), + DIV(CLK_DOUT_PERI_HSI2C2, "dout_peri_hsi2c2", "gout_peri_hsi2c2", + CLK_CON_DIV_DIV_CLK_PERI_HSI2C_2, 0, 5), +- DIV(CLK_DOUT_PERI_SPI0, "dout_peri_spi0", "mout_peri_spi_user", +- CLK_CON_DIV_DIV_CLK_PERI_SPI_0, 0, 5), ++ DIV_F(CLK_DOUT_PERI_SPI0, "dout_peri_spi0", "mout_peri_spi_user", ++ CLK_CON_DIV_DIV_CLK_PERI_SPI_0, 0, 5, CLK_SET_RATE_PARENT, 0), + }; + + static const struct samsung_gate_clock peri_gate_clks[] __initconst = { +@@ -1611,7 +1612,7 @@ static const struct samsung_gate_clock peri_gate_clks[] __initconst = { + "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_PWM_MOTOR_PCLK, 21, 0, 0), + GATE(CLK_GOUT_SPI0_IPCLK, "gout_spi0_ipclk", "dout_peri_spi0", +- CLK_CON_GAT_GOUT_PERI_SPI_0_IPCLK, 21, 0, 0), ++ CLK_CON_GAT_GOUT_PERI_SPI_0_IPCLK, 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_SPI0_PCLK, "gout_spi0_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_SPI_0_PCLK, 21, 0, 0), + GATE(CLK_GOUT_SYSREG_PERI_PCLK, "gout_sysreg_peri_pclk", +diff --git a/drivers/clk/samsung/clk-exynosautov9.c b/drivers/clk/samsung/clk-exynosautov9.c +index e9c06eb93e6665..f04bacacab2cb8 100644 +--- a/drivers/clk/samsung/clk-exynosautov9.c ++++ b/drivers/clk/samsung/clk-exynosautov9.c +@@ -352,13 +352,13 @@ static const struct samsung_pll_clock top_pll_clks[] __initconst = { + /* CMU_TOP_PURECLKCOMP */ + PLL(pll_0822x, FOUT_SHARED0_PLL, "fout_shared0_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED0, PLL_CON3_PLL_SHARED0, NULL), +- PLL(pll_0822x, FOUT_SHARED0_PLL, "fout_shared1_pll", "oscclk", ++ PLL(pll_0822x, FOUT_SHARED1_PLL, "fout_shared1_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED1, PLL_CON3_PLL_SHARED1, NULL), +- PLL(pll_0822x, FOUT_SHARED0_PLL, "fout_shared2_pll", "oscclk", ++ PLL(pll_0822x, FOUT_SHARED2_PLL, "fout_shared2_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED2, PLL_CON3_PLL_SHARED2, NULL), +- PLL(pll_0822x, FOUT_SHARED0_PLL, "fout_shared3_pll", "oscclk", ++ PLL(pll_0822x, FOUT_SHARED3_PLL, "fout_shared3_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED3, PLL_CON3_PLL_SHARED3, NULL), +- PLL(pll_0822x, FOUT_SHARED0_PLL, "fout_shared4_pll", "oscclk", ++ PLL(pll_0822x, FOUT_SHARED4_PLL, "fout_shared4_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED4, PLL_CON3_PLL_SHARED4, NULL), + }; + +diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c +index af81eb835bc235..b1be6a2d24aa9c 100644 +--- a/drivers/clk/sifive/sifive-prci.c ++++ b/drivers/clk/sifive/sifive-prci.c +@@ -4,7 +4,6 @@ + * Copyright (C) 2020 Zong Li + */ + +-#include + #include + #include + #include +@@ -536,13 +535,6 @@ static int __prci_register_clocks(struct device *dev, struct __prci_data *pd, + return r; + } + +- r = clk_hw_register_clkdev(&pic->hw, pic->name, dev_name(dev)); +- if (r) { +- dev_warn(dev, "Failed to register clkdev for %s: %d\n", +- init.name, r); +- return r; +- } +- + pd->hw_clks.hws[i] = &pic->hw; + } + +diff --git a/drivers/clk/socfpga/stratix10-clk.h b/drivers/clk/socfpga/stratix10-clk.h +index 75234e0783e1cc..83fe4eb3133cbe 100644 +--- a/drivers/clk/socfpga/stratix10-clk.h ++++ b/drivers/clk/socfpga/stratix10-clk.h +@@ -7,8 +7,10 @@ + #define __STRATIX10_CLK_H + + struct stratix10_clock_data { +- struct clk_hw_onecell_data clk_data; + void __iomem *base; ++ ++ /* Must be last */ ++ struct clk_hw_onecell_data clk_data; + }; + + struct stratix10_pll_clock { +diff --git a/drivers/clk/starfive/clk-starfive-jh7110-sys.c b/drivers/clk/starfive/clk-starfive-jh7110-sys.c +index 3884eff9fe9315..58ef7c6d69cce9 100644 +--- a/drivers/clk/starfive/clk-starfive-jh7110-sys.c ++++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c +@@ -385,6 +385,32 @@ int jh7110_reset_controller_register(struct jh71x0_clk_priv *priv, + } + EXPORT_SYMBOL_GPL(jh7110_reset_controller_register); + ++/* ++ * This clock notifier is called when the rate of PLL0 clock is to be changed. ++ * The cpu_root clock should save the curent parent clock and switch its parent ++ * clock to osc before PLL0 rate will be changed. Then switch its parent clock ++ * back after the PLL0 rate is completed. ++ */ ++static int jh7110_pll0_clk_notifier_cb(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ struct jh71x0_clk_priv *priv = container_of(nb, struct jh71x0_clk_priv, pll_clk_nb); ++ struct clk *cpu_root = priv->reg[JH7110_SYSCLK_CPU_ROOT].hw.clk; ++ int ret = 0; ++ ++ if (action == PRE_RATE_CHANGE) { ++ struct clk *osc = clk_get(priv->dev, "osc"); ++ ++ priv->original_clk = clk_get_parent(cpu_root); ++ ret = clk_set_parent(cpu_root, osc); ++ clk_put(osc); ++ } else if (action == POST_RATE_CHANGE) { ++ ret = clk_set_parent(cpu_root, priv->original_clk); ++ } ++ ++ return notifier_from_errno(ret); ++} ++ + static int __init jh7110_syscrg_probe(struct platform_device *pdev) + { + struct jh71x0_clk_priv *priv; +@@ -413,7 +439,10 @@ static int __init jh7110_syscrg_probe(struct platform_device *pdev) + if (IS_ERR(priv->pll[0])) + return PTR_ERR(priv->pll[0]); + } else { +- clk_put(pllclk); ++ priv->pll_clk_nb.notifier_call = jh7110_pll0_clk_notifier_cb; ++ ret = clk_notifier_register(pllclk, &priv->pll_clk_nb); ++ if (ret) ++ return ret; + priv->pll[0] = NULL; + } + +diff --git a/drivers/clk/starfive/clk-starfive-jh7110-vout.c b/drivers/clk/starfive/clk-starfive-jh7110-vout.c +index 10cc1ec4392517..36340ca42cc7ed 100644 +--- a/drivers/clk/starfive/clk-starfive-jh7110-vout.c ++++ b/drivers/clk/starfive/clk-starfive-jh7110-vout.c +@@ -145,7 +145,7 @@ static int jh7110_voutcrg_probe(struct platform_device *pdev) + + /* enable power domain and clocks */ + pm_runtime_enable(priv->dev); +- ret = pm_runtime_get_sync(priv->dev); ++ ret = pm_runtime_resume_and_get(priv->dev); + if (ret < 0) + return dev_err_probe(priv->dev, ret, "failed to turn on power\n"); + +diff --git a/drivers/clk/starfive/clk-starfive-jh71x0.h b/drivers/clk/starfive/clk-starfive-jh71x0.h +index 34bb11c72eb73b..ebc55b9ef83705 100644 +--- a/drivers/clk/starfive/clk-starfive-jh71x0.h ++++ b/drivers/clk/starfive/clk-starfive-jh71x0.h +@@ -114,6 +114,8 @@ struct jh71x0_clk_priv { + spinlock_t rmw_lock; + struct device *dev; + void __iomem *base; ++ struct clk *original_clk; ++ struct notifier_block pll_clk_nb; + struct clk_hw *pll[3]; + struct jh71x0_clk reg[]; + }; +diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +index 8951ffc14ff52c..6a4b2b9ef30a82 100644 +--- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c ++++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +@@ -182,6 +182,8 @@ static struct ccu_nkm pll_mipi_clk = { + &ccu_nkm_ops, + CLK_SET_RATE_UNGATE | CLK_SET_RATE_PARENT), + .features = CCU_FEATURE_CLOSEST_RATE, ++ .min_rate = 500000000, ++ .max_rate = 1400000000, + }, + }; + +diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c +index 42568c6161814d..892df807275c8e 100644 +--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c ++++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c +@@ -1181,11 +1181,18 @@ static const u32 usb2_clk_regs[] = { + SUN50I_H6_USB3_CLK_REG, + }; + ++static struct ccu_mux_nb sun50i_h6_cpu_nb = { ++ .common = &cpux_clk.common, ++ .cm = &cpux_clk.mux, ++ .delay_us = 1, ++ .bypass_index = 0, /* index of 24 MHz oscillator */ ++}; ++ + static int sun50i_h6_ccu_probe(struct platform_device *pdev) + { + void __iomem *reg; ++ int i, ret; + u32 val; +- int i; + + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) +@@ -1252,7 +1259,15 @@ static int sun50i_h6_ccu_probe(struct platform_device *pdev) + val |= BIT(24); + writel(val, reg + SUN50I_H6_HDMI_CEC_CLK_REG); + +- return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_h6_ccu_desc); ++ ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_h6_ccu_desc); ++ if (ret) ++ return ret; ++ ++ /* Reparent CPU during PLL CPUX rate changes */ ++ ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk, ++ &sun50i_h6_cpu_nb); ++ ++ return 0; + } + + static const struct of_device_id sun50i_h6_ccu_ids[] = { +diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c +index 8babce55302f5f..be375ce0149c8b 100644 +--- a/drivers/clk/sunxi-ng/ccu_common.c ++++ b/drivers/clk/sunxi-ng/ccu_common.c +@@ -44,6 +44,16 @@ bool ccu_is_better_rate(struct ccu_common *common, + unsigned long current_rate, + unsigned long best_rate) + { ++ unsigned long min_rate, max_rate; ++ ++ clk_hw_get_rate_range(&common->hw, &min_rate, &max_rate); ++ ++ if (current_rate > max_rate) ++ return false; ++ ++ if (current_rate < min_rate) ++ return false; ++ + if (common->features & CCU_FEATURE_CLOSEST_RATE) + return abs(current_rate - target_rate) < abs(best_rate - target_rate); + +@@ -138,6 +148,21 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev, + } + } + ++ for (i = 0; i < desc->num_ccu_clks; i++) { ++ struct ccu_common *cclk = desc->ccu_clks[i]; ++ ++ if (!cclk) ++ continue; ++ ++ if (cclk->max_rate) ++ clk_hw_set_rate_range(&cclk->hw, cclk->min_rate, ++ cclk->max_rate); ++ else ++ WARN(cclk->min_rate, ++ "No max_rate, ignoring min_rate of clock %d - %s\n", ++ i, clk_hw_get_name(&cclk->hw)); ++ } ++ + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, + desc->hw_clks); + if (ret) +diff --git a/drivers/clk/sunxi-ng/ccu_common.h b/drivers/clk/sunxi-ng/ccu_common.h +index 942a72c0943744..329734f8cf42b4 100644 +--- a/drivers/clk/sunxi-ng/ccu_common.h ++++ b/drivers/clk/sunxi-ng/ccu_common.h +@@ -31,6 +31,9 @@ struct ccu_common { + u16 lock_reg; + u32 prediv; + ++ unsigned long min_rate; ++ unsigned long max_rate; ++ + unsigned long features; + spinlock_t *lock; + struct clk_hw hw; +diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c +index d964e3affd42ce..0eab7f3e2eab9e 100644 +--- a/drivers/clk/ti/clk-dra7-atl.c ++++ b/drivers/clk/ti/clk-dra7-atl.c +@@ -240,6 +240,7 @@ static int of_dra7_atl_clk_probe(struct platform_device *pdev) + } + + clk = of_clk_get_from_provider(&clkspec); ++ of_node_put(clkspec.np); + if (IS_ERR(clk)) { + pr_err("%s: failed to get atl clock %d from provider\n", + __func__, i); +diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c +index 768a1f3398b47d..5d5bb123ba9494 100644 +--- a/drivers/clk/ti/divider.c ++++ b/drivers/clk/ti/divider.c +@@ -309,7 +309,6 @@ static struct clk *_register_divider(struct device_node *node, + u32 flags, + struct clk_omap_divider *div) + { +- struct clk *clk; + struct clk_init_data init; + const char *parent_name; + const char *name; +@@ -326,12 +325,7 @@ static struct clk *_register_divider(struct device_node *node, + div->hw.init = &init; + + /* register the clock */ +- clk = of_ti_clk_register(node, &div->hw, name); +- +- if (IS_ERR(clk)) +- kfree(div); +- +- return clk; ++ return of_ti_clk_register(node, &div->hw, name); + } + + int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div, +diff --git a/drivers/clk/visconti/pll.c b/drivers/clk/visconti/pll.c +index 1f3234f2266744..e9cd80e085dc3b 100644 +--- a/drivers/clk/visconti/pll.c ++++ b/drivers/clk/visconti/pll.c +@@ -329,12 +329,12 @@ struct visconti_pll_provider * __init visconti_init_pll(struct device_node *np, + if (!ctx) + return ERR_PTR(-ENOMEM); + +- for (i = 0; i < nr_plls; ++i) +- ctx->clk_data.hws[i] = ERR_PTR(-ENOENT); +- + ctx->node = np; + ctx->reg_base = base; + ctx->clk_data.num = nr_plls; + ++ for (i = 0; i < nr_plls; ++i) ++ ctx->clk_data.hws[i] = ERR_PTR(-ENOENT); ++ + return ctx; + } +diff --git a/drivers/clk/visconti/pll.h b/drivers/clk/visconti/pll.h +index 01d07f1bf01b10..c4bd40676da4bf 100644 +--- a/drivers/clk/visconti/pll.h ++++ b/drivers/clk/visconti/pll.h +@@ -15,8 +15,10 @@ + + struct visconti_pll_provider { + void __iomem *reg_base; +- struct clk_hw_onecell_data clk_data; + struct device_node *node; ++ ++ /* Must be last */ ++ struct clk_hw_onecell_data clk_data; + }; + + #define VISCONTI_PLL_RATE(_rate, _dacen, _dsmen, \ +diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c +index 7bdeaff2bfd68b..c28d3dacf0fb22 100644 +--- a/drivers/clk/zynq/clkc.c ++++ b/drivers/clk/zynq/clkc.c +@@ -42,6 +42,7 @@ static void __iomem *zynq_clkc_base; + #define SLCR_SWDT_CLK_SEL (zynq_clkc_base + 0x204) + + #define NUM_MIO_PINS 54 ++#define CLK_NAME_LEN 16 + + #define DBG_CLK_CTRL_CLKACT_TRC BIT(0) + #define DBG_CLK_CTRL_CPU_1XCLKACT BIT(1) +@@ -215,7 +216,7 @@ static void __init zynq_clk_setup(struct device_node *np) + int i; + u32 tmp; + int ret; +- char *clk_name; ++ char clk_name[CLK_NAME_LEN]; + unsigned int fclk_enable = 0; + const char *clk_output_name[clk_max]; + const char *cpu_parents[4]; +@@ -426,12 +427,10 @@ static void __init zynq_clk_setup(struct device_node *np) + "gem1_emio_mux", CLK_SET_RATE_PARENT, + SLCR_GEM1_CLK_CTRL, 0, 0, &gem1clk_lock); + +- tmp = strlen("mio_clk_00x"); +- clk_name = kmalloc(tmp, GFP_KERNEL); + for (i = 0; i < NUM_MIO_PINS; i++) { + int idx; + +- snprintf(clk_name, tmp, "mio_clk_%2.2d", i); ++ snprintf(clk_name, CLK_NAME_LEN, "mio_clk_%2.2d", i); + idx = of_property_match_string(np, "clock-names", clk_name); + if (idx >= 0) + can_mio_mux_parents[i] = of_clk_get_parent_name(np, +@@ -439,7 +438,6 @@ static void __init zynq_clk_setup(struct device_node *np) + else + can_mio_mux_parents[i] = dummy_nm; + } +- kfree(clk_name); + clk_register_mux(NULL, "can_mux", periph_parents, 4, + CLK_SET_RATE_NO_REPARENT, SLCR_CAN_CLK_CTRL, 4, 2, 0, + &canclk_lock); +diff --git a/drivers/clk/zynqmp/clk-mux-zynqmp.c b/drivers/clk/zynqmp/clk-mux-zynqmp.c +index 60359333f26dbe..9b5d3050b74229 100644 +--- a/drivers/clk/zynqmp/clk-mux-zynqmp.c ++++ b/drivers/clk/zynqmp/clk-mux-zynqmp.c +@@ -89,7 +89,7 @@ static int zynqmp_clk_mux_set_parent(struct clk_hw *hw, u8 index) + static const struct clk_ops zynqmp_clk_mux_ops = { + .get_parent = zynqmp_clk_mux_get_parent, + .set_parent = zynqmp_clk_mux_set_parent, +- .determine_rate = __clk_mux_determine_rate, ++ .determine_rate = __clk_mux_determine_rate_closest, + }; + + static const struct clk_ops zynqmp_clk_mux_ro_ops = { +diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c +index 33a3b2a226595d..5a00487ae408be 100644 +--- a/drivers/clk/zynqmp/divider.c ++++ b/drivers/clk/zynqmp/divider.c +@@ -110,52 +110,6 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw, + return DIV_ROUND_UP_ULL(parent_rate, value); + } + +-static void zynqmp_get_divider2_val(struct clk_hw *hw, +- unsigned long rate, +- struct zynqmp_clk_divider *divider, +- u32 *bestdiv) +-{ +- int div1; +- int div2; +- long error = LONG_MAX; +- unsigned long div1_prate; +- struct clk_hw *div1_parent_hw; +- struct zynqmp_clk_divider *pdivider; +- struct clk_hw *div2_parent_hw = clk_hw_get_parent(hw); +- +- if (!div2_parent_hw) +- return; +- +- pdivider = to_zynqmp_clk_divider(div2_parent_hw); +- if (!pdivider) +- return; +- +- div1_parent_hw = clk_hw_get_parent(div2_parent_hw); +- if (!div1_parent_hw) +- return; +- +- div1_prate = clk_hw_get_rate(div1_parent_hw); +- *bestdiv = 1; +- for (div1 = 1; div1 <= pdivider->max_div;) { +- for (div2 = 1; div2 <= divider->max_div;) { +- long new_error = ((div1_prate / div1) / div2) - rate; +- +- if (abs(new_error) < abs(error)) { +- *bestdiv = div2; +- error = new_error; +- } +- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) +- div2 = div2 << 1; +- else +- div2++; +- } +- if (pdivider->flags & CLK_DIVIDER_POWER_OF_TWO) +- div1 = div1 << 1; +- else +- div1++; +- } +-} +- + /** + * zynqmp_clk_divider_round_rate() - Round rate of divider clock + * @hw: handle between common and hardware-specific interfaces +@@ -174,6 +128,7 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw, + u32 div_type = divider->div_type; + u32 bestdiv; + int ret; ++ u8 width; + + /* if read only, just return current value */ + if (divider->flags & CLK_DIVIDER_READ_ONLY) { +@@ -193,23 +148,12 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw, + return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); + } + +- bestdiv = zynqmp_divider_get_val(*prate, rate, divider->flags); +- +- /* +- * In case of two divisors, compute best divider values and return +- * divider2 value based on compute value. div1 will be automatically +- * set to optimum based on required total divider value. +- */ +- if (div_type == TYPE_DIV2 && +- (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { +- zynqmp_get_divider2_val(hw, rate, divider, &bestdiv); +- } ++ width = fls(divider->max_div); + +- if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && divider->is_frac) +- bestdiv = rate % *prate ? 1 : bestdiv; ++ rate = divider_round_rate(hw, rate, prate, NULL, width, divider->flags); + +- bestdiv = min_t(u32, bestdiv, divider->max_div); +- *prate = rate * bestdiv; ++ if (divider->is_frac && (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && (rate % *prate)) ++ *prate = rate; + + return rate; + } +diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c +index 7dd2c615bce231..071b04f1ee7309 100644 +--- a/drivers/clocksource/arm_arch_timer.c ++++ b/drivers/clocksource/arm_arch_timer.c +@@ -836,8 +836,9 @@ static u64 __arch_timer_check_delta(void) + * Note that TVAL is signed, thus has only 31 of its + * 32 bits to express magnitude. + */ +- MIDR_ALL_VERSIONS(MIDR_CPU_MODEL(ARM_CPU_IMP_APM, +- APM_CPU_PART_POTENZA)), ++ MIDR_REV_RANGE(MIDR_CPU_MODEL(ARM_CPU_IMP_APM, ++ APM_CPU_PART_XGENE), ++ APM_CPU_VAR_POTENZA, 0x0, 0xf), + {}, + }; + +diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c +index 44a61dc6f93208..22a58d35a41fa5 100644 +--- a/drivers/clocksource/arm_global_timer.c ++++ b/drivers/clocksource/arm_global_timer.c +@@ -32,7 +32,7 @@ + #define GT_CONTROL_IRQ_ENABLE BIT(2) /* banked */ + #define GT_CONTROL_AUTO_INC BIT(3) /* banked */ + #define GT_CONTROL_PRESCALER_SHIFT 8 +-#define GT_CONTROL_PRESCALER_MAX 0xF ++#define GT_CONTROL_PRESCALER_MAX 0xFF + #define GT_CONTROL_PRESCALER_MASK (GT_CONTROL_PRESCALER_MAX << \ + GT_CONTROL_PRESCALER_SHIFT) + +@@ -290,18 +290,17 @@ static int gt_clk_rate_change_cb(struct notifier_block *nb, + switch (event) { + case PRE_RATE_CHANGE: + { +- int psv; ++ unsigned long psv; + +- psv = DIV_ROUND_CLOSEST(ndata->new_rate, +- gt_target_rate); +- +- if (abs(gt_target_rate - (ndata->new_rate / psv)) > MAX_F_ERR) ++ psv = DIV_ROUND_CLOSEST(ndata->new_rate, gt_target_rate); ++ if (!psv || ++ abs(gt_target_rate - (ndata->new_rate / psv)) > MAX_F_ERR) + return NOTIFY_BAD; + + psv--; + + /* prescaler within legal range? */ +- if (psv < 0 || psv > GT_CONTROL_PRESCALER_MAX) ++ if (psv > GT_CONTROL_PRESCALER_MAX) + return NOTIFY_BAD; + + /* +diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c +index 26919556ef5f0b..b72b36e0abed86 100644 +--- a/drivers/clocksource/sh_cmt.c ++++ b/drivers/clocksource/sh_cmt.c +@@ -528,6 +528,7 @@ static void sh_cmt_set_next(struct sh_cmt_channel *ch, unsigned long delta) + static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id) + { + struct sh_cmt_channel *ch = dev_id; ++ unsigned long flags; + + /* clear flags */ + sh_cmt_write_cmcsr(ch, sh_cmt_read_cmcsr(ch) & +@@ -558,6 +559,8 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id) + + ch->flags &= ~FLAG_SKIPEVENT; + ++ raw_spin_lock_irqsave(&ch->lock, flags); ++ + if (ch->flags & FLAG_REPROGRAM) { + ch->flags &= ~FLAG_REPROGRAM; + sh_cmt_clock_event_program_verify(ch, 1); +@@ -570,6 +573,8 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id) + + ch->flags &= ~FLAG_IRQCONTEXT; + ++ raw_spin_unlock_irqrestore(&ch->lock, flags); ++ + return IRQ_HANDLED; + } + +@@ -780,12 +785,18 @@ static int sh_cmt_clock_event_next(unsigned long delta, + struct clock_event_device *ced) + { + struct sh_cmt_channel *ch = ced_to_sh_cmt(ced); ++ unsigned long flags; + + BUG_ON(!clockevent_state_oneshot(ced)); ++ ++ raw_spin_lock_irqsave(&ch->lock, flags); ++ + if (likely(ch->flags & FLAG_IRQCONTEXT)) + ch->next_match_value = delta - 1; + else +- sh_cmt_set_next(ch, delta - 1); ++ __sh_cmt_set_next(ch, delta - 1); ++ ++ raw_spin_unlock_irqrestore(&ch->lock, flags); + + return 0; + } +diff --git a/drivers/clocksource/timer-atmel-tcb.c b/drivers/clocksource/timer-atmel-tcb.c +index 27af17c9959004..2a90c92a9182ab 100644 +--- a/drivers/clocksource/timer-atmel-tcb.c ++++ b/drivers/clocksource/timer-atmel-tcb.c +@@ -315,6 +315,7 @@ static void __init tcb_setup_dual_chan(struct atmel_tc *tc, int mck_divisor_idx) + writel(mck_divisor_idx /* likely divide-by-8 */ + | ATMEL_TC_WAVE + | ATMEL_TC_WAVESEL_UP /* free-run */ ++ | ATMEL_TC_ASWTRG_SET /* TIOA0 rises at software trigger */ + | ATMEL_TC_ACPA_SET /* TIOA0 rises at 0 */ + | ATMEL_TC_ACPC_CLEAR, /* (duty cycle 50%) */ + tcaddr + ATMEL_TC_REG(0, CMR)); +diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c +index 28ab4f1a7c713b..6a878d227a13b5 100644 +--- a/drivers/clocksource/timer-imx-gpt.c ++++ b/drivers/clocksource/timer-imx-gpt.c +@@ -434,12 +434,16 @@ static int __init mxc_timer_init_dt(struct device_node *np, enum imx_gpt_type t + return -ENOMEM; + + imxtm->base = of_iomap(np, 0); +- if (!imxtm->base) +- return -ENXIO; ++ if (!imxtm->base) { ++ ret = -ENXIO; ++ goto err_kfree; ++ } + + imxtm->irq = irq_of_parse_and_map(np, 0); +- if (imxtm->irq <= 0) +- return -EINVAL; ++ if (imxtm->irq <= 0) { ++ ret = -EINVAL; ++ goto err_kfree; ++ } + + imxtm->clk_ipg = of_clk_get_by_name(np, "ipg"); + +@@ -452,11 +456,15 @@ static int __init mxc_timer_init_dt(struct device_node *np, enum imx_gpt_type t + + ret = _mxc_timer_init(imxtm); + if (ret) +- return ret; ++ goto err_kfree; + + initialized = 1; + + return 0; ++ ++err_kfree: ++ kfree(imxtm); ++ return ret; + } + + static int __init imx1_timer_init_dt(struct device_node *np) +diff --git a/drivers/clocksource/timer-imx-tpm.c b/drivers/clocksource/timer-imx-tpm.c +index bd64a8a8427f3c..92c025b70eb62f 100644 +--- a/drivers/clocksource/timer-imx-tpm.c ++++ b/drivers/clocksource/timer-imx-tpm.c +@@ -83,20 +83,28 @@ static u64 notrace tpm_read_sched_clock(void) + static int tpm_set_next_event(unsigned long delta, + struct clock_event_device *evt) + { +- unsigned long next, now; ++ unsigned long next, prev, now; + +- next = tpm_read_counter(); +- next += delta; ++ prev = tpm_read_counter(); ++ next = prev + delta; + writel(next, timer_base + TPM_C0V); + now = tpm_read_counter(); + ++ /* ++ * Need to wait CNT increase at least 1 cycle to make sure ++ * the C0V has been updated into HW. ++ */ ++ if ((next & 0xffffffff) != readl(timer_base + TPM_C0V)) ++ while (now == tpm_read_counter()) ++ ; ++ + /* + * NOTE: We observed in a very small probability, the bus fabric + * contention between GPU and A7 may results a few cycles delay + * of writing CNT registers which may cause the min_delta event got + * missed, so we need add a ETIME check here in case it happened. + */ +- return (int)(next - now) <= 0 ? -ETIME : 0; ++ return (now - prev) >= delta ? -ETIME : 0; + } + + static int tpm_set_state_oneshot(struct clock_event_device *evt) +diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c +index c3f54d9912be79..420202bf76e42c 100644 +--- a/drivers/clocksource/timer-of.c ++++ b/drivers/clocksource/timer-of.c +@@ -25,10 +25,7 @@ static __init void timer_of_irq_exit(struct of_timer_irq *of_irq) + + struct clock_event_device *clkevt = &to->clkevt; + +- if (of_irq->percpu) +- free_percpu_irq(of_irq->irq, clkevt); +- else +- free_irq(of_irq->irq, clkevt); ++ free_irq(of_irq->irq, clkevt); + } + + /** +@@ -42,9 +39,6 @@ static __init void timer_of_irq_exit(struct of_timer_irq *of_irq) + * - Get interrupt number by name + * - Get interrupt number by index + * +- * When the interrupt is per CPU, 'request_percpu_irq()' is called, +- * otherwise 'request_irq()' is used. +- * + * Returns 0 on success, < 0 otherwise + */ + static __init int timer_of_irq_init(struct device_node *np, +@@ -69,12 +63,9 @@ static __init int timer_of_irq_init(struct device_node *np, + return -EINVAL; + } + +- ret = of_irq->percpu ? +- request_percpu_irq(of_irq->irq, of_irq->handler, +- np->full_name, clkevt) : +- request_irq(of_irq->irq, of_irq->handler, +- of_irq->flags ? of_irq->flags : IRQF_TIMER, +- np->full_name, clkevt); ++ ret = request_irq(of_irq->irq, of_irq->handler, ++ of_irq->flags ? of_irq->flags : IRQF_TIMER, ++ np->full_name, clkevt); + if (ret) { + pr_err("Failed to request irq %d for %pOF\n", of_irq->irq, np); + return ret; +diff --git a/drivers/clocksource/timer-of.h b/drivers/clocksource/timer-of.h +index a5478f3e8589df..01a2c6b7db0659 100644 +--- a/drivers/clocksource/timer-of.h ++++ b/drivers/clocksource/timer-of.h +@@ -11,7 +11,6 @@ + struct of_timer_irq { + int irq; + int index; +- int percpu; + const char *name; + unsigned long flags; + irq_handler_t handler; +diff --git a/drivers/clocksource/timer-qcom.c b/drivers/clocksource/timer-qcom.c +index b4afe3a6758351..eac4c95c6127f2 100644 +--- a/drivers/clocksource/timer-qcom.c ++++ b/drivers/clocksource/timer-qcom.c +@@ -233,6 +233,7 @@ static int __init msm_dt_timer_init(struct device_node *np) + } + + if (of_property_read_u32(np, "clock-frequency", &freq)) { ++ iounmap(cpu0_base); + pr_err("Unknown frequency\n"); + return -EINVAL; + } +@@ -243,7 +244,11 @@ static int __init msm_dt_timer_init(struct device_node *np) + freq /= 4; + writel_relaxed(DGT_CLK_CTL_DIV_4, source_base + DGT_CLK_CTL); + +- return msm_timer_init(freq, 32, irq, !!percpu_offset); ++ ret = msm_timer_init(freq, 32, irq, !!percpu_offset); ++ if (ret) ++ iounmap(cpu0_base); ++ ++ return ret; + } + TIMER_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); + TIMER_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init); +diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c +index 09ab29cb7f6416..56acf26172621f 100644 +--- a/drivers/clocksource/timer-ti-dm.c ++++ b/drivers/clocksource/timer-ti-dm.c +@@ -140,6 +140,8 @@ struct dmtimer { + struct platform_device *pdev; + struct list_head node; + struct notifier_block nb; ++ struct notifier_block fclk_nb; ++ unsigned long fclk_rate; + }; + + static u32 omap_reserved_systimers; +@@ -181,7 +183,7 @@ static inline u32 dmtimer_read(struct dmtimer *timer, u32 reg) + * dmtimer_write - write timer registers in posted and non-posted mode + * @timer: timer pointer over which write operation is to perform + * @reg: lowest byte holds the register offset +- * @value: data to write into the register ++ * @val: data to write into the register + * + * The posted mode bit is encoded in reg. Note that in posted mode, the write + * pending bit must be checked. Otherwise a write on a register which has a +@@ -253,8 +255,7 @@ static inline void __omap_dm_timer_enable_posted(struct dmtimer *timer) + timer->posted = OMAP_TIMER_POSTED; + } + +-static inline void __omap_dm_timer_stop(struct dmtimer *timer, +- unsigned long rate) ++static inline void __omap_dm_timer_stop(struct dmtimer *timer) + { + u32 l; + +@@ -269,7 +270,7 @@ static inline void __omap_dm_timer_stop(struct dmtimer *timer, + * Wait for functional clock period x 3.5 to make sure that + * timer is stopped + */ +- udelay(3500000 / rate + 1); ++ udelay(3500000 / timer->fclk_rate + 1); + #endif + } + +@@ -348,6 +349,21 @@ static int omap_timer_context_notifier(struct notifier_block *nb, + return NOTIFY_OK; + } + ++static int omap_timer_fclk_notifier(struct notifier_block *nb, ++ unsigned long event, void *data) ++{ ++ struct clk_notifier_data *clk_data = data; ++ struct dmtimer *timer = container_of(nb, struct dmtimer, fclk_nb); ++ ++ switch (event) { ++ case POST_RATE_CHANGE: ++ timer->fclk_rate = clk_data->new_rate; ++ return NOTIFY_OK; ++ default: ++ return NOTIFY_DONE; ++ } ++} ++ + static int omap_dm_timer_reset(struct dmtimer *timer) + { + u32 l, timeout = 100000; +@@ -754,7 +770,6 @@ static int omap_dm_timer_stop(struct omap_dm_timer *cookie) + { + struct dmtimer *timer; + struct device *dev; +- unsigned long rate = 0; + + timer = to_dmtimer(cookie); + if (unlikely(!timer)) +@@ -762,10 +777,7 @@ static int omap_dm_timer_stop(struct omap_dm_timer *cookie) + + dev = &timer->pdev->dev; + +- if (!timer->omap1) +- rate = clk_get_rate(timer->fclk); +- +- __omap_dm_timer_stop(timer, rate); ++ __omap_dm_timer_stop(timer); + + pm_runtime_put_sync(dev); + +@@ -937,7 +949,7 @@ static int omap_dm_timer_set_int_enable(struct omap_dm_timer *cookie, + + /** + * omap_dm_timer_set_int_disable - disable timer interrupts +- * @timer: pointer to timer handle ++ * @cookie: pointer to timer cookie + * @mask: bit mask of interrupts to be disabled + * + * Disables the specified timer interrupts for a timer. +@@ -1124,6 +1136,14 @@ static int omap_dm_timer_probe(struct platform_device *pdev) + timer->fclk = devm_clk_get(dev, "fck"); + if (IS_ERR(timer->fclk)) + return PTR_ERR(timer->fclk); ++ ++ timer->fclk_nb.notifier_call = omap_timer_fclk_notifier; ++ ret = devm_clk_notifier_register(dev, timer->fclk, ++ &timer->fclk_nb); ++ if (ret) ++ return ret; ++ ++ timer->fclk_rate = clk_get_rate(timer->fclk); + } else { + timer->fclk = ERR_PTR(-ENODEV); + } +diff --git a/drivers/comedi/drivers/comedi_test.c b/drivers/comedi/drivers/comedi_test.c +index 30ea8b53ebf819..05ae9122823f80 100644 +--- a/drivers/comedi/drivers/comedi_test.c ++++ b/drivers/comedi/drivers/comedi_test.c +@@ -87,6 +87,8 @@ struct waveform_private { + struct comedi_device *dev; /* parent comedi device */ + u64 ao_last_scan_time; /* time of previous AO scan in usec */ + unsigned int ao_scan_period; /* AO scan period in usec */ ++ bool ai_timer_enable:1; /* should AI timer be running? */ ++ bool ao_timer_enable:1; /* should AO timer be running? */ + unsigned short ao_loopbacks[N_CHANS]; + }; + +@@ -236,8 +238,12 @@ static void waveform_ai_timer(struct timer_list *t) + time_increment = devpriv->ai_convert_time - now; + else + time_increment = 1; +- mod_timer(&devpriv->ai_timer, +- jiffies + usecs_to_jiffies(time_increment)); ++ spin_lock(&dev->spinlock); ++ if (devpriv->ai_timer_enable) { ++ mod_timer(&devpriv->ai_timer, ++ jiffies + usecs_to_jiffies(time_increment)); ++ } ++ spin_unlock(&dev->spinlock); + } + + overrun: +@@ -393,9 +399,12 @@ static int waveform_ai_cmd(struct comedi_device *dev, + * Seem to need an extra jiffy here, otherwise timer expires slightly + * early! + */ ++ spin_lock_bh(&dev->spinlock); ++ devpriv->ai_timer_enable = true; + devpriv->ai_timer.expires = + jiffies + usecs_to_jiffies(devpriv->ai_convert_period) + 1; + add_timer(&devpriv->ai_timer); ++ spin_unlock_bh(&dev->spinlock); + return 0; + } + +@@ -404,6 +413,9 @@ static int waveform_ai_cancel(struct comedi_device *dev, + { + struct waveform_private *devpriv = dev->private; + ++ spin_lock_bh(&dev->spinlock); ++ devpriv->ai_timer_enable = false; ++ spin_unlock_bh(&dev->spinlock); + if (in_softirq()) { + /* Assume we were called from the timer routine itself. */ + del_timer(&devpriv->ai_timer); +@@ -495,8 +507,12 @@ static void waveform_ao_timer(struct timer_list *t) + unsigned int time_inc = devpriv->ao_last_scan_time + + devpriv->ao_scan_period - now; + +- mod_timer(&devpriv->ao_timer, +- jiffies + usecs_to_jiffies(time_inc)); ++ spin_lock(&dev->spinlock); ++ if (devpriv->ao_timer_enable) { ++ mod_timer(&devpriv->ao_timer, ++ jiffies + usecs_to_jiffies(time_inc)); ++ } ++ spin_unlock(&dev->spinlock); + } + + underrun: +@@ -517,9 +533,12 @@ static int waveform_ao_inttrig_start(struct comedi_device *dev, + async->inttrig = NULL; + + devpriv->ao_last_scan_time = ktime_to_us(ktime_get()); ++ spin_lock_bh(&dev->spinlock); ++ devpriv->ao_timer_enable = true; + devpriv->ao_timer.expires = + jiffies + usecs_to_jiffies(devpriv->ao_scan_period); + add_timer(&devpriv->ao_timer); ++ spin_unlock_bh(&dev->spinlock); + + return 1; + } +@@ -604,6 +623,9 @@ static int waveform_ao_cancel(struct comedi_device *dev, + struct waveform_private *devpriv = dev->private; + + s->async->inttrig = NULL; ++ spin_lock_bh(&dev->spinlock); ++ devpriv->ao_timer_enable = false; ++ spin_unlock_bh(&dev->spinlock); + if (in_softirq()) { + /* Assume we were called from the timer routine itself. */ + del_timer(&devpriv->ao_timer); +diff --git a/drivers/comedi/drivers/ni_routing/tools/convert_c_to_py.c b/drivers/comedi/drivers/ni_routing/tools/convert_c_to_py.c +index d55521b5bdcb2d..892a66b2cea665 100644 +--- a/drivers/comedi/drivers/ni_routing/tools/convert_c_to_py.c ++++ b/drivers/comedi/drivers/ni_routing/tools/convert_c_to_py.c +@@ -140,6 +140,11 @@ int main(void) + { + FILE *fp = fopen("ni_values.py", "w"); + ++ if (fp == NULL) { ++ fprintf(stderr, "Could not open file!"); ++ return -1; ++ } ++ + /* write route register values */ + fprintf(fp, "ni_route_values = {\n"); + for (int i = 0; ni_all_route_values[i]; ++i) +diff --git a/drivers/comedi/drivers/vmk80xx.c b/drivers/comedi/drivers/vmk80xx.c +index 4536ed43f65b27..84dce5184a77ae 100644 +--- a/drivers/comedi/drivers/vmk80xx.c ++++ b/drivers/comedi/drivers/vmk80xx.c +@@ -641,33 +641,22 @@ static int vmk80xx_find_usb_endpoints(struct comedi_device *dev) + struct vmk80xx_private *devpriv = dev->private; + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usb_host_interface *iface_desc = intf->cur_altsetting; +- struct usb_endpoint_descriptor *ep_desc; +- int i; +- +- if (iface_desc->desc.bNumEndpoints != 2) +- return -ENODEV; +- +- for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { +- ep_desc = &iface_desc->endpoint[i].desc; +- +- if (usb_endpoint_is_int_in(ep_desc) || +- usb_endpoint_is_bulk_in(ep_desc)) { +- if (!devpriv->ep_rx) +- devpriv->ep_rx = ep_desc; +- continue; +- } ++ struct usb_endpoint_descriptor *ep_rx_desc, *ep_tx_desc; ++ int ret; + +- if (usb_endpoint_is_int_out(ep_desc) || +- usb_endpoint_is_bulk_out(ep_desc)) { +- if (!devpriv->ep_tx) +- devpriv->ep_tx = ep_desc; +- continue; +- } +- } ++ if (devpriv->model == VMK8061_MODEL) ++ ret = usb_find_common_endpoints(iface_desc, &ep_rx_desc, ++ &ep_tx_desc, NULL, NULL); ++ else ++ ret = usb_find_common_endpoints(iface_desc, NULL, NULL, ++ &ep_rx_desc, &ep_tx_desc); + +- if (!devpriv->ep_rx || !devpriv->ep_tx) ++ if (ret) + return -ENODEV; + ++ devpriv->ep_rx = ep_rx_desc; ++ devpriv->ep_tx = ep_tx_desc; ++ + if (!usb_endpoint_maxp(devpriv->ep_rx) || !usb_endpoint_maxp(devpriv->ep_tx)) + return -EINVAL; + +diff --git a/drivers/counter/ti-eqep.c b/drivers/counter/ti-eqep.c +index b0f24cf3e891de..4d3de4a35801fc 100644 +--- a/drivers/counter/ti-eqep.c ++++ b/drivers/counter/ti-eqep.c +@@ -6,6 +6,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -376,6 +377,7 @@ static int ti_eqep_probe(struct platform_device *pdev) + struct counter_device *counter; + struct ti_eqep_cnt *priv; + void __iomem *base; ++ struct clk *clk; + int err; + + counter = devm_counter_alloc(dev, sizeof(*priv)); +@@ -415,6 +417,10 @@ static int ti_eqep_probe(struct platform_device *pdev) + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + ++ clk = devm_clk_get_enabled(dev, NULL); ++ if (IS_ERR(clk)) ++ return dev_err_probe(dev, PTR_ERR(clk), "failed to enable clock\n"); ++ + err = counter_add(counter); + if (err < 0) { + pm_runtime_put_sync(dev); +diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm +index 123b4bbfcfee19..c5cecbd89ba9ce 100644 +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -173,6 +173,7 @@ config ARM_QCOM_CPUFREQ_NVMEM + config ARM_QCOM_CPUFREQ_HW + tristate "QCOM CPUFreq HW driver" + depends on ARCH_QCOM || COMPILE_TEST ++ depends on COMMON_CLK + help + Support for the CPUFreq HW driver. + Some QCOM chipsets have a HW engine to offload the steps +diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c +index 37f1cdf46d2918..4ac3a35dcd983c 100644 +--- a/drivers/cpufreq/acpi-cpufreq.c ++++ b/drivers/cpufreq/acpi-cpufreq.c +@@ -890,8 +890,10 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) + if (perf->states[0].core_frequency * 1000 != freq_table[0].frequency) + pr_warn(FW_WARN "P-state 0 is not max freq\n"); + +- if (acpi_cpufreq_driver.set_boost) ++ if (acpi_cpufreq_driver.set_boost) { + set_boost(policy, acpi_cpufreq_driver.boost_enabled); ++ policy->boost_enabled = acpi_cpufreq_driver.boost_enabled; ++ } + + return result; + +diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c +index 9a1e194d5cf882..f461f99eb040c6 100644 +--- a/drivers/cpufreq/amd-pstate.c ++++ b/drivers/cpufreq/amd-pstate.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -49,6 +50,8 @@ + + #define AMD_PSTATE_TRANSITION_LATENCY 20000 + #define AMD_PSTATE_TRANSITION_DELAY 1000 ++#define CPPC_HIGHEST_PERF_PERFORMANCE 196 ++#define CPPC_HIGHEST_PERF_DEFAULT 166 + + /* + * TODO: We need more time to fine tune processors with shared memory solution +@@ -64,6 +67,7 @@ static struct cpufreq_driver amd_pstate_driver; + static struct cpufreq_driver amd_pstate_epp_driver; + static int cppc_state = AMD_PSTATE_UNDEFINED; + static bool cppc_enabled; ++static bool amd_pstate_prefcore = true; + + /* + * AMD Energy Preference Performance (EPP) +@@ -175,6 +179,26 @@ static int amd_pstate_get_energy_pref_index(struct amd_cpudata *cpudata) + return index; + } + ++static void pstate_update_perf(struct amd_cpudata *cpudata, u32 min_perf, ++ u32 des_perf, u32 max_perf, bool fast_switch) ++{ ++ if (fast_switch) ++ wrmsrl(MSR_AMD_CPPC_REQ, READ_ONCE(cpudata->cppc_req_cached)); ++ else ++ wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, ++ READ_ONCE(cpudata->cppc_req_cached)); ++} ++ ++DEFINE_STATIC_CALL(amd_pstate_update_perf, pstate_update_perf); ++ ++static inline void amd_pstate_update_perf(struct amd_cpudata *cpudata, ++ u32 min_perf, u32 des_perf, ++ u32 max_perf, bool fast_switch) ++{ ++ static_call(amd_pstate_update_perf)(cpudata, min_perf, des_perf, ++ max_perf, fast_switch); ++} ++ + static int amd_pstate_set_epp(struct amd_cpudata *cpudata, u32 epp) + { + int ret; +@@ -191,6 +215,9 @@ static int amd_pstate_set_epp(struct amd_cpudata *cpudata, u32 epp) + if (!ret) + cpudata->epp_cached = epp; + } else { ++ amd_pstate_update_perf(cpudata, cpudata->min_limit_perf, 0U, ++ cpudata->max_limit_perf, false); ++ + perf_ctrls.energy_perf = epp; + ret = cppc_set_epp_perf(cpudata->cpu, &perf_ctrls, 1); + if (ret) { +@@ -287,6 +314,21 @@ static inline int amd_pstate_enable(bool enable) + return static_call(amd_pstate_enable)(enable); + } + ++static u32 amd_pstate_highest_perf_set(struct amd_cpudata *cpudata) ++{ ++ struct cpuinfo_x86 *c = &cpu_data(0); ++ ++ /* ++ * For AMD CPUs with Family ID 19H and Model ID range 0x70 to 0x7f, ++ * the highest performance level is set to 196. ++ * https://bugzilla.kernel.org/show_bug.cgi?id=218759 ++ */ ++ if (c->x86 == 0x19 && (c->x86_model >= 0x70 && c->x86_model <= 0x7f)) ++ return CPPC_HIGHEST_PERF_PERFORMANCE; ++ ++ return CPPC_HIGHEST_PERF_DEFAULT; ++} ++ + static int pstate_init_perf(struct amd_cpudata *cpudata) + { + u64 cap1; +@@ -297,21 +339,22 @@ static int pstate_init_perf(struct amd_cpudata *cpudata) + if (ret) + return ret; + +- /* +- * TODO: Introduce AMD specific power feature. +- * +- * CPPC entry doesn't indicate the highest performance in some ASICs. ++ /* For platforms that do not support the preferred core feature, the ++ * highest_pef may be configured with 166 or 255, to avoid max frequency ++ * calculated wrongly. we take the AMD_CPPC_HIGHEST_PERF(cap1) value as ++ * the default max perf. + */ +- highest_perf = amd_get_highest_perf(); +- if (highest_perf > AMD_CPPC_HIGHEST_PERF(cap1)) ++ if (cpudata->hw_prefcore) ++ highest_perf = amd_pstate_highest_perf_set(cpudata); ++ else + highest_perf = AMD_CPPC_HIGHEST_PERF(cap1); + + WRITE_ONCE(cpudata->highest_perf, highest_perf); +- ++ WRITE_ONCE(cpudata->max_limit_perf, highest_perf); + WRITE_ONCE(cpudata->nominal_perf, AMD_CPPC_NOMINAL_PERF(cap1)); + WRITE_ONCE(cpudata->lowest_nonlinear_perf, AMD_CPPC_LOWNONLIN_PERF(cap1)); + WRITE_ONCE(cpudata->lowest_perf, AMD_CPPC_LOWEST_PERF(cap1)); +- ++ WRITE_ONCE(cpudata->min_limit_perf, AMD_CPPC_LOWEST_PERF(cap1)); + return 0; + } + +@@ -324,16 +367,18 @@ static int cppc_init_perf(struct amd_cpudata *cpudata) + if (ret) + return ret; + +- highest_perf = amd_get_highest_perf(); +- if (highest_perf > cppc_perf.highest_perf) ++ if (cpudata->hw_prefcore) ++ highest_perf = amd_pstate_highest_perf_set(cpudata); ++ else + highest_perf = cppc_perf.highest_perf; + + WRITE_ONCE(cpudata->highest_perf, highest_perf); +- ++ WRITE_ONCE(cpudata->max_limit_perf, highest_perf); + WRITE_ONCE(cpudata->nominal_perf, cppc_perf.nominal_perf); + WRITE_ONCE(cpudata->lowest_nonlinear_perf, + cppc_perf.lowest_nonlinear_perf); + WRITE_ONCE(cpudata->lowest_perf, cppc_perf.lowest_perf); ++ WRITE_ONCE(cpudata->min_limit_perf, cppc_perf.lowest_perf); + + if (cppc_state == AMD_PSTATE_ACTIVE) + return 0; +@@ -360,16 +405,6 @@ static inline int amd_pstate_init_perf(struct amd_cpudata *cpudata) + return static_call(amd_pstate_init_perf)(cpudata); + } + +-static void pstate_update_perf(struct amd_cpudata *cpudata, u32 min_perf, +- u32 des_perf, u32 max_perf, bool fast_switch) +-{ +- if (fast_switch) +- wrmsrl(MSR_AMD_CPPC_REQ, READ_ONCE(cpudata->cppc_req_cached)); +- else +- wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, +- READ_ONCE(cpudata->cppc_req_cached)); +-} +- + static void cppc_update_perf(struct amd_cpudata *cpudata, + u32 min_perf, u32 des_perf, + u32 max_perf, bool fast_switch) +@@ -383,16 +418,6 @@ static void cppc_update_perf(struct amd_cpudata *cpudata, + cppc_set_perf(cpudata->cpu, &perf_ctrls); + } + +-DEFINE_STATIC_CALL(amd_pstate_update_perf, pstate_update_perf); +- +-static inline void amd_pstate_update_perf(struct amd_cpudata *cpudata, +- u32 min_perf, u32 des_perf, +- u32 max_perf, bool fast_switch) +-{ +- static_call(amd_pstate_update_perf)(cpudata, min_perf, des_perf, +- max_perf, fast_switch); +-} +- + static inline bool amd_pstate_sample(struct amd_cpudata *cpudata) + { + u64 aperf, mperf, tsc; +@@ -432,6 +457,10 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf, + u64 prev = READ_ONCE(cpudata->cppc_req_cached); + u64 value = prev; + ++ min_perf = clamp_t(unsigned long, min_perf, cpudata->min_limit_perf, ++ cpudata->max_limit_perf); ++ max_perf = clamp_t(unsigned long, max_perf, cpudata->min_limit_perf, ++ cpudata->max_limit_perf); + des_perf = clamp_t(unsigned long, des_perf, min_perf, max_perf); + + if ((cppc_state == AMD_PSTATE_GUIDED) && (gov_flags & CPUFREQ_GOV_DYNAMIC_SWITCHING)) { +@@ -470,6 +499,22 @@ static int amd_pstate_verify(struct cpufreq_policy_data *policy) + return 0; + } + ++static int amd_pstate_update_min_max_limit(struct cpufreq_policy *policy) ++{ ++ u32 max_limit_perf, min_limit_perf; ++ struct amd_cpudata *cpudata = policy->driver_data; ++ ++ max_limit_perf = div_u64(policy->max * cpudata->highest_perf, cpudata->max_freq); ++ min_limit_perf = div_u64(policy->min * cpudata->highest_perf, cpudata->max_freq); ++ ++ WRITE_ONCE(cpudata->max_limit_perf, max_limit_perf); ++ WRITE_ONCE(cpudata->min_limit_perf, min_limit_perf); ++ WRITE_ONCE(cpudata->max_limit_freq, policy->max); ++ WRITE_ONCE(cpudata->min_limit_freq, policy->min); ++ ++ return 0; ++} ++ + static int amd_pstate_update_freq(struct cpufreq_policy *policy, + unsigned int target_freq, bool fast_switch) + { +@@ -480,6 +525,9 @@ static int amd_pstate_update_freq(struct cpufreq_policy *policy, + if (!cpudata->max_freq) + return -ENODEV; + ++ if (policy->min != cpudata->min_limit_freq || policy->max != cpudata->max_limit_freq) ++ amd_pstate_update_min_max_limit(policy); ++ + cap_perf = READ_ONCE(cpudata->highest_perf); + min_perf = READ_ONCE(cpudata->lowest_perf); + max_perf = cap_perf; +@@ -518,7 +566,9 @@ static int amd_pstate_target(struct cpufreq_policy *policy, + static unsigned int amd_pstate_fast_switch(struct cpufreq_policy *policy, + unsigned int target_freq) + { +- return amd_pstate_update_freq(policy, target_freq, true); ++ if (!amd_pstate_update_freq(policy, target_freq, true)) ++ return target_freq; ++ return policy->cur; + } + + static void amd_pstate_adjust_perf(unsigned int cpu, +@@ -532,6 +582,10 @@ static void amd_pstate_adjust_perf(unsigned int cpu, + struct amd_cpudata *cpudata = policy->driver_data; + unsigned int target_freq; + ++ if (policy->min != cpudata->min_limit_freq || policy->max != cpudata->max_limit_freq) ++ amd_pstate_update_min_max_limit(policy); ++ ++ + cap_perf = READ_ONCE(cpudata->highest_perf); + lowest_nonlinear_perf = READ_ONCE(cpudata->lowest_nonlinear_perf); + max_freq = READ_ONCE(cpudata->max_freq); +@@ -540,7 +594,7 @@ static void amd_pstate_adjust_perf(unsigned int cpu, + if (target_perf < capacity) + des_perf = DIV_ROUND_UP(cap_perf * target_perf, capacity); + +- min_perf = READ_ONCE(cpudata->highest_perf); ++ min_perf = READ_ONCE(cpudata->lowest_perf); + if (_min_perf < capacity) + min_perf = DIV_ROUND_UP(cap_perf * _min_perf, capacity); + +@@ -676,6 +730,80 @@ static void amd_perf_ctl_reset(unsigned int cpu) + wrmsrl_on_cpu(cpu, MSR_AMD_PERF_CTL, 0); + } + ++/* ++ * Set amd-pstate preferred core enable can't be done directly from cpufreq callbacks ++ * due to locking, so queue the work for later. ++ */ ++static void amd_pstste_sched_prefcore_workfn(struct work_struct *work) ++{ ++ sched_set_itmt_support(); ++} ++static DECLARE_WORK(sched_prefcore_work, amd_pstste_sched_prefcore_workfn); ++ ++/* ++ * Get the highest performance register value. ++ * @cpu: CPU from which to get highest performance. ++ * @highest_perf: Return address. ++ * ++ * Return: 0 for success, -EIO otherwise. ++ */ ++static int amd_pstate_get_highest_perf(int cpu, u32 *highest_perf) ++{ ++ int ret; ++ ++ if (boot_cpu_has(X86_FEATURE_CPPC)) { ++ u64 cap1; ++ ++ ret = rdmsrl_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &cap1); ++ if (ret) ++ return ret; ++ WRITE_ONCE(*highest_perf, AMD_CPPC_HIGHEST_PERF(cap1)); ++ } else { ++ u64 cppc_highest_perf; ++ ++ ret = cppc_get_highest_perf(cpu, &cppc_highest_perf); ++ if (ret) ++ return ret; ++ WRITE_ONCE(*highest_perf, cppc_highest_perf); ++ } ++ ++ return (ret); ++} ++ ++#define CPPC_MAX_PERF U8_MAX ++ ++static void amd_pstate_init_prefcore(struct amd_cpudata *cpudata) ++{ ++ int ret, prio; ++ u32 highest_perf; ++ ++ ret = amd_pstate_get_highest_perf(cpudata->cpu, &highest_perf); ++ if (ret) ++ return; ++ ++ cpudata->hw_prefcore = true; ++ /* check if CPPC preferred core feature is enabled*/ ++ if (highest_perf < CPPC_MAX_PERF) ++ prio = (int)highest_perf; ++ else { ++ pr_debug("AMD CPPC preferred core is unsupported!\n"); ++ cpudata->hw_prefcore = false; ++ return; ++ } ++ ++ if (!amd_pstate_prefcore) ++ return; ++ ++ /* ++ * The priorities can be set regardless of whether or not ++ * sched_set_itmt_support(true) has been called and it is valid to ++ * update them at any time after it has been called. ++ */ ++ sched_set_itmt_core_prio(prio, cpudata->cpu); ++ ++ schedule_work(&sched_prefcore_work); ++} ++ + static int amd_pstate_cpu_init(struct cpufreq_policy *policy) + { + int min_freq, max_freq, nominal_freq, lowest_nonlinear_freq, ret; +@@ -697,6 +825,8 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy) + + cpudata->cpu = policy->cpu; + ++ amd_pstate_init_prefcore(cpudata); ++ + ret = amd_pstate_init_perf(cpudata); + if (ret) + goto free_cpudata1; +@@ -745,6 +875,8 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy) + /* Initial processor data capability frequencies */ + cpudata->max_freq = max_freq; + cpudata->min_freq = min_freq; ++ cpudata->max_limit_freq = max_freq; ++ cpudata->min_limit_freq = min_freq; + cpudata->nominal_freq = nominal_freq; + cpudata->lowest_nonlinear_freq = lowest_nonlinear_freq; + +@@ -845,16 +977,32 @@ static ssize_t show_amd_pstate_highest_perf(struct cpufreq_policy *policy, + return sysfs_emit(buf, "%u\n", perf); + } + ++static ssize_t show_amd_pstate_hw_prefcore(struct cpufreq_policy *policy, ++ char *buf) ++{ ++ bool hw_prefcore; ++ struct amd_cpudata *cpudata = policy->driver_data; ++ ++ hw_prefcore = READ_ONCE(cpudata->hw_prefcore); ++ ++ return sysfs_emit(buf, "%s\n", str_enabled_disabled(hw_prefcore)); ++} ++ + static ssize_t show_energy_performance_available_preferences( + struct cpufreq_policy *policy, char *buf) + { + int i = 0; + int offset = 0; ++ struct amd_cpudata *cpudata = policy->driver_data; ++ ++ if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) ++ return sysfs_emit_at(buf, offset, "%s\n", ++ energy_perf_strings[EPP_INDEX_PERFORMANCE]); + + while (energy_perf_strings[i] != NULL) + offset += sysfs_emit_at(buf, offset, "%s ", energy_perf_strings[i++]); + +- sysfs_emit_at(buf, offset, "\n"); ++ offset += sysfs_emit_at(buf, offset, "\n"); + + return offset; + } +@@ -1037,18 +1185,27 @@ static ssize_t status_store(struct device *a, struct device_attribute *b, + return ret < 0 ? ret : count; + } + ++static ssize_t prefcore_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ return sysfs_emit(buf, "%s\n", str_enabled_disabled(amd_pstate_prefcore)); ++} ++ + cpufreq_freq_attr_ro(amd_pstate_max_freq); + cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq); + + cpufreq_freq_attr_ro(amd_pstate_highest_perf); ++cpufreq_freq_attr_ro(amd_pstate_hw_prefcore); + cpufreq_freq_attr_rw(energy_performance_preference); + cpufreq_freq_attr_ro(energy_performance_available_preferences); + static DEVICE_ATTR_RW(status); ++static DEVICE_ATTR_RO(prefcore); + + static struct freq_attr *amd_pstate_attr[] = { + &amd_pstate_max_freq, + &amd_pstate_lowest_nonlinear_freq, + &amd_pstate_highest_perf, ++ &amd_pstate_hw_prefcore, + NULL, + }; + +@@ -1056,6 +1213,7 @@ static struct freq_attr *amd_pstate_epp_attr[] = { + &amd_pstate_max_freq, + &amd_pstate_lowest_nonlinear_freq, + &amd_pstate_highest_perf, ++ &amd_pstate_hw_prefcore, + &energy_performance_preference, + &energy_performance_available_preferences, + NULL, +@@ -1063,6 +1221,7 @@ static struct freq_attr *amd_pstate_epp_attr[] = { + + static struct attribute *pstate_global_attributes[] = { + &dev_attr_status.attr, ++ &dev_attr_prefcore.attr, + NULL + }; + +@@ -1114,6 +1273,8 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) + cpudata->cpu = policy->cpu; + cpudata->epp_policy = 0; + ++ amd_pstate_init_prefcore(cpudata); ++ + ret = amd_pstate_init_perf(cpudata); + if (ret) + goto free_cpudata1; +@@ -1179,21 +1340,36 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) + + static int amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy) + { ++ struct amd_cpudata *cpudata = policy->driver_data; ++ ++ if (cpudata) { ++ kfree(cpudata); ++ policy->driver_data = NULL; ++ } ++ + pr_debug("CPU %d exiting\n", policy->cpu); + return 0; + } + +-static void amd_pstate_epp_init(unsigned int cpu) ++static void amd_pstate_epp_update_limit(struct cpufreq_policy *policy) + { +- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); + struct amd_cpudata *cpudata = policy->driver_data; +- u32 max_perf, min_perf; ++ u32 max_perf, min_perf, min_limit_perf, max_limit_perf; + u64 value; + s16 epp; + + max_perf = READ_ONCE(cpudata->highest_perf); + min_perf = READ_ONCE(cpudata->lowest_perf); ++ max_limit_perf = div_u64(policy->max * cpudata->highest_perf, cpudata->max_freq); ++ min_limit_perf = div_u64(policy->min * cpudata->highest_perf, cpudata->max_freq); + ++ WRITE_ONCE(cpudata->max_limit_perf, max_limit_perf); ++ WRITE_ONCE(cpudata->min_limit_perf, min_limit_perf); ++ ++ max_perf = clamp_t(unsigned long, max_perf, cpudata->min_limit_perf, ++ cpudata->max_limit_perf); ++ min_perf = clamp_t(unsigned long, min_perf, cpudata->min_limit_perf, ++ cpudata->max_limit_perf); + value = READ_ONCE(cpudata->cppc_req_cached); + + if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) +@@ -1210,9 +1386,6 @@ static void amd_pstate_epp_init(unsigned int cpu) + value &= ~AMD_CPPC_DES_PERF(~0L); + value |= AMD_CPPC_DES_PERF(0); + +- if (cpudata->epp_policy == cpudata->policy) +- goto skip_epp; +- + cpudata->epp_policy = cpudata->policy; + + /* Get BIOS pre-defined epp value */ +@@ -1222,7 +1395,7 @@ static void amd_pstate_epp_init(unsigned int cpu) + * This return value can only be negative for shared_memory + * systems where EPP register read/write not supported. + */ +- goto skip_epp; ++ return; + } + + if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) +@@ -1236,8 +1409,6 @@ static void amd_pstate_epp_init(unsigned int cpu) + + WRITE_ONCE(cpudata->cppc_req_cached, value); + amd_pstate_set_epp(cpudata, epp); +-skip_epp: +- cpufreq_cpu_put(policy); + } + + static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy) +@@ -1252,7 +1423,7 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy) + + cpudata->policy = policy->policy; + +- amd_pstate_epp_init(policy->cpu); ++ amd_pstate_epp_update_limit(policy); + + return 0; + } +@@ -1527,7 +1698,17 @@ static int __init amd_pstate_param(char *str) + + return amd_pstate_set_driver(mode_idx); + } ++ ++static int __init amd_prefcore_param(char *str) ++{ ++ if (!strcmp(str, "disable")) ++ amd_pstate_prefcore = false; ++ ++ return 0; ++} ++ + early_param("amd_pstate", amd_pstate_param); ++early_param("amd_prefcore", amd_prefcore_param); + + MODULE_AUTHOR("Huang Rui "); + MODULE_DESCRIPTION("AMD Processor P-state Frequency Driver"); +diff --git a/drivers/cpufreq/brcmstb-avs-cpufreq.c b/drivers/cpufreq/brcmstb-avs-cpufreq.c +index 35fb3a559ea97b..ea8438550b4901 100644 +--- a/drivers/cpufreq/brcmstb-avs-cpufreq.c ++++ b/drivers/cpufreq/brcmstb-avs-cpufreq.c +@@ -481,7 +481,12 @@ static bool brcm_avs_is_firmware_loaded(struct private_data *priv) + static unsigned int brcm_avs_cpufreq_get(unsigned int cpu) + { + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); +- struct private_data *priv = policy->driver_data; ++ struct private_data *priv; ++ ++ if (!policy) ++ return 0; ++ ++ priv = policy->driver_data; + + cpufreq_cpu_put(policy); + +diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c +index fe08ca419b3dc3..1ba3943be8a3dd 100644 +--- a/drivers/cpufreq/cppc_cpufreq.c ++++ b/drivers/cpufreq/cppc_cpufreq.c +@@ -844,10 +844,15 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) + { + struct cppc_perf_fb_ctrs fb_ctrs_t0 = {0}, fb_ctrs_t1 = {0}; + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); +- struct cppc_cpudata *cpu_data = policy->driver_data; ++ struct cppc_cpudata *cpu_data; + u64 delivered_perf; + int ret; + ++ if (!policy) ++ return -ENODEV; ++ ++ cpu_data = policy->driver_data; ++ + cpufreq_cpu_put(policy); + + ret = cppc_get_perf_ctrs(cpu, &fb_ctrs_t0); +@@ -927,10 +932,15 @@ static struct cpufreq_driver cppc_cpufreq_driver = { + static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpu) + { + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); +- struct cppc_cpudata *cpu_data = policy->driver_data; ++ struct cppc_cpudata *cpu_data; + u64 desired_perf; + int ret; + ++ if (!policy) ++ return -ENODEV; ++ ++ cpu_data = policy->driver_data; ++ + cpufreq_cpu_put(policy); + + ret = cppc_get_desired_perf(cpu, &desired_perf); +diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c +index 8bd6e5e8f121ce..2d83bbc65dd0bd 100644 +--- a/drivers/cpufreq/cpufreq-dt.c ++++ b/drivers/cpufreq/cpufreq-dt.c +@@ -208,7 +208,7 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu) + if (!priv) + return -ENOMEM; + +- if (!alloc_cpumask_var(&priv->cpus, GFP_KERNEL)) ++ if (!zalloc_cpumask_var(&priv->cpus, GFP_KERNEL)) + return -ENOMEM; + + cpumask_set_cpu(cpu, priv->cpus); +diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c +index 60ed89000e82dc..df445b44e9ec0b 100644 +--- a/drivers/cpufreq/cpufreq.c ++++ b/drivers/cpufreq/cpufreq.c +@@ -644,14 +644,16 @@ static ssize_t store_local_boost(struct cpufreq_policy *policy, + if (policy->boost_enabled == enable) + return count; + ++ policy->boost_enabled = enable; ++ + cpus_read_lock(); + ret = cpufreq_driver->set_boost(policy, enable); + cpus_read_unlock(); + +- if (ret) ++ if (ret) { ++ policy->boost_enabled = !policy->boost_enabled; + return ret; +- +- policy->boost_enabled = enable; ++ } + + return count; + } +@@ -1419,6 +1421,10 @@ static int cpufreq_online(unsigned int cpu) + goto out_free_policy; + } + ++ /* Let the per-policy boost flag mirror the cpufreq_driver boost during init */ ++ if (cpufreq_boost_enabled() && policy_has_boost_freq(policy)) ++ policy->boost_enabled = true; ++ + /* + * The initialization has succeeded and the policy is online. + * If there is a problem with its frequency table, take it +@@ -1571,7 +1577,8 @@ static int cpufreq_online(unsigned int cpu) + if (cpufreq_driver->ready) + cpufreq_driver->ready(policy); + +- if (cpufreq_thermal_control_enabled(cpufreq_driver)) ++ /* Register cpufreq cooling only for a new policy */ ++ if (new_policy && cpufreq_thermal_control_enabled(cpufreq_driver)) + policy->cdev = of_cpufreq_cooling_register(policy); + + pr_debug("initialization complete\n"); +@@ -1655,11 +1662,6 @@ static void __cpufreq_offline(unsigned int cpu, struct cpufreq_policy *policy) + else + policy->last_policy = policy->policy; + +- if (cpufreq_thermal_control_enabled(cpufreq_driver)) { +- cpufreq_cooling_unregister(policy->cdev); +- policy->cdev = NULL; +- } +- + if (has_target()) + cpufreq_exit_governor(policy); + +@@ -1669,10 +1671,13 @@ static void __cpufreq_offline(unsigned int cpu, struct cpufreq_policy *policy) + */ + if (cpufreq_driver->offline) { + cpufreq_driver->offline(policy); +- } else if (cpufreq_driver->exit) { +- cpufreq_driver->exit(policy); +- policy->freq_table = NULL; ++ return; + } ++ ++ if (cpufreq_driver->exit) ++ cpufreq_driver->exit(policy); ++ ++ policy->freq_table = NULL; + } + + static int cpufreq_offline(unsigned int cpu) +@@ -1720,8 +1725,17 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) + return; + } + ++ /* ++ * Unregister cpufreq cooling once all the CPUs of the policy are ++ * removed. ++ */ ++ if (cpufreq_thermal_control_enabled(cpufreq_driver)) { ++ cpufreq_cooling_unregister(policy->cdev); ++ policy->cdev = NULL; ++ } ++ + /* We did light-weight exit earlier, do full tear down now */ +- if (cpufreq_driver->offline) ++ if (cpufreq_driver->offline && cpufreq_driver->exit) + cpufreq_driver->exit(policy); + + up_write(&policy->rwsem); +@@ -2756,11 +2770,12 @@ int cpufreq_boost_trigger_state(int state) + + cpus_read_lock(); + for_each_active_policy(policy) { ++ policy->boost_enabled = state; + ret = cpufreq_driver->set_boost(policy, state); +- if (ret) ++ if (ret) { ++ policy->boost_enabled = !policy->boost_enabled; + goto err_reset_state; +- +- policy->boost_enabled = state; ++ } + } + cpus_read_unlock(); + +diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c +index a33df3c66c88c2..40a9ff18da068c 100644 +--- a/drivers/cpufreq/cpufreq_stats.c ++++ b/drivers/cpufreq/cpufreq_stats.c +@@ -131,23 +131,23 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) + len += sysfs_emit_at(buf, len, " From : To\n"); + len += sysfs_emit_at(buf, len, " : "); + for (i = 0; i < stats->state_num; i++) { +- if (len >= PAGE_SIZE) ++ if (len >= PAGE_SIZE - 1) + break; + len += sysfs_emit_at(buf, len, "%9u ", stats->freq_table[i]); + } +- if (len >= PAGE_SIZE) +- return PAGE_SIZE; ++ if (len >= PAGE_SIZE - 1) ++ return PAGE_SIZE - 1; + + len += sysfs_emit_at(buf, len, "\n"); + + for (i = 0; i < stats->state_num; i++) { +- if (len >= PAGE_SIZE) ++ if (len >= PAGE_SIZE - 1) + break; + + len += sysfs_emit_at(buf, len, "%9u: ", stats->freq_table[i]); + + for (j = 0; j < stats->state_num; j++) { +- if (len >= PAGE_SIZE) ++ if (len >= PAGE_SIZE - 1) + break; + + if (pending) +@@ -157,12 +157,12 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) + + len += sysfs_emit_at(buf, len, "%9u ", count); + } +- if (len >= PAGE_SIZE) ++ if (len >= PAGE_SIZE - 1) + break; + len += sysfs_emit_at(buf, len, "\n"); + } + +- if (len >= PAGE_SIZE) { ++ if (len >= PAGE_SIZE - 1) { + pr_warn_once("cpufreq transition table exceeds PAGE_SIZE. Disabling\n"); + return -EFBIG; + } +diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c +index c4d4643b6ca650..c17dc51a5a022d 100644 +--- a/drivers/cpufreq/freq_table.c ++++ b/drivers/cpufreq/freq_table.c +@@ -40,7 +40,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, + cpufreq_for_each_valid_entry(pos, table) { + freq = pos->frequency; + +- if (!cpufreq_boost_enabled() ++ if ((!cpufreq_boost_enabled() || !policy->boost_enabled) + && (pos->flags & CPUFREQ_BOOST_FREQ)) + continue; + +diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c +index 494d044b9e7207..33728c242f66ca 100644 +--- a/drivers/cpufreq/imx6q-cpufreq.c ++++ b/drivers/cpufreq/imx6q-cpufreq.c +@@ -327,7 +327,7 @@ static int imx6ul_opp_check_speed_grading(struct device *dev) + imx6x_disable_freq_in_opp(dev, 696000000); + + if (of_machine_is_compatible("fsl,imx6ull")) { +- if (val != OCOTP_CFG3_6ULL_SPEED_792MHZ) ++ if (val < OCOTP_CFG3_6ULL_SPEED_792MHZ) + imx6x_disable_freq_in_opp(dev, 792000000); + + if (val != OCOTP_CFG3_6ULL_SPEED_900MHZ) +diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c +index dc50c9fb488dfc..8a4fdf212ce0de 100644 +--- a/drivers/cpufreq/intel_pstate.c ++++ b/drivers/cpufreq/intel_pstate.c +@@ -356,15 +356,14 @@ static void intel_pstate_set_itmt_prio(int cpu) + int ret; + + ret = cppc_get_perf_caps(cpu, &cppc_perf); +- if (ret) +- return; +- + /* +- * On some systems with overclocking enabled, CPPC.highest_perf is hardcoded to 0xff. +- * In this case we can't use CPPC.highest_perf to enable ITMT. +- * In this case we can look at MSR_HWP_CAPABILITIES bits [8:0] to decide. ++ * If CPPC is not available, fall back to MSR_HWP_CAPABILITIES bits [8:0]. ++ * ++ * Also, on some systems with overclocking enabled, CPPC.highest_perf is ++ * hardcoded to 0xff, so CPPC.highest_perf cannot be used to enable ITMT. ++ * Fall back to MSR_HWP_CAPABILITIES then too. + */ +- if (cppc_perf.highest_perf == CPPC_MAX_PERF) ++ if (ret || cppc_perf.highest_perf == CPPC_MAX_PERF) + cppc_perf.highest_perf = HWP_HIGHEST_PERF(READ_ONCE(all_cpu_data[cpu]->hwp_cap_cached)); + + /* +@@ -526,6 +525,30 @@ static int intel_pstate_cppc_get_scaling(int cpu) + } + #endif /* CONFIG_ACPI_CPPC_LIB */ + ++static int intel_pstate_freq_to_hwp_rel(struct cpudata *cpu, int freq, ++ unsigned int relation) ++{ ++ if (freq == cpu->pstate.turbo_freq) ++ return cpu->pstate.turbo_pstate; ++ ++ if (freq == cpu->pstate.max_freq) ++ return cpu->pstate.max_pstate; ++ ++ switch (relation) { ++ case CPUFREQ_RELATION_H: ++ return freq / cpu->pstate.scaling; ++ case CPUFREQ_RELATION_C: ++ return DIV_ROUND_CLOSEST(freq, cpu->pstate.scaling); ++ } ++ ++ return DIV_ROUND_UP(freq, cpu->pstate.scaling); ++} ++ ++static int intel_pstate_freq_to_hwp(struct cpudata *cpu, int freq) ++{ ++ return intel_pstate_freq_to_hwp_rel(cpu, freq, CPUFREQ_RELATION_L); ++} ++ + /** + * intel_pstate_hybrid_hwp_adjust - Calibrate HWP performance levels. + * @cpu: Target CPU. +@@ -543,6 +566,7 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu) + int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling; + int perf_ctl_turbo = pstate_funcs.get_turbo(cpu->cpu); + int scaling = cpu->pstate.scaling; ++ int freq; + + pr_debug("CPU%d: perf_ctl_max_phys = %d\n", cpu->cpu, perf_ctl_max_phys); + pr_debug("CPU%d: perf_ctl_turbo = %d\n", cpu->cpu, perf_ctl_turbo); +@@ -556,16 +580,16 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu) + cpu->pstate.max_freq = rounddown(cpu->pstate.max_pstate * scaling, + perf_ctl_scaling); + +- cpu->pstate.max_pstate_physical = +- DIV_ROUND_UP(perf_ctl_max_phys * perf_ctl_scaling, +- scaling); ++ freq = perf_ctl_max_phys * perf_ctl_scaling; ++ cpu->pstate.max_pstate_physical = intel_pstate_freq_to_hwp(cpu, freq); + +- cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling; ++ freq = cpu->pstate.min_pstate * perf_ctl_scaling; ++ cpu->pstate.min_freq = freq; + /* + * Cast the min P-state value retrieved via pstate_funcs.get_min() to + * the effective range of HWP performance levels. + */ +- cpu->pstate.min_pstate = DIV_ROUND_UP(cpu->pstate.min_freq, scaling); ++ cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, freq); + } + + static inline void update_turbo_state(void) +@@ -1608,7 +1632,7 @@ static void intel_pstate_notify_work(struct work_struct *work) + wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_STATUS, 0); + } + +-static DEFINE_SPINLOCK(hwp_notify_lock); ++static DEFINE_RAW_SPINLOCK(hwp_notify_lock); + static cpumask_t hwp_intr_enable_mask; + + void notify_hwp_interrupt(void) +@@ -1625,7 +1649,7 @@ void notify_hwp_interrupt(void) + if (!(value & 0x01)) + return; + +- spin_lock_irqsave(&hwp_notify_lock, flags); ++ raw_spin_lock_irqsave(&hwp_notify_lock, flags); + + if (!cpumask_test_cpu(this_cpu, &hwp_intr_enable_mask)) + goto ack_intr; +@@ -1649,13 +1673,13 @@ void notify_hwp_interrupt(void) + + schedule_delayed_work(&cpudata->hwp_notify_work, msecs_to_jiffies(10)); + +- spin_unlock_irqrestore(&hwp_notify_lock, flags); ++ raw_spin_unlock_irqrestore(&hwp_notify_lock, flags); + + return; + + ack_intr: + wrmsrl_safe(MSR_HWP_STATUS, 0); +- spin_unlock_irqrestore(&hwp_notify_lock, flags); ++ raw_spin_unlock_irqrestore(&hwp_notify_lock, flags); + } + + static void intel_pstate_disable_hwp_interrupt(struct cpudata *cpudata) +@@ -1668,10 +1692,10 @@ static void intel_pstate_disable_hwp_interrupt(struct cpudata *cpudata) + /* wrmsrl_on_cpu has to be outside spinlock as this can result in IPC */ + wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x00); + +- spin_lock_irqsave(&hwp_notify_lock, flags); ++ raw_spin_lock_irqsave(&hwp_notify_lock, flags); + if (cpumask_test_and_clear_cpu(cpudata->cpu, &hwp_intr_enable_mask)) + cancel_delayed_work(&cpudata->hwp_notify_work); +- spin_unlock_irqrestore(&hwp_notify_lock, flags); ++ raw_spin_unlock_irqrestore(&hwp_notify_lock, flags); + } + + static void intel_pstate_enable_hwp_interrupt(struct cpudata *cpudata) +@@ -1680,10 +1704,10 @@ static void intel_pstate_enable_hwp_interrupt(struct cpudata *cpudata) + if (boot_cpu_has(X86_FEATURE_HWP_NOTIFY)) { + unsigned long flags; + +- spin_lock_irqsave(&hwp_notify_lock, flags); ++ raw_spin_lock_irqsave(&hwp_notify_lock, flags); + INIT_DELAYED_WORK(&cpudata->hwp_notify_work, intel_pstate_notify_work); + cpumask_set_cpu(cpudata->cpu, &hwp_intr_enable_mask); +- spin_unlock_irqrestore(&hwp_notify_lock, flags); ++ raw_spin_unlock_irqrestore(&hwp_notify_lock, flags); + + /* wrmsrl_on_cpu has to be outside spinlock as this can result in IPC */ + wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x01); +@@ -2528,13 +2552,12 @@ static void intel_pstate_update_perf_limits(struct cpudata *cpu, + * abstract values to represent performance rather than pure ratios. + */ + if (hwp_active && cpu->pstate.scaling != perf_ctl_scaling) { +- int scaling = cpu->pstate.scaling; + int freq; + + freq = max_policy_perf * perf_ctl_scaling; +- max_policy_perf = DIV_ROUND_UP(freq, scaling); ++ max_policy_perf = intel_pstate_freq_to_hwp(cpu, freq); + freq = min_policy_perf * perf_ctl_scaling; +- min_policy_perf = DIV_ROUND_UP(freq, scaling); ++ min_policy_perf = intel_pstate_freq_to_hwp(cpu, freq); + } + + pr_debug("cpu:%d min_policy_perf:%d max_policy_perf:%d\n", +@@ -2908,18 +2931,7 @@ static int intel_cpufreq_target(struct cpufreq_policy *policy, + + cpufreq_freq_transition_begin(policy, &freqs); + +- switch (relation) { +- case CPUFREQ_RELATION_L: +- target_pstate = DIV_ROUND_UP(freqs.new, cpu->pstate.scaling); +- break; +- case CPUFREQ_RELATION_H: +- target_pstate = freqs.new / cpu->pstate.scaling; +- break; +- default: +- target_pstate = DIV_ROUND_CLOSEST(freqs.new, cpu->pstate.scaling); +- break; +- } +- ++ target_pstate = intel_pstate_freq_to_hwp_rel(cpu, freqs.new, relation); + target_pstate = intel_cpufreq_update_pstate(policy, target_pstate, false); + + freqs.new = target_pstate * cpu->pstate.scaling; +@@ -2937,7 +2949,7 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy, + + update_turbo_state(); + +- target_pstate = DIV_ROUND_UP(target_freq, cpu->pstate.scaling); ++ target_pstate = intel_pstate_freq_to_hwp(cpu, target_freq); + + target_pstate = intel_cpufreq_update_pstate(policy, target_pstate, true); + +@@ -2974,6 +2986,9 @@ static void intel_cpufreq_adjust_perf(unsigned int cpunum, + if (min_pstate < cpu->min_perf_ratio) + min_pstate = cpu->min_perf_ratio; + ++ if (min_pstate > cpu->max_perf_ratio) ++ min_pstate = cpu->max_perf_ratio; ++ + max_pstate = min(cap_pstate, cpu->max_perf_ratio); + if (max_pstate < min_pstate) + max_pstate = min_pstate; +@@ -3121,10 +3136,10 @@ static void intel_pstate_driver_cleanup(void) + if (intel_pstate_driver == &intel_pstate) + intel_pstate_clear_update_util_hook(cpu); + +- spin_lock(&hwp_notify_lock); ++ raw_spin_lock(&hwp_notify_lock); + kfree(all_cpu_data[cpu]); + WRITE_ONCE(all_cpu_data[cpu], NULL); +- spin_unlock(&hwp_notify_lock); ++ raw_spin_unlock(&hwp_notify_lock); + } + } + cpus_read_unlock(); +diff --git a/drivers/cpufreq/mediatek-cpufreq-hw.c b/drivers/cpufreq/mediatek-cpufreq-hw.c +index d46afb3c009230..8d097dcddda47d 100644 +--- a/drivers/cpufreq/mediatek-cpufreq-hw.c ++++ b/drivers/cpufreq/mediatek-cpufreq-hw.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + #define LUT_MAX_ENTRIES 32U +@@ -300,7 +301,23 @@ static struct cpufreq_driver cpufreq_mtk_hw_driver = { + static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev) + { + const void *data; +- int ret; ++ int ret, cpu; ++ struct device *cpu_dev; ++ struct regulator *cpu_reg; ++ ++ /* Make sure that all CPU supplies are available before proceeding. */ ++ for_each_possible_cpu(cpu) { ++ cpu_dev = get_cpu_device(cpu); ++ if (!cpu_dev) ++ return dev_err_probe(&pdev->dev, -EPROBE_DEFER, ++ "Failed to get cpu%d device\n", cpu); ++ ++ cpu_reg = devm_regulator_get(cpu_dev, "cpu"); ++ if (IS_ERR(cpu_reg)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(cpu_reg), ++ "CPU%d regulator get failed\n", cpu); ++ } ++ + + data = of_device_get_match_data(&pdev->dev); + if (!data) +diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c +index 84d7033e5efe83..ef51dfb39baa92 100644 +--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c ++++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c +@@ -40,10 +40,14 @@ struct qcom_cpufreq_match_data { + const char **genpd_names; + }; + ++struct qcom_cpufreq_drv_cpu { ++ int opp_token; ++}; ++ + struct qcom_cpufreq_drv { +- int *opp_tokens; + u32 versions; + const struct qcom_cpufreq_match_data *data; ++ struct qcom_cpufreq_drv_cpu cpus[]; + }; + + static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev; +@@ -243,42 +247,39 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) + return -ENOENT; + } + +- drv = kzalloc(sizeof(*drv), GFP_KERNEL); +- if (!drv) ++ drv = devm_kzalloc(&pdev->dev, struct_size(drv, cpus, num_possible_cpus()), ++ GFP_KERNEL); ++ if (!drv) { ++ of_node_put(np); + return -ENOMEM; ++ } + + match = pdev->dev.platform_data; + drv->data = match->data; + if (!drv->data) { +- ret = -ENODEV; +- goto free_drv; ++ of_node_put(np); ++ return -ENODEV; + } + + if (drv->data->get_version) { + speedbin_nvmem = of_nvmem_cell_get(np, NULL); + if (IS_ERR(speedbin_nvmem)) { +- ret = dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem), +- "Could not get nvmem cell\n"); +- goto free_drv; ++ of_node_put(np); ++ return dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem), ++ "Could not get nvmem cell\n"); + } + + ret = drv->data->get_version(cpu_dev, + speedbin_nvmem, &pvs_name, drv); + if (ret) { ++ of_node_put(np); + nvmem_cell_put(speedbin_nvmem); +- goto free_drv; ++ return ret; + } + nvmem_cell_put(speedbin_nvmem); + } + of_node_put(np); + +- drv->opp_tokens = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tokens), +- GFP_KERNEL); +- if (!drv->opp_tokens) { +- ret = -ENOMEM; +- goto free_drv; +- } +- + for_each_possible_cpu(cpu) { + struct dev_pm_opp_config config = { + .supported_hw = NULL, +@@ -304,9 +305,9 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) + } + + if (config.supported_hw || config.genpd_names) { +- drv->opp_tokens[cpu] = dev_pm_opp_set_config(cpu_dev, &config); +- if (drv->opp_tokens[cpu] < 0) { +- ret = drv->opp_tokens[cpu]; ++ drv->cpus[cpu].opp_token = dev_pm_opp_set_config(cpu_dev, &config); ++ if (drv->cpus[cpu].opp_token < 0) { ++ ret = drv->cpus[cpu].opp_token; + dev_err(cpu_dev, "Failed to set OPP config\n"); + goto free_opp; + } +@@ -325,11 +326,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) + + free_opp: + for_each_possible_cpu(cpu) +- dev_pm_opp_clear_config(drv->opp_tokens[cpu]); +- kfree(drv->opp_tokens); +-free_drv: +- kfree(drv); +- ++ dev_pm_opp_clear_config(drv->cpus[cpu].opp_token); + return ret; + } + +@@ -341,10 +338,7 @@ static void qcom_cpufreq_remove(struct platform_device *pdev) + platform_device_unregister(cpufreq_dt_pdev); + + for_each_possible_cpu(cpu) +- dev_pm_opp_clear_config(drv->opp_tokens[cpu]); +- +- kfree(drv->opp_tokens); +- kfree(drv); ++ dev_pm_opp_clear_config(drv->cpus[cpu].opp_token); + } + + static struct platform_driver qcom_cpufreq_driver = { +diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c +index f34e6382a4c500..079940c69ee0ba 100644 +--- a/drivers/cpufreq/scmi-cpufreq.c ++++ b/drivers/cpufreq/scmi-cpufreq.c +@@ -62,9 +62,9 @@ static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy, + unsigned int target_freq) + { + struct scmi_data *priv = policy->driver_data; ++ unsigned long freq = target_freq; + +- if (!perf_ops->freq_set(ph, priv->domain_id, +- target_freq * 1000, true)) ++ if (!perf_ops->freq_set(ph, priv->domain_id, freq * 1000, true)) + return target_freq; + + return 0; +@@ -310,8 +310,11 @@ static int scmi_cpufreq_probe(struct scmi_device *sdev) + + #ifdef CONFIG_COMMON_CLK + /* dummy clock provider as needed by OPP if clocks property is used */ +- if (of_property_present(dev->of_node, "#clock-cells")) +- devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, NULL); ++ if (of_property_present(dev->of_node, "#clock-cells")) { ++ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, NULL); ++ if (ret) ++ return dev_err_probe(dev, ret, "%s: registering clock provider failed\n", __func__); ++ } + #endif + + ret = cpufreq_register_driver(&scmi_cpufreq_driver); +diff --git a/drivers/cpufreq/tegra194-cpufreq.c b/drivers/cpufreq/tegra194-cpufreq.c +index 88ef5e57ccd05c..386aed3637b4ef 100644 +--- a/drivers/cpufreq/tegra194-cpufreq.c ++++ b/drivers/cpufreq/tegra194-cpufreq.c +@@ -450,6 +450,8 @@ static int tegra_cpufreq_init_cpufreq_table(struct cpufreq_policy *policy, + if (IS_ERR(opp)) + continue; + ++ dev_pm_opp_put(opp); ++ + ret = dev_pm_opp_enable(cpu_dev, pos->frequency * KHZ); + if (ret < 0) + return ret; +diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c +index 3c37d78996607f..cb5d1c8fefeb44 100644 +--- a/drivers/cpufreq/ti-cpufreq.c ++++ b/drivers/cpufreq/ti-cpufreq.c +@@ -61,6 +61,9 @@ struct ti_cpufreq_soc_data { + unsigned long efuse_shift; + unsigned long rev_offset; + bool multi_regulator; ++/* Backward compatibility hack: Might have missing syscon */ ++#define TI_QUIRK_SYSCON_MAY_BE_MISSING 0x1 ++ u8 quirks; + }; + + struct ti_cpufreq_data { +@@ -182,6 +185,7 @@ static struct ti_cpufreq_soc_data omap34xx_soc_data = { + .efuse_mask = BIT(3), + .rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE, + .multi_regulator = false, ++ .quirks = TI_QUIRK_SYSCON_MAY_BE_MISSING, + }; + + /* +@@ -209,6 +213,7 @@ static struct ti_cpufreq_soc_data omap36xx_soc_data = { + .efuse_mask = BIT(9), + .rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE, + .multi_regulator = true, ++ .quirks = TI_QUIRK_SYSCON_MAY_BE_MISSING, + }; + + /* +@@ -223,6 +228,7 @@ static struct ti_cpufreq_soc_data am3517_soc_data = { + .efuse_mask = 0, + .rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE, + .multi_regulator = false, ++ .quirks = TI_QUIRK_SYSCON_MAY_BE_MISSING, + }; + + static struct ti_cpufreq_soc_data am625_soc_data = { +@@ -250,7 +256,7 @@ static int ti_cpufreq_get_efuse(struct ti_cpufreq_data *opp_data, + + ret = regmap_read(opp_data->syscon, opp_data->soc_data->efuse_offset, + &efuse); +- if (ret == -EIO) { ++ if (opp_data->soc_data->quirks & TI_QUIRK_SYSCON_MAY_BE_MISSING && ret == -EIO) { + /* not a syscon register! */ + void __iomem *regs = ioremap(OMAP3_SYSCON_BASE + + opp_data->soc_data->efuse_offset, 4); +@@ -291,7 +297,7 @@ static int ti_cpufreq_get_rev(struct ti_cpufreq_data *opp_data, + + ret = regmap_read(opp_data->syscon, opp_data->soc_data->rev_offset, + &revision); +- if (ret == -EIO) { ++ if (opp_data->soc_data->quirks & TI_QUIRK_SYSCON_MAY_BE_MISSING && ret == -EIO) { + /* not a syscon register! */ + void __iomem *regs = ioremap(OMAP3_SYSCON_BASE + + opp_data->soc_data->rev_offset, 4); +@@ -418,7 +424,7 @@ static int ti_cpufreq_probe(struct platform_device *pdev) + + ret = dev_pm_opp_set_config(opp_data->cpu_dev, &config); + if (ret < 0) { +- dev_err(opp_data->cpu_dev, "Failed to set OPP config\n"); ++ dev_err_probe(opp_data->cpu_dev, ret, "Failed to set OPP config\n"); + goto fail_put_node; + } + +diff --git a/drivers/cpuidle/cpuidle-haltpoll.c b/drivers/cpuidle/cpuidle-haltpoll.c +index e66df22f96955f..d8515d5c0853dc 100644 +--- a/drivers/cpuidle/cpuidle-haltpoll.c ++++ b/drivers/cpuidle/cpuidle-haltpoll.c +@@ -25,13 +25,12 @@ MODULE_PARM_DESC(force, "Load unconditionally"); + static struct cpuidle_device __percpu *haltpoll_cpuidle_devices; + static enum cpuhp_state haltpoll_hp_state; + +-static int default_enter_idle(struct cpuidle_device *dev, +- struct cpuidle_driver *drv, int index) ++static __cpuidle int default_enter_idle(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index) + { +- if (current_clr_polling_and_test()) { +- local_irq_enable(); ++ if (current_clr_polling_and_test()) + return index; +- } ++ + arch_cpu_idle(); + return index; + } +diff --git a/drivers/cpuidle/cpuidle-riscv-sbi.c b/drivers/cpuidle/cpuidle-riscv-sbi.c +index e8094fc92491eb..c0fe92409175a4 100644 +--- a/drivers/cpuidle/cpuidle-riscv-sbi.c ++++ b/drivers/cpuidle/cpuidle-riscv-sbi.c +@@ -8,6 +8,7 @@ + + #define pr_fmt(fmt) "cpuidle-riscv-sbi: " fmt + ++#include + #include + #include + #include +@@ -267,19 +268,16 @@ static int sbi_cpuidle_dt_init_states(struct device *dev, + { + struct sbi_cpuidle_data *data = per_cpu_ptr(&sbi_cpuidle_data, cpu); + struct device_node *state_node; +- struct device_node *cpu_node; + u32 *states; + int i, ret; + +- cpu_node = of_cpu_device_node_get(cpu); ++ struct device_node *cpu_node __free(device_node) = of_cpu_device_node_get(cpu); + if (!cpu_node) + return -ENODEV; + + states = devm_kcalloc(dev, state_count, sizeof(*states), GFP_KERNEL); +- if (!states) { +- ret = -ENOMEM; +- goto fail; +- } ++ if (!states) ++ return -ENOMEM; + + /* Parse SBI specific details from state DT nodes */ + for (i = 1; i < state_count; i++) { +@@ -295,10 +293,8 @@ static int sbi_cpuidle_dt_init_states(struct device *dev, + + pr_debug("sbi-state %#x index %d\n", states[i], i); + } +- if (i != state_count) { +- ret = -ENODEV; +- goto fail; +- } ++ if (i != state_count) ++ return -ENODEV; + + /* Initialize optional data, used for the hierarchical topology. */ + ret = sbi_dt_cpu_init_topology(drv, data, state_count, cpu); +@@ -308,10 +304,7 @@ static int sbi_cpuidle_dt_init_states(struct device *dev, + /* Store states in the per-cpu struct. */ + data->states = states; + +-fail: +- of_node_put(cpu_node); +- +- return ret; ++ return 0; + } + + static void sbi_cpuidle_deinit_cpu(int cpu) +diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c +index d9cda7f6ccb98d..cf5873cc45dc8c 100644 +--- a/drivers/cpuidle/driver.c ++++ b/drivers/cpuidle/driver.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + + #include "cpuidle.h" + +@@ -187,7 +188,7 @@ static void __cpuidle_driver_init(struct cpuidle_driver *drv) + s->target_residency = div_u64(s->target_residency_ns, NSEC_PER_USEC); + + if (s->exit_latency > 0) +- s->exit_latency_ns = s->exit_latency * NSEC_PER_USEC; ++ s->exit_latency_ns = mul_u32_u32(s->exit_latency, NSEC_PER_USEC); + else if (s->exit_latency_ns < 0) + s->exit_latency_ns = 0; + else +diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c +index 8d4c42863a621e..d2cf9619018b1a 100644 +--- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c ++++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c +@@ -299,22 +299,6 @@ static int sun8i_ce_cipher_prepare(struct crypto_engine *engine, void *async_req + return err; + } + +-static void sun8i_ce_cipher_run(struct crypto_engine *engine, void *areq) +-{ +- struct skcipher_request *breq = container_of(areq, struct skcipher_request, base); +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(breq); +- struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); +- struct sun8i_ce_dev *ce = op->ce; +- struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(breq); +- int flow, err; +- +- flow = rctx->flow; +- err = sun8i_ce_run_task(ce, flow, crypto_tfm_alg_name(breq->base.tfm)); +- local_bh_disable(); +- crypto_finalize_skcipher_request(engine, breq, err); +- local_bh_enable(); +-} +- + static void sun8i_ce_cipher_unprepare(struct crypto_engine *engine, + void *async_req) + { +@@ -360,6 +344,23 @@ static void sun8i_ce_cipher_unprepare(struct crypto_engine *engine, + dma_unmap_single(ce->dev, rctx->addr_key, op->keylen, DMA_TO_DEVICE); + } + ++static void sun8i_ce_cipher_run(struct crypto_engine *engine, void *areq) ++{ ++ struct skcipher_request *breq = container_of(areq, struct skcipher_request, base); ++ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(breq); ++ struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); ++ struct sun8i_ce_dev *ce = op->ce; ++ struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(breq); ++ int flow, err; ++ ++ flow = rctx->flow; ++ err = sun8i_ce_run_task(ce, flow, crypto_tfm_alg_name(breq->base.tfm)); ++ sun8i_ce_cipher_unprepare(engine, areq); ++ local_bh_disable(); ++ crypto_finalize_skcipher_request(engine, breq, err); ++ local_bh_enable(); ++} ++ + int sun8i_ce_cipher_do_one(struct crypto_engine *engine, void *areq) + { + int err = sun8i_ce_cipher_prepare(engine, areq); +@@ -368,7 +369,6 @@ int sun8i_ce_cipher_do_one(struct crypto_engine *engine, void *areq) + return err; + + sun8i_ce_cipher_run(engine, areq); +- sun8i_ce_cipher_unprepare(engine, areq); + return 0; + } + +diff --git a/drivers/crypto/bcm/spu2.c b/drivers/crypto/bcm/spu2.c +index 07989bb8c220a4..3fdc64b5a65e7e 100644 +--- a/drivers/crypto/bcm/spu2.c ++++ b/drivers/crypto/bcm/spu2.c +@@ -495,7 +495,7 @@ static void spu2_dump_omd(u8 *omd, u16 hash_key_len, u16 ciph_key_len, + if (hash_iv_len) { + packet_log(" Hash IV Length %u bytes\n", hash_iv_len); + packet_dump(" hash IV: ", ptr, hash_iv_len); +- ptr += ciph_key_len; ++ ptr += hash_iv_len; + } + + if (ciph_iv_len) { +diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c +index eba2d750c3b074..066f08a3a040d8 100644 +--- a/drivers/crypto/caam/caamalg.c ++++ b/drivers/crypto/caam/caamalg.c +@@ -575,7 +575,8 @@ static int chachapoly_setkey(struct crypto_aead *aead, const u8 *key, + if (keylen != CHACHA_KEY_SIZE + saltlen) + return -EINVAL; + +- ctx->cdata.key_virt = key; ++ memcpy(ctx->key, key, keylen); ++ ctx->cdata.key_virt = ctx->key; + ctx->cdata.keylen = keylen - saltlen; + + return chachapoly_set_sh_desc(aead); +diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c +index 9156bbe038b7b0..a148ff1f0872c4 100644 +--- a/drivers/crypto/caam/caamalg_qi2.c ++++ b/drivers/crypto/caam/caamalg_qi2.c +@@ -641,7 +641,8 @@ static int chachapoly_setkey(struct crypto_aead *aead, const u8 *key, + if (keylen != CHACHA_KEY_SIZE + saltlen) + return -EINVAL; + +- ctx->cdata.key_virt = key; ++ memcpy(ctx->key, key, keylen); ++ ctx->cdata.key_virt = ctx->key; + ctx->cdata.keylen = keylen - saltlen; + + return chachapoly_set_sh_desc(aead); +diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c +index 290c8500c247f9..65785dc5b73b2b 100644 +--- a/drivers/crypto/caam/caamhash.c ++++ b/drivers/crypto/caam/caamhash.c +@@ -708,6 +708,7 @@ static struct ahash_edesc *ahash_edesc_alloc(struct ahash_request *req, + GFP_KERNEL : GFP_ATOMIC; + struct ahash_edesc *edesc; + ++ sg_num = pad_sg_nents(sg_num); + edesc = kzalloc(struct_size(edesc, sec4_sg, sg_num), flags); + if (!edesc) + return NULL; +diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c +index aa4e1a5006919d..cb8e99936abb72 100644 +--- a/drivers/crypto/ccp/ccp-ops.c ++++ b/drivers/crypto/ccp/ccp-ops.c +@@ -179,8 +179,11 @@ static int ccp_init_dm_workarea(struct ccp_dm_workarea *wa, + + wa->dma.address = dma_map_single(wa->dev, wa->address, len, + dir); +- if (dma_mapping_error(wa->dev, wa->dma.address)) ++ if (dma_mapping_error(wa->dev, wa->dma.address)) { ++ kfree(wa->address); ++ wa->address = NULL; + return -ENOMEM; ++ } + + wa->dma.length = len; + } +diff --git a/drivers/crypto/ccp/dbc.c b/drivers/crypto/ccp/dbc.c +index 839ea14b9a853f..6f33149ef80df0 100644 +--- a/drivers/crypto/ccp/dbc.c ++++ b/drivers/crypto/ccp/dbc.c +@@ -205,7 +205,7 @@ int dbc_dev_init(struct psp_device *psp) + return -ENOMEM; + + BUILD_BUG_ON(sizeof(union dbc_buffer) > PAGE_SIZE); +- dbc_dev->mbox = (void *)devm_get_free_pages(dev, GFP_KERNEL, 0); ++ dbc_dev->mbox = (void *)devm_get_free_pages(dev, GFP_KERNEL | __GFP_ZERO, 0); + if (!dbc_dev->mbox) { + ret = -ENOMEM; + goto cleanup_dev; +diff --git a/drivers/crypto/ccp/platform-access.c b/drivers/crypto/ccp/platform-access.c +index 94367bc49e35b8..1b8ed33897332e 100644 +--- a/drivers/crypto/ccp/platform-access.c ++++ b/drivers/crypto/ccp/platform-access.c +@@ -118,9 +118,16 @@ int psp_send_platform_access_msg(enum psp_platform_access_msg msg, + goto unlock; + } + +- /* Store the status in request header for caller to investigate */ ++ /* ++ * Read status from PSP. If status is non-zero, it indicates an error ++ * occurred during "processing" of the command. ++ * If status is zero, it indicates the command was "processed" ++ * successfully, but the result of the command is in the payload. ++ * Return both cases to the caller as -EIO to investigate. ++ */ + cmd_reg = ioread32(cmd); +- req->header.status = FIELD_GET(PSP_CMDRESP_STS, cmd_reg); ++ if (FIELD_GET(PSP_CMDRESP_STS, cmd_reg)) ++ req->header.status = FIELD_GET(PSP_CMDRESP_STS, cmd_reg); + if (req->header.status) { + ret = -EIO; + goto unlock; +diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c +index f97166fba9d930..07e6f782b62252 100644 +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -520,10 +520,16 @@ EXPORT_SYMBOL_GPL(sev_platform_init); + + static int __sev_platform_shutdown_locked(int *error) + { +- struct sev_device *sev = psp_master->sev_data; ++ struct psp_device *psp = psp_master; ++ struct sev_device *sev; + int ret; + +- if (!sev || sev->state == SEV_STATE_UNINIT) ++ if (!psp || !psp->sev_data) ++ return 0; ++ ++ sev = psp->sev_data; ++ ++ if (sev->state == SEV_STATE_UNINIT) + return 0; + + ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, NULL, error); +@@ -1361,6 +1367,8 @@ void sev_pci_init(void) + return; + + err: ++ sev_dev_destroy(psp_master); ++ + psp_master->sev_data = NULL; + } + +diff --git a/drivers/crypto/ccp/sp-platform.c b/drivers/crypto/ccp/sp-platform.c +index 7d79a8744f9a6a..c43ad7e1acf7ea 100644 +--- a/drivers/crypto/ccp/sp-platform.c ++++ b/drivers/crypto/ccp/sp-platform.c +@@ -39,44 +39,38 @@ static const struct sp_dev_vdata dev_vdata[] = { + }, + }; + +-#ifdef CONFIG_ACPI + static const struct acpi_device_id sp_acpi_match[] = { + { "AMDI0C00", (kernel_ulong_t)&dev_vdata[0] }, + { }, + }; + MODULE_DEVICE_TABLE(acpi, sp_acpi_match); +-#endif + +-#ifdef CONFIG_OF + static const struct of_device_id sp_of_match[] = { + { .compatible = "amd,ccp-seattle-v1a", + .data = (const void *)&dev_vdata[0] }, + { }, + }; + MODULE_DEVICE_TABLE(of, sp_of_match); +-#endif + + static struct sp_dev_vdata *sp_get_of_version(struct platform_device *pdev) + { +-#ifdef CONFIG_OF + const struct of_device_id *match; + + match = of_match_node(sp_of_match, pdev->dev.of_node); + if (match && match->data) + return (struct sp_dev_vdata *)match->data; +-#endif ++ + return NULL; + } + + static struct sp_dev_vdata *sp_get_acpi_version(struct platform_device *pdev) + { +-#ifdef CONFIG_ACPI + const struct acpi_device_id *match; + + match = acpi_match_device(sp_acpi_match, &pdev->dev); + if (match && match->driver_data) + return (struct sp_dev_vdata *)match->driver_data; +-#endif ++ + return NULL; + } + +@@ -214,12 +208,8 @@ static int sp_platform_resume(struct platform_device *pdev) + static struct platform_driver sp_platform_driver = { + .driver = { + .name = "ccp", +-#ifdef CONFIG_ACPI + .acpi_match_table = sp_acpi_match, +-#endif +-#ifdef CONFIG_OF + .of_match_table = sp_of_match, +-#endif + }, + .probe = sp_platform_probe, + .remove = sp_platform_remove, +diff --git a/drivers/crypto/hisilicon/debugfs.c b/drivers/crypto/hisilicon/debugfs.c +index 2cc1591949db7e..bd205f1f2279e4 100644 +--- a/drivers/crypto/hisilicon/debugfs.c ++++ b/drivers/crypto/hisilicon/debugfs.c +@@ -794,8 +794,14 @@ static void dfx_regs_uninit(struct hisi_qm *qm, + { + int i; + ++ if (!dregs) ++ return; ++ + /* Setting the pointer is NULL to prevent double free */ + for (i = 0; i < reg_len; i++) { ++ if (!dregs[i].regs) ++ continue; ++ + kfree(dregs[i].regs); + dregs[i].regs = NULL; + } +@@ -845,14 +851,21 @@ static struct dfx_diff_registers *dfx_regs_init(struct hisi_qm *qm, + static int qm_diff_regs_init(struct hisi_qm *qm, + struct dfx_diff_registers *dregs, u32 reg_len) + { ++ int ret; ++ + qm->debug.qm_diff_regs = dfx_regs_init(qm, qm_diff_regs, ARRAY_SIZE(qm_diff_regs)); +- if (IS_ERR(qm->debug.qm_diff_regs)) +- return PTR_ERR(qm->debug.qm_diff_regs); ++ if (IS_ERR(qm->debug.qm_diff_regs)) { ++ ret = PTR_ERR(qm->debug.qm_diff_regs); ++ qm->debug.qm_diff_regs = NULL; ++ return ret; ++ } + + qm->debug.acc_diff_regs = dfx_regs_init(qm, dregs, reg_len); + if (IS_ERR(qm->debug.acc_diff_regs)) { + dfx_regs_uninit(qm, qm->debug.qm_diff_regs, ARRAY_SIZE(qm_diff_regs)); +- return PTR_ERR(qm->debug.acc_diff_regs); ++ ret = PTR_ERR(qm->debug.acc_diff_regs); ++ qm->debug.acc_diff_regs = NULL; ++ return ret; + } + + return 0; +@@ -893,7 +906,9 @@ static int qm_last_regs_init(struct hisi_qm *qm) + static void qm_diff_regs_uninit(struct hisi_qm *qm, u32 reg_len) + { + dfx_regs_uninit(qm, qm->debug.acc_diff_regs, reg_len); ++ qm->debug.acc_diff_regs = NULL; + dfx_regs_uninit(qm, qm->debug.qm_diff_regs, ARRAY_SIZE(qm_diff_regs)); ++ qm->debug.qm_diff_regs = NULL; + } + + /** +diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c +index 39297ce70f441e..3463f5ee83c0df 100644 +--- a/drivers/crypto/hisilicon/hpre/hpre_main.c ++++ b/drivers/crypto/hisilicon/hpre/hpre_main.c +@@ -13,9 +13,7 @@ + #include + #include "hpre.h" + +-#define HPRE_QM_ABNML_INT_MASK 0x100004 + #define HPRE_CTRL_CNT_CLR_CE_BIT BIT(0) +-#define HPRE_COMM_CNT_CLR_CE 0x0 + #define HPRE_CTRL_CNT_CLR_CE 0x301000 + #define HPRE_FSM_MAX_CNT 0x301008 + #define HPRE_VFG_AXQOS 0x30100c +@@ -42,7 +40,6 @@ + #define HPRE_HAC_INT_SET 0x301500 + #define HPRE_RNG_TIMEOUT_NUM 0x301A34 + #define HPRE_CORE_INT_ENABLE 0 +-#define HPRE_CORE_INT_DISABLE GENMASK(21, 0) + #define HPRE_RDCHN_INI_ST 0x301a00 + #define HPRE_CLSTR_BASE 0x302000 + #define HPRE_CORE_EN_OFFSET 0x04 +@@ -66,7 +63,6 @@ + #define HPRE_CLSTR_ADDR_INTRVL 0x1000 + #define HPRE_CLUSTER_INQURY 0x100 + #define HPRE_CLSTR_ADDR_INQRY_RSLT 0x104 +-#define HPRE_TIMEOUT_ABNML_BIT 6 + #define HPRE_PASID_EN_BIT 9 + #define HPRE_REG_RD_INTVRL_US 10 + #define HPRE_REG_RD_TMOUT_US 1000 +@@ -117,8 +113,6 @@ + #define HPRE_DFX_COMMON2_LEN 0xE + #define HPRE_DFX_CORE_LEN 0x43 + +-#define HPRE_DEV_ALG_MAX_LEN 256 +- + static const char hpre_name[] = "hisi_hpre"; + static struct dentry *hpre_debugfs_root; + static const struct pci_device_id hpre_dev_ids[] = { +@@ -134,12 +128,7 @@ struct hpre_hw_error { + const char *msg; + }; + +-struct hpre_dev_alg { +- u32 alg_msk; +- const char *alg; +-}; +- +-static const struct hpre_dev_alg hpre_dev_algs[] = { ++static const struct qm_dev_alg hpre_dev_algs[] = { + { + .alg_msk = BIT(0), + .alg = "rsa\n" +@@ -209,9 +198,9 @@ static const struct hisi_qm_cap_info hpre_basic_info[] = { + {HPRE_QM_RESET_MASK_CAP, 0x3128, 0, GENMASK(31, 0), 0x0, 0xC37, 0x6C37}, + {HPRE_QM_OOO_SHUTDOWN_MASK_CAP, 0x3128, 0, GENMASK(31, 0), 0x0, 0x4, 0x6C37}, + {HPRE_QM_CE_MASK_CAP, 0x312C, 0, GENMASK(31, 0), 0x0, 0x8, 0x8}, +- {HPRE_NFE_MASK_CAP, 0x3130, 0, GENMASK(31, 0), 0x0, 0x3FFFFE, 0x1FFFFFE}, +- {HPRE_RESET_MASK_CAP, 0x3134, 0, GENMASK(31, 0), 0x0, 0x3FFFFE, 0xBFFFFE}, +- {HPRE_OOO_SHUTDOWN_MASK_CAP, 0x3134, 0, GENMASK(31, 0), 0x0, 0x22, 0xBFFFFE}, ++ {HPRE_NFE_MASK_CAP, 0x3130, 0, GENMASK(31, 0), 0x0, 0x3FFFFE, 0x1FFFC3E}, ++ {HPRE_RESET_MASK_CAP, 0x3134, 0, GENMASK(31, 0), 0x0, 0x3FFFFE, 0xBFFC3E}, ++ {HPRE_OOO_SHUTDOWN_MASK_CAP, 0x3134, 0, GENMASK(31, 0), 0x0, 0x22, 0xBFFC3E}, + {HPRE_CE_MASK_CAP, 0x3138, 0, GENMASK(31, 0), 0x0, 0x1, 0x1}, + {HPRE_CLUSTER_NUM_CAP, 0x313c, 20, GENMASK(3, 0), 0x0, 0x4, 0x1}, + {HPRE_CORE_TYPE_NUM_CAP, 0x313c, 16, GENMASK(3, 0), 0x0, 0x2, 0x2}, +@@ -232,6 +221,20 @@ static const struct hisi_qm_cap_info hpre_basic_info[] = { + {HPRE_CORE10_ALG_BITMAP_CAP, 0x3170, 0, GENMASK(31, 0), 0x0, 0x10, 0x10} + }; + ++enum hpre_pre_store_cap_idx { ++ HPRE_CLUSTER_NUM_CAP_IDX = 0x0, ++ HPRE_CORE_ENABLE_BITMAP_CAP_IDX, ++ HPRE_DRV_ALG_BITMAP_CAP_IDX, ++ HPRE_DEV_ALG_BITMAP_CAP_IDX, ++}; ++ ++static const u32 hpre_pre_store_caps[] = { ++ HPRE_CLUSTER_NUM_CAP, ++ HPRE_CORE_ENABLE_BITMAP_CAP, ++ HPRE_DRV_ALG_BITMAP_CAP, ++ HPRE_DEV_ALG_BITMAP_CAP, ++}; ++ + static const struct hpre_hw_error hpre_hw_errors[] = { + { + .int_msk = BIT(0), +@@ -350,46 +353,19 @@ static struct dfx_diff_registers hpre_diff_regs[] = { + }, + }; + ++static const struct hisi_qm_err_ini hpre_err_ini; ++ + bool hpre_check_alg_support(struct hisi_qm *qm, u32 alg) + { + u32 cap_val; + +- cap_val = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_DRV_ALG_BITMAP_CAP, qm->cap_ver); ++ cap_val = qm->cap_tables.dev_cap_table[HPRE_DRV_ALG_BITMAP_CAP_IDX].cap_val; + if (alg & cap_val) + return true; + + return false; + } + +-static int hpre_set_qm_algs(struct hisi_qm *qm) +-{ +- struct device *dev = &qm->pdev->dev; +- char *algs, *ptr; +- u32 alg_msk; +- int i; +- +- if (!qm->use_sva) +- return 0; +- +- algs = devm_kzalloc(dev, HPRE_DEV_ALG_MAX_LEN * sizeof(char), GFP_KERNEL); +- if (!algs) +- return -ENOMEM; +- +- alg_msk = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_DEV_ALG_BITMAP_CAP, qm->cap_ver); +- +- for (i = 0; i < ARRAY_SIZE(hpre_dev_algs); i++) +- if (alg_msk & hpre_dev_algs[i].alg_msk) +- strcat(algs, hpre_dev_algs[i].alg); +- +- ptr = strrchr(algs, '\n'); +- if (ptr) +- *ptr = '\0'; +- +- qm->uacce->algs = algs; +- +- return 0; +-} +- + static int hpre_diff_regs_show(struct seq_file *s, void *unused) + { + struct hisi_qm *qm = s->private; +@@ -433,8 +409,11 @@ static u32 uacce_mode = UACCE_MODE_NOUACCE; + module_param_cb(uacce_mode, &hpre_uacce_mode_ops, &uacce_mode, 0444); + MODULE_PARM_DESC(uacce_mode, UACCE_MODE_DESC); + ++static bool pf_q_num_flag; + static int pf_q_num_set(const char *val, const struct kernel_param *kp) + { ++ pf_q_num_flag = true; ++ + return q_num_set(val, kp, PCI_DEVICE_ID_HUAWEI_HPRE_PF); + } + +@@ -456,16 +435,6 @@ static u32 vfs_num; + module_param_cb(vfs_num, &vfs_num_ops, &vfs_num, 0444); + MODULE_PARM_DESC(vfs_num, "Number of VFs to enable(1-63), 0(default)"); + +-static inline int hpre_cluster_num(struct hisi_qm *qm) +-{ +- return hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_CLUSTER_NUM_CAP, qm->cap_ver); +-} +- +-static inline int hpre_cluster_core_mask(struct hisi_qm *qm) +-{ +- return hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_CORE_ENABLE_BITMAP_CAP, qm->cap_ver); +-} +- + struct hisi_qp *hpre_create_qp(u8 type) + { + int node = cpu_to_node(smp_processor_id()); +@@ -532,13 +501,15 @@ static int hpre_cfg_by_dsm(struct hisi_qm *qm) + + static int hpre_set_cluster(struct hisi_qm *qm) + { +- u32 cluster_core_mask = hpre_cluster_core_mask(qm); +- u8 clusters_num = hpre_cluster_num(qm); + struct device *dev = &qm->pdev->dev; + unsigned long offset; ++ u32 cluster_core_mask; ++ u8 clusters_num; + u32 val = 0; + int ret, i; + ++ cluster_core_mask = qm->cap_tables.dev_cap_table[HPRE_CORE_ENABLE_BITMAP_CAP_IDX].cap_val; ++ clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; + for (i = 0; i < clusters_num; i++) { + offset = i * HPRE_CLSTR_ADDR_INTRVL; + +@@ -680,11 +651,6 @@ static int hpre_set_user_domain_and_cache(struct hisi_qm *qm) + writel(HPRE_QM_USR_CFG_MASK, qm->io_base + QM_AWUSER_M_CFG_ENABLE); + writel_relaxed(HPRE_QM_AXI_CFG_MASK, qm->io_base + QM_AXI_M_CFG); + +- /* HPRE need more time, we close this interrupt */ +- val = readl_relaxed(qm->io_base + HPRE_QM_ABNML_INT_MASK); +- val |= BIT(HPRE_TIMEOUT_ABNML_BIT); +- writel_relaxed(val, qm->io_base + HPRE_QM_ABNML_INT_MASK); +- + if (qm->ver >= QM_HW_V3) + writel(HPRE_RSA_ENB | HPRE_ECC_ENB, + qm->io_base + HPRE_TYPES_ENB); +@@ -693,9 +659,7 @@ static int hpre_set_user_domain_and_cache(struct hisi_qm *qm) + + writel(HPRE_QM_VFG_AX_MASK, qm->io_base + HPRE_VFG_AXCACHE); + writel(0x0, qm->io_base + HPRE_BD_ENDIAN); +- writel(0x0, qm->io_base + HPRE_INT_MASK); + writel(0x0, qm->io_base + HPRE_POISON_BYPASS); +- writel(0x0, qm->io_base + HPRE_COMM_CNT_CLR_CE); + writel(0x0, qm->io_base + HPRE_ECC_BYPASS); + + writel(HPRE_BD_USR_MASK, qm->io_base + HPRE_BD_ARUSR_CFG); +@@ -733,11 +697,12 @@ static int hpre_set_user_domain_and_cache(struct hisi_qm *qm) + + static void hpre_cnt_regs_clear(struct hisi_qm *qm) + { +- u8 clusters_num = hpre_cluster_num(qm); + unsigned long offset; ++ u8 clusters_num; + int i; + + /* clear clusterX/cluster_ctrl */ ++ clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; + for (i = 0; i < clusters_num; i++) { + offset = HPRE_CLSTR_BASE + i * HPRE_CLSTR_ADDR_INTRVL; + writel(0x0, qm->io_base + offset + HPRE_CLUSTER_INQURY); +@@ -784,7 +749,7 @@ static void hpre_hw_error_disable(struct hisi_qm *qm) + + static void hpre_hw_error_enable(struct hisi_qm *qm) + { +- u32 ce, nfe; ++ u32 ce, nfe, err_en; + + ce = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_CE_MASK_CAP, qm->cap_ver); + nfe = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_NFE_MASK_CAP, qm->cap_ver); +@@ -801,7 +766,8 @@ static void hpre_hw_error_enable(struct hisi_qm *qm) + hpre_master_ooo_ctrl(qm, true); + + /* enable hpre hw error interrupts */ +- writel(HPRE_CORE_INT_ENABLE, qm->io_base + HPRE_INT_MASK); ++ err_en = ce | nfe | HPRE_HAC_RAS_FE_ENABLE; ++ writel(~err_en, qm->io_base + HPRE_INT_MASK); + } + + static inline struct hisi_qm *hpre_file_to_qm(struct hpre_debugfs_file *file) +@@ -1024,16 +990,17 @@ static int hpre_pf_comm_regs_debugfs_init(struct hisi_qm *qm) + + static int hpre_cluster_debugfs_init(struct hisi_qm *qm) + { +- u8 clusters_num = hpre_cluster_num(qm); + struct device *dev = &qm->pdev->dev; + char buf[HPRE_DBGFS_VAL_MAX_LEN]; + struct debugfs_regset32 *regset; + struct dentry *tmp_d; ++ u8 clusters_num; + int i, ret; + ++ clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; + for (i = 0; i < clusters_num; i++) { + ret = snprintf(buf, HPRE_DBGFS_VAL_MAX_LEN, "cluster%d", i); +- if (ret < 0) ++ if (ret >= HPRE_DBGFS_VAL_MAX_LEN) + return -EINVAL; + tmp_d = debugfs_create_dir(buf, qm->debug.debug_root); + +@@ -1135,8 +1102,37 @@ static void hpre_debugfs_exit(struct hisi_qm *qm) + debugfs_remove_recursive(qm->debug.debug_root); + } + ++static int hpre_pre_store_cap_reg(struct hisi_qm *qm) ++{ ++ struct hisi_qm_cap_record *hpre_cap; ++ struct device *dev = &qm->pdev->dev; ++ size_t i, size; ++ ++ size = ARRAY_SIZE(hpre_pre_store_caps); ++ hpre_cap = devm_kzalloc(dev, sizeof(*hpre_cap) * size, GFP_KERNEL); ++ if (!hpre_cap) ++ return -ENOMEM; ++ ++ for (i = 0; i < size; i++) { ++ hpre_cap[i].type = hpre_pre_store_caps[i]; ++ hpre_cap[i].cap_val = hisi_qm_get_hw_info(qm, hpre_basic_info, ++ hpre_pre_store_caps[i], qm->cap_ver); ++ } ++ ++ if (hpre_cap[HPRE_CLUSTER_NUM_CAP_IDX].cap_val > HPRE_CLUSTERS_NUM_MAX) { ++ dev_err(dev, "Device cluster num %u is out of range for driver supports %d!\n", ++ hpre_cap[HPRE_CLUSTER_NUM_CAP_IDX].cap_val, HPRE_CLUSTERS_NUM_MAX); ++ return -EINVAL; ++ } ++ ++ qm->cap_tables.dev_cap_table = hpre_cap; ++ ++ return 0; ++} ++ + static int hpre_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) + { ++ u64 alg_msk; + int ret; + + if (pdev->revision == QM_HW_V1) { +@@ -1157,6 +1153,9 @@ static int hpre_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) + qm->qp_num = pf_q_num; + qm->debug.curr_qm_qp_num = pf_q_num; + qm->qm_list = &hpre_devices; ++ qm->err_ini = &hpre_err_ini; ++ if (pf_q_num_flag) ++ set_bit(QM_MODULE_PARAM, &qm->misc_ctl); + } + + ret = hisi_qm_init(qm); +@@ -1165,7 +1164,16 @@ static int hpre_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) + return ret; + } + +- ret = hpre_set_qm_algs(qm); ++ /* Fetch and save the value of capability registers */ ++ ret = hpre_pre_store_cap_reg(qm); ++ if (ret) { ++ pci_err(pdev, "Failed to pre-store capability registers!\n"); ++ hisi_qm_uninit(qm); ++ return ret; ++ } ++ ++ alg_msk = qm->cap_tables.dev_cap_table[HPRE_DEV_ALG_BITMAP_CAP_IDX].cap_val; ++ ret = hisi_qm_set_algs(qm, alg_msk, hpre_dev_algs, ARRAY_SIZE(hpre_dev_algs)); + if (ret) { + pci_err(pdev, "Failed to set hpre algs!\n"); + hisi_qm_uninit(qm); +@@ -1178,11 +1186,12 @@ static int hpre_show_last_regs_init(struct hisi_qm *qm) + { + int cluster_dfx_regs_num = ARRAY_SIZE(hpre_cluster_dfx_regs); + int com_dfx_regs_num = ARRAY_SIZE(hpre_com_dfx_regs); +- u8 clusters_num = hpre_cluster_num(qm); + struct qm_debug *debug = &qm->debug; + void __iomem *io_base; ++ u8 clusters_num; + int i, j, idx; + ++ clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; + debug->last_words = kcalloc(cluster_dfx_regs_num * clusters_num + + com_dfx_regs_num, sizeof(unsigned int), GFP_KERNEL); + if (!debug->last_words) +@@ -1219,10 +1228,10 @@ static void hpre_show_last_dfx_regs(struct hisi_qm *qm) + { + int cluster_dfx_regs_num = ARRAY_SIZE(hpre_cluster_dfx_regs); + int com_dfx_regs_num = ARRAY_SIZE(hpre_com_dfx_regs); +- u8 clusters_num = hpre_cluster_num(qm); + struct qm_debug *debug = &qm->debug; + struct pci_dev *pdev = qm->pdev; + void __iomem *io_base; ++ u8 clusters_num; + int i, j, idx; + u32 val; + +@@ -1237,6 +1246,7 @@ static void hpre_show_last_dfx_regs(struct hisi_qm *qm) + hpre_com_dfx_regs[i].name, debug->last_words[i], val); + } + ++ clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; + for (i = 0; i < clusters_num; i++) { + io_base = qm->io_base + hpre_cluster_offsets[i]; + for (j = 0; j < cluster_dfx_regs_num; j++) { +@@ -1333,8 +1343,6 @@ static int hpre_pf_probe_init(struct hpre *hpre) + + hpre_open_sva_prefetch(qm); + +- qm->err_ini = &hpre_err_ini; +- qm->err_ini->err_info_init(qm); + hisi_qm_dev_err_init(qm); + ret = hpre_show_last_regs_init(qm); + if (ret) +@@ -1363,6 +1371,18 @@ static int hpre_probe_init(struct hpre *hpre) + return 0; + } + ++static void hpre_probe_uninit(struct hisi_qm *qm) ++{ ++ if (qm->fun_type == QM_HW_VF) ++ return; ++ ++ hpre_cnt_regs_clear(qm); ++ qm->debug.curr_qm_qp_num = 0; ++ hpre_show_last_regs_uninit(qm); ++ hpre_close_sva_prefetch(qm); ++ hisi_qm_dev_err_uninit(qm); ++} ++ + static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id) + { + struct hisi_qm *qm; +@@ -1388,7 +1408,7 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id) + + ret = hisi_qm_start(qm); + if (ret) +- goto err_with_err_init; ++ goto err_with_probe_init; + + ret = hpre_debugfs_init(qm); + if (ret) +@@ -1425,9 +1445,8 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id) + hpre_debugfs_exit(qm); + hisi_qm_stop(qm, QM_NORMAL); + +-err_with_err_init: +- hpre_show_last_regs_uninit(qm); +- hisi_qm_dev_err_uninit(qm); ++err_with_probe_init: ++ hpre_probe_uninit(qm); + + err_with_qm_init: + hisi_qm_uninit(qm); +@@ -1448,13 +1467,7 @@ static void hpre_remove(struct pci_dev *pdev) + hpre_debugfs_exit(qm); + hisi_qm_stop(qm, QM_NORMAL); + +- if (qm->fun_type == QM_HW_PF) { +- hpre_cnt_regs_clear(qm); +- qm->debug.curr_qm_qp_num = 0; +- hpre_show_last_regs_uninit(qm); +- hisi_qm_dev_err_uninit(qm); +- } +- ++ hpre_probe_uninit(qm); + hisi_qm_uninit(qm); + } + +diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c +index a99fd589445cef..1b00edbbfe26a9 100644 +--- a/drivers/crypto/hisilicon/qm.c ++++ b/drivers/crypto/hisilicon/qm.c +@@ -206,8 +206,6 @@ + #define WAIT_PERIOD 20 + #define REMOVE_WAIT_DELAY 10 + +-#define QM_DRIVER_REMOVING 0 +-#define QM_RST_SCHED 1 + #define QM_QOS_PARAM_NUM 2 + #define QM_QOS_MAX_VAL 1000 + #define QM_QOS_RATE 100 +@@ -230,6 +228,8 @@ + #define QM_QOS_MAX_CIR_U 6 + #define QM_AUTOSUSPEND_DELAY 3000 + ++#define QM_DEV_ALG_MAX_LEN 256 ++ + #define QM_MK_CQC_DW3_V1(hop_num, pg_sz, buf_sz, cqe_sz) \ + (((hop_num) << QM_CQ_HOP_NUM_SHIFT) | \ + ((pg_sz) << QM_CQ_PAGE_SIZE_SHIFT) | \ +@@ -308,6 +308,13 @@ enum qm_basic_type { + QM_VF_IRQ_NUM_CAP, + }; + ++enum qm_pre_store_cap_idx { ++ QM_EQ_IRQ_TYPE_CAP_IDX = 0x0, ++ QM_AEQ_IRQ_TYPE_CAP_IDX, ++ QM_ABN_IRQ_TYPE_CAP_IDX, ++ QM_PF2VF_IRQ_TYPE_CAP_IDX, ++}; ++ + static const struct hisi_qm_cap_info qm_cap_info_comm[] = { + {QM_SUPPORT_DB_ISOLATION, 0x30, 0, BIT(0), 0x0, 0x0, 0x0}, + {QM_SUPPORT_FUNC_QOS, 0x3100, 0, BIT(8), 0x0, 0x0, 0x1}, +@@ -337,6 +344,13 @@ static const struct hisi_qm_cap_info qm_basic_info[] = { + {QM_VF_IRQ_NUM_CAP, 0x311c, 0, GENMASK(15, 0), 0x1, 0x2, 0x3}, + }; + ++static const u32 qm_pre_store_caps[] = { ++ QM_EQ_IRQ_TYPE_CAP, ++ QM_AEQ_IRQ_TYPE_CAP, ++ QM_ABN_IRQ_TYPE_CAP, ++ QM_PF2VF_IRQ_TYPE_CAP, ++}; ++ + struct qm_mailbox { + __le16 w0; + __le16 queue_num; +@@ -441,6 +455,7 @@ static struct qm_typical_qos_table shaper_cbs_s[] = { + }; + + static void qm_irqs_unregister(struct hisi_qm *qm); ++static int qm_reset_device(struct hisi_qm *qm); + + static bool qm_avail_state(struct hisi_qm *qm, enum qm_state new) + { +@@ -789,6 +804,40 @@ static void qm_get_xqc_depth(struct hisi_qm *qm, u16 *low_bits, + *high_bits = (depth >> QM_XQ_DEPTH_SHIFT) & QM_XQ_DEPTH_MASK; + } + ++int hisi_qm_set_algs(struct hisi_qm *qm, u64 alg_msk, const struct qm_dev_alg *dev_algs, ++ u32 dev_algs_size) ++{ ++ struct device *dev = &qm->pdev->dev; ++ char *algs, *ptr; ++ int i; ++ ++ if (!qm->uacce) ++ return 0; ++ ++ if (dev_algs_size >= QM_DEV_ALG_MAX_LEN) { ++ dev_err(dev, "algs size %u is equal or larger than %d.\n", ++ dev_algs_size, QM_DEV_ALG_MAX_LEN); ++ return -EINVAL; ++ } ++ ++ algs = devm_kzalloc(dev, QM_DEV_ALG_MAX_LEN * sizeof(char), GFP_KERNEL); ++ if (!algs) ++ return -ENOMEM; ++ ++ for (i = 0; i < dev_algs_size; i++) ++ if (alg_msk & dev_algs[i].alg_msk) ++ strcat(algs, dev_algs[i].alg); ++ ++ ptr = strrchr(algs, '\n'); ++ if (ptr) { ++ *ptr = '\0'; ++ qm->uacce->algs = algs; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(hisi_qm_set_algs); ++ + static u32 qm_get_irq_num(struct hisi_qm *qm) + { + if (qm->fun_type == QM_HW_PF) +@@ -849,53 +898,23 @@ static void qm_poll_req_cb(struct hisi_qp *qp) + qm_db(qm, qp->qp_id, QM_DOORBELL_CMD_CQ, + qp->qp_status.cq_head, 0); + atomic_dec(&qp->qp_status.used); ++ ++ cond_resched(); + } + + /* set c_flag */ + qm_db(qm, qp->qp_id, QM_DOORBELL_CMD_CQ, qp->qp_status.cq_head, 1); + } + +-static int qm_get_complete_eqe_num(struct hisi_qm_poll_data *poll_data) +-{ +- struct hisi_qm *qm = poll_data->qm; +- struct qm_eqe *eqe = qm->eqe + qm->status.eq_head; +- u16 eq_depth = qm->eq_depth; +- int eqe_num = 0; +- u16 cqn; +- +- while (QM_EQE_PHASE(eqe) == qm->status.eqc_phase) { +- cqn = le32_to_cpu(eqe->dw0) & QM_EQE_CQN_MASK; +- poll_data->qp_finish_id[eqe_num] = cqn; +- eqe_num++; +- +- if (qm->status.eq_head == eq_depth - 1) { +- qm->status.eqc_phase = !qm->status.eqc_phase; +- eqe = qm->eqe; +- qm->status.eq_head = 0; +- } else { +- eqe++; +- qm->status.eq_head++; +- } +- +- if (eqe_num == (eq_depth >> 1) - 1) +- break; +- } +- +- qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0); +- +- return eqe_num; +-} +- + static void qm_work_process(struct work_struct *work) + { + struct hisi_qm_poll_data *poll_data = + container_of(work, struct hisi_qm_poll_data, work); + struct hisi_qm *qm = poll_data->qm; ++ u16 eqe_num = poll_data->eqe_num; + struct hisi_qp *qp; +- int eqe_num, i; ++ int i; + +- /* Get qp id of completed tasks and re-enable the interrupt. */ +- eqe_num = qm_get_complete_eqe_num(poll_data); + for (i = eqe_num - 1; i >= 0; i--) { + qp = &qm->qp_array[poll_data->qp_finish_id[i]]; + if (unlikely(atomic_read(&qp->qp_status.flags) == QP_STOP)) +@@ -911,39 +930,55 @@ static void qm_work_process(struct work_struct *work) + } + } + +-static bool do_qm_eq_irq(struct hisi_qm *qm) ++static void qm_get_complete_eqe_num(struct hisi_qm *qm) + { + struct qm_eqe *eqe = qm->eqe + qm->status.eq_head; +- struct hisi_qm_poll_data *poll_data; +- u16 cqn; ++ struct hisi_qm_poll_data *poll_data = NULL; ++ u16 eq_depth = qm->eq_depth; ++ u16 cqn, eqe_num = 0; + +- if (!readl(qm->io_base + QM_VF_EQ_INT_SOURCE)) +- return false; ++ if (QM_EQE_PHASE(eqe) != qm->status.eqc_phase) { ++ atomic64_inc(&qm->debug.dfx.err_irq_cnt); ++ qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0); ++ return; ++ } + +- if (QM_EQE_PHASE(eqe) == qm->status.eqc_phase) { ++ cqn = le32_to_cpu(eqe->dw0) & QM_EQE_CQN_MASK; ++ if (unlikely(cqn >= qm->qp_num)) ++ return; ++ poll_data = &qm->poll_data[cqn]; ++ ++ while (QM_EQE_PHASE(eqe) == qm->status.eqc_phase) { + cqn = le32_to_cpu(eqe->dw0) & QM_EQE_CQN_MASK; +- poll_data = &qm->poll_data[cqn]; +- queue_work(qm->wq, &poll_data->work); ++ poll_data->qp_finish_id[eqe_num] = cqn; ++ eqe_num++; ++ ++ if (qm->status.eq_head == eq_depth - 1) { ++ qm->status.eqc_phase = !qm->status.eqc_phase; ++ eqe = qm->eqe; ++ qm->status.eq_head = 0; ++ } else { ++ eqe++; ++ qm->status.eq_head++; ++ } + +- return true; ++ if (eqe_num == (eq_depth >> 1) - 1) ++ break; + } + +- return false; ++ poll_data->eqe_num = eqe_num; ++ queue_work(qm->wq, &poll_data->work); ++ qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0); + } + + static irqreturn_t qm_eq_irq(int irq, void *data) + { + struct hisi_qm *qm = data; +- bool ret; +- +- ret = do_qm_eq_irq(qm); +- if (ret) +- return IRQ_HANDLED; + +- atomic64_inc(&qm->debug.dfx.err_irq_cnt); +- qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0); ++ /* Get qp id of completed tasks and re-enable the interrupt */ ++ qm_get_complete_eqe_num(qm); + +- return IRQ_NONE; ++ return IRQ_HANDLED; + } + + static irqreturn_t qm_mb_cmd_irq(int irq, void *data) +@@ -1025,6 +1060,8 @@ static irqreturn_t qm_aeq_thread(int irq, void *data) + u16 aeq_depth = qm->aeq_depth; + u32 type, qp_id; + ++ atomic64_inc(&qm->debug.dfx.aeq_irq_cnt); ++ + while (QM_AEQE_PHASE(aeqe) == qm->status.aeqc_phase) { + type = le32_to_cpu(aeqe->dw0) >> QM_AEQE_TYPE_SHIFT; + qp_id = le32_to_cpu(aeqe->dw0) & QM_AEQE_CQN_MASK; +@@ -1062,17 +1099,6 @@ static irqreturn_t qm_aeq_thread(int irq, void *data) + return IRQ_HANDLED; + } + +-static irqreturn_t qm_aeq_irq(int irq, void *data) +-{ +- struct hisi_qm *qm = data; +- +- atomic64_inc(&qm->debug.dfx.aeq_irq_cnt); +- if (!readl(qm->io_base + QM_VF_AEQ_INT_SOURCE)) +- return IRQ_NONE; +- +- return IRQ_WAKE_THREAD; +-} +- + static void qm_init_qp_status(struct hisi_qp *qp) + { + struct hisi_qp_status *qp_status = &qp->qp_status; +@@ -2824,7 +2850,6 @@ static void hisi_qm_pre_init(struct hisi_qm *qm) + mutex_init(&qm->mailbox_lock); + init_rwsem(&qm->qps_lock); + qm->qp_in_used = 0; +- qm->misc_ctl = false; + if (test_bit(QM_SUPPORT_RPM, &qm->caps)) { + if (!acpi_device_power_manageable(ACPI_COMPANION(&pdev->dev))) + dev_info(&pdev->dev, "_PS0 and _PR0 are not defined"); +@@ -2928,12 +2953,9 @@ void hisi_qm_uninit(struct hisi_qm *qm) + hisi_qm_set_state(qm, QM_NOT_READY); + up_write(&qm->qps_lock); + ++ qm_remove_uacce(qm); + qm_irqs_unregister(qm); + hisi_qm_pci_uninit(qm); +- if (qm->use_sva) { +- uacce_remove(qm->uacce); +- qm->uacce = NULL; +- } + } + EXPORT_SYMBOL_GPL(hisi_qm_uninit); + +@@ -4084,6 +4106,28 @@ static int qm_set_vf_mse(struct hisi_qm *qm, bool set) + return -ETIMEDOUT; + } + ++static void qm_dev_ecc_mbit_handle(struct hisi_qm *qm) ++{ ++ u32 nfe_enb = 0; ++ ++ /* Kunpeng930 hardware automatically close master ooo when NFE occurs */ ++ if (qm->ver >= QM_HW_V3) ++ return; ++ ++ if (!qm->err_status.is_dev_ecc_mbit && ++ qm->err_status.is_qm_ecc_mbit && ++ qm->err_ini->close_axi_master_ooo) { ++ qm->err_ini->close_axi_master_ooo(qm); ++ } else if (qm->err_status.is_dev_ecc_mbit && ++ !qm->err_status.is_qm_ecc_mbit && ++ !qm->err_ini->close_axi_master_ooo) { ++ nfe_enb = readl(qm->io_base + QM_RAS_NFE_ENABLE); ++ writel(nfe_enb & QM_RAS_NFE_MBIT_DISABLE, ++ qm->io_base + QM_RAS_NFE_ENABLE); ++ writel(QM_ECC_MBIT, qm->io_base + QM_ABNORMAL_INT_SET); ++ } ++} ++ + static int qm_vf_reset_prepare(struct hisi_qm *qm, + enum qm_stop_reason stop_reason) + { +@@ -4148,6 +4192,8 @@ static int qm_controller_reset_prepare(struct hisi_qm *qm) + return ret; + } + ++ qm_dev_ecc_mbit_handle(qm); ++ + /* PF obtains the information of VF by querying the register. */ + qm_cmd_uninit(qm); + +@@ -4178,33 +4224,26 @@ static int qm_controller_reset_prepare(struct hisi_qm *qm) + return 0; + } + +-static void qm_dev_ecc_mbit_handle(struct hisi_qm *qm) ++static int qm_master_ooo_check(struct hisi_qm *qm) + { +- u32 nfe_enb = 0; ++ u32 val; ++ int ret; + +- /* Kunpeng930 hardware automatically close master ooo when NFE occurs */ +- if (qm->ver >= QM_HW_V3) +- return; ++ /* Check the ooo register of the device before resetting the device. */ ++ writel(ACC_MASTER_GLOBAL_CTRL_SHUTDOWN, qm->io_base + ACC_MASTER_GLOBAL_CTRL); ++ ret = readl_relaxed_poll_timeout(qm->io_base + ACC_MASTER_TRANS_RETURN, ++ val, (val == ACC_MASTER_TRANS_RETURN_RW), ++ POLL_PERIOD, POLL_TIMEOUT); ++ if (ret) ++ pci_warn(qm->pdev, "Bus lock! Please reset system.\n"); + +- if (!qm->err_status.is_dev_ecc_mbit && +- qm->err_status.is_qm_ecc_mbit && +- qm->err_ini->close_axi_master_ooo) { +- qm->err_ini->close_axi_master_ooo(qm); +- } else if (qm->err_status.is_dev_ecc_mbit && +- !qm->err_status.is_qm_ecc_mbit && +- !qm->err_ini->close_axi_master_ooo) { +- nfe_enb = readl(qm->io_base + QM_RAS_NFE_ENABLE); +- writel(nfe_enb & QM_RAS_NFE_MBIT_DISABLE, +- qm->io_base + QM_RAS_NFE_ENABLE); +- writel(QM_ECC_MBIT, qm->io_base + QM_ABNORMAL_INT_SET); +- } ++ return ret; + } + +-static int qm_soft_reset(struct hisi_qm *qm) ++static int qm_soft_reset_prepare(struct hisi_qm *qm) + { + struct pci_dev *pdev = qm->pdev; + int ret; +- u32 val; + + /* Ensure all doorbells and mailboxes received by QM */ + ret = qm_check_req_recv(qm); +@@ -4225,30 +4264,23 @@ static int qm_soft_reset(struct hisi_qm *qm) + return ret; + } + +- qm_dev_ecc_mbit_handle(qm); +- +- /* OOO register set and check */ +- writel(ACC_MASTER_GLOBAL_CTRL_SHUTDOWN, +- qm->io_base + ACC_MASTER_GLOBAL_CTRL); +- +- /* If bus lock, reset chip */ +- ret = readl_relaxed_poll_timeout(qm->io_base + ACC_MASTER_TRANS_RETURN, +- val, +- (val == ACC_MASTER_TRANS_RETURN_RW), +- POLL_PERIOD, POLL_TIMEOUT); +- if (ret) { +- pci_emerg(pdev, "Bus lock! Please reset system.\n"); ++ ret = qm_master_ooo_check(qm); ++ if (ret) + return ret; +- } + + if (qm->err_ini->close_sva_prefetch) + qm->err_ini->close_sva_prefetch(qm); + + ret = qm_set_pf_mse(qm, false); +- if (ret) { ++ if (ret) + pci_err(pdev, "Fails to disable pf MSE bit.\n"); +- return ret; +- } ++ ++ return ret; ++} ++ ++static int qm_reset_device(struct hisi_qm *qm) ++{ ++ struct pci_dev *pdev = qm->pdev; + + /* The reset related sub-control registers are not in PCI BAR */ + if (ACPI_HANDLE(&pdev->dev)) { +@@ -4267,12 +4299,23 @@ static int qm_soft_reset(struct hisi_qm *qm) + pci_err(pdev, "Reset step %llu failed!\n", value); + return -EIO; + } +- } else { +- pci_err(pdev, "No reset method!\n"); +- return -EINVAL; ++ ++ return 0; + } + +- return 0; ++ pci_err(pdev, "No reset method!\n"); ++ return -EINVAL; ++} ++ ++static int qm_soft_reset(struct hisi_qm *qm) ++{ ++ int ret; ++ ++ ret = qm_soft_reset_prepare(qm); ++ if (ret) ++ return ret; ++ ++ return qm_reset_device(qm); + } + + static int qm_vf_reset_done(struct hisi_qm *qm) +@@ -4929,7 +4972,7 @@ static void qm_unregister_abnormal_irq(struct hisi_qm *qm) + if (qm->fun_type == QM_HW_VF) + return; + +- val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_ABN_IRQ_TYPE_CAP, qm->cap_ver); ++ val = qm->cap_tables.qm_cap_table[QM_ABN_IRQ_TYPE_CAP_IDX].cap_val; + if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_ABN_IRQ_TYPE_MASK)) + return; + +@@ -4946,7 +4989,7 @@ static int qm_register_abnormal_irq(struct hisi_qm *qm) + if (qm->fun_type == QM_HW_VF) + return 0; + +- val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_ABN_IRQ_TYPE_CAP, qm->cap_ver); ++ val = qm->cap_tables.qm_cap_table[QM_ABN_IRQ_TYPE_CAP_IDX].cap_val; + if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_ABN_IRQ_TYPE_MASK)) + return 0; + +@@ -4963,7 +5006,7 @@ static void qm_unregister_mb_cmd_irq(struct hisi_qm *qm) + struct pci_dev *pdev = qm->pdev; + u32 irq_vector, val; + +- val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_PF2VF_IRQ_TYPE_CAP, qm->cap_ver); ++ val = qm->cap_tables.qm_cap_table[QM_PF2VF_IRQ_TYPE_CAP_IDX].cap_val; + if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) + return; + +@@ -4977,7 +5020,7 @@ static int qm_register_mb_cmd_irq(struct hisi_qm *qm) + u32 irq_vector, val; + int ret; + +- val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_PF2VF_IRQ_TYPE_CAP, qm->cap_ver); ++ val = qm->cap_tables.qm_cap_table[QM_PF2VF_IRQ_TYPE_CAP_IDX].cap_val; + if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) + return 0; + +@@ -4994,7 +5037,7 @@ static void qm_unregister_aeq_irq(struct hisi_qm *qm) + struct pci_dev *pdev = qm->pdev; + u32 irq_vector, val; + +- val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_AEQ_IRQ_TYPE_CAP, qm->cap_ver); ++ val = qm->cap_tables.qm_cap_table[QM_AEQ_IRQ_TYPE_CAP_IDX].cap_val; + if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) + return; + +@@ -5008,13 +5051,13 @@ static int qm_register_aeq_irq(struct hisi_qm *qm) + u32 irq_vector, val; + int ret; + +- val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_AEQ_IRQ_TYPE_CAP, qm->cap_ver); ++ val = qm->cap_tables.qm_cap_table[QM_AEQ_IRQ_TYPE_CAP_IDX].cap_val; + if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) + return 0; + + irq_vector = val & QM_IRQ_VECTOR_MASK; +- ret = request_threaded_irq(pci_irq_vector(pdev, irq_vector), qm_aeq_irq, +- qm_aeq_thread, 0, qm->dev_name, qm); ++ ret = request_threaded_irq(pci_irq_vector(pdev, irq_vector), NULL, ++ qm_aeq_thread, IRQF_ONESHOT, qm->dev_name, qm); + if (ret) + dev_err(&pdev->dev, "failed to request eq irq, ret = %d", ret); + +@@ -5026,7 +5069,7 @@ static void qm_unregister_eq_irq(struct hisi_qm *qm) + struct pci_dev *pdev = qm->pdev; + u32 irq_vector, val; + +- val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_EQ_IRQ_TYPE_CAP, qm->cap_ver); ++ val = qm->cap_tables.qm_cap_table[QM_EQ_IRQ_TYPE_CAP_IDX].cap_val; + if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) + return; + +@@ -5040,7 +5083,7 @@ static int qm_register_eq_irq(struct hisi_qm *qm) + u32 irq_vector, val; + int ret; + +- val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_EQ_IRQ_TYPE_CAP, qm->cap_ver); ++ val = qm->cap_tables.qm_cap_table[QM_EQ_IRQ_TYPE_CAP_IDX].cap_val; + if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) + return 0; + +@@ -5093,6 +5136,7 @@ static int qm_irqs_register(struct hisi_qm *qm) + + static int qm_get_qp_num(struct hisi_qm *qm) + { ++ struct device *dev = &qm->pdev->dev; + bool is_db_isolation; + + /* VF's qp_num assigned by PF in v2, and VF can get qp_num by vft. */ +@@ -5109,17 +5153,47 @@ static int qm_get_qp_num(struct hisi_qm *qm) + qm->max_qp_num = hisi_qm_get_hw_info(qm, qm_basic_info, + QM_FUNC_MAX_QP_CAP, is_db_isolation); + +- /* check if qp number is valid */ +- if (qm->qp_num > qm->max_qp_num) { +- dev_err(&qm->pdev->dev, "qp num(%u) is more than max qp num(%u)!\n", ++ if (qm->qp_num <= qm->max_qp_num) ++ return 0; ++ ++ if (test_bit(QM_MODULE_PARAM, &qm->misc_ctl)) { ++ /* Check whether the set qp number is valid */ ++ dev_err(dev, "qp num(%u) is more than max qp num(%u)!\n", + qm->qp_num, qm->max_qp_num); + return -EINVAL; + } + ++ dev_info(dev, "Default qp num(%u) is too big, reset it to Function's max qp num(%u)!\n", ++ qm->qp_num, qm->max_qp_num); ++ qm->qp_num = qm->max_qp_num; ++ qm->debug.curr_qm_qp_num = qm->qp_num; ++ ++ return 0; ++} ++ ++static int qm_pre_store_irq_type_caps(struct hisi_qm *qm) ++{ ++ struct hisi_qm_cap_record *qm_cap; ++ struct pci_dev *pdev = qm->pdev; ++ size_t i, size; ++ ++ size = ARRAY_SIZE(qm_pre_store_caps); ++ qm_cap = devm_kzalloc(&pdev->dev, sizeof(*qm_cap) * size, GFP_KERNEL); ++ if (!qm_cap) ++ return -ENOMEM; ++ ++ for (i = 0; i < size; i++) { ++ qm_cap[i].type = qm_pre_store_caps[i]; ++ qm_cap[i].cap_val = hisi_qm_get_hw_info(qm, qm_basic_info, ++ qm_pre_store_caps[i], qm->cap_ver); ++ } ++ ++ qm->cap_tables.qm_cap_table = qm_cap; ++ + return 0; + } + +-static void qm_get_hw_caps(struct hisi_qm *qm) ++static int qm_get_hw_caps(struct hisi_qm *qm) + { + const struct hisi_qm_cap_info *cap_info = qm->fun_type == QM_HW_PF ? + qm_cap_info_pf : qm_cap_info_vf; +@@ -5150,6 +5224,9 @@ static void qm_get_hw_caps(struct hisi_qm *qm) + if (val) + set_bit(cap_info[i].type, &qm->caps); + } ++ ++ /* Fetch and save the value of irq type related capability registers */ ++ return qm_pre_store_irq_type_caps(qm); + } + + static int qm_get_pci_res(struct hisi_qm *qm) +@@ -5171,7 +5248,10 @@ static int qm_get_pci_res(struct hisi_qm *qm) + goto err_request_mem_regions; + } + +- qm_get_hw_caps(qm); ++ ret = qm_get_hw_caps(qm); ++ if (ret) ++ goto err_ioremap; ++ + if (test_bit(QM_SUPPORT_DB_ISOLATION, &qm->caps)) { + qm->db_interval = QM_QP_DB_INTERVAL; + qm->db_phys_base = pci_resource_start(pdev, PCI_BAR_4); +@@ -5203,6 +5283,35 @@ static int qm_get_pci_res(struct hisi_qm *qm) + return ret; + } + ++static int qm_clear_device(struct hisi_qm *qm) ++{ ++ acpi_handle handle = ACPI_HANDLE(&qm->pdev->dev); ++ int ret; ++ ++ if (qm->fun_type == QM_HW_VF) ++ return 0; ++ ++ /* Device does not support reset, return */ ++ if (!qm->err_ini->err_info_init) ++ return 0; ++ qm->err_ini->err_info_init(qm); ++ ++ if (!handle) ++ return 0; ++ ++ /* No reset method, return */ ++ if (!acpi_has_method(handle, qm->err_info.acpi_rst)) ++ return 0; ++ ++ ret = qm_master_ooo_check(qm); ++ if (ret) { ++ writel(0x0, qm->io_base + ACC_MASTER_GLOBAL_CTRL); ++ return ret; ++ } ++ ++ return qm_reset_device(qm); ++} ++ + static int hisi_qm_pci_init(struct hisi_qm *qm) + { + struct pci_dev *pdev = qm->pdev; +@@ -5232,8 +5341,14 @@ static int hisi_qm_pci_init(struct hisi_qm *qm) + goto err_get_pci_res; + } + ++ ret = qm_clear_device(qm); ++ if (ret) ++ goto err_free_vectors; ++ + return 0; + ++err_free_vectors: ++ pci_free_irq_vectors(pdev); + err_get_pci_res: + qm_put_pci_res(qm); + err_disable_pcidev: +@@ -5499,7 +5614,6 @@ static int qm_prepare_for_suspend(struct hisi_qm *qm) + { + struct pci_dev *pdev = qm->pdev; + int ret; +- u32 val; + + ret = qm->ops->set_msi(qm, false); + if (ret) { +@@ -5507,18 +5621,9 @@ static int qm_prepare_for_suspend(struct hisi_qm *qm) + return ret; + } + +- /* shutdown OOO register */ +- writel(ACC_MASTER_GLOBAL_CTRL_SHUTDOWN, +- qm->io_base + ACC_MASTER_GLOBAL_CTRL); +- +- ret = readl_relaxed_poll_timeout(qm->io_base + ACC_MASTER_TRANS_RETURN, +- val, +- (val == ACC_MASTER_TRANS_RETURN_RW), +- POLL_PERIOD, POLL_TIMEOUT); +- if (ret) { +- pci_emerg(pdev, "Bus lock! Please reset system.\n"); ++ ret = qm_master_ooo_check(qm); ++ if (ret) + return ret; +- } + + ret = qm_set_pf_mse(qm, false); + if (ret) +diff --git a/drivers/crypto/hisilicon/qm_common.h b/drivers/crypto/hisilicon/qm_common.h +index 1406a422d45517..8e36aa9c681be4 100644 +--- a/drivers/crypto/hisilicon/qm_common.h ++++ b/drivers/crypto/hisilicon/qm_common.h +@@ -4,7 +4,6 @@ + #define QM_COMMON_H + + #define QM_DBG_READ_LEN 256 +-#define QM_RESETTING 2 + + struct qm_cqe { + __le32 rsvd0; +diff --git a/drivers/crypto/hisilicon/sec2/sec.h b/drivers/crypto/hisilicon/sec2/sec.h +index 3e57fc04b37703..410c83712e2851 100644 +--- a/drivers/crypto/hisilicon/sec2/sec.h ++++ b/drivers/crypto/hisilicon/sec2/sec.h +@@ -220,6 +220,13 @@ enum sec_cap_type { + SEC_CORE4_ALG_BITMAP_HIGH, + }; + ++enum sec_cap_reg_record_idx { ++ SEC_DRV_ALG_BITMAP_LOW_IDX = 0x0, ++ SEC_DRV_ALG_BITMAP_HIGH_IDX, ++ SEC_DEV_ALG_BITMAP_LOW_IDX, ++ SEC_DEV_ALG_BITMAP_HIGH_IDX, ++}; ++ + void sec_destroy_qps(struct hisi_qp **qps, int qp_num); + struct hisi_qp **sec_create_qps(void); + int sec_register_to_crypto(struct hisi_qm *qm); +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index 074e50ef512c11..932cc277eb3a5e 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -478,8 +478,10 @@ static void sec_alg_resource_free(struct sec_ctx *ctx, + + if (ctx->pbuf_supported) + sec_free_pbuf_resource(dev, qp_ctx->res); +- if (ctx->alg_type == SEC_AEAD) ++ if (ctx->alg_type == SEC_AEAD) { + sec_free_mac_resource(dev, qp_ctx->res); ++ sec_free_aiv_resource(dev, qp_ctx->res); ++ } + } + + static int sec_alloc_qp_ctx_resource(struct hisi_qm *qm, struct sec_ctx *ctx, +@@ -2543,8 +2545,12 @@ static int sec_register_aead(u64 alg_mask) + + int sec_register_to_crypto(struct hisi_qm *qm) + { +- u64 alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH, SEC_DRV_ALG_BITMAP_LOW); +- int ret; ++ u64 alg_mask; ++ int ret = 0; ++ ++ alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH_IDX, ++ SEC_DRV_ALG_BITMAP_LOW_IDX); ++ + + ret = sec_register_skcipher(alg_mask); + if (ret) +@@ -2559,7 +2565,10 @@ int sec_register_to_crypto(struct hisi_qm *qm) + + void sec_unregister_from_crypto(struct hisi_qm *qm) + { +- u64 alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH, SEC_DRV_ALG_BITMAP_LOW); ++ u64 alg_mask; ++ ++ alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH_IDX, ++ SEC_DRV_ALG_BITMAP_LOW_IDX); + + sec_unregister_aead(alg_mask, ARRAY_SIZE(sec_aeads)); + sec_unregister_skcipher(alg_mask, ARRAY_SIZE(sec_skciphers)); +diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c +index 77f9f131b85035..cf7b6a37e7df7a 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_main.c ++++ b/drivers/crypto/hisilicon/sec2/sec_main.c +@@ -120,7 +120,6 @@ + GENMASK_ULL(42, 25)) + #define SEC_AEAD_BITMAP (GENMASK_ULL(7, 6) | GENMASK_ULL(18, 17) | \ + GENMASK_ULL(45, 43)) +-#define SEC_DEV_ALG_MAX_LEN 256 + + struct sec_hw_error { + u32 int_msk; +@@ -132,11 +131,6 @@ struct sec_dfx_item { + u32 offset; + }; + +-struct sec_dev_alg { +- u64 alg_msk; +- const char *algs; +-}; +- + static const char sec_name[] = "hisi_sec2"; + static struct dentry *sec_debugfs_root; + +@@ -173,15 +167,22 @@ static const struct hisi_qm_cap_info sec_basic_info[] = { + {SEC_CORE4_ALG_BITMAP_HIGH, 0x3170, 0, GENMASK(31, 0), 0x3FFF, 0x3FFF, 0x3FFF}, + }; + +-static const struct sec_dev_alg sec_dev_algs[] = { { ++static const u32 sec_pre_store_caps[] = { ++ SEC_DRV_ALG_BITMAP_LOW, ++ SEC_DRV_ALG_BITMAP_HIGH, ++ SEC_DEV_ALG_BITMAP_LOW, ++ SEC_DEV_ALG_BITMAP_HIGH, ++}; ++ ++static const struct qm_dev_alg sec_dev_algs[] = { { + .alg_msk = SEC_CIPHER_BITMAP, +- .algs = "cipher\n", ++ .alg = "cipher\n", + }, { + .alg_msk = SEC_DIGEST_BITMAP, +- .algs = "digest\n", ++ .alg = "digest\n", + }, { + .alg_msk = SEC_AEAD_BITMAP, +- .algs = "aead\n", ++ .alg = "aead\n", + }, + }; + +@@ -311,8 +312,11 @@ static int sec_diff_regs_show(struct seq_file *s, void *unused) + } + DEFINE_SHOW_ATTRIBUTE(sec_diff_regs); + ++static bool pf_q_num_flag; + static int sec_pf_q_num_set(const char *val, const struct kernel_param *kp) + { ++ pf_q_num_flag = true; ++ + return q_num_set(val, kp, PCI_DEVICE_ID_HUAWEI_SEC_PF); + } + +@@ -391,8 +395,8 @@ u64 sec_get_alg_bitmap(struct hisi_qm *qm, u32 high, u32 low) + { + u32 cap_val_h, cap_val_l; + +- cap_val_h = hisi_qm_get_hw_info(qm, sec_basic_info, high, qm->cap_ver); +- cap_val_l = hisi_qm_get_hw_info(qm, sec_basic_info, low, qm->cap_ver); ++ cap_val_h = qm->cap_tables.dev_cap_table[high].cap_val; ++ cap_val_l = qm->cap_tables.dev_cap_table[low].cap_val; + + return ((u64)cap_val_h << SEC_ALG_BITMAP_SHIFT) | (u64)cap_val_l; + } +@@ -1057,9 +1061,6 @@ static int sec_pf_probe_init(struct sec_dev *sec) + struct hisi_qm *qm = &sec->qm; + int ret; + +- qm->err_ini = &sec_err_ini; +- qm->err_ini->err_info_init(qm); +- + ret = sec_set_user_domain_and_cache(qm); + if (ret) + return ret; +@@ -1074,37 +1075,31 @@ static int sec_pf_probe_init(struct sec_dev *sec) + return ret; + } + +-static int sec_set_qm_algs(struct hisi_qm *qm) ++static int sec_pre_store_cap_reg(struct hisi_qm *qm) + { +- struct device *dev = &qm->pdev->dev; +- char *algs, *ptr; +- u64 alg_mask; +- int i; +- +- if (!qm->use_sva) +- return 0; ++ struct hisi_qm_cap_record *sec_cap; ++ struct pci_dev *pdev = qm->pdev; ++ size_t i, size; + +- algs = devm_kzalloc(dev, SEC_DEV_ALG_MAX_LEN * sizeof(char), GFP_KERNEL); +- if (!algs) ++ size = ARRAY_SIZE(sec_pre_store_caps); ++ sec_cap = devm_kzalloc(&pdev->dev, sizeof(*sec_cap) * size, GFP_KERNEL); ++ if (!sec_cap) + return -ENOMEM; + +- alg_mask = sec_get_alg_bitmap(qm, SEC_DEV_ALG_BITMAP_HIGH, SEC_DEV_ALG_BITMAP_LOW); +- +- for (i = 0; i < ARRAY_SIZE(sec_dev_algs); i++) +- if (alg_mask & sec_dev_algs[i].alg_msk) +- strcat(algs, sec_dev_algs[i].algs); +- +- ptr = strrchr(algs, '\n'); +- if (ptr) +- *ptr = '\0'; ++ for (i = 0; i < size; i++) { ++ sec_cap[i].type = sec_pre_store_caps[i]; ++ sec_cap[i].cap_val = hisi_qm_get_hw_info(qm, sec_basic_info, ++ sec_pre_store_caps[i], qm->cap_ver); ++ } + +- qm->uacce->algs = algs; ++ qm->cap_tables.dev_cap_table = sec_cap; + + return 0; + } + + static int sec_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) + { ++ u64 alg_msk; + int ret; + + qm->pdev = pdev; +@@ -1120,6 +1115,9 @@ static int sec_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) + qm->qp_num = pf_q_num; + qm->debug.curr_qm_qp_num = pf_q_num; + qm->qm_list = &sec_devices; ++ qm->err_ini = &sec_err_ini; ++ if (pf_q_num_flag) ++ set_bit(QM_MODULE_PARAM, &qm->misc_ctl); + } else if (qm->fun_type == QM_HW_VF && qm->ver == QM_HW_V1) { + /* + * have no way to get qm configure in VM in v1 hardware, +@@ -1137,7 +1135,16 @@ static int sec_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) + return ret; + } + +- ret = sec_set_qm_algs(qm); ++ /* Fetch and save the value of capability registers */ ++ ret = sec_pre_store_cap_reg(qm); ++ if (ret) { ++ pci_err(qm->pdev, "Failed to pre-store capability registers!\n"); ++ hisi_qm_uninit(qm); ++ return ret; ++ } ++ ++ alg_msk = sec_get_alg_bitmap(qm, SEC_DEV_ALG_BITMAP_HIGH_IDX, SEC_DEV_ALG_BITMAP_LOW_IDX); ++ ret = hisi_qm_set_algs(qm, alg_msk, sec_dev_algs, ARRAY_SIZE(sec_dev_algs)); + if (ret) { + pci_err(qm->pdev, "Failed to set sec algs!\n"); + hisi_qm_uninit(qm); +@@ -1173,6 +1180,12 @@ static int sec_probe_init(struct sec_dev *sec) + + static void sec_probe_uninit(struct hisi_qm *qm) + { ++ if (qm->fun_type == QM_HW_VF) ++ return; ++ ++ sec_debug_regs_clear(qm); ++ sec_show_last_regs_uninit(qm); ++ sec_close_sva_prefetch(qm); + hisi_qm_dev_err_uninit(qm); + } + +@@ -1265,7 +1278,6 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id) + sec_debugfs_exit(qm); + hisi_qm_stop(qm, QM_NORMAL); + err_probe_uninit: +- sec_show_last_regs_uninit(qm); + sec_probe_uninit(qm); + err_qm_uninit: + sec_qm_uninit(qm); +@@ -1287,11 +1299,6 @@ static void sec_remove(struct pci_dev *pdev) + sec_debugfs_exit(qm); + + (void)hisi_qm_stop(qm, QM_NORMAL); +- +- if (qm->fun_type == QM_HW_PF) +- sec_debug_regs_clear(qm); +- sec_show_last_regs_uninit(qm); +- + sec_probe_uninit(qm); + + sec_qm_uninit(qm); +diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c +index f3ce34198775d8..9d47b3675da7d4 100644 +--- a/drivers/crypto/hisilicon/zip/zip_main.c ++++ b/drivers/crypto/hisilicon/zip/zip_main.c +@@ -73,7 +73,6 @@ + #define HZIP_AXI_SHUTDOWN_ENABLE BIT(14) + #define HZIP_WR_PORT BIT(11) + +-#define HZIP_DEV_ALG_MAX_LEN 256 + #define HZIP_ALG_ZLIB_BIT GENMASK(1, 0) + #define HZIP_ALG_GZIP_BIT GENMASK(3, 2) + #define HZIP_ALG_DEFLATE_BIT GENMASK(5, 4) +@@ -106,6 +105,14 @@ + #define HZIP_CLOCK_GATED_EN (HZIP_CORE_GATED_EN | \ + HZIP_CORE_GATED_OOO_EN) + ++/* zip comp high performance */ ++#define HZIP_HIGH_PERF_OFFSET 0x301208 ++ ++enum { ++ HZIP_HIGH_COMP_RATE, ++ HZIP_HIGH_COMP_PERF, ++}; ++ + static const char hisi_zip_name[] = "hisi_zip"; + static struct dentry *hzip_debugfs_root; + +@@ -119,23 +126,18 @@ struct zip_dfx_item { + u32 offset; + }; + +-struct zip_dev_alg { +- u32 alg_msk; +- const char *algs; +-}; +- +-static const struct zip_dev_alg zip_dev_algs[] = { { ++static const struct qm_dev_alg zip_dev_algs[] = { { + .alg_msk = HZIP_ALG_ZLIB_BIT, +- .algs = "zlib\n", ++ .alg = "zlib\n", + }, { + .alg_msk = HZIP_ALG_GZIP_BIT, +- .algs = "gzip\n", ++ .alg = "gzip\n", + }, { + .alg_msk = HZIP_ALG_DEFLATE_BIT, +- .algs = "deflate\n", ++ .alg = "deflate\n", + }, { + .alg_msk = HZIP_ALG_LZ77_BIT, +- .algs = "lz77_zstd\n", ++ .alg = "lz77_zstd\n", + }, + }; + +@@ -246,6 +248,26 @@ static struct hisi_qm_cap_info zip_basic_cap_info[] = { + {ZIP_CAP_MAX, 0x317c, 0, GENMASK(0, 0), 0x0, 0x0, 0x0} + }; + ++enum zip_pre_store_cap_idx { ++ ZIP_CORE_NUM_CAP_IDX = 0x0, ++ ZIP_CLUSTER_COMP_NUM_CAP_IDX, ++ ZIP_CLUSTER_DECOMP_NUM_CAP_IDX, ++ ZIP_DECOMP_ENABLE_BITMAP_IDX, ++ ZIP_COMP_ENABLE_BITMAP_IDX, ++ ZIP_DRV_ALG_BITMAP_IDX, ++ ZIP_DEV_ALG_BITMAP_IDX, ++}; ++ ++static const u32 zip_pre_store_caps[] = { ++ ZIP_CORE_NUM_CAP, ++ ZIP_CLUSTER_COMP_NUM_CAP, ++ ZIP_CLUSTER_DECOMP_NUM_CAP, ++ ZIP_DECOMP_ENABLE_BITMAP, ++ ZIP_COMP_ENABLE_BITMAP, ++ ZIP_DRV_ALG_BITMAP, ++ ZIP_DEV_ALG_BITMAP, ++}; ++ + enum { + HZIP_COMP_CORE0, + HZIP_COMP_CORE1, +@@ -351,6 +373,37 @@ static int hzip_diff_regs_show(struct seq_file *s, void *unused) + return 0; + } + DEFINE_SHOW_ATTRIBUTE(hzip_diff_regs); ++ ++static int perf_mode_set(const char *val, const struct kernel_param *kp) ++{ ++ int ret; ++ u32 n; ++ ++ if (!val) ++ return -EINVAL; ++ ++ ret = kstrtou32(val, 10, &n); ++ if (ret != 0 || (n != HZIP_HIGH_COMP_PERF && ++ n != HZIP_HIGH_COMP_RATE)) ++ return -EINVAL; ++ ++ return param_set_int(val, kp); ++} ++ ++static const struct kernel_param_ops zip_com_perf_ops = { ++ .set = perf_mode_set, ++ .get = param_get_int, ++}; ++ ++/* ++ * perf_mode = 0 means enable high compression rate mode, ++ * perf_mode = 1 means enable high compression performance mode. ++ * These two modes only apply to the compression direction. ++ */ ++static u32 perf_mode = HZIP_HIGH_COMP_RATE; ++module_param_cb(perf_mode, &zip_com_perf_ops, &perf_mode, 0444); ++MODULE_PARM_DESC(perf_mode, "ZIP high perf mode 0(default), 1(enable)"); ++ + static const struct kernel_param_ops zip_uacce_mode_ops = { + .set = uacce_mode_set, + .get = param_get_int, +@@ -364,8 +417,11 @@ static u32 uacce_mode = UACCE_MODE_NOUACCE; + module_param_cb(uacce_mode, &zip_uacce_mode_ops, &uacce_mode, 0444); + MODULE_PARM_DESC(uacce_mode, UACCE_MODE_DESC); + ++static bool pf_q_num_flag; + static int pf_q_num_set(const char *val, const struct kernel_param *kp) + { ++ pf_q_num_flag = true; ++ + return q_num_set(val, kp, PCI_DEVICE_ID_HUAWEI_ZIP_PF); + } + +@@ -406,40 +462,33 @@ bool hisi_zip_alg_support(struct hisi_qm *qm, u32 alg) + { + u32 cap_val; + +- cap_val = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_DRV_ALG_BITMAP, qm->cap_ver); ++ cap_val = qm->cap_tables.dev_cap_table[ZIP_DRV_ALG_BITMAP_IDX].cap_val; + if ((alg & cap_val) == alg) + return true; + + return false; + } + +-static int hisi_zip_set_qm_algs(struct hisi_qm *qm) ++static int hisi_zip_set_high_perf(struct hisi_qm *qm) + { +- struct device *dev = &qm->pdev->dev; +- char *algs, *ptr; +- u32 alg_mask; +- int i; +- +- if (!qm->use_sva) +- return 0; +- +- algs = devm_kzalloc(dev, HZIP_DEV_ALG_MAX_LEN * sizeof(char), GFP_KERNEL); +- if (!algs) +- return -ENOMEM; +- +- alg_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_DEV_ALG_BITMAP, qm->cap_ver); +- +- for (i = 0; i < ARRAY_SIZE(zip_dev_algs); i++) +- if (alg_mask & zip_dev_algs[i].alg_msk) +- strcat(algs, zip_dev_algs[i].algs); +- +- ptr = strrchr(algs, '\n'); +- if (ptr) +- *ptr = '\0'; ++ u32 val; ++ int ret; + +- qm->uacce->algs = algs; ++ val = readl_relaxed(qm->io_base + HZIP_HIGH_PERF_OFFSET); ++ if (perf_mode == HZIP_HIGH_COMP_PERF) ++ val |= HZIP_HIGH_COMP_PERF; ++ else ++ val &= ~HZIP_HIGH_COMP_PERF; ++ ++ /* Set perf mode */ ++ writel(val, qm->io_base + HZIP_HIGH_PERF_OFFSET); ++ ret = readl_relaxed_poll_timeout(qm->io_base + HZIP_HIGH_PERF_OFFSET, ++ val, val == perf_mode, HZIP_DELAY_1_US, ++ HZIP_POLL_TIMEOUT_US); ++ if (ret) ++ pci_err(qm->pdev, "failed to set perf mode\n"); + +- return 0; ++ return ret; + } + + static void hisi_zip_open_sva_prefetch(struct hisi_qm *qm) +@@ -538,10 +587,8 @@ static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm) + } + + /* let's open all compression/decompression cores */ +- dcomp_bm = hisi_qm_get_hw_info(qm, zip_basic_cap_info, +- ZIP_DECOMP_ENABLE_BITMAP, qm->cap_ver); +- comp_bm = hisi_qm_get_hw_info(qm, zip_basic_cap_info, +- ZIP_COMP_ENABLE_BITMAP, qm->cap_ver); ++ dcomp_bm = qm->cap_tables.dev_cap_table[ZIP_DECOMP_ENABLE_BITMAP_IDX].cap_val; ++ comp_bm = qm->cap_tables.dev_cap_table[ZIP_COMP_ENABLE_BITMAP_IDX].cap_val; + writel(HZIP_DECOMP_CHECK_ENABLE | dcomp_bm | comp_bm, base + HZIP_CLOCK_GATE_CTRL); + + /* enable sqc,cqc writeback */ +@@ -768,9 +815,8 @@ static int hisi_zip_core_debug_init(struct hisi_qm *qm) + char buf[HZIP_BUF_SIZE]; + int i; + +- zip_core_num = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CORE_NUM_CAP, qm->cap_ver); +- zip_comp_core_num = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CLUSTER_COMP_NUM_CAP, +- qm->cap_ver); ++ zip_core_num = qm->cap_tables.dev_cap_table[ZIP_CORE_NUM_CAP_IDX].cap_val; ++ zip_comp_core_num = qm->cap_tables.dev_cap_table[ZIP_CLUSTER_COMP_NUM_CAP_IDX].cap_val; + + for (i = 0; i < zip_core_num; i++) { + if (i < zip_comp_core_num) +@@ -912,7 +958,7 @@ static int hisi_zip_show_last_regs_init(struct hisi_qm *qm) + u32 zip_core_num; + int i, j, idx; + +- zip_core_num = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CORE_NUM_CAP, qm->cap_ver); ++ zip_core_num = qm->cap_tables.dev_cap_table[ZIP_CORE_NUM_CAP_IDX].cap_val; + + debug->last_words = kcalloc(core_dfx_regs_num * zip_core_num + com_dfx_regs_num, + sizeof(unsigned int), GFP_KERNEL); +@@ -968,9 +1014,9 @@ static void hisi_zip_show_last_dfx_regs(struct hisi_qm *qm) + hzip_com_dfx_regs[i].name, debug->last_words[i], val); + } + +- zip_core_num = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CORE_NUM_CAP, qm->cap_ver); +- zip_comp_core_num = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CLUSTER_COMP_NUM_CAP, +- qm->cap_ver); ++ zip_core_num = qm->cap_tables.dev_cap_table[ZIP_CORE_NUM_CAP_IDX].cap_val; ++ zip_comp_core_num = qm->cap_tables.dev_cap_table[ZIP_CLUSTER_COMP_NUM_CAP_IDX].cap_val; ++ + for (i = 0; i < zip_core_num; i++) { + if (i < zip_comp_core_num) + scnprintf(buf, sizeof(buf), "Comp_core-%d", i); +@@ -1104,13 +1150,15 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip) + + hisi_zip->ctrl = ctrl; + ctrl->hisi_zip = hisi_zip; +- qm->err_ini = &hisi_zip_err_ini; +- qm->err_ini->err_info_init(qm); + + ret = hisi_zip_set_user_domain_and_cache(qm); + if (ret) + return ret; + ++ ret = hisi_zip_set_high_perf(qm); ++ if (ret) ++ return ret; ++ + hisi_zip_open_sva_prefetch(qm); + hisi_qm_dev_err_init(qm); + hisi_zip_debug_regs_clear(qm); +@@ -1122,8 +1170,31 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip) + return ret; + } + ++static int zip_pre_store_cap_reg(struct hisi_qm *qm) ++{ ++ struct hisi_qm_cap_record *zip_cap; ++ struct pci_dev *pdev = qm->pdev; ++ size_t i, size; ++ ++ size = ARRAY_SIZE(zip_pre_store_caps); ++ zip_cap = devm_kzalloc(&pdev->dev, sizeof(*zip_cap) * size, GFP_KERNEL); ++ if (!zip_cap) ++ return -ENOMEM; ++ ++ for (i = 0; i < size; i++) { ++ zip_cap[i].type = zip_pre_store_caps[i]; ++ zip_cap[i].cap_val = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ++ zip_pre_store_caps[i], qm->cap_ver); ++ } ++ ++ qm->cap_tables.dev_cap_table = zip_cap; ++ ++ return 0; ++} ++ + static int hisi_zip_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) + { ++ u64 alg_msk; + int ret; + + qm->pdev = pdev; +@@ -1139,6 +1210,9 @@ static int hisi_zip_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) + qm->qp_num = pf_q_num; + qm->debug.curr_qm_qp_num = pf_q_num; + qm->qm_list = &zip_devices; ++ qm->err_ini = &hisi_zip_err_ini; ++ if (pf_q_num_flag) ++ set_bit(QM_MODULE_PARAM, &qm->misc_ctl); + } else if (qm->fun_type == QM_HW_VF && qm->ver == QM_HW_V1) { + /* + * have no way to get qm configure in VM in v1 hardware, +@@ -1157,7 +1231,16 @@ static int hisi_zip_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) + return ret; + } + +- ret = hisi_zip_set_qm_algs(qm); ++ /* Fetch and save the value of capability registers */ ++ ret = zip_pre_store_cap_reg(qm); ++ if (ret) { ++ pci_err(qm->pdev, "Failed to pre-store capability registers!\n"); ++ hisi_qm_uninit(qm); ++ return ret; ++ } ++ ++ alg_msk = qm->cap_tables.dev_cap_table[ZIP_DEV_ALG_BITMAP_IDX].cap_val; ++ ret = hisi_qm_set_algs(qm, alg_msk, zip_dev_algs, ARRAY_SIZE(zip_dev_algs)); + if (ret) { + pci_err(qm->pdev, "Failed to set zip algs!\n"); + hisi_qm_uninit(qm); +@@ -1194,6 +1277,16 @@ static int hisi_zip_probe_init(struct hisi_zip *hisi_zip) + return 0; + } + ++static void hisi_zip_probe_uninit(struct hisi_qm *qm) ++{ ++ if (qm->fun_type == QM_HW_VF) ++ return; ++ ++ hisi_zip_show_last_regs_uninit(qm); ++ hisi_zip_close_sva_prefetch(qm); ++ hisi_qm_dev_err_uninit(qm); ++} ++ + static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id) + { + struct hisi_zip *hisi_zip; +@@ -1220,7 +1313,7 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id) + + ret = hisi_qm_start(qm); + if (ret) +- goto err_dev_err_uninit; ++ goto err_probe_uninit; + + ret = hisi_zip_debugfs_init(qm); + if (ret) +@@ -1257,9 +1350,8 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id) + hisi_zip_debugfs_exit(qm); + hisi_qm_stop(qm, QM_NORMAL); + +-err_dev_err_uninit: +- hisi_zip_show_last_regs_uninit(qm); +- hisi_qm_dev_err_uninit(qm); ++err_probe_uninit: ++ hisi_zip_probe_uninit(qm); + + err_qm_uninit: + hisi_zip_qm_uninit(qm); +@@ -1280,8 +1372,7 @@ static void hisi_zip_remove(struct pci_dev *pdev) + + hisi_zip_debugfs_exit(qm); + hisi_qm_stop(qm, QM_NORMAL); +- hisi_zip_show_last_regs_uninit(qm); +- hisi_qm_dev_err_uninit(qm); ++ hisi_zip_probe_uninit(qm); + hisi_zip_qm_uninit(qm); + } + +diff --git a/drivers/crypto/inside-secure/safexcel_cipher.c b/drivers/crypto/inside-secure/safexcel_cipher.c +index 272c28b5a0883e..b83818634ae477 100644 +--- a/drivers/crypto/inside-secure/safexcel_cipher.c ++++ b/drivers/crypto/inside-secure/safexcel_cipher.c +@@ -742,9 +742,9 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring, + max(totlen_src, totlen_dst)); + return -EINVAL; + } +- if (sreq->nr_src > 0) +- dma_map_sg(priv->dev, src, sreq->nr_src, +- DMA_BIDIRECTIONAL); ++ if (sreq->nr_src > 0 && ++ !dma_map_sg(priv->dev, src, sreq->nr_src, DMA_BIDIRECTIONAL)) ++ return -EIO; + } else { + if (unlikely(totlen_src && (sreq->nr_src <= 0))) { + dev_err(priv->dev, "Source buffer not large enough (need %d bytes)!", +@@ -752,8 +752,9 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring, + return -EINVAL; + } + +- if (sreq->nr_src > 0) +- dma_map_sg(priv->dev, src, sreq->nr_src, DMA_TO_DEVICE); ++ if (sreq->nr_src > 0 && ++ !dma_map_sg(priv->dev, src, sreq->nr_src, DMA_TO_DEVICE)) ++ return -EIO; + + if (unlikely(totlen_dst && (sreq->nr_dst <= 0))) { + dev_err(priv->dev, "Dest buffer not large enough (need %d bytes)!", +@@ -762,9 +763,11 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring, + goto unmap; + } + +- if (sreq->nr_dst > 0) +- dma_map_sg(priv->dev, dst, sreq->nr_dst, +- DMA_FROM_DEVICE); ++ if (sreq->nr_dst > 0 && ++ !dma_map_sg(priv->dev, dst, sreq->nr_dst, DMA_FROM_DEVICE)) { ++ ret = -EIO; ++ goto unmap; ++ } + } + + memcpy(ctx->base.ctxr->data, ctx->key, ctx->key_len); +diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +index dd4464b7e00b18..615af08832076a 100644 +--- a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +@@ -3,6 +3,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -13,6 +14,10 @@ + #include "adf_4xxx_hw_data.h" + #include "icp_qat_hw.h" + ++#define ADF_AE_GROUP_0 GENMASK(3, 0) ++#define ADF_AE_GROUP_1 GENMASK(7, 4) ++#define ADF_AE_GROUP_2 BIT(8) ++ + enum adf_fw_objs { + ADF_FW_SYM_OBJ, + ADF_FW_ASYM_OBJ, +@@ -40,39 +45,45 @@ struct adf_fw_config { + }; + + static const struct adf_fw_config adf_fw_cy_config[] = { +- {0xF0, ADF_FW_SYM_OBJ}, +- {0xF, ADF_FW_ASYM_OBJ}, +- {0x100, ADF_FW_ADMIN_OBJ}, ++ {ADF_AE_GROUP_1, ADF_FW_SYM_OBJ}, ++ {ADF_AE_GROUP_0, ADF_FW_ASYM_OBJ}, ++ {ADF_AE_GROUP_2, ADF_FW_ADMIN_OBJ}, + }; + + static const struct adf_fw_config adf_fw_dc_config[] = { +- {0xF0, ADF_FW_DC_OBJ}, +- {0xF, ADF_FW_DC_OBJ}, +- {0x100, ADF_FW_ADMIN_OBJ}, ++ {ADF_AE_GROUP_1, ADF_FW_DC_OBJ}, ++ {ADF_AE_GROUP_0, ADF_FW_DC_OBJ}, ++ {ADF_AE_GROUP_2, ADF_FW_ADMIN_OBJ}, + }; + + static const struct adf_fw_config adf_fw_sym_config[] = { +- {0xF0, ADF_FW_SYM_OBJ}, +- {0xF, ADF_FW_SYM_OBJ}, +- {0x100, ADF_FW_ADMIN_OBJ}, ++ {ADF_AE_GROUP_1, ADF_FW_SYM_OBJ}, ++ {ADF_AE_GROUP_0, ADF_FW_SYM_OBJ}, ++ {ADF_AE_GROUP_2, ADF_FW_ADMIN_OBJ}, + }; + + static const struct adf_fw_config adf_fw_asym_config[] = { +- {0xF0, ADF_FW_ASYM_OBJ}, +- {0xF, ADF_FW_ASYM_OBJ}, +- {0x100, ADF_FW_ADMIN_OBJ}, ++ {ADF_AE_GROUP_1, ADF_FW_ASYM_OBJ}, ++ {ADF_AE_GROUP_0, ADF_FW_ASYM_OBJ}, ++ {ADF_AE_GROUP_2, ADF_FW_ADMIN_OBJ}, + }; + + static const struct adf_fw_config adf_fw_asym_dc_config[] = { +- {0xF0, ADF_FW_ASYM_OBJ}, +- {0xF, ADF_FW_DC_OBJ}, +- {0x100, ADF_FW_ADMIN_OBJ}, ++ {ADF_AE_GROUP_1, ADF_FW_ASYM_OBJ}, ++ {ADF_AE_GROUP_0, ADF_FW_DC_OBJ}, ++ {ADF_AE_GROUP_2, ADF_FW_ADMIN_OBJ}, + }; + + static const struct adf_fw_config adf_fw_sym_dc_config[] = { +- {0xF0, ADF_FW_SYM_OBJ}, +- {0xF, ADF_FW_DC_OBJ}, +- {0x100, ADF_FW_ADMIN_OBJ}, ++ {ADF_AE_GROUP_1, ADF_FW_SYM_OBJ}, ++ {ADF_AE_GROUP_0, ADF_FW_DC_OBJ}, ++ {ADF_AE_GROUP_2, ADF_FW_ADMIN_OBJ}, ++}; ++ ++static const struct adf_fw_config adf_fw_dcc_config[] = { ++ {ADF_AE_GROUP_1, ADF_FW_DC_OBJ}, ++ {ADF_AE_GROUP_0, ADF_FW_SYM_OBJ}, ++ {ADF_AE_GROUP_2, ADF_FW_ADMIN_OBJ}, + }; + + static_assert(ARRAY_SIZE(adf_fw_cy_config) == ARRAY_SIZE(adf_fw_dc_config)); +@@ -80,6 +91,7 @@ static_assert(ARRAY_SIZE(adf_fw_cy_config) == ARRAY_SIZE(adf_fw_sym_config)); + static_assert(ARRAY_SIZE(adf_fw_cy_config) == ARRAY_SIZE(adf_fw_asym_config)); + static_assert(ARRAY_SIZE(adf_fw_cy_config) == ARRAY_SIZE(adf_fw_asym_dc_config)); + static_assert(ARRAY_SIZE(adf_fw_cy_config) == ARRAY_SIZE(adf_fw_sym_dc_config)); ++static_assert(ARRAY_SIZE(adf_fw_cy_config) == ARRAY_SIZE(adf_fw_dcc_config)); + + /* Worker thread to service arbiter mappings */ + static const u32 default_thrd_to_arb_map[ADF_4XXX_MAX_ACCELENGINES] = { +@@ -94,59 +106,18 @@ static const u32 thrd_to_arb_map_dc[ADF_4XXX_MAX_ACCELENGINES] = { + 0x0 + }; + ++static const u32 thrd_to_arb_map_dcc[ADF_4XXX_MAX_ACCELENGINES] = { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, ++ 0x0 ++}; ++ + static struct adf_hw_device_class adf_4xxx_class = { + .name = ADF_4XXX_DEVICE_NAME, + .type = DEV_4XXX, + .instances = 0, + }; + +-enum dev_services { +- SVC_CY = 0, +- SVC_CY2, +- SVC_DC, +- SVC_SYM, +- SVC_ASYM, +- SVC_DC_ASYM, +- SVC_ASYM_DC, +- SVC_DC_SYM, +- SVC_SYM_DC, +-}; +- +-static const char *const dev_cfg_services[] = { +- [SVC_CY] = ADF_CFG_CY, +- [SVC_CY2] = ADF_CFG_ASYM_SYM, +- [SVC_DC] = ADF_CFG_DC, +- [SVC_SYM] = ADF_CFG_SYM, +- [SVC_ASYM] = ADF_CFG_ASYM, +- [SVC_DC_ASYM] = ADF_CFG_DC_ASYM, +- [SVC_ASYM_DC] = ADF_CFG_ASYM_DC, +- [SVC_DC_SYM] = ADF_CFG_DC_SYM, +- [SVC_SYM_DC] = ADF_CFG_SYM_DC, +-}; +- +-static int get_service_enabled(struct adf_accel_dev *accel_dev) +-{ +- char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0}; +- int ret; +- +- ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, +- ADF_SERVICES_ENABLED, services); +- if (ret) { +- dev_err(&GET_DEV(accel_dev), +- ADF_SERVICES_ENABLED " param not found\n"); +- return ret; +- } +- +- ret = match_string(dev_cfg_services, ARRAY_SIZE(dev_cfg_services), +- services); +- if (ret < 0) +- dev_err(&GET_DEV(accel_dev), +- "Invalid value of " ADF_SERVICES_ENABLED " param: %s\n", +- services); +- +- return ret; +-} +- + static u32 get_accel_mask(struct adf_hw_device_data *self) + { + return ADF_4XXX_ACCELERATORS_MASK; +@@ -212,6 +183,7 @@ static u32 get_accel_cap(struct adf_accel_dev *accel_dev) + { + struct pci_dev *pdev = accel_dev->accel_pci_dev.pci_dev; + u32 capabilities_sym, capabilities_asym, capabilities_dc; ++ u32 capabilities_dcc; + u32 fusectl1; + + /* Read accelerator capabilities mask */ +@@ -278,12 +250,20 @@ static u32 get_accel_cap(struct adf_accel_dev *accel_dev) + capabilities_dc &= ~ICP_ACCEL_CAPABILITIES_CNV_INTEGRITY64; + } + +- switch (get_service_enabled(accel_dev)) { ++ switch (adf_get_service_enabled(accel_dev)) { + case SVC_CY: + case SVC_CY2: + return capabilities_sym | capabilities_asym; + case SVC_DC: + return capabilities_dc; ++ case SVC_DCC: ++ /* ++ * Sym capabilities are available for chaining operations, ++ * but sym crypto instances cannot be supported ++ */ ++ capabilities_dcc = capabilities_dc | capabilities_sym; ++ capabilities_dcc &= ~ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC; ++ return capabilities_dcc; + case SVC_SYM: + return capabilities_sym; + case SVC_ASYM: +@@ -306,9 +286,11 @@ static enum dev_sku_info get_sku(struct adf_hw_device_data *self) + + static const u32 *adf_get_arbiter_mapping(struct adf_accel_dev *accel_dev) + { +- switch (get_service_enabled(accel_dev)) { ++ switch (adf_get_service_enabled(accel_dev)) { + case SVC_DC: + return thrd_to_arb_map_dc; ++ case SVC_DCC: ++ return thrd_to_arb_map_dcc; + default: + return default_thrd_to_arb_map; + } +@@ -393,38 +375,104 @@ static u32 uof_get_num_objs(void) + return ARRAY_SIZE(adf_fw_cy_config); + } + +-static const char *uof_get_name(struct adf_accel_dev *accel_dev, u32 obj_num, +- const char * const fw_objs[], int num_objs) ++static const struct adf_fw_config *get_fw_config(struct adf_accel_dev *accel_dev) + { +- int id; +- +- switch (get_service_enabled(accel_dev)) { ++ switch (adf_get_service_enabled(accel_dev)) { + case SVC_CY: + case SVC_CY2: +- id = adf_fw_cy_config[obj_num].obj; +- break; ++ return adf_fw_cy_config; + case SVC_DC: +- id = adf_fw_dc_config[obj_num].obj; +- break; ++ return adf_fw_dc_config; ++ case SVC_DCC: ++ return adf_fw_dcc_config; + case SVC_SYM: +- id = adf_fw_sym_config[obj_num].obj; +- break; ++ return adf_fw_sym_config; + case SVC_ASYM: +- id = adf_fw_asym_config[obj_num].obj; +- break; ++ return adf_fw_asym_config; + case SVC_ASYM_DC: + case SVC_DC_ASYM: +- id = adf_fw_asym_dc_config[obj_num].obj; +- break; ++ return adf_fw_asym_dc_config; + case SVC_SYM_DC: + case SVC_DC_SYM: +- id = adf_fw_sym_dc_config[obj_num].obj; +- break; ++ return adf_fw_sym_dc_config; + default: +- id = -EINVAL; +- break; ++ return NULL; ++ } ++} ++ ++enum adf_rp_groups { ++ RP_GROUP_0 = 0, ++ RP_GROUP_1, ++ RP_GROUP_COUNT ++}; ++ ++static u16 get_ring_to_svc_map(struct adf_accel_dev *accel_dev) ++{ ++ enum adf_cfg_service_type rps[RP_GROUP_COUNT]; ++ const struct adf_fw_config *fw_config; ++ u16 ring_to_svc_map; ++ int i, j; ++ ++ fw_config = get_fw_config(accel_dev); ++ if (!fw_config) ++ return 0; ++ ++ /* If dcc, all rings handle compression requests */ ++ if (adf_get_service_enabled(accel_dev) == SVC_DCC) { ++ for (i = 0; i < RP_GROUP_COUNT; i++) ++ rps[i] = COMP; ++ goto set_mask; + } + ++ for (i = 0; i < RP_GROUP_COUNT; i++) { ++ switch (fw_config[i].ae_mask) { ++ case ADF_AE_GROUP_0: ++ j = RP_GROUP_0; ++ break; ++ case ADF_AE_GROUP_1: ++ j = RP_GROUP_1; ++ break; ++ default: ++ return 0; ++ } ++ ++ switch (fw_config[i].obj) { ++ case ADF_FW_SYM_OBJ: ++ rps[j] = SYM; ++ break; ++ case ADF_FW_ASYM_OBJ: ++ rps[j] = ASYM; ++ break; ++ case ADF_FW_DC_OBJ: ++ rps[j] = COMP; ++ break; ++ default: ++ rps[j] = 0; ++ break; ++ } ++ } ++ ++set_mask: ++ ring_to_svc_map = rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_0_SHIFT | ++ rps[RP_GROUP_1] << ADF_CFG_SERV_RING_PAIR_1_SHIFT | ++ rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_2_SHIFT | ++ rps[RP_GROUP_1] << ADF_CFG_SERV_RING_PAIR_3_SHIFT; ++ ++ return ring_to_svc_map; ++} ++ ++static const char *uof_get_name(struct adf_accel_dev *accel_dev, u32 obj_num, ++ const char * const fw_objs[], int num_objs) ++{ ++ const struct adf_fw_config *fw_config; ++ int id; ++ ++ fw_config = get_fw_config(accel_dev); ++ if (fw_config) ++ id = fw_config[obj_num].obj; ++ else ++ id = -EINVAL; ++ + if (id < 0 || id > num_objs) + return NULL; + +@@ -447,26 +495,13 @@ static const char *uof_get_name_402xx(struct adf_accel_dev *accel_dev, u32 obj_n + + static u32 uof_get_ae_mask(struct adf_accel_dev *accel_dev, u32 obj_num) + { +- switch (get_service_enabled(accel_dev)) { +- case SVC_CY: +- return adf_fw_cy_config[obj_num].ae_mask; +- case SVC_DC: +- return adf_fw_dc_config[obj_num].ae_mask; +- case SVC_CY2: +- return adf_fw_cy_config[obj_num].ae_mask; +- case SVC_SYM: +- return adf_fw_sym_config[obj_num].ae_mask; +- case SVC_ASYM: +- return adf_fw_asym_config[obj_num].ae_mask; +- case SVC_ASYM_DC: +- case SVC_DC_ASYM: +- return adf_fw_asym_dc_config[obj_num].ae_mask; +- case SVC_SYM_DC: +- case SVC_DC_SYM: +- return adf_fw_sym_dc_config[obj_num].ae_mask; +- default: ++ const struct adf_fw_config *fw_config; ++ ++ fw_config = get_fw_config(accel_dev); ++ if (!fw_config) + return 0; +- } ++ ++ return fw_config[obj_num].ae_mask; + } + + void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data, u32 dev_id) +@@ -522,6 +557,7 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data, u32 dev_id) + hw_data->uof_get_ae_mask = uof_get_ae_mask; + hw_data->set_msix_rttable = set_msix_default_rttable; + hw_data->set_ssm_wdtimer = adf_gen4_set_ssm_wdtimer; ++ hw_data->get_ring_to_svc_map = get_ring_to_svc_map; + hw_data->disable_iov = adf_disable_sriov; + hw_data->ring_pair_reset = adf_gen4_ring_pair_reset; + hw_data->enable_pm = adf_gen4_enable_pm; +diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c +index 6d4e2e139ffa24..f6f9e20f74b543 100644 +--- a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c ++++ b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c +@@ -11,6 +11,7 @@ + #include + + #include "adf_4xxx_hw_data.h" ++#include "adf_cfg_services.h" + #include "qat_compression.h" + #include "qat_crypto.h" + #include "adf_transport_access_macros.h" +@@ -23,30 +24,6 @@ static const struct pci_device_id adf_pci_tbl[] = { + }; + MODULE_DEVICE_TABLE(pci, adf_pci_tbl); + +-enum configs { +- DEV_CFG_CY = 0, +- DEV_CFG_DC, +- DEV_CFG_SYM, +- DEV_CFG_ASYM, +- DEV_CFG_ASYM_SYM, +- DEV_CFG_ASYM_DC, +- DEV_CFG_DC_ASYM, +- DEV_CFG_SYM_DC, +- DEV_CFG_DC_SYM, +-}; +- +-static const char * const services_operations[] = { +- ADF_CFG_CY, +- ADF_CFG_DC, +- ADF_CFG_SYM, +- ADF_CFG_ASYM, +- ADF_CFG_ASYM_SYM, +- ADF_CFG_ASYM_DC, +- ADF_CFG_DC_ASYM, +- ADF_CFG_SYM_DC, +- ADF_CFG_DC_SYM, +-}; +- + static void adf_cleanup_accel(struct adf_accel_dev *accel_dev) + { + if (accel_dev->hw_device) { +@@ -292,16 +269,17 @@ int adf_gen4_dev_config(struct adf_accel_dev *accel_dev) + if (ret) + goto err; + +- ret = sysfs_match_string(services_operations, services); ++ ret = sysfs_match_string(adf_cfg_services, services); + if (ret < 0) + goto err; + + switch (ret) { +- case DEV_CFG_CY: +- case DEV_CFG_ASYM_SYM: ++ case SVC_CY: ++ case SVC_CY2: + ret = adf_crypto_dev_config(accel_dev); + break; +- case DEV_CFG_DC: ++ case SVC_DC: ++ case SVC_DCC: + ret = adf_comp_dev_config(accel_dev); + break; + default: +@@ -485,7 +463,9 @@ module_pci_driver(adf_driver); + MODULE_LICENSE("Dual BSD/GPL"); + MODULE_AUTHOR("Intel"); + MODULE_FIRMWARE(ADF_4XXX_FW); ++MODULE_FIRMWARE(ADF_402XX_FW); + MODULE_FIRMWARE(ADF_4XXX_MMP); ++MODULE_FIRMWARE(ADF_402XX_MMP); + MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); + MODULE_VERSION(ADF_DRV_VERSION); + MODULE_SOFTDEP("pre: crypto-intel_qat"); +diff --git a/drivers/crypto/intel/qat/qat_common/Makefile b/drivers/crypto/intel/qat/qat_common/Makefile +index 43622c7fca712c..8dbf146de3fa59 100644 +--- a/drivers/crypto/intel/qat/qat_common/Makefile ++++ b/drivers/crypto/intel/qat/qat_common/Makefile +@@ -3,6 +3,7 @@ obj-$(CONFIG_CRYPTO_DEV_QAT) += intel_qat.o + intel_qat-objs := adf_cfg.o \ + adf_isr.o \ + adf_ctl_drv.o \ ++ adf_cfg_services.o \ + adf_dev_mgr.o \ + adf_init.o \ + adf_accel_engine.o \ +diff --git a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h +index e57abde66f4fb3..79d5a1535eda34 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h ++++ b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h +@@ -29,7 +29,7 @@ + #define ADF_PCI_MAX_BARS 3 + #define ADF_DEVICE_NAME_LENGTH 32 + #define ADF_ETR_MAX_RINGS_PER_BANK 16 +-#define ADF_MAX_MSIX_VECTOR_NAME 16 ++#define ADF_MAX_MSIX_VECTOR_NAME 48 + #define ADF_DEVICE_NAME_PREFIX "qat_" + + enum adf_accel_capabilities { +@@ -182,6 +182,7 @@ struct adf_hw_device_data { + void (*get_arb_info)(struct arb_info *arb_csrs_info); + void (*get_admin_info)(struct admin_info *admin_csrs_info); + enum dev_sku_info (*get_sku)(struct adf_hw_device_data *self); ++ u16 (*get_ring_to_svc_map)(struct adf_accel_dev *accel_dev); + int (*alloc_irq)(struct adf_accel_dev *accel_dev); + void (*free_irq)(struct adf_accel_dev *accel_dev); + void (*enable_error_correction)(struct adf_accel_dev *accel_dev); +diff --git a/drivers/crypto/intel/qat/qat_common/adf_admin.c b/drivers/crypto/intel/qat/qat_common/adf_admin.c +index ff790823b86861..194d64d4b99a1b 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_admin.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_admin.c +@@ -8,6 +8,7 @@ + #include + #include "adf_accel_devices.h" + #include "adf_common_drv.h" ++#include "adf_cfg.h" + #include "adf_heartbeat.h" + #include "icp_qat_fw_init_admin.h" + +@@ -212,6 +213,17 @@ int adf_get_fw_timestamp(struct adf_accel_dev *accel_dev, u64 *timestamp) + return 0; + } + ++static int adf_set_chaining(struct adf_accel_dev *accel_dev) ++{ ++ u32 ae_mask = GET_HW_DATA(accel_dev)->ae_mask; ++ struct icp_qat_fw_init_admin_resp resp = { }; ++ struct icp_qat_fw_init_admin_req req = { }; ++ ++ req.cmd_id = ICP_QAT_FW_DC_CHAIN_INIT; ++ ++ return adf_send_admin(accel_dev, &req, &resp, ae_mask); ++} ++ + static int adf_get_dc_capabilities(struct adf_accel_dev *accel_dev, + u32 *capabilities) + { +@@ -284,6 +296,19 @@ int adf_send_admin_hb_timer(struct adf_accel_dev *accel_dev, uint32_t ticks) + return adf_send_admin(accel_dev, &req, &resp, ae_mask); + } + ++static bool is_dcc_enabled(struct adf_accel_dev *accel_dev) ++{ ++ char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0}; ++ int ret; ++ ++ ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, ++ ADF_SERVICES_ENABLED, services); ++ if (ret) ++ return false; ++ ++ return !strcmp(services, "dcc"); ++} ++ + /** + * adf_send_admin_init() - Function sends init message to FW + * @accel_dev: Pointer to acceleration device. +@@ -297,6 +322,16 @@ int adf_send_admin_init(struct adf_accel_dev *accel_dev) + u32 dc_capabilities = 0; + int ret; + ++ ret = adf_set_fw_constants(accel_dev); ++ if (ret) ++ return ret; ++ ++ if (is_dcc_enabled(accel_dev)) { ++ ret = adf_set_chaining(accel_dev); ++ if (ret) ++ return ret; ++ } ++ + ret = adf_get_dc_capabilities(accel_dev, &dc_capabilities); + if (ret) { + dev_err(&GET_DEV(accel_dev), "Cannot get dc capabilities\n"); +@@ -304,10 +339,6 @@ int adf_send_admin_init(struct adf_accel_dev *accel_dev) + } + accel_dev->hw_device->extended_dc_capabilities = dc_capabilities; + +- ret = adf_set_fw_constants(accel_dev); +- if (ret) +- return ret; +- + return adf_init_ae(accel_dev); + } + EXPORT_SYMBOL_GPL(adf_send_admin_init); +diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c +index 04af32a2811c8f..af495a6f039f6b 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_aer.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c +@@ -92,7 +92,8 @@ static void adf_device_reset_worker(struct work_struct *work) + if (adf_dev_restart(accel_dev)) { + /* The device hanged and we can't restart it so stop here */ + dev_err(&GET_DEV(accel_dev), "Restart device failed\n"); +- kfree(reset_data); ++ if (reset_data->mode == ADF_DEV_RESET_ASYNC) ++ kfree(reset_data); + WARN(1, "QAT: device restart failed. Device is unusable\n"); + return; + } +@@ -100,10 +101,10 @@ static void adf_device_reset_worker(struct work_struct *work) + clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status); + + /* The dev is back alive. Notify the caller if in sync mode */ +- if (reset_data->mode == ADF_DEV_RESET_SYNC) +- complete(&reset_data->compl); +- else ++ if (reset_data->mode == ADF_DEV_RESET_ASYNC) + kfree(reset_data); ++ else ++ complete(&reset_data->compl); + } + + static int adf_dev_aer_schedule_reset(struct adf_accel_dev *accel_dev, +@@ -135,6 +136,7 @@ static int adf_dev_aer_schedule_reset(struct adf_accel_dev *accel_dev, + if (!timeout) { + dev_err(&GET_DEV(accel_dev), + "Reset device timeout expired\n"); ++ cancel_work_sync(&reset_data->reset_work); + ret = -EFAULT; + } + kfree(reset_data); +diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg.c b/drivers/crypto/intel/qat/qat_common/adf_cfg.c +index 8836f015c39c41..2cf102ad4ca82d 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_cfg.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_cfg.c +@@ -290,17 +290,19 @@ int adf_cfg_add_key_value_param(struct adf_accel_dev *accel_dev, + * 3. if the key exists with the same value, then return without doing + * anything (the newly created key_val is freed). + */ ++ down_write(&cfg->lock); + if (!adf_cfg_key_val_get(accel_dev, section_name, key, temp_val)) { + if (strncmp(temp_val, key_val->val, sizeof(temp_val))) { + adf_cfg_keyval_remove(key, section); + } else { + kfree(key_val); +- return 0; ++ goto out; + } + } + +- down_write(&cfg->lock); + adf_cfg_keyval_add(key_val, section); ++ ++out: + up_write(&cfg->lock); + return 0; + } +diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c b/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c +new file mode 100644 +index 00000000000000..26805229446843 +--- /dev/null ++++ b/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c +@@ -0,0 +1,47 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* Copyright(c) 2023 Intel Corporation */ ++ ++#include ++#include ++#include ++#include "adf_cfg.h" ++#include "adf_cfg_services.h" ++#include "adf_cfg_strings.h" ++ ++const char *const adf_cfg_services[] = { ++ [SVC_CY] = ADF_CFG_CY, ++ [SVC_CY2] = ADF_CFG_ASYM_SYM, ++ [SVC_DC] = ADF_CFG_DC, ++ [SVC_DCC] = ADF_CFG_DCC, ++ [SVC_SYM] = ADF_CFG_SYM, ++ [SVC_ASYM] = ADF_CFG_ASYM, ++ [SVC_DC_ASYM] = ADF_CFG_DC_ASYM, ++ [SVC_ASYM_DC] = ADF_CFG_ASYM_DC, ++ [SVC_DC_SYM] = ADF_CFG_DC_SYM, ++ [SVC_SYM_DC] = ADF_CFG_SYM_DC, ++}; ++EXPORT_SYMBOL_GPL(adf_cfg_services); ++ ++int adf_get_service_enabled(struct adf_accel_dev *accel_dev) ++{ ++ char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0}; ++ int ret; ++ ++ ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, ++ ADF_SERVICES_ENABLED, services); ++ if (ret) { ++ dev_err(&GET_DEV(accel_dev), ++ ADF_SERVICES_ENABLED " param not found\n"); ++ return ret; ++ } ++ ++ ret = match_string(adf_cfg_services, ARRAY_SIZE(adf_cfg_services), ++ services); ++ if (ret < 0) ++ dev_err(&GET_DEV(accel_dev), ++ "Invalid value of " ADF_SERVICES_ENABLED " param: %s\n", ++ services); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(adf_get_service_enabled); +diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg_services.h b/drivers/crypto/intel/qat/qat_common/adf_cfg_services.h +new file mode 100644 +index 00000000000000..c6b0328b0f5b03 +--- /dev/null ++++ b/drivers/crypto/intel/qat/qat_common/adf_cfg_services.h +@@ -0,0 +1,28 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* Copyright(c) 2023 Intel Corporation */ ++#ifndef _ADF_CFG_SERVICES_H_ ++#define _ADF_CFG_SERVICES_H_ ++ ++#include "adf_cfg_strings.h" ++ ++struct adf_accel_dev; ++ ++enum adf_services { ++ SVC_CY = 0, ++ SVC_CY2, ++ SVC_DC, ++ SVC_DCC, ++ SVC_SYM, ++ SVC_ASYM, ++ SVC_DC_ASYM, ++ SVC_ASYM_DC, ++ SVC_DC_SYM, ++ SVC_SYM_DC, ++ SVC_COUNT ++}; ++ ++extern const char *const adf_cfg_services[SVC_COUNT]; ++ ++int adf_get_service_enabled(struct adf_accel_dev *accel_dev); ++ ++#endif +diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg_strings.h b/drivers/crypto/intel/qat/qat_common/adf_cfg_strings.h +index 6066dc637352ca..322b76903a737d 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_cfg_strings.h ++++ b/drivers/crypto/intel/qat/qat_common/adf_cfg_strings.h +@@ -32,6 +32,7 @@ + #define ADF_CFG_DC_ASYM "dc;asym" + #define ADF_CFG_SYM_DC "sym;dc" + #define ADF_CFG_DC_SYM "dc;sym" ++#define ADF_CFG_DCC "dcc" + #define ADF_SERVICES_ENABLED "ServicesEnabled" + #define ADF_PM_IDLE_SUPPORT "PmIdleSupport" + #define ADF_ETRMGR_COALESCING_ENABLED "InterruptCoalescingEnabled" +diff --git a/drivers/crypto/intel/qat/qat_common/adf_clock.c b/drivers/crypto/intel/qat/qat_common/adf_clock.c +index dc0778691eb0ba..eae44969dc84fa 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_clock.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_clock.c +@@ -82,6 +82,9 @@ static int measure_clock(struct adf_accel_dev *accel_dev, u32 *frequency) + } + + delta_us = timespec_to_us(&ts3) - timespec_to_us(&ts1); ++ if (!delta_us) ++ return -EINVAL; ++ + temp = (timestamp2 - timestamp1) * ME_CLK_DIVIDER * 10; + temp = DIV_ROUND_CLOSEST_ULL(temp, delta_us); + /* +diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h +index 673b5044c62a50..79ff7982378d9f 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h ++++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h +@@ -25,6 +25,8 @@ + #define ADF_STATUS_AE_STARTED 6 + #define ADF_STATUS_PF_RUNNING 7 + #define ADF_STATUS_IRQ_ALLOCATED 8 ++#define ADF_STATUS_CRYPTO_ALGS_REGISTERED 9 ++#define ADF_STATUS_COMP_ALGS_REGISTERED 10 + + enum adf_dev_reset_mode { + ADF_DEV_RESET_ASYNC = 0, +diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen2_pfvf.c b/drivers/crypto/intel/qat/qat_common/adf_gen2_pfvf.c +index 70ef1196393814..43af81fcab8686 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_gen2_pfvf.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_gen2_pfvf.c +@@ -100,7 +100,9 @@ static u32 adf_gen2_disable_pending_vf2pf_interrupts(void __iomem *pmisc_addr) + errmsk3 |= ADF_GEN2_ERR_MSK_VF2PF(ADF_GEN2_VF_MSK); + ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, errmsk3); + +- errmsk3 &= ADF_GEN2_ERR_MSK_VF2PF(sources | disabled); ++ /* Update only section of errmsk3 related to VF2PF */ ++ errmsk3 &= ~ADF_GEN2_ERR_MSK_VF2PF(ADF_GEN2_VF_MSK); ++ errmsk3 |= ADF_GEN2_ERR_MSK_VF2PF(sources | disabled); + ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, errmsk3); + + /* Return the sources of the (new) interrupt(s) */ +diff --git a/drivers/crypto/intel/qat/qat_common/adf_init.c b/drivers/crypto/intel/qat/qat_common/adf_init.c +index 89001fe92e7629..0f9e2d59ce3857 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_init.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_init.c +@@ -97,6 +97,9 @@ static int adf_dev_init(struct adf_accel_dev *accel_dev) + return -EFAULT; + } + ++ if (hw_data->get_ring_to_svc_map) ++ hw_data->ring_to_svc_map = hw_data->get_ring_to_svc_map(accel_dev); ++ + if (adf_ae_init(accel_dev)) { + dev_err(&GET_DEV(accel_dev), + "Failed to initialise Acceleration Engine\n"); +@@ -231,6 +234,7 @@ static int adf_dev_start(struct adf_accel_dev *accel_dev) + clear_bit(ADF_STATUS_STARTED, &accel_dev->status); + return -EFAULT; + } ++ set_bit(ADF_STATUS_CRYPTO_ALGS_REGISTERED, &accel_dev->status); + + if (!list_empty(&accel_dev->compression_list) && qat_comp_algs_register()) { + dev_err(&GET_DEV(accel_dev), +@@ -239,6 +243,7 @@ static int adf_dev_start(struct adf_accel_dev *accel_dev) + clear_bit(ADF_STATUS_STARTED, &accel_dev->status); + return -EFAULT; + } ++ set_bit(ADF_STATUS_COMP_ALGS_REGISTERED, &accel_dev->status); + + adf_dbgfs_add(accel_dev); + +@@ -272,13 +277,17 @@ static void adf_dev_stop(struct adf_accel_dev *accel_dev) + clear_bit(ADF_STATUS_STARTING, &accel_dev->status); + clear_bit(ADF_STATUS_STARTED, &accel_dev->status); + +- if (!list_empty(&accel_dev->crypto_list)) { ++ if (!list_empty(&accel_dev->crypto_list) && ++ test_bit(ADF_STATUS_CRYPTO_ALGS_REGISTERED, &accel_dev->status)) { + qat_algs_unregister(); + qat_asym_algs_unregister(); + } ++ clear_bit(ADF_STATUS_CRYPTO_ALGS_REGISTERED, &accel_dev->status); + +- if (!list_empty(&accel_dev->compression_list)) ++ if (!list_empty(&accel_dev->compression_list) && ++ test_bit(ADF_STATUS_COMP_ALGS_REGISTERED, &accel_dev->status)) + qat_comp_algs_unregister(); ++ clear_bit(ADF_STATUS_COMP_ALGS_REGISTERED, &accel_dev->status); + + list_for_each(list_itr, &service_table) { + service = list_entry(list_itr, struct service_hndl, list); +@@ -440,13 +449,6 @@ int adf_dev_down(struct adf_accel_dev *accel_dev, bool reconfig) + + mutex_lock(&accel_dev->state_lock); + +- if (!adf_dev_started(accel_dev)) { +- dev_info(&GET_DEV(accel_dev), "Device qat_dev%d already down\n", +- accel_dev->accel_id); +- ret = -EINVAL; +- goto out; +- } +- + if (reconfig) { + ret = adf_dev_shutdown_cache_cfg(accel_dev); + goto out; +diff --git a/drivers/crypto/intel/qat/qat_common/adf_sysfs.c b/drivers/crypto/intel/qat/qat_common/adf_sysfs.c +index a74d2f93036709..8f04b0d3c5ac89 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_sysfs.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_sysfs.c +@@ -5,6 +5,7 @@ + #include + #include "adf_accel_devices.h" + #include "adf_cfg.h" ++#include "adf_cfg_services.h" + #include "adf_common_drv.h" + + static const char * const state_operations[] = { +@@ -52,6 +53,13 @@ static ssize_t state_store(struct device *dev, struct device_attribute *attr, + case DEV_DOWN: + dev_info(dev, "Stopping device qat_dev%d\n", accel_id); + ++ if (!adf_dev_started(accel_dev)) { ++ dev_info(&GET_DEV(accel_dev), "Device qat_dev%d already down\n", ++ accel_id); ++ ++ break; ++ } ++ + ret = adf_dev_down(accel_dev, true); + if (ret < 0) + return -EINVAL; +@@ -61,7 +69,9 @@ static ssize_t state_store(struct device *dev, struct device_attribute *attr, + dev_info(dev, "Starting device qat_dev%d\n", accel_id); + + ret = adf_dev_up(accel_dev, true); +- if (ret < 0) { ++ if (ret == -EALREADY) { ++ break; ++ } else if (ret) { + dev_err(dev, "Failed to start device qat_dev%d\n", + accel_id); + adf_dev_down(accel_dev, true); +@@ -75,18 +85,6 @@ static ssize_t state_store(struct device *dev, struct device_attribute *attr, + return count; + } + +-static const char * const services_operations[] = { +- ADF_CFG_CY, +- ADF_CFG_DC, +- ADF_CFG_SYM, +- ADF_CFG_ASYM, +- ADF_CFG_ASYM_SYM, +- ADF_CFG_ASYM_DC, +- ADF_CFG_DC_ASYM, +- ADF_CFG_SYM_DC, +- ADF_CFG_DC_SYM, +-}; +- + static ssize_t cfg_services_show(struct device *dev, struct device_attribute *attr, + char *buf) + { +@@ -121,7 +119,7 @@ static ssize_t cfg_services_store(struct device *dev, struct device_attribute *a + struct adf_accel_dev *accel_dev; + int ret; + +- ret = sysfs_match_string(services_operations, buf); ++ ret = sysfs_match_string(adf_cfg_services, buf); + if (ret < 0) + return ret; + +@@ -135,7 +133,7 @@ static ssize_t cfg_services_store(struct device *dev, struct device_attribute *a + return -EINVAL; + } + +- ret = adf_sysfs_update_dev_config(accel_dev, services_operations[ret]); ++ ret = adf_sysfs_update_dev_config(accel_dev, adf_cfg_services[ret]); + if (ret < 0) + return ret; + +diff --git a/drivers/crypto/intel/qat/qat_common/adf_transport_debug.c b/drivers/crypto/intel/qat/qat_common/adf_transport_debug.c +index 08bca1c506c0ef..e2dd568b87b519 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_transport_debug.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_transport_debug.c +@@ -90,7 +90,7 @@ DEFINE_SEQ_ATTRIBUTE(adf_ring_debug); + int adf_ring_debugfs_add(struct adf_etr_ring_data *ring, const char *name) + { + struct adf_etr_ring_debug_entry *ring_debug; +- char entry_name[8]; ++ char entry_name[16]; + + ring_debug = kzalloc(sizeof(*ring_debug), GFP_KERNEL); + if (!ring_debug) +@@ -192,7 +192,7 @@ int adf_bank_debugfs_add(struct adf_etr_bank_data *bank) + { + struct adf_accel_dev *accel_dev = bank->accel_dev; + struct dentry *parent = accel_dev->transport->debug; +- char name[8]; ++ char name[16]; + + snprintf(name, sizeof(name), "bank_%02d", bank->bank_number); + bank->bank_debug_dir = debugfs_create_dir(name, parent); +diff --git a/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h b/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h +index 3e968a4bcc9cd5..019a6443834e0b 100644 +--- a/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h ++++ b/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h +@@ -16,6 +16,7 @@ enum icp_qat_fw_init_admin_cmd_id { + ICP_QAT_FW_HEARTBEAT_SYNC = 7, + ICP_QAT_FW_HEARTBEAT_GET = 8, + ICP_QAT_FW_COMP_CAPABILITY_GET = 9, ++ ICP_QAT_FW_DC_CHAIN_INIT = 11, + ICP_QAT_FW_HEARTBEAT_TIMER_SET = 13, + ICP_QAT_FW_TIMER_GET = 19, + ICP_QAT_FW_PM_STATE_CONFIG = 128, +diff --git a/drivers/crypto/intel/qat/qat_common/qat_algs_send.c b/drivers/crypto/intel/qat/qat_common/qat_algs_send.c +index bb80455b3e81e2..b97b678823a975 100644 +--- a/drivers/crypto/intel/qat/qat_common/qat_algs_send.c ++++ b/drivers/crypto/intel/qat/qat_common/qat_algs_send.c +@@ -40,40 +40,44 @@ void qat_alg_send_backlog(struct qat_instance_backlog *backlog) + spin_unlock_bh(&backlog->lock); + } + +-static void qat_alg_backlog_req(struct qat_alg_req *req, +- struct qat_instance_backlog *backlog) +-{ +- INIT_LIST_HEAD(&req->list); +- +- spin_lock_bh(&backlog->lock); +- list_add_tail(&req->list, &backlog->list); +- spin_unlock_bh(&backlog->lock); +-} +- +-static int qat_alg_send_message_maybacklog(struct qat_alg_req *req) ++static bool qat_alg_try_enqueue(struct qat_alg_req *req) + { + struct qat_instance_backlog *backlog = req->backlog; + struct adf_etr_ring_data *tx_ring = req->tx_ring; + u32 *fw_req = req->fw_req; + +- /* If any request is already backlogged, then add to backlog list */ ++ /* Check if any request is already backlogged */ + if (!list_empty(&backlog->list)) +- goto enqueue; ++ return false; + +- /* If ring is nearly full, then add to backlog list */ ++ /* Check if ring is nearly full */ + if (adf_ring_nearly_full(tx_ring)) +- goto enqueue; ++ return false; + +- /* If adding request to HW ring fails, then add to backlog list */ ++ /* Try to enqueue to HW ring */ + if (adf_send_message(tx_ring, fw_req)) +- goto enqueue; ++ return false; + +- return -EINPROGRESS; ++ return true; ++} + +-enqueue: +- qat_alg_backlog_req(req, backlog); + +- return -EBUSY; ++static int qat_alg_send_message_maybacklog(struct qat_alg_req *req) ++{ ++ struct qat_instance_backlog *backlog = req->backlog; ++ int ret = -EINPROGRESS; ++ ++ if (qat_alg_try_enqueue(req)) ++ return ret; ++ ++ spin_lock_bh(&backlog->lock); ++ if (!qat_alg_try_enqueue(req)) { ++ list_add_tail(&req->list, &backlog->list); ++ ret = -EBUSY; ++ } ++ spin_unlock_bh(&backlog->lock); ++ ++ return ret; + } + + int qat_alg_send_message(struct qat_alg_req *req) +diff --git a/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c +index 09551f94912653..0e40897cc983a8 100644 +--- a/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c +@@ -191,8 +191,12 @@ static u32 disable_pending_vf2pf_interrupts(void __iomem *pmisc_addr) + ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, errmsk3); + ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK5, errmsk5); + +- errmsk3 &= ADF_DH895XCC_ERR_MSK_VF2PF_L(sources | disabled); +- errmsk5 &= ADF_DH895XCC_ERR_MSK_VF2PF_U(sources | disabled); ++ /* Update only section of errmsk3 and errmsk5 related to VF2PF */ ++ errmsk3 &= ~ADF_DH895XCC_ERR_MSK_VF2PF_L(ADF_DH895XCC_VF_MSK); ++ errmsk5 &= ~ADF_DH895XCC_ERR_MSK_VF2PF_U(ADF_DH895XCC_VF_MSK); ++ ++ errmsk3 |= ADF_DH895XCC_ERR_MSK_VF2PF_L(sources | disabled); ++ errmsk5 |= ADF_DH895XCC_ERR_MSK_VF2PF_U(sources | disabled); + ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, errmsk3); + ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK5, errmsk5); + +diff --git a/drivers/crypto/marvell/Kconfig b/drivers/crypto/marvell/Kconfig +index a48591af12d025..78217577aa5403 100644 +--- a/drivers/crypto/marvell/Kconfig ++++ b/drivers/crypto/marvell/Kconfig +@@ -28,6 +28,7 @@ config CRYPTO_DEV_OCTEONTX_CPT + select CRYPTO_SKCIPHER + select CRYPTO_HASH + select CRYPTO_AEAD ++ select CRYPTO_AUTHENC + select CRYPTO_DEV_MARVELL + help + This driver allows you to utilize the Marvell Cryptographic +@@ -47,6 +48,7 @@ config CRYPTO_DEV_OCTEONTX2_CPT + select CRYPTO_SKCIPHER + select CRYPTO_HASH + select CRYPTO_AEAD ++ select CRYPTO_AUTHENC + select NET_DEVLINK + help + This driver allows you to utilize the Marvell Cryptographic +diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c b/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c +index 1c2c870e887aab..f64b72398eced9 100644 +--- a/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c ++++ b/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c +@@ -17,7 +17,6 @@ + #include + #include + #include +-#include + #include + #include + #include "otx_cptvf.h" +@@ -66,6 +65,8 @@ static struct cpt_device_table ae_devices = { + .count = ATOMIC_INIT(0) + }; + ++static struct otx_cpt_sdesc *alloc_sdesc(struct crypto_shash *alg); ++ + static inline int get_se_device(struct pci_dev **pdev, int *cpu_num) + { + int count, ret = 0; +@@ -515,44 +516,61 @@ static int cpt_aead_init(struct crypto_aead *tfm, u8 cipher_type, u8 mac_type) + ctx->cipher_type = cipher_type; + ctx->mac_type = mac_type; + ++ switch (ctx->mac_type) { ++ case OTX_CPT_SHA1: ++ ctx->hashalg = crypto_alloc_shash("sha1", 0, 0); ++ break; ++ ++ case OTX_CPT_SHA256: ++ ctx->hashalg = crypto_alloc_shash("sha256", 0, 0); ++ break; ++ ++ case OTX_CPT_SHA384: ++ ctx->hashalg = crypto_alloc_shash("sha384", 0, 0); ++ break; ++ ++ case OTX_CPT_SHA512: ++ ctx->hashalg = crypto_alloc_shash("sha512", 0, 0); ++ break; ++ } ++ ++ if (IS_ERR(ctx->hashalg)) ++ return PTR_ERR(ctx->hashalg); ++ ++ crypto_aead_set_reqsize_dma(tfm, sizeof(struct otx_cpt_req_ctx)); ++ ++ if (!ctx->hashalg) ++ return 0; ++ + /* + * When selected cipher is NULL we use HMAC opcode instead of + * FLEXICRYPTO opcode therefore we don't need to use HASH algorithms + * for calculating ipad and opad + */ + if (ctx->cipher_type != OTX_CPT_CIPHER_NULL) { +- switch (ctx->mac_type) { +- case OTX_CPT_SHA1: +- ctx->hashalg = crypto_alloc_shash("sha1", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; +- +- case OTX_CPT_SHA256: +- ctx->hashalg = crypto_alloc_shash("sha256", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; ++ int ss = crypto_shash_statesize(ctx->hashalg); + +- case OTX_CPT_SHA384: +- ctx->hashalg = crypto_alloc_shash("sha384", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; ++ ctx->ipad = kzalloc(ss, GFP_KERNEL); ++ if (!ctx->ipad) { ++ crypto_free_shash(ctx->hashalg); ++ return -ENOMEM; ++ } + +- case OTX_CPT_SHA512: +- ctx->hashalg = crypto_alloc_shash("sha512", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; ++ ctx->opad = kzalloc(ss, GFP_KERNEL); ++ if (!ctx->opad) { ++ kfree(ctx->ipad); ++ crypto_free_shash(ctx->hashalg); ++ return -ENOMEM; + } + } + +- crypto_aead_set_reqsize_dma(tfm, sizeof(struct otx_cpt_req_ctx)); ++ ctx->sdesc = alloc_sdesc(ctx->hashalg); ++ if (!ctx->sdesc) { ++ kfree(ctx->opad); ++ kfree(ctx->ipad); ++ crypto_free_shash(ctx->hashalg); ++ return -ENOMEM; ++ } + + return 0; + } +@@ -608,8 +626,7 @@ static void otx_cpt_aead_exit(struct crypto_aead *tfm) + + kfree(ctx->ipad); + kfree(ctx->opad); +- if (ctx->hashalg) +- crypto_free_shash(ctx->hashalg); ++ crypto_free_shash(ctx->hashalg); + kfree(ctx->sdesc); + } + +@@ -705,7 +722,7 @@ static inline void swap_data64(void *buf, u32 len) + *dst = cpu_to_be64p(src); + } + +-static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad) ++static int swap_pad(u8 mac_type, u8 *pad) + { + struct sha512_state *sha512; + struct sha256_state *sha256; +@@ -713,22 +730,19 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad) + + switch (mac_type) { + case OTX_CPT_SHA1: +- sha1 = (struct sha1_state *) in_pad; ++ sha1 = (struct sha1_state *)pad; + swap_data32(sha1->state, SHA1_DIGEST_SIZE); +- memcpy(out_pad, &sha1->state, SHA1_DIGEST_SIZE); + break; + + case OTX_CPT_SHA256: +- sha256 = (struct sha256_state *) in_pad; ++ sha256 = (struct sha256_state *)pad; + swap_data32(sha256->state, SHA256_DIGEST_SIZE); +- memcpy(out_pad, &sha256->state, SHA256_DIGEST_SIZE); + break; + + case OTX_CPT_SHA384: + case OTX_CPT_SHA512: +- sha512 = (struct sha512_state *) in_pad; ++ sha512 = (struct sha512_state *)pad; + swap_data64(sha512->state, SHA512_DIGEST_SIZE); +- memcpy(out_pad, &sha512->state, SHA512_DIGEST_SIZE); + break; + + default: +@@ -738,55 +752,53 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad) + return 0; + } + +-static int aead_hmac_init(struct crypto_aead *cipher) ++static int aead_hmac_init(struct crypto_aead *cipher, ++ struct crypto_authenc_keys *keys) + { + struct otx_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher); +- int state_size = crypto_shash_statesize(ctx->hashalg); + int ds = crypto_shash_digestsize(ctx->hashalg); + int bs = crypto_shash_blocksize(ctx->hashalg); +- int authkeylen = ctx->auth_key_len; ++ int authkeylen = keys->authkeylen; + u8 *ipad = NULL, *opad = NULL; +- int ret = 0, icount = 0; ++ int icount = 0; ++ int ret; + +- ctx->sdesc = alloc_sdesc(ctx->hashalg); +- if (!ctx->sdesc) +- return -ENOMEM; ++ if (authkeylen > bs) { ++ ret = crypto_shash_digest(&ctx->sdesc->shash, keys->authkey, ++ authkeylen, ctx->key); ++ if (ret) ++ return ret; ++ authkeylen = ds; ++ } else ++ memcpy(ctx->key, keys->authkey, authkeylen); + +- ctx->ipad = kzalloc(bs, GFP_KERNEL); +- if (!ctx->ipad) { +- ret = -ENOMEM; +- goto calc_fail; +- } ++ ctx->enc_key_len = keys->enckeylen; ++ ctx->auth_key_len = authkeylen; + +- ctx->opad = kzalloc(bs, GFP_KERNEL); +- if (!ctx->opad) { +- ret = -ENOMEM; +- goto calc_fail; +- } ++ if (ctx->cipher_type == OTX_CPT_CIPHER_NULL) ++ return keys->enckeylen ? -EINVAL : 0; + +- ipad = kzalloc(state_size, GFP_KERNEL); +- if (!ipad) { +- ret = -ENOMEM; +- goto calc_fail; ++ switch (keys->enckeylen) { ++ case AES_KEYSIZE_128: ++ ctx->key_type = OTX_CPT_AES_128_BIT; ++ break; ++ case AES_KEYSIZE_192: ++ ctx->key_type = OTX_CPT_AES_192_BIT; ++ break; ++ case AES_KEYSIZE_256: ++ ctx->key_type = OTX_CPT_AES_256_BIT; ++ break; ++ default: ++ /* Invalid key length */ ++ return -EINVAL; + } + +- opad = kzalloc(state_size, GFP_KERNEL); +- if (!opad) { +- ret = -ENOMEM; +- goto calc_fail; +- } ++ memcpy(ctx->key + authkeylen, keys->enckey, keys->enckeylen); + +- if (authkeylen > bs) { +- ret = crypto_shash_digest(&ctx->sdesc->shash, ctx->key, +- authkeylen, ipad); +- if (ret) +- goto calc_fail; +- +- authkeylen = ds; +- } else { +- memcpy(ipad, ctx->key, authkeylen); +- } ++ ipad = ctx->ipad; ++ opad = ctx->opad; + ++ memcpy(ipad, ctx->key, authkeylen); + memset(ipad + authkeylen, 0, bs - authkeylen); + memcpy(opad, ipad, bs); + +@@ -804,7 +816,7 @@ static int aead_hmac_init(struct crypto_aead *cipher) + crypto_shash_init(&ctx->sdesc->shash); + crypto_shash_update(&ctx->sdesc->shash, ipad, bs); + crypto_shash_export(&ctx->sdesc->shash, ipad); +- ret = copy_pad(ctx->mac_type, ctx->ipad, ipad); ++ ret = swap_pad(ctx->mac_type, ipad); + if (ret) + goto calc_fail; + +@@ -812,25 +824,9 @@ static int aead_hmac_init(struct crypto_aead *cipher) + crypto_shash_init(&ctx->sdesc->shash); + crypto_shash_update(&ctx->sdesc->shash, opad, bs); + crypto_shash_export(&ctx->sdesc->shash, opad); +- ret = copy_pad(ctx->mac_type, ctx->opad, opad); +- if (ret) +- goto calc_fail; +- +- kfree(ipad); +- kfree(opad); +- +- return 0; ++ ret = swap_pad(ctx->mac_type, opad); + + calc_fail: +- kfree(ctx->ipad); +- ctx->ipad = NULL; +- kfree(ctx->opad); +- ctx->opad = NULL; +- kfree(ipad); +- kfree(opad); +- kfree(ctx->sdesc); +- ctx->sdesc = NULL; +- + return ret; + } + +@@ -838,57 +834,15 @@ static int otx_cpt_aead_cbc_aes_sha_setkey(struct crypto_aead *cipher, + const unsigned char *key, + unsigned int keylen) + { +- struct otx_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher); +- struct crypto_authenc_key_param *param; +- int enckeylen = 0, authkeylen = 0; +- struct rtattr *rta = (void *)key; +- int status = -EINVAL; +- +- if (!RTA_OK(rta, keylen)) +- goto badkey; +- +- if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) +- goto badkey; +- +- if (RTA_PAYLOAD(rta) < sizeof(*param)) +- goto badkey; +- +- param = RTA_DATA(rta); +- enckeylen = be32_to_cpu(param->enckeylen); +- key += RTA_ALIGN(rta->rta_len); +- keylen -= RTA_ALIGN(rta->rta_len); +- if (keylen < enckeylen) +- goto badkey; ++ struct crypto_authenc_keys authenc_keys; ++ int status; + +- if (keylen > OTX_CPT_MAX_KEY_SIZE) +- goto badkey; +- +- authkeylen = keylen - enckeylen; +- memcpy(ctx->key, key, keylen); +- +- switch (enckeylen) { +- case AES_KEYSIZE_128: +- ctx->key_type = OTX_CPT_AES_128_BIT; +- break; +- case AES_KEYSIZE_192: +- ctx->key_type = OTX_CPT_AES_192_BIT; +- break; +- case AES_KEYSIZE_256: +- ctx->key_type = OTX_CPT_AES_256_BIT; +- break; +- default: +- /* Invalid key length */ +- goto badkey; +- } +- +- ctx->enc_key_len = enckeylen; +- ctx->auth_key_len = authkeylen; +- +- status = aead_hmac_init(cipher); ++ status = crypto_authenc_extractkeys(&authenc_keys, key, keylen); + if (status) + goto badkey; + +- return 0; ++ status = aead_hmac_init(cipher, &authenc_keys); ++ + badkey: + return status; + } +@@ -897,36 +851,7 @@ static int otx_cpt_aead_ecb_null_sha_setkey(struct crypto_aead *cipher, + const unsigned char *key, + unsigned int keylen) + { +- struct otx_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher); +- struct crypto_authenc_key_param *param; +- struct rtattr *rta = (void *)key; +- int enckeylen = 0; +- +- if (!RTA_OK(rta, keylen)) +- goto badkey; +- +- if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) +- goto badkey; +- +- if (RTA_PAYLOAD(rta) < sizeof(*param)) +- goto badkey; +- +- param = RTA_DATA(rta); +- enckeylen = be32_to_cpu(param->enckeylen); +- key += RTA_ALIGN(rta->rta_len); +- keylen -= RTA_ALIGN(rta->rta_len); +- if (enckeylen != 0) +- goto badkey; +- +- if (keylen > OTX_CPT_MAX_KEY_SIZE) +- goto badkey; +- +- memcpy(ctx->key, key, keylen); +- ctx->enc_key_len = enckeylen; +- ctx->auth_key_len = keylen; +- return 0; +-badkey: +- return -EINVAL; ++ return otx_cpt_aead_cbc_aes_sha_setkey(cipher, key, keylen); + } + + static int otx_cpt_aead_gcm_aes_setkey(struct crypto_aead *cipher, +diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptlf.c b/drivers/crypto/marvell/octeontx2/otx2_cptlf.c +index 6edd27ff8c4e3c..e4bd3f030ceca7 100644 +--- a/drivers/crypto/marvell/octeontx2/otx2_cptlf.c ++++ b/drivers/crypto/marvell/octeontx2/otx2_cptlf.c +@@ -419,8 +419,8 @@ int otx2_cptlf_init(struct otx2_cptlfs_info *lfs, u8 eng_grp_mask, int pri, + return 0; + + free_iq: +- otx2_cpt_free_instruction_queues(lfs); + cptlf_hw_cleanup(lfs); ++ otx2_cpt_free_instruction_queues(lfs); + detach_rsrcs: + otx2_cpt_detach_rsrcs_msg(lfs); + clear_lfs_num: +@@ -431,11 +431,13 @@ EXPORT_SYMBOL_NS_GPL(otx2_cptlf_init, CRYPTO_DEV_OCTEONTX2_CPT); + + void otx2_cptlf_shutdown(struct otx2_cptlfs_info *lfs) + { +- lfs->lfs_num = 0; + /* Cleanup LFs hardware side */ + cptlf_hw_cleanup(lfs); ++ /* Free instruction queues */ ++ otx2_cpt_free_instruction_queues(lfs); + /* Send request to detach LFs */ + otx2_cpt_detach_rsrcs_msg(lfs); ++ lfs->lfs_num = 0; + } + EXPORT_SYMBOL_NS_GPL(otx2_cptlf_shutdown, CRYPTO_DEV_OCTEONTX2_CPT); + +diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c +index e27ddd3c4e5581..4385d3df52b4d4 100644 +--- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c ++++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c +@@ -11,7 +11,6 @@ + #include + #include + #include +-#include + #include + #include + #include "otx2_cptvf.h" +@@ -54,6 +53,8 @@ static struct cpt_device_table se_devices = { + .count = ATOMIC_INIT(0) + }; + ++static struct otx2_cpt_sdesc *alloc_sdesc(struct crypto_shash *alg); ++ + static inline int get_se_device(struct pci_dev **pdev, int *cpu_num) + { + int count; +@@ -580,40 +581,56 @@ static int cpt_aead_init(struct crypto_aead *atfm, u8 cipher_type, u8 mac_type) + ctx->cipher_type = cipher_type; + ctx->mac_type = mac_type; + ++ switch (ctx->mac_type) { ++ case OTX2_CPT_SHA1: ++ ctx->hashalg = crypto_alloc_shash("sha1", 0, 0); ++ break; ++ ++ case OTX2_CPT_SHA256: ++ ctx->hashalg = crypto_alloc_shash("sha256", 0, 0); ++ break; ++ ++ case OTX2_CPT_SHA384: ++ ctx->hashalg = crypto_alloc_shash("sha384", 0, 0); ++ break; ++ ++ case OTX2_CPT_SHA512: ++ ctx->hashalg = crypto_alloc_shash("sha512", 0, 0); ++ break; ++ } ++ ++ if (IS_ERR(ctx->hashalg)) ++ return PTR_ERR(ctx->hashalg); ++ ++ if (ctx->hashalg) { ++ ctx->sdesc = alloc_sdesc(ctx->hashalg); ++ if (!ctx->sdesc) { ++ crypto_free_shash(ctx->hashalg); ++ return -ENOMEM; ++ } ++ } ++ + /* + * When selected cipher is NULL we use HMAC opcode instead of + * FLEXICRYPTO opcode therefore we don't need to use HASH algorithms + * for calculating ipad and opad + */ +- if (ctx->cipher_type != OTX2_CPT_CIPHER_NULL) { +- switch (ctx->mac_type) { +- case OTX2_CPT_SHA1: +- ctx->hashalg = crypto_alloc_shash("sha1", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; +- +- case OTX2_CPT_SHA256: +- ctx->hashalg = crypto_alloc_shash("sha256", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; ++ if (ctx->cipher_type != OTX2_CPT_CIPHER_NULL && ctx->hashalg) { ++ int ss = crypto_shash_statesize(ctx->hashalg); + +- case OTX2_CPT_SHA384: +- ctx->hashalg = crypto_alloc_shash("sha384", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; ++ ctx->ipad = kzalloc(ss, GFP_KERNEL); ++ if (!ctx->ipad) { ++ kfree(ctx->sdesc); ++ crypto_free_shash(ctx->hashalg); ++ return -ENOMEM; ++ } + +- case OTX2_CPT_SHA512: +- ctx->hashalg = crypto_alloc_shash("sha512", 0, +- CRYPTO_ALG_ASYNC); +- if (IS_ERR(ctx->hashalg)) +- return PTR_ERR(ctx->hashalg); +- break; ++ ctx->opad = kzalloc(ss, GFP_KERNEL); ++ if (!ctx->opad) { ++ kfree(ctx->ipad); ++ kfree(ctx->sdesc); ++ crypto_free_shash(ctx->hashalg); ++ return -ENOMEM; + } + } + switch (ctx->cipher_type) { +@@ -686,8 +703,7 @@ static void otx2_cpt_aead_exit(struct crypto_aead *tfm) + + kfree(ctx->ipad); + kfree(ctx->opad); +- if (ctx->hashalg) +- crypto_free_shash(ctx->hashalg); ++ crypto_free_shash(ctx->hashalg); + kfree(ctx->sdesc); + + if (ctx->fbk_cipher) { +@@ -760,7 +776,7 @@ static inline void swap_data64(void *buf, u32 len) + cpu_to_be64s(src); + } + +-static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad) ++static int swap_pad(u8 mac_type, u8 *pad) + { + struct sha512_state *sha512; + struct sha256_state *sha256; +@@ -768,22 +784,19 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad) + + switch (mac_type) { + case OTX2_CPT_SHA1: +- sha1 = (struct sha1_state *) in_pad; ++ sha1 = (struct sha1_state *)pad; + swap_data32(sha1->state, SHA1_DIGEST_SIZE); +- memcpy(out_pad, &sha1->state, SHA1_DIGEST_SIZE); + break; + + case OTX2_CPT_SHA256: +- sha256 = (struct sha256_state *) in_pad; ++ sha256 = (struct sha256_state *)pad; + swap_data32(sha256->state, SHA256_DIGEST_SIZE); +- memcpy(out_pad, &sha256->state, SHA256_DIGEST_SIZE); + break; + + case OTX2_CPT_SHA384: + case OTX2_CPT_SHA512: +- sha512 = (struct sha512_state *) in_pad; ++ sha512 = (struct sha512_state *)pad; + swap_data64(sha512->state, SHA512_DIGEST_SIZE); +- memcpy(out_pad, &sha512->state, SHA512_DIGEST_SIZE); + break; + + default: +@@ -793,55 +806,54 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad) + return 0; + } + +-static int aead_hmac_init(struct crypto_aead *cipher) ++static int aead_hmac_init(struct crypto_aead *cipher, ++ struct crypto_authenc_keys *keys) + { + struct otx2_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher); +- int state_size = crypto_shash_statesize(ctx->hashalg); + int ds = crypto_shash_digestsize(ctx->hashalg); + int bs = crypto_shash_blocksize(ctx->hashalg); +- int authkeylen = ctx->auth_key_len; ++ int authkeylen = keys->authkeylen; + u8 *ipad = NULL, *opad = NULL; +- int ret = 0, icount = 0; ++ int icount = 0; ++ int ret; + +- ctx->sdesc = alloc_sdesc(ctx->hashalg); +- if (!ctx->sdesc) +- return -ENOMEM; ++ if (authkeylen > bs) { ++ ret = crypto_shash_digest(&ctx->sdesc->shash, keys->authkey, ++ authkeylen, ctx->key); ++ if (ret) ++ goto calc_fail; + +- ctx->ipad = kzalloc(bs, GFP_KERNEL); +- if (!ctx->ipad) { +- ret = -ENOMEM; +- goto calc_fail; +- } ++ authkeylen = ds; ++ } else ++ memcpy(ctx->key, keys->authkey, authkeylen); + +- ctx->opad = kzalloc(bs, GFP_KERNEL); +- if (!ctx->opad) { +- ret = -ENOMEM; +- goto calc_fail; +- } ++ ctx->enc_key_len = keys->enckeylen; ++ ctx->auth_key_len = authkeylen; + +- ipad = kzalloc(state_size, GFP_KERNEL); +- if (!ipad) { +- ret = -ENOMEM; +- goto calc_fail; +- } ++ if (ctx->cipher_type == OTX2_CPT_CIPHER_NULL) ++ return keys->enckeylen ? -EINVAL : 0; + +- opad = kzalloc(state_size, GFP_KERNEL); +- if (!opad) { +- ret = -ENOMEM; +- goto calc_fail; ++ switch (keys->enckeylen) { ++ case AES_KEYSIZE_128: ++ ctx->key_type = OTX2_CPT_AES_128_BIT; ++ break; ++ case AES_KEYSIZE_192: ++ ctx->key_type = OTX2_CPT_AES_192_BIT; ++ break; ++ case AES_KEYSIZE_256: ++ ctx->key_type = OTX2_CPT_AES_256_BIT; ++ break; ++ default: ++ /* Invalid key length */ ++ return -EINVAL; + } + +- if (authkeylen > bs) { +- ret = crypto_shash_digest(&ctx->sdesc->shash, ctx->key, +- authkeylen, ipad); +- if (ret) +- goto calc_fail; ++ memcpy(ctx->key + authkeylen, keys->enckey, keys->enckeylen); + +- authkeylen = ds; +- } else { +- memcpy(ipad, ctx->key, authkeylen); +- } ++ ipad = ctx->ipad; ++ opad = ctx->opad; + ++ memcpy(ipad, ctx->key, authkeylen); + memset(ipad + authkeylen, 0, bs - authkeylen); + memcpy(opad, ipad, bs); + +@@ -859,7 +871,7 @@ static int aead_hmac_init(struct crypto_aead *cipher) + crypto_shash_init(&ctx->sdesc->shash); + crypto_shash_update(&ctx->sdesc->shash, ipad, bs); + crypto_shash_export(&ctx->sdesc->shash, ipad); +- ret = copy_pad(ctx->mac_type, ctx->ipad, ipad); ++ ret = swap_pad(ctx->mac_type, ipad); + if (ret) + goto calc_fail; + +@@ -867,25 +879,9 @@ static int aead_hmac_init(struct crypto_aead *cipher) + crypto_shash_init(&ctx->sdesc->shash); + crypto_shash_update(&ctx->sdesc->shash, opad, bs); + crypto_shash_export(&ctx->sdesc->shash, opad); +- ret = copy_pad(ctx->mac_type, ctx->opad, opad); +- if (ret) +- goto calc_fail; +- +- kfree(ipad); +- kfree(opad); +- +- return 0; ++ ret = swap_pad(ctx->mac_type, opad); + + calc_fail: +- kfree(ctx->ipad); +- ctx->ipad = NULL; +- kfree(ctx->opad); +- ctx->opad = NULL; +- kfree(ipad); +- kfree(opad); +- kfree(ctx->sdesc); +- ctx->sdesc = NULL; +- + return ret; + } + +@@ -893,87 +889,17 @@ static int otx2_cpt_aead_cbc_aes_sha_setkey(struct crypto_aead *cipher, + const unsigned char *key, + unsigned int keylen) + { +- struct otx2_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher); +- struct crypto_authenc_key_param *param; +- int enckeylen = 0, authkeylen = 0; +- struct rtattr *rta = (void *)key; +- +- if (!RTA_OK(rta, keylen)) +- return -EINVAL; ++ struct crypto_authenc_keys authenc_keys; + +- if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) +- return -EINVAL; +- +- if (RTA_PAYLOAD(rta) < sizeof(*param)) +- return -EINVAL; +- +- param = RTA_DATA(rta); +- enckeylen = be32_to_cpu(param->enckeylen); +- key += RTA_ALIGN(rta->rta_len); +- keylen -= RTA_ALIGN(rta->rta_len); +- if (keylen < enckeylen) +- return -EINVAL; +- +- if (keylen > OTX2_CPT_MAX_KEY_SIZE) +- return -EINVAL; +- +- authkeylen = keylen - enckeylen; +- memcpy(ctx->key, key, keylen); +- +- switch (enckeylen) { +- case AES_KEYSIZE_128: +- ctx->key_type = OTX2_CPT_AES_128_BIT; +- break; +- case AES_KEYSIZE_192: +- ctx->key_type = OTX2_CPT_AES_192_BIT; +- break; +- case AES_KEYSIZE_256: +- ctx->key_type = OTX2_CPT_AES_256_BIT; +- break; +- default: +- /* Invalid key length */ +- return -EINVAL; +- } +- +- ctx->enc_key_len = enckeylen; +- ctx->auth_key_len = authkeylen; +- +- return aead_hmac_init(cipher); ++ return crypto_authenc_extractkeys(&authenc_keys, key, keylen) ?: ++ aead_hmac_init(cipher, &authenc_keys); + } + + static int otx2_cpt_aead_ecb_null_sha_setkey(struct crypto_aead *cipher, + const unsigned char *key, + unsigned int keylen) + { +- struct otx2_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher); +- struct crypto_authenc_key_param *param; +- struct rtattr *rta = (void *)key; +- int enckeylen = 0; +- +- if (!RTA_OK(rta, keylen)) +- return -EINVAL; +- +- if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) +- return -EINVAL; +- +- if (RTA_PAYLOAD(rta) < sizeof(*param)) +- return -EINVAL; +- +- param = RTA_DATA(rta); +- enckeylen = be32_to_cpu(param->enckeylen); +- key += RTA_ALIGN(rta->rta_len); +- keylen -= RTA_ALIGN(rta->rta_len); +- if (enckeylen != 0) +- return -EINVAL; +- +- if (keylen > OTX2_CPT_MAX_KEY_SIZE) +- return -EINVAL; +- +- memcpy(ctx->key, key, keylen); +- ctx->enc_key_len = enckeylen; +- ctx->auth_key_len = keylen; +- +- return 0; ++ return otx2_cpt_aead_cbc_aes_sha_setkey(cipher, key, keylen); + } + + static int otx2_cpt_aead_gcm_aes_setkey(struct crypto_aead *cipher, +diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c +index bac729c885f960..215a1b17b6ce0a 100644 +--- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c ++++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c +@@ -249,8 +249,11 @@ static void cptvf_lf_shutdown(struct otx2_cptlfs_info *lfs) + otx2_cptlf_unregister_interrupts(lfs); + /* Cleanup LFs software side */ + lf_sw_cleanup(lfs); ++ /* Free instruction queues */ ++ otx2_cpt_free_instruction_queues(lfs); + /* Send request to detach LFs */ + otx2_cpt_detach_rsrcs_msg(lfs); ++ lfs->lfs_num = 0; + } + + static int cptvf_lf_init(struct otx2_cptvf_dev *cptvf) +diff --git a/drivers/crypto/rockchip/rk3288_crypto_ahash.c b/drivers/crypto/rockchip/rk3288_crypto_ahash.c +index 8c143180645e5b..29c9537216fa6d 100644 +--- a/drivers/crypto/rockchip/rk3288_crypto_ahash.c ++++ b/drivers/crypto/rockchip/rk3288_crypto_ahash.c +@@ -332,12 +332,12 @@ static int rk_hash_run(struct crypto_engine *engine, void *breq) + theend: + pm_runtime_put_autosuspend(rkc->dev); + ++ rk_hash_unprepare(engine, breq); ++ + local_bh_disable(); + crypto_finalize_hash_request(engine, breq, err); + local_bh_enable(); + +- rk_hash_unprepare(engine, breq); +- + return 0; + } + +diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c +index 6238d34f8db2f6..94eb6f6afa2572 100644 +--- a/drivers/crypto/sa2ul.c ++++ b/drivers/crypto/sa2ul.c +@@ -1869,9 +1869,8 @@ static int sa_aead_setkey(struct crypto_aead *authenc, + crypto_aead_set_flags(ctx->fallback.aead, + crypto_aead_get_flags(authenc) & + CRYPTO_TFM_REQ_MASK); +- crypto_aead_setkey(ctx->fallback.aead, key, keylen); + +- return 0; ++ return crypto_aead_setkey(ctx->fallback.aead, key, keylen); + } + + static int sa_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) +diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c +index 62d93526920f80..8e84dd98a273da 100644 +--- a/drivers/crypto/sahara.c ++++ b/drivers/crypto/sahara.c +@@ -43,7 +43,6 @@ + #define FLAGS_MODE_MASK 0x000f + #define FLAGS_ENCRYPT BIT(0) + #define FLAGS_CBC BIT(1) +-#define FLAGS_NEW_KEY BIT(3) + + #define SAHARA_HDR_BASE 0x00800000 + #define SAHARA_HDR_SKHA_ALG_AES 0 +@@ -141,8 +140,6 @@ struct sahara_hw_link { + }; + + struct sahara_ctx { +- unsigned long flags; +- + /* AES-specific context */ + int keylen; + u8 key[AES_KEYSIZE_128]; +@@ -151,6 +148,7 @@ struct sahara_ctx { + + struct sahara_aes_reqctx { + unsigned long mode; ++ u8 iv_out[AES_BLOCK_SIZE]; + struct skcipher_request fallback_req; // keep at the end + }; + +@@ -446,27 +444,24 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) + int ret; + int i, j; + int idx = 0; ++ u32 len; + +- /* Copy new key if necessary */ +- if (ctx->flags & FLAGS_NEW_KEY) { +- memcpy(dev->key_base, ctx->key, ctx->keylen); +- ctx->flags &= ~FLAGS_NEW_KEY; ++ memcpy(dev->key_base, ctx->key, ctx->keylen); + +- if (dev->flags & FLAGS_CBC) { +- dev->hw_desc[idx]->len1 = AES_BLOCK_SIZE; +- dev->hw_desc[idx]->p1 = dev->iv_phys_base; +- } else { +- dev->hw_desc[idx]->len1 = 0; +- dev->hw_desc[idx]->p1 = 0; +- } +- dev->hw_desc[idx]->len2 = ctx->keylen; +- dev->hw_desc[idx]->p2 = dev->key_phys_base; +- dev->hw_desc[idx]->next = dev->hw_phys_desc[1]; ++ if (dev->flags & FLAGS_CBC) { ++ dev->hw_desc[idx]->len1 = AES_BLOCK_SIZE; ++ dev->hw_desc[idx]->p1 = dev->iv_phys_base; ++ } else { ++ dev->hw_desc[idx]->len1 = 0; ++ dev->hw_desc[idx]->p1 = 0; ++ } ++ dev->hw_desc[idx]->len2 = ctx->keylen; ++ dev->hw_desc[idx]->p2 = dev->key_phys_base; ++ dev->hw_desc[idx]->next = dev->hw_phys_desc[1]; ++ dev->hw_desc[idx]->hdr = sahara_aes_key_hdr(dev); + +- dev->hw_desc[idx]->hdr = sahara_aes_key_hdr(dev); ++ idx++; + +- idx++; +- } + + dev->nb_in_sg = sg_nents_for_len(dev->in_sg, dev->total); + if (dev->nb_in_sg < 0) { +@@ -488,24 +483,27 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) + DMA_TO_DEVICE); + if (!ret) { + dev_err(dev->device, "couldn't map in sg\n"); +- goto unmap_in; ++ return -EINVAL; + } ++ + ret = dma_map_sg(dev->device, dev->out_sg, dev->nb_out_sg, + DMA_FROM_DEVICE); + if (!ret) { + dev_err(dev->device, "couldn't map out sg\n"); +- goto unmap_out; ++ goto unmap_in; + } + + /* Create input links */ + dev->hw_desc[idx]->p1 = dev->hw_phys_link[0]; + sg = dev->in_sg; ++ len = dev->total; + for (i = 0; i < dev->nb_in_sg; i++) { +- dev->hw_link[i]->len = sg->length; ++ dev->hw_link[i]->len = min(len, sg->length); + dev->hw_link[i]->p = sg->dma_address; + if (i == (dev->nb_in_sg - 1)) { + dev->hw_link[i]->next = 0; + } else { ++ len -= min(len, sg->length); + dev->hw_link[i]->next = dev->hw_phys_link[i + 1]; + sg = sg_next(sg); + } +@@ -514,12 +512,14 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) + /* Create output links */ + dev->hw_desc[idx]->p2 = dev->hw_phys_link[i]; + sg = dev->out_sg; ++ len = dev->total; + for (j = i; j < dev->nb_out_sg + i; j++) { +- dev->hw_link[j]->len = sg->length; ++ dev->hw_link[j]->len = min(len, sg->length); + dev->hw_link[j]->p = sg->dma_address; + if (j == (dev->nb_out_sg + i - 1)) { + dev->hw_link[j]->next = 0; + } else { ++ len -= min(len, sg->length); + dev->hw_link[j]->next = dev->hw_phys_link[j + 1]; + sg = sg_next(sg); + } +@@ -538,9 +538,6 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) + + return 0; + +-unmap_out: +- dma_unmap_sg(dev->device, dev->out_sg, dev->nb_out_sg, +- DMA_FROM_DEVICE); + unmap_in: + dma_unmap_sg(dev->device, dev->in_sg, dev->nb_in_sg, + DMA_TO_DEVICE); +@@ -548,8 +545,24 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) + return -EINVAL; + } + ++static void sahara_aes_cbc_update_iv(struct skcipher_request *req) ++{ ++ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); ++ struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); ++ unsigned int ivsize = crypto_skcipher_ivsize(skcipher); ++ ++ /* Update IV buffer to contain the last ciphertext block */ ++ if (rctx->mode & FLAGS_ENCRYPT) { ++ sg_pcopy_to_buffer(req->dst, sg_nents(req->dst), req->iv, ++ ivsize, req->cryptlen - ivsize); ++ } else { ++ memcpy(req->iv, rctx->iv_out, ivsize); ++ } ++} ++ + static int sahara_aes_process(struct skcipher_request *req) + { ++ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct sahara_dev *dev = dev_ptr; + struct sahara_ctx *ctx; + struct sahara_aes_reqctx *rctx; +@@ -571,8 +584,17 @@ static int sahara_aes_process(struct skcipher_request *req) + rctx->mode &= FLAGS_MODE_MASK; + dev->flags = (dev->flags & ~FLAGS_MODE_MASK) | rctx->mode; + +- if ((dev->flags & FLAGS_CBC) && req->iv) +- memcpy(dev->iv_base, req->iv, AES_KEYSIZE_128); ++ if ((dev->flags & FLAGS_CBC) && req->iv) { ++ unsigned int ivsize = crypto_skcipher_ivsize(skcipher); ++ ++ memcpy(dev->iv_base, req->iv, ivsize); ++ ++ if (!(dev->flags & FLAGS_ENCRYPT)) { ++ sg_pcopy_to_buffer(req->src, sg_nents(req->src), ++ rctx->iv_out, ivsize, ++ req->cryptlen - ivsize); ++ } ++ } + + /* assign new context to device */ + dev->ctx = ctx; +@@ -585,16 +607,20 @@ static int sahara_aes_process(struct skcipher_request *req) + + timeout = wait_for_completion_timeout(&dev->dma_completion, + msecs_to_jiffies(SAHARA_TIMEOUT_MS)); +- if (!timeout) { +- dev_err(dev->device, "AES timeout\n"); +- return -ETIMEDOUT; +- } + + dma_unmap_sg(dev->device, dev->out_sg, dev->nb_out_sg, + DMA_FROM_DEVICE); + dma_unmap_sg(dev->device, dev->in_sg, dev->nb_in_sg, + DMA_TO_DEVICE); + ++ if (!timeout) { ++ dev_err(dev->device, "AES timeout\n"); ++ return -ETIMEDOUT; ++ } ++ ++ if ((dev->flags & FLAGS_CBC) && req->iv) ++ sahara_aes_cbc_update_iv(req); ++ + return 0; + } + +@@ -608,7 +634,6 @@ static int sahara_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, + /* SAHARA only supports 128bit keys */ + if (keylen == AES_KEYSIZE_128) { + memcpy(ctx->key, key, keylen); +- ctx->flags |= FLAGS_NEW_KEY; + return 0; + } + +@@ -624,12 +649,40 @@ static int sahara_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, + return crypto_skcipher_setkey(ctx->fallback, key, keylen); + } + ++static int sahara_aes_fallback(struct skcipher_request *req, unsigned long mode) ++{ ++ struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); ++ struct sahara_ctx *ctx = crypto_skcipher_ctx( ++ crypto_skcipher_reqtfm(req)); ++ ++ skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); ++ skcipher_request_set_callback(&rctx->fallback_req, ++ req->base.flags, ++ req->base.complete, ++ req->base.data); ++ skcipher_request_set_crypt(&rctx->fallback_req, req->src, ++ req->dst, req->cryptlen, req->iv); ++ ++ if (mode & FLAGS_ENCRYPT) ++ return crypto_skcipher_encrypt(&rctx->fallback_req); ++ ++ return crypto_skcipher_decrypt(&rctx->fallback_req); ++} ++ + static int sahara_aes_crypt(struct skcipher_request *req, unsigned long mode) + { + struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); ++ struct sahara_ctx *ctx = crypto_skcipher_ctx( ++ crypto_skcipher_reqtfm(req)); + struct sahara_dev *dev = dev_ptr; + int err = 0; + ++ if (!req->cryptlen) ++ return 0; ++ ++ if (unlikely(ctx->keylen != AES_KEYSIZE_128)) ++ return sahara_aes_fallback(req, mode); ++ + dev_dbg(dev->device, "nbytes: %d, enc: %d, cbc: %d\n", + req->cryptlen, !!(mode & FLAGS_ENCRYPT), !!(mode & FLAGS_CBC)); + +@@ -652,81 +705,21 @@ static int sahara_aes_crypt(struct skcipher_request *req, unsigned long mode) + + static int sahara_aes_ecb_encrypt(struct skcipher_request *req) + { +- struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); +- struct sahara_ctx *ctx = crypto_skcipher_ctx( +- crypto_skcipher_reqtfm(req)); +- +- if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { +- skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); +- skcipher_request_set_callback(&rctx->fallback_req, +- req->base.flags, +- req->base.complete, +- req->base.data); +- skcipher_request_set_crypt(&rctx->fallback_req, req->src, +- req->dst, req->cryptlen, req->iv); +- return crypto_skcipher_encrypt(&rctx->fallback_req); +- } +- + return sahara_aes_crypt(req, FLAGS_ENCRYPT); + } + + static int sahara_aes_ecb_decrypt(struct skcipher_request *req) + { +- struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); +- struct sahara_ctx *ctx = crypto_skcipher_ctx( +- crypto_skcipher_reqtfm(req)); +- +- if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { +- skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); +- skcipher_request_set_callback(&rctx->fallback_req, +- req->base.flags, +- req->base.complete, +- req->base.data); +- skcipher_request_set_crypt(&rctx->fallback_req, req->src, +- req->dst, req->cryptlen, req->iv); +- return crypto_skcipher_decrypt(&rctx->fallback_req); +- } +- + return sahara_aes_crypt(req, 0); + } + + static int sahara_aes_cbc_encrypt(struct skcipher_request *req) + { +- struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); +- struct sahara_ctx *ctx = crypto_skcipher_ctx( +- crypto_skcipher_reqtfm(req)); +- +- if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { +- skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); +- skcipher_request_set_callback(&rctx->fallback_req, +- req->base.flags, +- req->base.complete, +- req->base.data); +- skcipher_request_set_crypt(&rctx->fallback_req, req->src, +- req->dst, req->cryptlen, req->iv); +- return crypto_skcipher_encrypt(&rctx->fallback_req); +- } +- + return sahara_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC); + } + + static int sahara_aes_cbc_decrypt(struct skcipher_request *req) + { +- struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); +- struct sahara_ctx *ctx = crypto_skcipher_ctx( +- crypto_skcipher_reqtfm(req)); +- +- if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { +- skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); +- skcipher_request_set_callback(&rctx->fallback_req, +- req->base.flags, +- req->base.complete, +- req->base.data); +- skcipher_request_set_crypt(&rctx->fallback_req, req->src, +- req->dst, req->cryptlen, req->iv); +- return crypto_skcipher_decrypt(&rctx->fallback_req); +- } +- + return sahara_aes_crypt(req, FLAGS_CBC); + } + +@@ -783,6 +776,7 @@ static int sahara_sha_hw_links_create(struct sahara_dev *dev, + int start) + { + struct scatterlist *sg; ++ unsigned int len; + unsigned int i; + int ret; + +@@ -804,12 +798,14 @@ static int sahara_sha_hw_links_create(struct sahara_dev *dev, + if (!ret) + return -EFAULT; + ++ len = rctx->total; + for (i = start; i < dev->nb_in_sg + start; i++) { +- dev->hw_link[i]->len = sg->length; ++ dev->hw_link[i]->len = min(len, sg->length); + dev->hw_link[i]->p = sg->dma_address; + if (i == (dev->nb_in_sg + start - 1)) { + dev->hw_link[i]->next = 0; + } else { ++ len -= min(len, sg->length); + dev->hw_link[i]->next = dev->hw_phys_link[i + 1]; + sg = sg_next(sg); + } +@@ -890,24 +886,6 @@ static int sahara_sha_hw_context_descriptor_create(struct sahara_dev *dev, + return 0; + } + +-static int sahara_walk_and_recalc(struct scatterlist *sg, unsigned int nbytes) +-{ +- if (!sg || !sg->length) +- return nbytes; +- +- while (nbytes && sg) { +- if (nbytes <= sg->length) { +- sg->length = nbytes; +- sg_mark_end(sg); +- break; +- } +- nbytes -= sg->length; +- sg = sg_next(sg); +- } +- +- return nbytes; +-} +- + static int sahara_sha_prepare_request(struct ahash_request *req) + { + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); +@@ -944,36 +922,20 @@ static int sahara_sha_prepare_request(struct ahash_request *req) + hash_later, 0); + } + +- /* nbytes should now be multiple of blocksize */ +- req->nbytes = req->nbytes - hash_later; +- +- sahara_walk_and_recalc(req->src, req->nbytes); +- ++ rctx->total = len - hash_later; + /* have data from previous operation and current */ + if (rctx->buf_cnt && req->nbytes) { + sg_init_table(rctx->in_sg_chain, 2); + sg_set_buf(rctx->in_sg_chain, rctx->rembuf, rctx->buf_cnt); +- + sg_chain(rctx->in_sg_chain, 2, req->src); +- +- rctx->total = req->nbytes + rctx->buf_cnt; + rctx->in_sg = rctx->in_sg_chain; +- +- req->src = rctx->in_sg_chain; + /* only data from previous operation */ + } else if (rctx->buf_cnt) { +- if (req->src) +- rctx->in_sg = req->src; +- else +- rctx->in_sg = rctx->in_sg_chain; +- /* buf was copied into rembuf above */ ++ rctx->in_sg = rctx->in_sg_chain; + sg_init_one(rctx->in_sg, rctx->rembuf, rctx->buf_cnt); +- rctx->total = rctx->buf_cnt; + /* no data from previous operation */ + } else { + rctx->in_sg = req->src; +- rctx->total = req->nbytes; +- req->src = rctx->in_sg; + } + + /* on next call, we only have the remaining data in the buffer */ +@@ -994,7 +956,10 @@ static int sahara_sha_process(struct ahash_request *req) + return ret; + + if (rctx->first) { +- sahara_sha_hw_data_descriptor_create(dev, rctx, req, 0); ++ ret = sahara_sha_hw_data_descriptor_create(dev, rctx, req, 0); ++ if (ret) ++ return ret; ++ + dev->hw_desc[0]->next = 0; + rctx->first = 0; + } else { +@@ -1002,7 +967,10 @@ static int sahara_sha_process(struct ahash_request *req) + + sahara_sha_hw_context_descriptor_create(dev, rctx, req, 0); + dev->hw_desc[0]->next = dev->hw_phys_desc[1]; +- sahara_sha_hw_data_descriptor_create(dev, rctx, req, 1); ++ ret = sahara_sha_hw_data_descriptor_create(dev, rctx, req, 1); ++ if (ret) ++ return ret; ++ + dev->hw_desc[1]->next = 0; + } + +@@ -1015,18 +983,19 @@ static int sahara_sha_process(struct ahash_request *req) + + timeout = wait_for_completion_timeout(&dev->dma_completion, + msecs_to_jiffies(SAHARA_TIMEOUT_MS)); +- if (!timeout) { +- dev_err(dev->device, "SHA timeout\n"); +- return -ETIMEDOUT; +- } + + if (rctx->sg_in_idx) + dma_unmap_sg(dev->device, dev->in_sg, dev->nb_in_sg, + DMA_TO_DEVICE); + ++ if (!timeout) { ++ dev_err(dev->device, "SHA timeout\n"); ++ return -ETIMEDOUT; ++ } ++ + memcpy(rctx->context, dev->context_base, rctx->context_size); + +- if (req->result) ++ if (req->result && rctx->last) + memcpy(req->result, rctx->context, rctx->digest_size); + + return 0; +@@ -1170,8 +1139,7 @@ static int sahara_sha_import(struct ahash_request *req, const void *in) + static int sahara_sha_cra_init(struct crypto_tfm *tfm) + { + crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), +- sizeof(struct sahara_sha_reqctx) + +- SHA_BUFFER_LEN + SHA256_BLOCK_SIZE); ++ sizeof(struct sahara_sha_reqctx)); + + return 0; + } +diff --git a/drivers/crypto/starfive/jh7110-cryp.c b/drivers/crypto/starfive/jh7110-cryp.c +index 08e974e0dd1247..4f5b6818208dc2 100644 +--- a/drivers/crypto/starfive/jh7110-cryp.c ++++ b/drivers/crypto/starfive/jh7110-cryp.c +@@ -168,7 +168,7 @@ static int starfive_cryp_probe(struct platform_device *pdev) + ret = devm_request_irq(&pdev->dev, irq, starfive_cryp_irq, 0, pdev->name, + (void *)cryp); + if (ret) +- return dev_err_probe(&pdev->dev, irq, ++ return dev_err_probe(&pdev->dev, ret, + "Failed to register interrupt handler\n"); + + clk_prepare_enable(cryp->hclk); +@@ -180,12 +180,8 @@ static int starfive_cryp_probe(struct platform_device *pdev) + spin_unlock(&dev_list.lock); + + ret = starfive_dma_init(cryp); +- if (ret) { +- if (ret == -EPROBE_DEFER) +- goto err_probe_defer; +- else +- goto err_dma_init; +- } ++ if (ret) ++ goto err_dma_init; + + /* Initialize crypto engine */ + cryp->engine = crypto_engine_alloc_init(&pdev->dev, 1); +@@ -233,7 +229,7 @@ static int starfive_cryp_probe(struct platform_device *pdev) + + tasklet_kill(&cryp->aes_done); + tasklet_kill(&cryp->hash_done); +-err_probe_defer: ++ + return ret; + } + +diff --git a/drivers/crypto/starfive/jh7110-cryp.h b/drivers/crypto/starfive/jh7110-cryp.h +index fe011d50473d76..607f70292b215d 100644 +--- a/drivers/crypto/starfive/jh7110-cryp.h ++++ b/drivers/crypto/starfive/jh7110-cryp.h +@@ -30,6 +30,7 @@ + #define MAX_KEY_SIZE SHA512_BLOCK_SIZE + #define STARFIVE_AES_IV_LEN AES_BLOCK_SIZE + #define STARFIVE_AES_CTR_LEN AES_BLOCK_SIZE ++#define STARFIVE_RSA_MAX_KEYSZ 256 + + union starfive_aes_csr { + u32 v; +@@ -212,12 +213,11 @@ struct starfive_cryp_request_ctx { + struct scatterlist *out_sg; + struct ahash_request ahash_fbk_req; + size_t total; +- size_t nents; + unsigned int blksize; + unsigned int digsize; + unsigned long in_sg_len; + unsigned char *adata; +- u8 rsa_data[] __aligned(sizeof(u32)); ++ u8 rsa_data[STARFIVE_RSA_MAX_KEYSZ] __aligned(sizeof(u32)); + }; + + struct starfive_cryp_dev *starfive_cryp_find_dev(struct starfive_cryp_ctx *ctx); +diff --git a/drivers/crypto/starfive/jh7110-rsa.c b/drivers/crypto/starfive/jh7110-rsa.c +index f31bbd825f883f..1db9a3d02848b5 100644 +--- a/drivers/crypto/starfive/jh7110-rsa.c ++++ b/drivers/crypto/starfive/jh7110-rsa.c +@@ -37,7 +37,6 @@ + // A * A * R mod N ==> A + #define CRYPTO_CMD_AARN 0x7 + +-#define STARFIVE_RSA_MAX_KEYSZ 256 + #define STARFIVE_RSA_RESET 0x2 + + static inline int starfive_pka_wait_done(struct starfive_cryp_ctx *ctx) +@@ -91,7 +90,7 @@ static int starfive_rsa_montgomery_form(struct starfive_cryp_ctx *ctx, + { + struct starfive_cryp_dev *cryp = ctx->cryp; + struct starfive_cryp_request_ctx *rctx = ctx->rctx; +- int count = rctx->total / sizeof(u32) - 1; ++ int count = (ALIGN(rctx->total, 4) / 4) - 1; + int loop; + u32 temp; + u8 opsize; +@@ -274,12 +273,17 @@ static int starfive_rsa_enc_core(struct starfive_cryp_ctx *ctx, int enc) + struct starfive_cryp_dev *cryp = ctx->cryp; + struct starfive_cryp_request_ctx *rctx = ctx->rctx; + struct starfive_rsa_key *key = &ctx->rsa_key; +- int ret = 0; ++ int ret = 0, shift = 0; + + writel(STARFIVE_RSA_RESET, cryp->base + STARFIVE_PKA_CACR_OFFSET); + +- rctx->total = sg_copy_to_buffer(rctx->in_sg, rctx->nents, +- rctx->rsa_data, rctx->total); ++ if (!IS_ALIGNED(rctx->total, sizeof(u32))) { ++ shift = sizeof(u32) - (rctx->total & 0x3); ++ memset(rctx->rsa_data, 0, shift); ++ } ++ ++ rctx->total = sg_copy_to_buffer(rctx->in_sg, sg_nents(rctx->in_sg), ++ rctx->rsa_data + shift, rctx->total); + + if (enc) { + key->bitlen = key->e_bitlen; +@@ -329,7 +333,6 @@ static int starfive_rsa_enc(struct akcipher_request *req) + rctx->in_sg = req->src; + rctx->out_sg = req->dst; + rctx->total = req->src_len; +- rctx->nents = sg_nents(rctx->in_sg); + ctx->rctx = rctx; + + return starfive_rsa_enc_core(ctx, 1); +diff --git a/drivers/crypto/stm32/stm32-crc32.c b/drivers/crypto/stm32/stm32-crc32.c +index 90a920e7f6642f..c439be1650c84d 100644 +--- a/drivers/crypto/stm32/stm32-crc32.c ++++ b/drivers/crypto/stm32/stm32-crc32.c +@@ -104,7 +104,7 @@ static struct stm32_crc *stm32_crc_get_next_crc(void) + struct stm32_crc *crc; + + spin_lock_bh(&crc_list.lock); +- crc = list_first_entry(&crc_list.dev_list, struct stm32_crc, list); ++ crc = list_first_entry_or_null(&crc_list.dev_list, struct stm32_crc, list); + if (crc) + list_move_tail(&crc->list, &crc_list.dev_list); + spin_unlock_bh(&crc_list.lock); +diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c +index f095f0065428a9..2f1b82cf10b1c4 100644 +--- a/drivers/crypto/stm32/stm32-cryp.c ++++ b/drivers/crypto/stm32/stm32-cryp.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1665,8 +1666,11 @@ static irqreturn_t stm32_cryp_irq_thread(int irq, void *arg) + it_mask &= ~IMSCR_OUT; + stm32_cryp_write(cryp, cryp->caps->imsc, it_mask); + +- if (!cryp->payload_in && !cryp->header_in && !cryp->payload_out) ++ if (!cryp->payload_in && !cryp->header_in && !cryp->payload_out) { ++ local_bh_disable(); + stm32_cryp_finish_req(cryp, 0); ++ local_bh_enable(); ++ } + + return IRQ_HANDLED; + } +diff --git a/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c b/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c +index 2621ff8a93764d..de53eddf6796b6 100644 +--- a/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c ++++ b/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c +@@ -104,7 +104,8 @@ static void virtio_crypto_dataq_akcipher_callback(struct virtio_crypto_request * + } + + static int virtio_crypto_alg_akcipher_init_session(struct virtio_crypto_akcipher_ctx *ctx, +- struct virtio_crypto_ctrl_header *header, void *para, ++ struct virtio_crypto_ctrl_header *header, ++ struct virtio_crypto_akcipher_session_para *para, + const uint8_t *key, unsigned int keylen) + { + struct scatterlist outhdr_sg, key_sg, inhdr_sg, *sgs[3]; +@@ -128,7 +129,7 @@ static int virtio_crypto_alg_akcipher_init_session(struct virtio_crypto_akcipher + + ctrl = &vc_ctrl_req->ctrl; + memcpy(&ctrl->header, header, sizeof(ctrl->header)); +- memcpy(&ctrl->u, para, sizeof(ctrl->u)); ++ memcpy(&ctrl->u.akcipher_create_session.para, para, sizeof(*para)); + input = &vc_ctrl_req->input; + input->status = cpu_to_le32(VIRTIO_CRYPTO_ERR); + +diff --git a/drivers/crypto/virtio/virtio_crypto_common.h b/drivers/crypto/virtio/virtio_crypto_common.h +index 154590e1f7643d..7059bbe5a2ebaa 100644 +--- a/drivers/crypto/virtio/virtio_crypto_common.h ++++ b/drivers/crypto/virtio/virtio_crypto_common.h +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -28,6 +29,7 @@ struct data_queue { + char name[32]; + + struct crypto_engine *engine; ++ struct tasklet_struct done_task; + }; + + struct virtio_crypto { +diff --git a/drivers/crypto/virtio/virtio_crypto_core.c b/drivers/crypto/virtio/virtio_crypto_core.c +index 43a0838d31ff01..b909c6a2bf1c34 100644 +--- a/drivers/crypto/virtio/virtio_crypto_core.c ++++ b/drivers/crypto/virtio/virtio_crypto_core.c +@@ -72,27 +72,28 @@ int virtio_crypto_ctrl_vq_request(struct virtio_crypto *vcrypto, struct scatterl + return 0; + } + +-static void virtcrypto_dataq_callback(struct virtqueue *vq) ++static void virtcrypto_done_task(unsigned long data) + { +- struct virtio_crypto *vcrypto = vq->vdev->priv; ++ struct data_queue *data_vq = (struct data_queue *)data; ++ struct virtqueue *vq = data_vq->vq; + struct virtio_crypto_request *vc_req; +- unsigned long flags; + unsigned int len; +- unsigned int qid = vq->index; + +- spin_lock_irqsave(&vcrypto->data_vq[qid].lock, flags); + do { + virtqueue_disable_cb(vq); + while ((vc_req = virtqueue_get_buf(vq, &len)) != NULL) { +- spin_unlock_irqrestore( +- &vcrypto->data_vq[qid].lock, flags); + if (vc_req->alg_cb) + vc_req->alg_cb(vc_req, len); +- spin_lock_irqsave( +- &vcrypto->data_vq[qid].lock, flags); + } + } while (!virtqueue_enable_cb(vq)); +- spin_unlock_irqrestore(&vcrypto->data_vq[qid].lock, flags); ++} ++ ++static void virtcrypto_dataq_callback(struct virtqueue *vq) ++{ ++ struct virtio_crypto *vcrypto = vq->vdev->priv; ++ struct data_queue *dq = &vcrypto->data_vq[vq->index]; ++ ++ tasklet_schedule(&dq->done_task); + } + + static int virtcrypto_find_vqs(struct virtio_crypto *vi) +@@ -150,6 +151,8 @@ static int virtcrypto_find_vqs(struct virtio_crypto *vi) + ret = -ENOMEM; + goto err_engine; + } ++ tasklet_init(&vi->data_vq[i].done_task, virtcrypto_done_task, ++ (unsigned long)&vi->data_vq[i]); + } + + kfree(names); +@@ -497,12 +500,15 @@ static void virtcrypto_free_unused_reqs(struct virtio_crypto *vcrypto) + static void virtcrypto_remove(struct virtio_device *vdev) + { + struct virtio_crypto *vcrypto = vdev->priv; ++ int i; + + dev_info(&vdev->dev, "Start virtcrypto_remove.\n"); + + flush_work(&vcrypto->config_work); + if (virtcrypto_dev_started(vcrypto)) + virtcrypto_dev_stop(vcrypto); ++ for (i = 0; i < vcrypto->max_data_queues; i++) ++ tasklet_kill(&vcrypto->data_vq[i].done_task); + virtio_reset_device(vdev); + virtcrypto_free_unused_reqs(vcrypto); + virtcrypto_clear_crypto_engines(vcrypto); +diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c +index ce335578b759ed..84103fc3f66f18 100644 +--- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c ++++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c +@@ -231,7 +231,10 @@ static int zynqmp_handle_aes_req(struct crypto_engine *engine, + err = zynqmp_aes_aead_cipher(areq); + } + ++ local_bh_disable(); + crypto_finalize_aead_request(engine, areq, err); ++ local_bh_enable(); ++ + return 0; + } + +diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c +index 40d055560e52fd..43195345583098 100644 +--- a/drivers/cxl/acpi.c ++++ b/drivers/cxl/acpi.c +@@ -194,31 +194,27 @@ struct cxl_cfmws_context { + int id; + }; + +-static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg, +- const unsigned long end) ++static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws, ++ struct cxl_cfmws_context *ctx) + { + int target_map[CXL_DECODER_MAX_INTERLEAVE]; +- struct cxl_cfmws_context *ctx = arg; + struct cxl_port *root_port = ctx->root_port; + struct resource *cxl_res = ctx->cxl_res; + struct cxl_cxims_context cxims_ctx; + struct cxl_root_decoder *cxlrd; + struct device *dev = ctx->dev; +- struct acpi_cedt_cfmws *cfmws; + cxl_calc_hb_fn cxl_calc_hb; + struct cxl_decoder *cxld; + unsigned int ways, i, ig; + struct resource *res; + int rc; + +- cfmws = (struct acpi_cedt_cfmws *) header; +- + rc = cxl_acpi_cfmws_verify(dev, cfmws); + if (rc) { + dev_err(dev, "CFMWS range %#llx-%#llx not registered\n", + cfmws->base_hpa, + cfmws->base_hpa + cfmws->window_size - 1); +- return 0; ++ return rc; + } + + rc = eiw_to_ways(cfmws->interleave_ways, &ways); +@@ -254,7 +250,7 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg, + + cxlrd = cxl_root_decoder_alloc(root_port, ways, cxl_calc_hb); + if (IS_ERR(cxlrd)) +- return 0; ++ return PTR_ERR(cxlrd); + + cxld = &cxlrd->cxlsd.cxld; + cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions); +@@ -295,16 +291,7 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg, + put_device(&cxld->dev); + else + rc = cxl_decoder_autoremove(dev, cxld); +- if (rc) { +- dev_err(dev, "Failed to add decode range: %pr", res); +- return rc; +- } +- dev_dbg(dev, "add: %s node: %d range [%#llx - %#llx]\n", +- dev_name(&cxld->dev), +- phys_to_target_node(cxld->hpa_range.start), +- cxld->hpa_range.start, cxld->hpa_range.end); +- +- return 0; ++ return rc; + + err_insert: + kfree(res->name); +@@ -313,6 +300,29 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg, + return -ENOMEM; + } + ++static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg, ++ const unsigned long end) ++{ ++ struct acpi_cedt_cfmws *cfmws = (struct acpi_cedt_cfmws *)header; ++ struct cxl_cfmws_context *ctx = arg; ++ struct device *dev = ctx->dev; ++ int rc; ++ ++ rc = __cxl_parse_cfmws(cfmws, ctx); ++ if (rc) ++ dev_err(dev, ++ "Failed to add decode range: [%#llx - %#llx] (%d)\n", ++ cfmws->base_hpa, ++ cfmws->base_hpa + cfmws->window_size - 1, rc); ++ else ++ dev_dbg(dev, "decode range: node: %d range [%#llx - %#llx]\n", ++ phys_to_target_node(cfmws->base_hpa), cfmws->base_hpa, ++ cfmws->base_hpa + cfmws->window_size - 1); ++ ++ /* never fail cxl_acpi load for a single window failure */ ++ return 0; ++} ++ + __mock struct acpi_device *to_cxl_host_bridge(struct device *host, + struct device *dev) + { +diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h +index 45e7e044cf4a04..6444cc827c9ceb 100644 +--- a/drivers/cxl/core/core.h ++++ b/drivers/cxl/core/core.h +@@ -27,7 +27,14 @@ void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled); + int cxl_region_init(void); + void cxl_region_exit(void); + int cxl_get_poison_by_endpoint(struct cxl_port *port); ++struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa); ++ + #else ++static inline ++struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa) ++{ ++ return NULL; ++} + static inline int cxl_get_poison_by_endpoint(struct cxl_port *port) + { + return 0; +@@ -75,6 +82,7 @@ resource_size_t __rcrb_to_component(struct device *dev, + enum cxl_rcrb which); + + extern struct rw_semaphore cxl_dpa_rwsem; ++extern struct rw_semaphore cxl_region_rwsem; + + int cxl_memdev_init(void); + void cxl_memdev_exit(void); +diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c +index 4449b34a80cc9b..3600b7cbfb5893 100644 +--- a/drivers/cxl/core/hdm.c ++++ b/drivers/cxl/core/hdm.c +@@ -52,6 +52,14 @@ int devm_cxl_add_passthrough_decoder(struct cxl_port *port) + struct cxl_dport *dport = NULL; + int single_port_map[1]; + unsigned long index; ++ struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev); ++ ++ /* ++ * Capability checks are moot for passthrough decoders, support ++ * any and all possibilities. ++ */ ++ cxlhdm->interleave_mask = ~0U; ++ cxlhdm->iw_cap_mask = ~0UL; + + cxlsd = cxl_switch_decoder_alloc(port, 1); + if (IS_ERR(cxlsd)) +@@ -79,13 +87,18 @@ static void parse_hdm_decoder_caps(struct cxl_hdm *cxlhdm) + cxlhdm->interleave_mask |= GENMASK(11, 8); + if (FIELD_GET(CXL_HDM_DECODER_INTERLEAVE_14_12, hdm_cap)) + cxlhdm->interleave_mask |= GENMASK(14, 12); ++ cxlhdm->iw_cap_mask = BIT(1) | BIT(2) | BIT(4) | BIT(8); ++ if (FIELD_GET(CXL_HDM_DECODER_INTERLEAVE_3_6_12_WAY, hdm_cap)) ++ cxlhdm->iw_cap_mask |= BIT(3) | BIT(6) | BIT(12); ++ if (FIELD_GET(CXL_HDM_DECODER_INTERLEAVE_16_WAY, hdm_cap)) ++ cxlhdm->iw_cap_mask |= BIT(16); + } + + static int map_hdm_decoder_regs(struct cxl_port *port, void __iomem *crb, + struct cxl_component_regs *regs) + { + struct cxl_register_map map = { +- .dev = &port->dev, ++ .host = &port->dev, + .resource = port->component_reg_phys, + .base = crb, + .max_size = CXL_COMPONENT_REG_BLOCK_SIZE, +@@ -373,10 +386,9 @@ resource_size_t cxl_dpa_resource_start(struct cxl_endpoint_decoder *cxled) + { + resource_size_t base = -1; + +- down_read(&cxl_dpa_rwsem); ++ lockdep_assert_held(&cxl_dpa_rwsem); + if (cxled->dpa_res) + base = cxled->dpa_res->start; +- up_read(&cxl_dpa_rwsem); + + return base; + } +@@ -575,17 +587,11 @@ static void cxld_set_type(struct cxl_decoder *cxld, u32 *ctrl) + CXL_HDM_DECODER0_CTRL_HOSTONLY); + } + +-static int cxlsd_set_targets(struct cxl_switch_decoder *cxlsd, u64 *tgt) ++static void cxlsd_set_targets(struct cxl_switch_decoder *cxlsd, u64 *tgt) + { + struct cxl_dport **t = &cxlsd->target[0]; + int ways = cxlsd->cxld.interleave_ways; + +- if (dev_WARN_ONCE(&cxlsd->cxld.dev, +- ways > 8 || ways > cxlsd->nr_targets, +- "ways: %d overflows targets: %d\n", ways, +- cxlsd->nr_targets)) +- return -ENXIO; +- + *tgt = FIELD_PREP(GENMASK(7, 0), t[0]->port_id); + if (ways > 1) + *tgt |= FIELD_PREP(GENMASK(15, 8), t[1]->port_id); +@@ -601,8 +607,6 @@ static int cxlsd_set_targets(struct cxl_switch_decoder *cxlsd, u64 *tgt) + *tgt |= FIELD_PREP(GENMASK_ULL(55, 48), t[6]->port_id); + if (ways > 7) + *tgt |= FIELD_PREP(GENMASK_ULL(63, 56), t[7]->port_id); +- +- return 0; + } + + /* +@@ -643,13 +647,33 @@ static int cxl_decoder_commit(struct cxl_decoder *cxld) + if (cxld->flags & CXL_DECODER_F_ENABLE) + return 0; + +- if (port->commit_end + 1 != id) { ++ if (cxl_num_decoders_committed(port) != id) { + dev_dbg(&port->dev, + "%s: out of order commit, expected decoder%d.%d\n", +- dev_name(&cxld->dev), port->id, port->commit_end + 1); ++ dev_name(&cxld->dev), port->id, ++ cxl_num_decoders_committed(port)); + return -EBUSY; + } + ++ /* ++ * For endpoint decoders hosted on CXL memory devices that ++ * support the sanitize operation, make sure sanitize is not in-flight. ++ */ ++ if (is_endpoint_decoder(&cxld->dev)) { ++ struct cxl_endpoint_decoder *cxled = ++ to_cxl_endpoint_decoder(&cxld->dev); ++ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); ++ struct cxl_memdev_state *mds = ++ to_cxl_memdev_state(cxlmd->cxlds); ++ ++ if (mds && mds->security.sanitize_active) { ++ dev_dbg(&cxlmd->dev, ++ "attempted to commit %s during sanitize\n", ++ dev_name(&cxld->dev)); ++ return -EBUSY; ++ } ++ } ++ + down_read(&cxl_dpa_rwsem); + /* common decoder settings */ + ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(cxld->id)); +@@ -670,13 +694,7 @@ static int cxl_decoder_commit(struct cxl_decoder *cxld) + void __iomem *tl_lo = hdm + CXL_HDM_DECODER0_TL_LOW(id); + u64 targets; + +- rc = cxlsd_set_targets(cxlsd, &targets); +- if (rc) { +- dev_dbg(&port->dev, "%s: target configuration error\n", +- dev_name(&cxld->dev)); +- goto err; +- } +- ++ cxlsd_set_targets(cxlsd, &targets); + writel(upper_32_bits(targets), tl_hi); + writel(lower_32_bits(targets), tl_lo); + } else { +@@ -694,7 +712,6 @@ static int cxl_decoder_commit(struct cxl_decoder *cxld) + + port->commit_end++; + rc = cxld_await_commit(hdm, cxld->id); +-err: + if (rc) { + dev_dbg(&port->dev, "%s: error %d committing decoder\n", + dev_name(&cxld->dev), rc); +@@ -844,7 +861,9 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, + cxld->target_type = CXL_DECODER_HOSTONLYMEM; + else + cxld->target_type = CXL_DECODER_DEVMEM; +- if (cxld->id != port->commit_end + 1) { ++ ++ guard(rwsem_write)(&cxl_region_rwsem); ++ if (cxld->id != cxl_num_decoders_committed(port)) { + dev_warn(&port->dev, + "decoder%d.%d: Committed out of order\n", + port->id, cxld->id); +diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c +index 4df4f614f490ef..fecaa18f4dd203 100644 +--- a/drivers/cxl/core/mbox.c ++++ b/drivers/cxl/core/mbox.c +@@ -928,7 +928,7 @@ static int cxl_clear_event_record(struct cxl_memdev_state *mds, + for (cnt = 0; cnt < total; cnt++) { + payload->handles[i++] = get_pl->records[cnt].hdr.handle; + dev_dbg(mds->cxlds.dev, "Event log '%d': Clearing %u\n", log, +- le16_to_cpu(payload->handles[i])); ++ le16_to_cpu(payload->handles[i - 1])); + + if (i == max_handles) { + payload->nr_recs = i; +@@ -959,24 +959,22 @@ static void cxl_mem_get_records_log(struct cxl_memdev_state *mds, + struct cxl_memdev *cxlmd = mds->cxlds.cxlmd; + struct device *dev = mds->cxlds.dev; + struct cxl_get_event_payload *payload; +- struct cxl_mbox_cmd mbox_cmd; + u8 log_type = type; + u16 nr_rec; + + mutex_lock(&mds->event.log_lock); + payload = mds->event.buf; + +- mbox_cmd = (struct cxl_mbox_cmd) { +- .opcode = CXL_MBOX_OP_GET_EVENT_RECORD, +- .payload_in = &log_type, +- .size_in = sizeof(log_type), +- .payload_out = payload, +- .size_out = mds->payload_size, +- .min_out = struct_size(payload, records, 0), +- }; +- + do { + int rc, i; ++ struct cxl_mbox_cmd mbox_cmd = (struct cxl_mbox_cmd) { ++ .opcode = CXL_MBOX_OP_GET_EVENT_RECORD, ++ .payload_in = &log_type, ++ .size_in = sizeof(log_type), ++ .payload_out = payload, ++ .size_out = mds->payload_size, ++ .min_out = struct_size(payload, records, 0), ++ }; + + rc = cxl_internal_send_cmd(mds, &mbox_cmd); + if (rc) { +@@ -1125,20 +1123,7 @@ int cxl_dev_state_identify(struct cxl_memdev_state *mds) + } + EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL); + +-/** +- * cxl_mem_sanitize() - Send a sanitization command to the device. +- * @mds: The device data for the operation +- * @cmd: The specific sanitization command opcode +- * +- * Return: 0 if the command was executed successfully, regardless of +- * whether or not the actual security operation is done in the background, +- * such as for the Sanitize case. +- * Error return values can be the result of the mailbox command, -EINVAL +- * when security requirements are not met or invalid contexts. +- * +- * See CXL 3.0 @8.2.9.8.5.1 Sanitize and @8.2.9.8.5.2 Secure Erase. +- */ +-int cxl_mem_sanitize(struct cxl_memdev_state *mds, u16 cmd) ++static int __cxl_mem_sanitize(struct cxl_memdev_state *mds, u16 cmd) + { + int rc; + u32 sec_out = 0; +@@ -1183,7 +1168,45 @@ int cxl_mem_sanitize(struct cxl_memdev_state *mds, u16 cmd) + + return 0; + } +-EXPORT_SYMBOL_NS_GPL(cxl_mem_sanitize, CXL); ++ ++ ++/** ++ * cxl_mem_sanitize() - Send a sanitization command to the device. ++ * @cxlmd: The device for the operation ++ * @cmd: The specific sanitization command opcode ++ * ++ * Return: 0 if the command was executed successfully, regardless of ++ * whether or not the actual security operation is done in the background, ++ * such as for the Sanitize case. ++ * Error return values can be the result of the mailbox command, -EINVAL ++ * when security requirements are not met or invalid contexts, or -EBUSY ++ * if the sanitize operation is already in flight. ++ * ++ * See CXL 3.0 @8.2.9.8.5.1 Sanitize and @8.2.9.8.5.2 Secure Erase. ++ */ ++int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd) ++{ ++ struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); ++ struct cxl_port *endpoint; ++ int rc; ++ ++ /* synchronize with cxl_mem_probe() and decoder write operations */ ++ device_lock(&cxlmd->dev); ++ endpoint = cxlmd->endpoint; ++ down_read(&cxl_region_rwsem); ++ /* ++ * Require an endpoint to be safe otherwise the driver can not ++ * be sure that the device is unmapped. ++ */ ++ if (endpoint && cxl_num_decoders_committed(endpoint) == 0) ++ rc = __cxl_mem_sanitize(mds, cmd); ++ else ++ rc = -EBUSY; ++ up_read(&cxl_region_rwsem); ++ device_unlock(&cxlmd->dev); ++ ++ return rc; ++} + + static int add_dpa_res(struct device *dev, struct resource *parent, + struct resource *res, resource_size_t start, +@@ -1285,7 +1308,6 @@ int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len, + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); + struct cxl_mbox_poison_out *po; + struct cxl_mbox_poison_in pi; +- struct cxl_mbox_cmd mbox_cmd; + int nr_records = 0; + int rc; + +@@ -1297,16 +1319,16 @@ int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len, + pi.offset = cpu_to_le64(offset); + pi.length = cpu_to_le64(len / CXL_POISON_LEN_MULT); + +- mbox_cmd = (struct cxl_mbox_cmd) { +- .opcode = CXL_MBOX_OP_GET_POISON, +- .size_in = sizeof(pi), +- .payload_in = &pi, +- .size_out = mds->payload_size, +- .payload_out = po, +- .min_out = struct_size(po, record, 0), +- }; +- + do { ++ struct cxl_mbox_cmd mbox_cmd = (struct cxl_mbox_cmd){ ++ .opcode = CXL_MBOX_OP_GET_POISON, ++ .size_in = sizeof(pi), ++ .payload_in = &pi, ++ .size_out = mds->payload_size, ++ .payload_out = po, ++ .min_out = struct_size(po, record, 0), ++ }; ++ + rc = cxl_internal_send_cmd(mds, &mbox_cmd); + if (rc) + break; +diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c +index 14b547c07f5476..eb895c70043fdf 100644 +--- a/drivers/cxl/core/memdev.c ++++ b/drivers/cxl/core/memdev.c +@@ -125,13 +125,16 @@ static ssize_t security_state_show(struct device *dev, + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); +- u64 reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_BG_CMD_STATUS_OFFSET); +- u32 pct = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_PCT_MASK, reg); +- u16 cmd = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_OPCODE_MASK, reg); + unsigned long state = mds->security.state; ++ int rc = 0; + +- if (cmd == CXL_MBOX_OP_SANITIZE && pct != 100) +- return sysfs_emit(buf, "sanitize\n"); ++ /* sync with latest submission state */ ++ mutex_lock(&mds->mbox_mutex); ++ if (mds->security.sanitize_active) ++ rc = sysfs_emit(buf, "sanitize\n"); ++ mutex_unlock(&mds->mbox_mutex); ++ if (rc) ++ return rc; + + if (!(state & CXL_PMEM_SEC_STATE_USER_PASS_SET)) + return sysfs_emit(buf, "disabled\n"); +@@ -152,24 +155,17 @@ static ssize_t security_sanitize_store(struct device *dev, + const char *buf, size_t len) + { + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); +- struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); +- struct cxl_port *port = cxlmd->endpoint; + bool sanitize; + ssize_t rc; + + if (kstrtobool(buf, &sanitize) || !sanitize) + return -EINVAL; + +- if (!port || !is_cxl_endpoint(port)) +- return -EINVAL; +- +- /* ensure no regions are mapped to this memdev */ +- if (port->commit_end != -1) +- return -EBUSY; +- +- rc = cxl_mem_sanitize(mds, CXL_MBOX_OP_SANITIZE); ++ rc = cxl_mem_sanitize(cxlmd, CXL_MBOX_OP_SANITIZE); ++ if (rc) ++ return rc; + +- return rc ? rc : len; ++ return len; + } + static struct device_attribute dev_attr_security_sanitize = + __ATTR(sanitize, 0200, NULL, security_sanitize_store); +@@ -179,24 +175,17 @@ static ssize_t security_erase_store(struct device *dev, + const char *buf, size_t len) + { + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); +- struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); +- struct cxl_port *port = cxlmd->endpoint; + ssize_t rc; + bool erase; + + if (kstrtobool(buf, &erase) || !erase) + return -EINVAL; + +- if (!port || !is_cxl_endpoint(port)) +- return -EINVAL; +- +- /* ensure no regions are mapped to this memdev */ +- if (port->commit_end != -1) +- return -EBUSY; +- +- rc = cxl_mem_sanitize(mds, CXL_MBOX_OP_SECURE_ERASE); ++ rc = cxl_mem_sanitize(cxlmd, CXL_MBOX_OP_SECURE_ERASE); ++ if (rc) ++ return rc; + +- return rc ? rc : len; ++ return len; + } + static struct device_attribute dev_attr_security_erase = + __ATTR(erase, 0200, NULL, security_erase_store); +@@ -238,11 +227,17 @@ int cxl_trigger_poison_list(struct cxl_memdev *cxlmd) + if (!port || !is_cxl_endpoint(port)) + return -EINVAL; + +- rc = down_read_interruptible(&cxl_dpa_rwsem); ++ rc = down_read_interruptible(&cxl_region_rwsem); + if (rc) + return rc; + +- if (port->commit_end == -1) { ++ rc = down_read_interruptible(&cxl_dpa_rwsem); ++ if (rc) { ++ up_read(&cxl_region_rwsem); ++ return rc; ++ } ++ ++ if (cxl_num_decoders_committed(port) == 0) { + /* No regions mapped to this memdev */ + rc = cxl_get_poison_by_memdev(cxlmd); + } else { +@@ -250,55 +245,12 @@ int cxl_trigger_poison_list(struct cxl_memdev *cxlmd) + rc = cxl_get_poison_by_endpoint(port); + } + up_read(&cxl_dpa_rwsem); ++ up_read(&cxl_region_rwsem); + + return rc; + } + EXPORT_SYMBOL_NS_GPL(cxl_trigger_poison_list, CXL); + +-struct cxl_dpa_to_region_context { +- struct cxl_region *cxlr; +- u64 dpa; +-}; +- +-static int __cxl_dpa_to_region(struct device *dev, void *arg) +-{ +- struct cxl_dpa_to_region_context *ctx = arg; +- struct cxl_endpoint_decoder *cxled; +- u64 dpa = ctx->dpa; +- +- if (!is_endpoint_decoder(dev)) +- return 0; +- +- cxled = to_cxl_endpoint_decoder(dev); +- if (!cxled->dpa_res || !resource_size(cxled->dpa_res)) +- return 0; +- +- if (dpa > cxled->dpa_res->end || dpa < cxled->dpa_res->start) +- return 0; +- +- dev_dbg(dev, "dpa:0x%llx mapped in region:%s\n", dpa, +- dev_name(&cxled->cxld.region->dev)); +- +- ctx->cxlr = cxled->cxld.region; +- +- return 1; +-} +- +-static struct cxl_region *cxl_dpa_to_region(struct cxl_memdev *cxlmd, u64 dpa) +-{ +- struct cxl_dpa_to_region_context ctx; +- struct cxl_port *port; +- +- ctx = (struct cxl_dpa_to_region_context) { +- .dpa = dpa, +- }; +- port = cxlmd->endpoint; +- if (port && is_cxl_endpoint(port) && port->commit_end != -1) +- device_for_each_child(&port->dev, &ctx, __cxl_dpa_to_region); +- +- return ctx.cxlr; +-} +- + static int cxl_validate_poison_dpa(struct cxl_memdev *cxlmd, u64 dpa) + { + struct cxl_dev_state *cxlds = cxlmd->cxlds; +@@ -335,10 +287,16 @@ int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa) + if (!IS_ENABLED(CONFIG_DEBUG_FS)) + return 0; + +- rc = down_read_interruptible(&cxl_dpa_rwsem); ++ rc = down_read_interruptible(&cxl_region_rwsem); + if (rc) + return rc; + ++ rc = down_read_interruptible(&cxl_dpa_rwsem); ++ if (rc) { ++ up_read(&cxl_region_rwsem); ++ return rc; ++ } ++ + rc = cxl_validate_poison_dpa(cxlmd, dpa); + if (rc) + goto out; +@@ -366,6 +324,7 @@ int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa) + trace_cxl_poison(cxlmd, cxlr, &record, 0, 0, CXL_POISON_TRACE_INJECT); + out: + up_read(&cxl_dpa_rwsem); ++ up_read(&cxl_region_rwsem); + + return rc; + } +@@ -383,10 +342,16 @@ int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa) + if (!IS_ENABLED(CONFIG_DEBUG_FS)) + return 0; + +- rc = down_read_interruptible(&cxl_dpa_rwsem); ++ rc = down_read_interruptible(&cxl_region_rwsem); + if (rc) + return rc; + ++ rc = down_read_interruptible(&cxl_dpa_rwsem); ++ if (rc) { ++ up_read(&cxl_region_rwsem); ++ return rc; ++ } ++ + rc = cxl_validate_poison_dpa(cxlmd, dpa); + if (rc) + goto out; +@@ -423,6 +388,7 @@ int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa) + trace_cxl_poison(cxlmd, cxlr, &record, 0, 0, CXL_POISON_TRACE_CLEAR); + out: + up_read(&cxl_dpa_rwsem); ++ up_read(&cxl_region_rwsem); + + return rc; + } +@@ -556,21 +522,11 @@ void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds, + } + EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, CXL); + +-static void cxl_memdev_security_shutdown(struct device *dev) +-{ +- struct cxl_memdev *cxlmd = to_cxl_memdev(dev); +- struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); +- +- if (mds->security.poll) +- cancel_delayed_work_sync(&mds->security.poll_dwork); +-} +- + static void cxl_memdev_shutdown(struct device *dev) + { + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + + down_write(&cxl_memdev_rwsem); +- cxl_memdev_security_shutdown(dev); + cxlmd->cxlds = NULL; + up_write(&cxl_memdev_rwsem); + } +@@ -580,8 +536,8 @@ static void cxl_memdev_unregister(void *_cxlmd) + struct cxl_memdev *cxlmd = _cxlmd; + struct device *dev = &cxlmd->dev; + +- cxl_memdev_shutdown(dev); + cdev_device_del(&cxlmd->cdev, dev); ++ cxl_memdev_shutdown(dev); + put_device(dev); + } + +@@ -961,17 +917,16 @@ static const struct fw_upload_ops cxl_memdev_fw_ops = { + .cleanup = cxl_fw_cleanup, + }; + +-static void devm_cxl_remove_fw_upload(void *fwl) ++static void cxl_remove_fw_upload(void *fwl) + { + firmware_upload_unregister(fwl); + } + +-int cxl_memdev_setup_fw_upload(struct cxl_memdev_state *mds) ++int devm_cxl_setup_fw_upload(struct device *host, struct cxl_memdev_state *mds) + { + struct cxl_dev_state *cxlds = &mds->cxlds; + struct device *dev = &cxlds->cxlmd->dev; + struct fw_upload *fwl; +- int rc; + + if (!test_bit(CXL_MEM_COMMAND_ID_GET_FW_INFO, mds->enabled_cmds)) + return 0; +@@ -979,19 +934,10 @@ int cxl_memdev_setup_fw_upload(struct cxl_memdev_state *mds) + fwl = firmware_upload_register(THIS_MODULE, dev, dev_name(dev), + &cxl_memdev_fw_ops, mds); + if (IS_ERR(fwl)) +- return dev_err_probe(dev, PTR_ERR(fwl), +- "Failed to register firmware loader\n"); +- +- rc = devm_add_action_or_reset(cxlds->dev, devm_cxl_remove_fw_upload, +- fwl); +- if (rc) +- dev_err(dev, +- "Failed to add firmware loader remove action: %d\n", +- rc); +- +- return rc; ++ return PTR_ERR(fwl); ++ return devm_add_action_or_reset(host, cxl_remove_fw_upload, fwl); + } +-EXPORT_SYMBOL_NS_GPL(cxl_memdev_setup_fw_upload, CXL); ++EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_fw_upload, CXL); + + static const struct file_operations cxl_memdev_fops = { + .owner = THIS_MODULE, +@@ -1002,36 +948,8 @@ static const struct file_operations cxl_memdev_fops = { + .llseek = noop_llseek, + }; + +-static void put_sanitize(void *data) +-{ +- struct cxl_memdev_state *mds = data; +- +- sysfs_put(mds->security.sanitize_node); +-} +- +-static int cxl_memdev_security_init(struct cxl_memdev *cxlmd) +-{ +- struct cxl_dev_state *cxlds = cxlmd->cxlds; +- struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); +- struct device *dev = &cxlmd->dev; +- struct kernfs_node *sec; +- +- sec = sysfs_get_dirent(dev->kobj.sd, "security"); +- if (!sec) { +- dev_err(dev, "sysfs_get_dirent 'security' failed\n"); +- return -ENODEV; +- } +- mds->security.sanitize_node = sysfs_get_dirent(sec, "state"); +- sysfs_put(sec); +- if (!mds->security.sanitize_node) { +- dev_err(dev, "sysfs_get_dirent 'state' failed\n"); +- return -ENODEV; +- } +- +- return devm_add_action_or_reset(cxlds->dev, put_sanitize, mds); +- } +- +-struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds) ++struct cxl_memdev *devm_cxl_add_memdev(struct device *host, ++ struct cxl_dev_state *cxlds) + { + struct cxl_memdev *cxlmd; + struct device *dev; +@@ -1059,11 +977,7 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds) + if (rc) + goto err; + +- rc = cxl_memdev_security_init(cxlmd); +- if (rc) +- goto err; +- +- rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd); ++ rc = devm_add_action_or_reset(host, cxl_memdev_unregister, cxlmd); + if (rc) + return ERR_PTR(rc); + return cxlmd; +@@ -1079,6 +993,50 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds) + } + EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, CXL); + ++static void sanitize_teardown_notifier(void *data) ++{ ++ struct cxl_memdev_state *mds = data; ++ struct kernfs_node *state; ++ ++ /* ++ * Prevent new irq triggered invocations of the workqueue and ++ * flush inflight invocations. ++ */ ++ mutex_lock(&mds->mbox_mutex); ++ state = mds->security.sanitize_node; ++ mds->security.sanitize_node = NULL; ++ mutex_unlock(&mds->mbox_mutex); ++ ++ cancel_delayed_work_sync(&mds->security.poll_dwork); ++ sysfs_put(state); ++} ++ ++int devm_cxl_sanitize_setup_notifier(struct device *host, ++ struct cxl_memdev *cxlmd) ++{ ++ struct cxl_dev_state *cxlds = cxlmd->cxlds; ++ struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); ++ struct kernfs_node *sec; ++ ++ if (!test_bit(CXL_SEC_ENABLED_SANITIZE, mds->security.enabled_cmds)) ++ return 0; ++ ++ /* ++ * Note, the expectation is that @cxlmd would have failed to be ++ * created if these sysfs_get_dirent calls fail. ++ */ ++ sec = sysfs_get_dirent(cxlmd->dev.kobj.sd, "security"); ++ if (!sec) ++ return -ENOENT; ++ mds->security.sanitize_node = sysfs_get_dirent(sec, "state"); ++ sysfs_put(sec); ++ if (!mds->security.sanitize_node) ++ return -ENOENT; ++ ++ return devm_add_action_or_reset(host, sanitize_teardown_notifier, mds); ++} ++EXPORT_SYMBOL_NS_GPL(devm_cxl_sanitize_setup_notifier, CXL); ++ + __init int cxl_memdev_init(void) + { + dev_t devt; +diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c +index c7a7887ebdcff8..6edfd054667373 100644 +--- a/drivers/cxl/core/pci.c ++++ b/drivers/cxl/core/pci.c +@@ -388,10 +388,6 @@ int cxl_dvsec_rr_decode(struct device *dev, int d, + + size |= temp & CXL_DVSEC_MEM_SIZE_LOW_MASK; + if (!size) { +- info->dvsec_range[i] = (struct range) { +- .start = 0, +- .end = CXL_RESOURCE_NONE, +- }; + continue; + } + +@@ -409,12 +405,10 @@ int cxl_dvsec_rr_decode(struct device *dev, int d, + + base |= temp & CXL_DVSEC_MEM_BASE_LOW_MASK; + +- info->dvsec_range[i] = (struct range) { ++ info->dvsec_range[ranges++] = (struct range) { + .start = base, + .end = base + size - 1 + }; +- +- ranges++; + } + + info->ranges = ranges; +@@ -475,9 +469,9 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm, + allowed++; + } + +- if (!allowed) { +- cxl_set_mem_enable(cxlds, 0); +- info->mem_enabled = 0; ++ if (!allowed && info->mem_enabled) { ++ dev_err(dev, "Range register decodes outside platform defined CXL ranges.\n"); ++ return -ENXIO; + } + + /* +diff --git a/drivers/cxl/core/pmu.c b/drivers/cxl/core/pmu.c +index 7684c843e5a59c..5d8e06b0ba6e88 100644 +--- a/drivers/cxl/core/pmu.c ++++ b/drivers/cxl/core/pmu.c +@@ -23,7 +23,7 @@ const struct device_type cxl_pmu_type = { + + static void remove_dev(void *dev) + { +- device_del(dev); ++ device_unregister(dev); + } + + int devm_cxl_pmu_add(struct device *parent, struct cxl_pmu_regs *regs, +diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c +index 7ca01a834e188c..c67cc8c9d5cc61 100644 +--- a/drivers/cxl/core/port.c ++++ b/drivers/cxl/core/port.c +@@ -28,9 +28,22 @@ + * instantiated by the core. + */ + ++/* ++ * All changes to the interleave configuration occur with this lock held ++ * for write. ++ */ ++DECLARE_RWSEM(cxl_region_rwsem); ++ + static DEFINE_IDA(cxl_port_ida); + static DEFINE_XARRAY(cxl_root_buses); + ++int cxl_num_decoders_committed(struct cxl_port *port) ++{ ++ lockdep_assert_held(&cxl_region_rwsem); ++ ++ return port->commit_end + 1; ++} ++ + static ssize_t devtype_show(struct device *dev, struct device_attribute *attr, + char *buf) + { +@@ -159,14 +172,10 @@ static ssize_t target_list_show(struct device *dev, + { + struct cxl_switch_decoder *cxlsd = to_cxl_switch_decoder(dev); + ssize_t offset; +- unsigned int seq; + int rc; + +- do { +- seq = read_seqbegin(&cxlsd->target_lock); +- rc = emit_target_list(cxlsd, buf); +- } while (read_seqretry(&cxlsd->target_lock, seq)); +- ++ guard(rwsem_read)(&cxl_region_rwsem); ++ rc = emit_target_list(cxlsd, buf); + if (rc < 0) + return rc; + offset = rc; +@@ -213,9 +222,9 @@ static ssize_t dpa_resource_show(struct device *dev, struct device_attribute *at + char *buf) + { + struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev); +- u64 base = cxl_dpa_resource_start(cxled); + +- return sysfs_emit(buf, "%#llx\n", base); ++ guard(rwsem_read)(&cxl_dpa_rwsem); ++ return sysfs_emit(buf, "%#llx\n", (u64)cxl_dpa_resource_start(cxled)); + } + static DEVICE_ATTR_RO(dpa_resource); + +@@ -691,14 +700,14 @@ static struct cxl_port *cxl_port_alloc(struct device *uport_dev, + return ERR_PTR(rc); + } + +-static int cxl_setup_comp_regs(struct device *dev, struct cxl_register_map *map, ++static int cxl_setup_comp_regs(struct device *host, struct cxl_register_map *map, + resource_size_t component_reg_phys) + { + if (component_reg_phys == CXL_RESOURCE_NONE) + return 0; + + *map = (struct cxl_register_map) { +- .dev = dev, ++ .host = host, + .reg_type = CXL_REGLOC_RBI_COMPONENT, + .resource = component_reg_phys, + .max_size = CXL_COMPONENT_REG_BLOCK_SIZE, +@@ -716,13 +725,23 @@ static int cxl_port_setup_regs(struct cxl_port *port, + component_reg_phys); + } + +-static int cxl_dport_setup_regs(struct cxl_dport *dport, ++static int cxl_dport_setup_regs(struct device *host, struct cxl_dport *dport, + resource_size_t component_reg_phys) + { ++ int rc; ++ + if (dev_is_platform(dport->dport_dev)) + return 0; +- return cxl_setup_comp_regs(dport->dport_dev, &dport->comp_map, +- component_reg_phys); ++ ++ /* ++ * use @dport->dport_dev for the context for error messages during ++ * register probing, and fixup @host after the fact, since @host may be ++ * NULL. ++ */ ++ rc = cxl_setup_comp_regs(dport->dport_dev, &dport->comp_map, ++ component_reg_phys); ++ dport->comp_map.host = host; ++ return rc; + } + + static struct cxl_port *__devm_cxl_add_port(struct device *host, +@@ -983,7 +1002,16 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, + if (!dport) + return ERR_PTR(-ENOMEM); + +- if (rcrb != CXL_RESOURCE_NONE) { ++ dport->dport_dev = dport_dev; ++ dport->port_id = port_id; ++ dport->port = port; ++ ++ if (rcrb == CXL_RESOURCE_NONE) { ++ rc = cxl_dport_setup_regs(&port->dev, dport, ++ component_reg_phys); ++ if (rc) ++ return ERR_PTR(rc); ++ } else { + dport->rcrb.base = rcrb; + component_reg_phys = __rcrb_to_component(dport_dev, &dport->rcrb, + CXL_RCRB_DOWNSTREAM); +@@ -992,6 +1020,14 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, + return ERR_PTR(-ENXIO); + } + ++ /* ++ * RCH @dport is not ready to map until associated with its ++ * memdev ++ */ ++ rc = cxl_dport_setup_regs(NULL, dport, component_reg_phys); ++ if (rc) ++ return ERR_PTR(rc); ++ + dport->rch = true; + } + +@@ -999,14 +1035,6 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, + dev_dbg(dport_dev, "Component Registers found for dport: %pa\n", + &component_reg_phys); + +- dport->dport_dev = dport_dev; +- dport->port_id = port_id; +- dport->port = port; +- +- rc = cxl_dport_setup_regs(dport, component_reg_phys); +- if (rc) +- return ERR_PTR(rc); +- + cond_cxl_root_lock(port); + rc = add_dport(port, dport); + cond_cxl_root_unlock(port); +@@ -1217,35 +1245,39 @@ static struct device *grandparent(struct device *dev) + return NULL; + } + ++static struct device *endpoint_host(struct cxl_port *endpoint) ++{ ++ struct cxl_port *port = to_cxl_port(endpoint->dev.parent); ++ ++ if (is_cxl_root(port)) ++ return port->uport_dev; ++ return &port->dev; ++} ++ + static void delete_endpoint(void *data) + { + struct cxl_memdev *cxlmd = data; + struct cxl_port *endpoint = cxlmd->endpoint; +- struct cxl_port *parent_port; +- struct device *parent; +- +- parent_port = cxl_mem_find_port(cxlmd, NULL); +- if (!parent_port) +- goto out; +- parent = &parent_port->dev; ++ struct device *host = endpoint_host(endpoint); + +- device_lock(parent); +- if (parent->driver && !endpoint->dead) { +- devm_release_action(parent, cxl_unlink_parent_dport, endpoint); +- devm_release_action(parent, cxl_unlink_uport, endpoint); +- devm_release_action(parent, unregister_port, endpoint); ++ device_lock(host); ++ if (host->driver && !endpoint->dead) { ++ devm_release_action(host, cxl_unlink_parent_dport, endpoint); ++ devm_release_action(host, cxl_unlink_uport, endpoint); ++ devm_release_action(host, unregister_port, endpoint); + } + cxlmd->endpoint = NULL; +- device_unlock(parent); +- put_device(parent); +-out: ++ device_unlock(host); + put_device(&endpoint->dev); ++ put_device(host); + } + + int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint) + { ++ struct device *host = endpoint_host(endpoint); + struct device *dev = &cxlmd->dev; + ++ get_device(host); + get_device(&endpoint->dev); + cxlmd->endpoint = endpoint; + cxlmd->depth = endpoint->depth; +@@ -1543,7 +1575,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_mem_find_port, CXL); + static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd, + struct cxl_port *port, int *target_map) + { +- int i, rc = 0; ++ int i; + + if (!target_map) + return 0; +@@ -1553,19 +1585,16 @@ static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd, + if (xa_empty(&port->dports)) + return -EINVAL; + +- write_seqlock(&cxlsd->target_lock); +- for (i = 0; i < cxlsd->nr_targets; i++) { ++ guard(rwsem_write)(&cxl_region_rwsem); ++ for (i = 0; i < cxlsd->cxld.interleave_ways; i++) { + struct cxl_dport *dport = find_dport(port, target_map[i]); + +- if (!dport) { +- rc = -ENXIO; +- break; +- } ++ if (!dport) ++ return -ENXIO; + cxlsd->target[i] = dport; + } +- write_sequnlock(&cxlsd->target_lock); + +- return rc; ++ return 0; + } + + struct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos) +@@ -1635,7 +1664,6 @@ static int cxl_switch_decoder_init(struct cxl_port *port, + return -EINVAL; + + cxlsd->nr_targets = nr_targets; +- seqlock_init(&cxlsd->target_lock); + return cxl_decoder_init(port, &cxlsd->cxld); + } + +diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c +index 6d63b8798c2992..5060d9802795ee 100644 +--- a/drivers/cxl/core/region.c ++++ b/drivers/cxl/core/region.c +@@ -28,12 +28,6 @@ + * 3. Decoder targets + */ + +-/* +- * All changes to the interleave configuration occur with this lock held +- * for write. +- */ +-static DECLARE_RWSEM(cxl_region_rwsem); +- + static struct cxl_region *to_cxl_region(struct device *dev); + + static ssize_t uuid_show(struct device *dev, struct device_attribute *attr, +@@ -294,7 +288,7 @@ static ssize_t commit_store(struct device *dev, struct device_attribute *attr, + */ + rc = cxl_region_invalidate_memregion(cxlr); + if (rc) +- return rc; ++ goto out; + + if (commit) { + rc = cxl_region_decode_commit(cxlr); +@@ -403,7 +397,7 @@ static ssize_t interleave_ways_store(struct device *dev, + return rc; + + /* +- * Even for x3, x9, and x12 interleaves the region interleave must be a ++ * Even for x3, x6, and x12 interleaves the region interleave must be a + * power of 2 multiple of the host bridge interleave. + */ + if (!is_power_of_2(val / cxld->interleave_ways) || +@@ -531,7 +525,7 @@ static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size) + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent); + struct cxl_region_params *p = &cxlr->params; + struct resource *res; +- u32 remainder = 0; ++ u64 remainder = 0; + + lockdep_assert_held_write(&cxl_region_rwsem); + +@@ -551,7 +545,7 @@ static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size) + (cxlr->mode == CXL_DECODER_PMEM && uuid_is_null(&p->uuid))) + return -ENXIO; + +- div_u64_rem(size, SZ_256M * p->interleave_ways, &remainder); ++ div64_u64_rem(size, (u64)SZ_256M * p->interleave_ways, &remainder); + if (remainder) + return -EINVAL; + +@@ -735,12 +729,17 @@ static int match_auto_decoder(struct device *dev, void *data) + return 0; + } + +-static struct cxl_decoder *cxl_region_find_decoder(struct cxl_port *port, +- struct cxl_region *cxlr) ++static struct cxl_decoder * ++cxl_region_find_decoder(struct cxl_port *port, ++ struct cxl_endpoint_decoder *cxled, ++ struct cxl_region *cxlr) + { + struct device *dev; + int id = 0; + ++ if (port == cxled_to_port(cxled)) ++ return &cxled->cxld; ++ + if (test_bit(CXL_REGION_F_AUTO, &cxlr->flags)) + dev = device_find_child(&port->dev, &cxlr->params, + match_auto_decoder); +@@ -758,8 +757,31 @@ static struct cxl_decoder *cxl_region_find_decoder(struct cxl_port *port, + return to_cxl_decoder(dev); + } + +-static struct cxl_region_ref *alloc_region_ref(struct cxl_port *port, +- struct cxl_region *cxlr) ++static bool auto_order_ok(struct cxl_port *port, struct cxl_region *cxlr_iter, ++ struct cxl_decoder *cxld) ++{ ++ struct cxl_region_ref *rr = cxl_rr_load(port, cxlr_iter); ++ struct cxl_decoder *cxld_iter = rr->decoder; ++ ++ /* ++ * Allow the out of order assembly of auto-discovered regions. ++ * Per CXL Spec 3.1 8.2.4.20.12 software must commit decoders ++ * in HPA order. Confirm that the decoder with the lesser HPA ++ * starting address has the lesser id. ++ */ ++ dev_dbg(&cxld->dev, "check for HPA violation %s:%d < %s:%d\n", ++ dev_name(&cxld->dev), cxld->id, ++ dev_name(&cxld_iter->dev), cxld_iter->id); ++ ++ if (cxld_iter->id > cxld->id) ++ return true; ++ ++ return false; ++} ++ ++static struct cxl_region_ref * ++alloc_region_ref(struct cxl_port *port, struct cxl_region *cxlr, ++ struct cxl_endpoint_decoder *cxled) + { + struct cxl_region_params *p = &cxlr->params; + struct cxl_region_ref *cxl_rr, *iter; +@@ -769,16 +791,21 @@ static struct cxl_region_ref *alloc_region_ref(struct cxl_port *port, + xa_for_each(&port->regions, index, iter) { + struct cxl_region_params *ip = &iter->region->params; + +- if (!ip->res) ++ if (!ip->res || ip->res->start < p->res->start) + continue; + +- if (ip->res->start > p->res->start) { +- dev_dbg(&cxlr->dev, +- "%s: HPA order violation %s:%pr vs %pr\n", +- dev_name(&port->dev), +- dev_name(&iter->region->dev), ip->res, p->res); +- return ERR_PTR(-EBUSY); ++ if (test_bit(CXL_REGION_F_AUTO, &cxlr->flags)) { ++ struct cxl_decoder *cxld; ++ ++ cxld = cxl_region_find_decoder(port, cxled, cxlr); ++ if (auto_order_ok(port, iter->region, cxld)) ++ continue; + } ++ dev_dbg(&cxlr->dev, "%s: HPA order violation %s:%pr vs %pr\n", ++ dev_name(&port->dev), ++ dev_name(&iter->region->dev), ip->res, p->res); ++ ++ return ERR_PTR(-EBUSY); + } + + cxl_rr = kzalloc(sizeof(*cxl_rr), GFP_KERNEL); +@@ -858,10 +885,7 @@ static int cxl_rr_alloc_decoder(struct cxl_port *port, struct cxl_region *cxlr, + { + struct cxl_decoder *cxld; + +- if (port == cxled_to_port(cxled)) +- cxld = &cxled->cxld; +- else +- cxld = cxl_region_find_decoder(port, cxlr); ++ cxld = cxl_region_find_decoder(port, cxled, cxlr); + if (!cxld) { + dev_dbg(&cxlr->dev, "%s: no decoder available\n", + dev_name(&port->dev)); +@@ -958,7 +982,7 @@ static int cxl_port_attach_region(struct cxl_port *port, + nr_targets_inc = true; + } + } else { +- cxl_rr = alloc_region_ref(port, cxlr); ++ cxl_rr = alloc_region_ref(port, cxlr, cxled); + if (IS_ERR(cxl_rr)) { + dev_dbg(&cxlr->dev, + "%s: failed to allocate region reference\n", +@@ -973,6 +997,26 @@ static int cxl_port_attach_region(struct cxl_port *port, + } + cxld = cxl_rr->decoder; + ++ /* ++ * the number of targets should not exceed the target_count ++ * of the decoder ++ */ ++ if (is_switch_decoder(&cxld->dev)) { ++ struct cxl_switch_decoder *cxlsd; ++ ++ cxlsd = to_cxl_switch_decoder(&cxld->dev); ++ if (cxl_rr->nr_targets > cxlsd->nr_targets) { ++ dev_dbg(&cxlr->dev, ++ "%s:%s %s add: %s:%s @ %d overflows targets: %d\n", ++ dev_name(port->uport_dev), dev_name(&port->dev), ++ dev_name(&cxld->dev), dev_name(&cxlmd->dev), ++ dev_name(&cxled->cxld.dev), pos, ++ cxlsd->nr_targets); ++ rc = -ENXIO; ++ goto out_erase; ++ } ++ } ++ + rc = cxl_rr_ep_add(cxl_rr, cxled); + if (rc) { + dev_dbg(&cxlr->dev, +@@ -1082,6 +1126,50 @@ static int check_last_peer(struct cxl_endpoint_decoder *cxled, + return 0; + } + ++static int check_interleave_cap(struct cxl_decoder *cxld, int iw, int ig) ++{ ++ struct cxl_port *port = to_cxl_port(cxld->dev.parent); ++ struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev); ++ unsigned int interleave_mask; ++ u8 eiw; ++ u16 eig; ++ int high_pos, low_pos; ++ ++ if (!test_bit(iw, &cxlhdm->iw_cap_mask)) ++ return -ENXIO; ++ /* ++ * Per CXL specification r3.1(8.2.4.20.13 Decoder Protection), ++ * if eiw < 8: ++ * DPAOFFSET[51: eig + 8] = HPAOFFSET[51: eig + 8 + eiw] ++ * DPAOFFSET[eig + 7: 0] = HPAOFFSET[eig + 7: 0] ++ * ++ * when the eiw is 0, all the bits of HPAOFFSET[51: 0] are used, the ++ * interleave bits are none. ++ * ++ * if eiw >= 8: ++ * DPAOFFSET[51: eig + 8] = HPAOFFSET[51: eig + eiw] / 3 ++ * DPAOFFSET[eig + 7: 0] = HPAOFFSET[eig + 7: 0] ++ * ++ * when the eiw is 8, all the bits of HPAOFFSET[51: 0] are used, the ++ * interleave bits are none. ++ */ ++ ways_to_eiw(iw, &eiw); ++ if (eiw == 0 || eiw == 8) ++ return 0; ++ ++ granularity_to_eig(ig, &eig); ++ if (eiw > 8) ++ high_pos = eiw + eig - 1; ++ else ++ high_pos = eiw + eig + 7; ++ low_pos = eig + 8; ++ interleave_mask = GENMASK(high_pos, low_pos); ++ if (interleave_mask & ~cxlhdm->interleave_mask) ++ return -ENXIO; ++ ++ return 0; ++} ++ + static int cxl_port_setup_targets(struct cxl_port *port, + struct cxl_region *cxlr, + struct cxl_endpoint_decoder *cxled) +@@ -1133,7 +1221,14 @@ static int cxl_port_setup_targets(struct cxl_port *port, + } + + if (is_cxl_root(parent_port)) { +- parent_ig = cxlrd->cxlsd.cxld.interleave_granularity; ++ /* ++ * Root decoder IG is always set to value in CFMWS which ++ * may be different than this region's IG. We can use the ++ * region's IG here since interleave_granularity_store() ++ * does not allow interleaved host-bridges with ++ * root IG != region IG. ++ */ ++ parent_ig = p->interleave_granularity; + parent_iw = cxlrd->cxlsd.cxld.interleave_ways; + /* + * For purposes of address bit routing, use power-of-2 math for +@@ -1195,6 +1290,14 @@ static int cxl_port_setup_targets(struct cxl_port *port, + return rc; + } + ++ if (iw > 8 || iw > cxlsd->nr_targets) { ++ dev_dbg(&cxlr->dev, ++ "%s:%s:%s: ways: %d overflows targets: %d\n", ++ dev_name(port->uport_dev), dev_name(&port->dev), ++ dev_name(&cxld->dev), iw, cxlsd->nr_targets); ++ return -ENXIO; ++ } ++ + if (test_bit(CXL_REGION_F_AUTO, &cxlr->flags)) { + if (cxld->interleave_ways != iw || + cxld->interleave_granularity != ig || +@@ -1217,6 +1320,15 @@ static int cxl_port_setup_targets(struct cxl_port *port, + return -ENXIO; + } + } else { ++ rc = check_interleave_cap(cxld, iw, ig); ++ if (rc) { ++ dev_dbg(&cxlr->dev, ++ "%s:%s iw: %d ig: %d is not supported\n", ++ dev_name(port->uport_dev), ++ dev_name(&port->dev), iw, ig); ++ return rc; ++ } ++ + cxld->interleave_ways = iw; + cxld->interleave_granularity = ig; + cxld->hpa_range = (struct range) { +@@ -1416,10 +1528,13 @@ static int cxl_region_attach_position(struct cxl_region *cxlr, + const struct cxl_dport *dport, int pos) + { + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); ++ struct cxl_switch_decoder *cxlsd = &cxlrd->cxlsd; ++ struct cxl_decoder *cxld = &cxlsd->cxld; ++ int iw = cxld->interleave_ways; + struct cxl_port *iter; + int rc; + +- if (cxlrd->calc_hb(cxlrd, pos) != dport) { ++ if (dport != cxlrd->cxlsd.target[pos % iw]) { + dev_dbg(&cxlr->dev, "%s:%s invalid target position for %s\n", + dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), + dev_name(&cxlrd->cxlsd.cxld.dev)); +@@ -1480,6 +1595,14 @@ static int cxl_region_attach_auto(struct cxl_region *cxlr, + return 0; + } + ++static int cmp_interleave_pos(const void *a, const void *b) ++{ ++ struct cxl_endpoint_decoder *cxled_a = *(typeof(cxled_a) *)a; ++ struct cxl_endpoint_decoder *cxled_b = *(typeof(cxled_b) *)b; ++ ++ return cxled_a->pos - cxled_b->pos; ++} ++ + static struct cxl_port *next_port(struct cxl_port *port) + { + if (!port->parent_dport) +@@ -1487,119 +1610,127 @@ static struct cxl_port *next_port(struct cxl_port *port) + return port->parent_dport->port; + } + +-static int decoder_match_range(struct device *dev, void *data) ++static int match_switch_decoder_by_range(struct device *dev, void *data) + { +- struct cxl_endpoint_decoder *cxled = data; + struct cxl_switch_decoder *cxlsd; ++ struct range *r1, *r2 = data; + + if (!is_switch_decoder(dev)) + return 0; + + cxlsd = to_cxl_switch_decoder(dev); +- return range_contains(&cxlsd->cxld.hpa_range, &cxled->cxld.hpa_range); +-} ++ r1 = &cxlsd->cxld.hpa_range; + +-static void find_positions(const struct cxl_switch_decoder *cxlsd, +- const struct cxl_port *iter_a, +- const struct cxl_port *iter_b, int *a_pos, +- int *b_pos) +-{ +- int i; +- +- for (i = 0, *a_pos = -1, *b_pos = -1; i < cxlsd->nr_targets; i++) { +- if (cxlsd->target[i] == iter_a->parent_dport) +- *a_pos = i; +- else if (cxlsd->target[i] == iter_b->parent_dport) +- *b_pos = i; +- if (*a_pos >= 0 && *b_pos >= 0) +- break; +- } ++ if (is_root_decoder(dev)) ++ return range_contains(r1, r2); ++ return (r1->start == r2->start && r1->end == r2->end); + } + +-static int cmp_decode_pos(const void *a, const void *b) ++static int find_pos_and_ways(struct cxl_port *port, struct range *range, ++ int *pos, int *ways) + { +- struct cxl_endpoint_decoder *cxled_a = *(typeof(cxled_a) *)a; +- struct cxl_endpoint_decoder *cxled_b = *(typeof(cxled_b) *)b; +- struct cxl_memdev *cxlmd_a = cxled_to_memdev(cxled_a); +- struct cxl_memdev *cxlmd_b = cxled_to_memdev(cxled_b); +- struct cxl_port *port_a = cxled_to_port(cxled_a); +- struct cxl_port *port_b = cxled_to_port(cxled_b); +- struct cxl_port *iter_a, *iter_b, *port = NULL; + struct cxl_switch_decoder *cxlsd; ++ struct cxl_port *parent; + struct device *dev; +- int a_pos, b_pos; +- unsigned int seq; +- +- /* Exit early if any prior sorting failed */ +- if (cxled_a->pos < 0 || cxled_b->pos < 0) +- return 0; ++ int rc = -ENXIO; + +- /* +- * Walk up the hierarchy to find a shared port, find the decoder that +- * maps the range, compare the relative position of those dport +- * mappings. +- */ +- for (iter_a = port_a; iter_a; iter_a = next_port(iter_a)) { +- struct cxl_port *next_a, *next_b; ++ parent = next_port(port); ++ if (!parent) ++ return rc; + +- next_a = next_port(iter_a); +- if (!next_a) +- break; ++ dev = device_find_child(&parent->dev, range, ++ match_switch_decoder_by_range); ++ if (!dev) { ++ dev_err(port->uport_dev, ++ "failed to find decoder mapping %#llx-%#llx\n", ++ range->start, range->end); ++ return rc; ++ } ++ cxlsd = to_cxl_switch_decoder(dev); ++ *ways = cxlsd->cxld.interleave_ways; + +- for (iter_b = port_b; iter_b; iter_b = next_port(iter_b)) { +- next_b = next_port(iter_b); +- if (next_a != next_b) +- continue; +- port = next_a; ++ for (int i = 0; i < *ways; i++) { ++ if (cxlsd->target[i] == port->parent_dport) { ++ *pos = i; ++ rc = 0; + break; + } +- +- if (port) +- break; + } ++ put_device(dev); + +- if (!port) { +- dev_err(cxlmd_a->dev.parent, +- "failed to find shared port with %s\n", +- dev_name(cxlmd_b->dev.parent)); +- goto err; +- } ++ return rc; ++} + +- dev = device_find_child(&port->dev, cxled_a, decoder_match_range); +- if (!dev) { +- struct range *range = &cxled_a->cxld.hpa_range; ++/** ++ * cxl_calc_interleave_pos() - calculate an endpoint position in a region ++ * @cxled: endpoint decoder member of given region ++ * ++ * The endpoint position is calculated by traversing the topology from ++ * the endpoint to the root decoder and iteratively applying this ++ * calculation: ++ * ++ * position = position * parent_ways + parent_pos; ++ * ++ * ...where @position is inferred from switch and root decoder target lists. ++ * ++ * Return: position >= 0 on success ++ * -ENXIO on failure ++ */ ++static int cxl_calc_interleave_pos(struct cxl_endpoint_decoder *cxled) ++{ ++ struct cxl_port *iter, *port = cxled_to_port(cxled); ++ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); ++ struct range *range = &cxled->cxld.hpa_range; ++ int parent_ways = 0, parent_pos = 0, pos = 0; ++ int rc; + +- dev_err(port->uport_dev, +- "failed to find decoder that maps %#llx-%#llx\n", +- range->start, range->end); +- goto err; +- } ++ /* ++ * Example: the expected interleave order of the 4-way region shown ++ * below is: mem0, mem2, mem1, mem3 ++ * ++ * root_port ++ * / \ ++ * host_bridge_0 host_bridge_1 ++ * | | | | ++ * mem0 mem1 mem2 mem3 ++ * ++ * In the example the calculator will iterate twice. The first iteration ++ * uses the mem position in the host-bridge and the ways of the host- ++ * bridge to generate the first, or local, position. The second ++ * iteration uses the host-bridge position in the root_port and the ways ++ * of the root_port to refine the position. ++ * ++ * A trace of the calculation per endpoint looks like this: ++ * mem0: pos = 0 * 2 + 0 mem2: pos = 0 * 2 + 0 ++ * pos = 0 * 2 + 0 pos = 0 * 2 + 1 ++ * pos: 0 pos: 1 ++ * ++ * mem1: pos = 0 * 2 + 1 mem3: pos = 0 * 2 + 1 ++ * pos = 1 * 2 + 0 pos = 1 * 2 + 1 ++ * pos: 2 pos = 3 ++ * ++ * Note that while this example is simple, the method applies to more ++ * complex topologies, including those with switches. ++ */ + +- cxlsd = to_cxl_switch_decoder(dev); +- do { +- seq = read_seqbegin(&cxlsd->target_lock); +- find_positions(cxlsd, iter_a, iter_b, &a_pos, &b_pos); +- } while (read_seqretry(&cxlsd->target_lock, seq)); ++ /* Iterate from endpoint to root_port refining the position */ ++ for (iter = port; iter; iter = next_port(iter)) { ++ if (is_cxl_root(iter)) ++ break; + +- put_device(dev); ++ rc = find_pos_and_ways(iter, range, &parent_pos, &parent_ways); ++ if (rc) ++ return rc; + +- if (a_pos < 0 || b_pos < 0) { +- dev_err(port->uport_dev, +- "failed to find shared decoder for %s and %s\n", +- dev_name(cxlmd_a->dev.parent), +- dev_name(cxlmd_b->dev.parent)); +- goto err; ++ pos = pos * parent_ways + parent_pos; + } + +- dev_dbg(port->uport_dev, "%s comes %s %s\n", +- dev_name(cxlmd_a->dev.parent), +- a_pos - b_pos < 0 ? "before" : "after", +- dev_name(cxlmd_b->dev.parent)); ++ dev_dbg(&cxlmd->dev, ++ "decoder:%s parent:%s port:%s range:%#llx-%#llx pos:%d\n", ++ dev_name(&cxled->cxld.dev), dev_name(cxlmd->dev.parent), ++ dev_name(&port->dev), range->start, range->end, pos); + +- return a_pos - b_pos; +-err: +- cxled_a->pos = -1; +- return 0; ++ return pos; + } + + static int cxl_region_sort_targets(struct cxl_region *cxlr) +@@ -1607,22 +1738,21 @@ static int cxl_region_sort_targets(struct cxl_region *cxlr) + struct cxl_region_params *p = &cxlr->params; + int i, rc = 0; + +- sort(p->targets, p->nr_targets, sizeof(p->targets[0]), cmp_decode_pos, +- NULL); +- + for (i = 0; i < p->nr_targets; i++) { + struct cxl_endpoint_decoder *cxled = p->targets[i]; + ++ cxled->pos = cxl_calc_interleave_pos(cxled); + /* +- * Record that sorting failed, but still continue to restore +- * cxled->pos with its ->targets[] position so that follow-on +- * code paths can reliably do p->targets[cxled->pos] to +- * self-reference their entry. ++ * Record that sorting failed, but still continue to calc ++ * cxled->pos so that follow-on code paths can reliably ++ * do p->targets[cxled->pos] to self-reference their entry. + */ + if (cxled->pos < 0) + rc = -ENXIO; +- cxled->pos = i; + } ++ /* Keep the cxlr target list in interleave position order */ ++ sort(p->targets, p->nr_targets, sizeof(p->targets[0]), ++ cmp_interleave_pos, NULL); + + dev_dbg(&cxlr->dev, "region sort %s\n", rc ? "failed" : "successful"); + return rc; +@@ -1638,6 +1768,15 @@ static int cxl_region_attach(struct cxl_region *cxlr, + struct cxl_dport *dport; + int rc = -ENXIO; + ++ rc = check_interleave_cap(&cxled->cxld, p->interleave_ways, ++ p->interleave_granularity); ++ if (rc) { ++ dev_dbg(&cxlr->dev, "%s iw: %d ig: %d is not supported\n", ++ dev_name(&cxled->cxld.dev), p->interleave_ways, ++ p->interleave_granularity); ++ return rc; ++ } ++ + if (cxled->mode != cxlr->mode) { + dev_dbg(&cxlr->dev, "%s region mode: %d mismatch: %d\n", + dev_name(&cxled->cxld.dev), cxlr->mode, cxled->mode); +@@ -1658,6 +1797,12 @@ static int cxl_region_attach(struct cxl_region *cxlr, + return -ENXIO; + } + ++ if (p->nr_targets >= p->interleave_ways) { ++ dev_dbg(&cxlr->dev, "region already has %d endpoints\n", ++ p->nr_targets); ++ return -EINVAL; ++ } ++ + ep_port = cxled_to_port(cxled); + root_port = cxlrd_to_port(cxlrd); + dport = cxl_find_dport_by_dev(root_port, ep_port->host_bridge); +@@ -1750,7 +1895,7 @@ static int cxl_region_attach(struct cxl_region *cxlr, + if (p->nr_targets == p->interleave_ways) { + rc = cxl_region_setup_targets(cxlr); + if (rc) +- goto err_decrement; ++ return rc; + p->state = CXL_CONFIG_ACTIVE; + } + +@@ -1761,13 +1906,27 @@ static int cxl_region_attach(struct cxl_region *cxlr, + .end = p->res->end, + }; + +- return 0; ++ if (p->nr_targets != p->interleave_ways) ++ return 0; + +-err_decrement: +- p->nr_targets--; +- cxled->pos = -1; +- p->targets[pos] = NULL; +- return rc; ++ /* ++ * Test the auto-discovery position calculator function ++ * against this successfully created user-defined region. ++ * A fail message here means that this interleave config ++ * will fail when presented as CXL_REGION_F_AUTO. ++ */ ++ for (int i = 0; i < p->nr_targets; i++) { ++ struct cxl_endpoint_decoder *cxled = p->targets[i]; ++ int test_pos; ++ ++ test_pos = cxl_calc_interleave_pos(cxled); ++ dev_dbg(&cxled->cxld.dev, ++ "Test cxl_calc_interleave_pos(): %s test_pos:%d cxled->pos:%d\n", ++ (test_pos == cxled->pos) ? "success" : "fail", ++ test_pos, cxled->pos); ++ } ++ ++ return 0; + } + + static int cxl_region_detach(struct cxl_endpoint_decoder *cxled) +@@ -2112,15 +2271,6 @@ static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd, + struct device *dev; + int rc; + +- switch (mode) { +- case CXL_DECODER_RAM: +- case CXL_DECODER_PMEM: +- break; +- default: +- dev_err(&cxlrd->cxlsd.cxld.dev, "unsupported mode %d\n", mode); +- return ERR_PTR(-EINVAL); +- } +- + cxlr = cxl_region_alloc(cxlrd, id); + if (IS_ERR(cxlr)) + return cxlr; +@@ -2171,6 +2321,15 @@ static struct cxl_region *__create_region(struct cxl_root_decoder *cxlrd, + { + int rc; + ++ switch (mode) { ++ case CXL_DECODER_RAM: ++ case CXL_DECODER_PMEM: ++ break; ++ default: ++ dev_err(&cxlrd->cxlsd.cxld.dev, "unsupported mode %d\n", mode); ++ return ERR_PTR(-EINVAL); ++ } ++ + rc = memregion_alloc(GFP_KERNEL); + if (rc < 0) + return ERR_PTR(rc); +@@ -2423,10 +2582,6 @@ int cxl_get_poison_by_endpoint(struct cxl_port *port) + struct cxl_poison_context ctx; + int rc = 0; + +- rc = down_read_interruptible(&cxl_region_rwsem); +- if (rc) +- return rc; +- + ctx = (struct cxl_poison_context) { + .port = port + }; +@@ -2436,10 +2591,64 @@ int cxl_get_poison_by_endpoint(struct cxl_port *port) + rc = cxl_get_poison_unmapped(to_cxl_memdev(port->uport_dev), + &ctx); + +- up_read(&cxl_region_rwsem); + return rc; + } + ++struct cxl_dpa_to_region_context { ++ struct cxl_region *cxlr; ++ u64 dpa; ++}; ++ ++static int __cxl_dpa_to_region(struct device *dev, void *arg) ++{ ++ struct cxl_dpa_to_region_context *ctx = arg; ++ struct cxl_endpoint_decoder *cxled; ++ struct cxl_region *cxlr; ++ u64 dpa = ctx->dpa; ++ ++ if (!is_endpoint_decoder(dev)) ++ return 0; ++ ++ cxled = to_cxl_endpoint_decoder(dev); ++ if (!cxled || !cxled->dpa_res || !resource_size(cxled->dpa_res)) ++ return 0; ++ ++ if (dpa > cxled->dpa_res->end || dpa < cxled->dpa_res->start) ++ return 0; ++ ++ /* ++ * Stop the region search (return 1) when an endpoint mapping is ++ * found. The region may not be fully constructed so offering ++ * the cxlr in the context structure is not guaranteed. ++ */ ++ cxlr = cxled->cxld.region; ++ if (cxlr) ++ dev_dbg(dev, "dpa:0x%llx mapped in region:%s\n", dpa, ++ dev_name(&cxlr->dev)); ++ else ++ dev_dbg(dev, "dpa:0x%llx mapped in endpoint:%s\n", dpa, ++ dev_name(dev)); ++ ++ ctx->cxlr = cxlr; ++ ++ return 1; ++} ++ ++struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa) ++{ ++ struct cxl_dpa_to_region_context ctx; ++ struct cxl_port *port; ++ ++ ctx = (struct cxl_dpa_to_region_context) { ++ .dpa = dpa, ++ }; ++ port = cxlmd->endpoint; ++ if (port && is_cxl_endpoint(port) && cxl_num_decoders_committed(port)) ++ device_for_each_child(&port->dev, &ctx, __cxl_dpa_to_region); ++ ++ return ctx.cxlr; ++} ++ + static struct lock_class_key cxl_pmem_region_key; + + static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr) +@@ -2480,6 +2689,7 @@ static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr) + if (i == 0) { + cxl_nvb = cxl_find_nvdimm_bridge(cxlmd); + if (!cxl_nvb) { ++ kfree(cxlr_pmem); + cxlr_pmem = ERR_PTR(-ENODEV); + goto out; + } +@@ -2696,7 +2906,7 @@ static int devm_cxl_add_dax_region(struct cxl_region *cxlr) + return rc; + } + +-static int match_decoder_by_range(struct device *dev, void *data) ++static int match_root_decoder_by_range(struct device *dev, void *data) + { + struct range *r1, *r2 = data; + struct cxl_root_decoder *cxlrd; +@@ -2827,7 +3037,7 @@ int cxl_add_to_region(struct cxl_port *root, struct cxl_endpoint_decoder *cxled) + int rc; + + cxlrd_dev = device_find_child(&root->dev, &cxld->hpa_range, +- match_decoder_by_range); ++ match_root_decoder_by_range); + if (!cxlrd_dev) { + dev_err(cxlmd->dev.parent, + "%s:%s no CXL window for range %#llx:%#llx\n", +diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c +index 6281127b3e9d97..bab4592db647f7 100644 +--- a/drivers/cxl/core/regs.c ++++ b/drivers/cxl/core/regs.c +@@ -204,7 +204,7 @@ int cxl_map_component_regs(const struct cxl_register_map *map, + struct cxl_component_regs *regs, + unsigned long map_mask) + { +- struct device *dev = map->dev; ++ struct device *host = map->host; + struct mapinfo { + const struct cxl_reg_map *rmap; + void __iomem **addr; +@@ -225,7 +225,7 @@ int cxl_map_component_regs(const struct cxl_register_map *map, + continue; + phys_addr = map->resource + mi->rmap->offset; + length = mi->rmap->size; +- *(mi->addr) = devm_cxl_iomap_block(dev, phys_addr, length); ++ *(mi->addr) = devm_cxl_iomap_block(host, phys_addr, length); + if (!*(mi->addr)) + return -ENOMEM; + } +@@ -237,7 +237,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_map_component_regs, CXL); + int cxl_map_device_regs(const struct cxl_register_map *map, + struct cxl_device_regs *regs) + { +- struct device *dev = map->dev; ++ struct device *host = map->host; + resource_size_t phys_addr = map->resource; + struct mapinfo { + const struct cxl_reg_map *rmap; +@@ -259,7 +259,7 @@ int cxl_map_device_regs(const struct cxl_register_map *map, + + addr = phys_addr + mi->rmap->offset; + length = mi->rmap->size; +- *(mi->addr) = devm_cxl_iomap_block(dev, addr, length); ++ *(mi->addr) = devm_cxl_iomap_block(host, addr, length); + if (!*(mi->addr)) + return -ENOMEM; + } +@@ -271,6 +271,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_map_device_regs, CXL); + static bool cxl_decode_regblock(struct pci_dev *pdev, u32 reg_lo, u32 reg_hi, + struct cxl_register_map *map) + { ++ u8 reg_type = FIELD_GET(CXL_DVSEC_REG_LOCATOR_BLOCK_ID_MASK, reg_lo); + int bar = FIELD_GET(CXL_DVSEC_REG_LOCATOR_BIR_MASK, reg_lo); + u64 offset = ((u64)reg_hi << 32) | + (reg_lo & CXL_DVSEC_REG_LOCATOR_BLOCK_OFF_LOW_MASK); +@@ -278,11 +279,11 @@ static bool cxl_decode_regblock(struct pci_dev *pdev, u32 reg_lo, u32 reg_hi, + if (offset > pci_resource_len(pdev, bar)) { + dev_warn(&pdev->dev, + "BAR%d: %pr: too small (offset: %pa, type: %d)\n", bar, +- &pdev->resource[bar], &offset, map->reg_type); ++ &pdev->resource[bar], &offset, reg_type); + return false; + } + +- map->reg_type = FIELD_GET(CXL_DVSEC_REG_LOCATOR_BLOCK_ID_MASK, reg_lo); ++ map->reg_type = reg_type; + map->resource = pci_resource_start(pdev, bar) + offset; + map->max_size = pci_resource_len(pdev, bar) - offset; + return true; +@@ -309,7 +310,7 @@ int cxl_find_regblock_instance(struct pci_dev *pdev, enum cxl_regloc_type type, + int regloc, i; + + *map = (struct cxl_register_map) { +- .dev = &pdev->dev, ++ .host = &pdev->dev, + .resource = CXL_RESOURCE_NONE, + }; + +@@ -403,15 +404,15 @@ EXPORT_SYMBOL_NS_GPL(cxl_map_pmu_regs, CXL); + + static int cxl_map_regblock(struct cxl_register_map *map) + { +- struct device *dev = map->dev; ++ struct device *host = map->host; + + map->base = ioremap(map->resource, map->max_size); + if (!map->base) { +- dev_err(dev, "failed to map registers\n"); ++ dev_err(host, "failed to map registers\n"); + return -ENOMEM; + } + +- dev_dbg(dev, "Mapped CXL Memory Device resource %pa\n", &map->resource); ++ dev_dbg(host, "Mapped CXL Memory Device resource %pa\n", &map->resource); + return 0; + } + +@@ -425,28 +426,28 @@ static int cxl_probe_regs(struct cxl_register_map *map) + { + struct cxl_component_reg_map *comp_map; + struct cxl_device_reg_map *dev_map; +- struct device *dev = map->dev; ++ struct device *host = map->host; + void __iomem *base = map->base; + + switch (map->reg_type) { + case CXL_REGLOC_RBI_COMPONENT: + comp_map = &map->component_map; +- cxl_probe_component_regs(dev, base, comp_map); +- dev_dbg(dev, "Set up component registers\n"); ++ cxl_probe_component_regs(host, base, comp_map); ++ dev_dbg(host, "Set up component registers\n"); + break; + case CXL_REGLOC_RBI_MEMDEV: + dev_map = &map->device_map; +- cxl_probe_device_regs(dev, base, dev_map); ++ cxl_probe_device_regs(host, base, dev_map); + if (!dev_map->status.valid || !dev_map->mbox.valid || + !dev_map->memdev.valid) { +- dev_err(dev, "registers not found: %s%s%s\n", ++ dev_err(host, "registers not found: %s%s%s\n", + !dev_map->status.valid ? "status " : "", + !dev_map->mbox.valid ? "mbox " : "", + !dev_map->memdev.valid ? "memdev " : ""); + return -ENXIO; + } + +- dev_dbg(dev, "Probing device registers...\n"); ++ dev_dbg(host, "Probing device registers...\n"); + break; + default: + break; +diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h +index a0b5819bc70b30..bdf24867d5174c 100644 +--- a/drivers/cxl/core/trace.h ++++ b/drivers/cxl/core/trace.h +@@ -252,8 +252,8 @@ TRACE_EVENT(cxl_generic_event, + * DRAM Event Record + * CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44 + */ +-#define CXL_DPA_FLAGS_MASK 0x3F +-#define CXL_DPA_MASK (~CXL_DPA_FLAGS_MASK) ++#define CXL_DPA_FLAGS_MASK GENMASK(1, 0) ++#define CXL_DPA_MASK GENMASK_ULL(63, 6) + + #define CXL_DPA_VOLATILE BIT(0) + #define CXL_DPA_NOT_REPAIRABLE BIT(1) +@@ -642,18 +642,18 @@ u64 cxl_trace_hpa(struct cxl_region *cxlr, struct cxl_memdev *memdev, u64 dpa); + + TRACE_EVENT(cxl_poison, + +- TP_PROTO(struct cxl_memdev *cxlmd, struct cxl_region *region, ++ TP_PROTO(struct cxl_memdev *cxlmd, struct cxl_region *cxlr, + const struct cxl_poison_record *record, u8 flags, + __le64 overflow_ts, enum cxl_poison_trace_type trace_type), + +- TP_ARGS(cxlmd, region, record, flags, overflow_ts, trace_type), ++ TP_ARGS(cxlmd, cxlr, record, flags, overflow_ts, trace_type), + + TP_STRUCT__entry( + __string(memdev, dev_name(&cxlmd->dev)) + __string(host, dev_name(cxlmd->dev.parent)) + __field(u64, serial) + __field(u8, trace_type) +- __string(region, region) ++ __string(region, cxlr ? dev_name(&cxlr->dev) : "") + __field(u64, overflow_ts) + __field(u64, hpa) + __field(u64, dpa) +@@ -673,10 +673,10 @@ TRACE_EVENT(cxl_poison, + __entry->source = cxl_poison_record_source(record); + __entry->trace_type = trace_type; + __entry->flags = flags; +- if (region) { +- __assign_str(region, dev_name(®ion->dev)); +- memcpy(__entry->uuid, ®ion->params.uuid, 16); +- __entry->hpa = cxl_trace_hpa(region, cxlmd, ++ if (cxlr) { ++ __assign_str(region, dev_name(&cxlr->dev)); ++ memcpy(__entry->uuid, &cxlr->params.uuid, 16); ++ __entry->hpa = cxl_trace_hpa(cxlr, cxlmd, + __entry->dpa); + } else { + __assign_str(region, ""); +diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h +index 76d92561af2949..bb3ad219b6b316 100644 +--- a/drivers/cxl/cxl.h ++++ b/drivers/cxl/cxl.h +@@ -43,6 +43,8 @@ + #define CXL_HDM_DECODER_TARGET_COUNT_MASK GENMASK(7, 4) + #define CXL_HDM_DECODER_INTERLEAVE_11_8 BIT(8) + #define CXL_HDM_DECODER_INTERLEAVE_14_12 BIT(9) ++#define CXL_HDM_DECODER_INTERLEAVE_3_6_12_WAY BIT(11) ++#define CXL_HDM_DECODER_INTERLEAVE_16_WAY BIT(12) + #define CXL_HDM_DECODER_CTRL_OFFSET 0x4 + #define CXL_HDM_DECODER_ENABLE BIT(1) + #define CXL_HDM_DECODER0_BASE_LOW_OFFSET(i) (0x20 * (i) + 0x10) +@@ -247,7 +249,7 @@ struct cxl_pmu_reg_map { + + /** + * struct cxl_register_map - DVSEC harvested register block mapping parameters +- * @dev: device for devm operations and logging ++ * @host: device for devm operations and logging + * @base: virtual base of the register-block-BAR + @block_offset + * @resource: physical resource base of the register block + * @max_size: maximum mapping size to perform register search +@@ -257,7 +259,7 @@ struct cxl_pmu_reg_map { + * @pmu_map: cxl_reg_maps for CXL Performance Monitoring Units + */ + struct cxl_register_map { +- struct device *dev; ++ struct device *host; + void __iomem *base; + resource_size_t resource; + resource_size_t max_size; +@@ -404,7 +406,6 @@ struct cxl_endpoint_decoder { + /** + * struct cxl_switch_decoder - Switch specific CXL HDM Decoder + * @cxld: base cxl_decoder object +- * @target_lock: coordinate coherent reads of the target list + * @nr_targets: number of elements in @target + * @target: active ordered target list in current decoder configuration + * +@@ -416,7 +417,6 @@ struct cxl_endpoint_decoder { + */ + struct cxl_switch_decoder { + struct cxl_decoder cxld; +- seqlock_t target_lock; + int nr_targets; + struct cxl_dport *target[]; + }; +@@ -679,6 +679,7 @@ static inline bool is_cxl_root(struct cxl_port *port) + return port->uport_dev == port->dev.parent; + } + ++int cxl_num_decoders_committed(struct cxl_port *port); + bool is_cxl_port(const struct device *dev); + struct cxl_port *to_cxl_port(const struct device *dev); + struct pci_bus; +diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h +index 706f8a6d1ef43c..edb46123e3eb0f 100644 +--- a/drivers/cxl/cxlmem.h ++++ b/drivers/cxl/cxlmem.h +@@ -84,9 +84,12 @@ static inline bool is_cxl_endpoint(struct cxl_port *port) + return is_cxl_memdev(port->uport_dev); + } + +-struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds); ++struct cxl_memdev *devm_cxl_add_memdev(struct device *host, ++ struct cxl_dev_state *cxlds); ++int devm_cxl_sanitize_setup_notifier(struct device *host, ++ struct cxl_memdev *cxlmd); + struct cxl_memdev_state; +-int cxl_memdev_setup_fw_upload(struct cxl_memdev_state *mds); ++int devm_cxl_setup_fw_upload(struct device *host, struct cxl_memdev_state *mds); + int devm_cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled, + resource_size_t base, resource_size_t len, + resource_size_t skipped); +@@ -360,16 +363,16 @@ struct cxl_fw_state { + * + * @state: state of last security operation + * @enabled_cmds: All security commands enabled in the CEL +- * @poll: polling for sanitization is enabled, device has no mbox irq support + * @poll_tmo_secs: polling timeout ++ * @sanitize_active: sanitize completion pending + * @poll_dwork: polling work item + * @sanitize_node: sanitation sysfs file to notify + */ + struct cxl_security_state { + unsigned long state; + DECLARE_BITMAP(enabled_cmds, CXL_SEC_ENABLED_MAX); +- bool poll; + int poll_tmo_secs; ++ bool sanitize_active; + struct delayed_work poll_dwork; + struct kernfs_node *sanitize_node; + }; +@@ -535,7 +538,7 @@ enum cxl_opcode { + 0x3b, 0x3f, 0x17) + + #define DEFINE_CXL_VENDOR_DEBUG_UUID \ +- UUID_INIT(0xe1819d9, 0x11a9, 0x400c, 0x81, 0x1f, 0xd6, 0x07, 0x19, \ ++ UUID_INIT(0x5e1819d9, 0x11a9, 0x400c, 0x81, 0x1f, 0xd6, 0x07, 0x19, \ + 0x40, 0x3d, 0x86) + + struct cxl_mbox_get_supported_logs { +@@ -883,13 +886,23 @@ static inline void cxl_mem_active_dec(void) + } + #endif + +-int cxl_mem_sanitize(struct cxl_memdev_state *mds, u16 cmd); ++int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd); + ++/** ++ * struct cxl_hdm - HDM Decoder registers and cached / decoded capabilities ++ * @regs: mapped registers, see devm_cxl_setup_hdm() ++ * @decoder_count: number of decoders for this port ++ * @target_count: for switch decoders, max downstream port targets ++ * @interleave_mask: interleave granularity capability, see check_interleave_cap() ++ * @iw_cap_mask: bitmask of supported interleave ways, see check_interleave_cap() ++ * @port: mapped cxl_port, see devm_cxl_setup_hdm() ++ */ + struct cxl_hdm { + struct cxl_component_regs regs; + unsigned int decoder_count; + unsigned int target_count; + unsigned int interleave_mask; ++ unsigned long iw_cap_mask; + struct cxl_port *port; + }; + +diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c +index 44a21ab7add51b..8bece1e2e2491d 100644 +--- a/drivers/cxl/pci.c ++++ b/drivers/cxl/pci.c +@@ -128,10 +128,10 @@ static irqreturn_t cxl_pci_mbox_irq(int irq, void *id) + reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_BG_CMD_STATUS_OFFSET); + opcode = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_OPCODE_MASK, reg); + if (opcode == CXL_MBOX_OP_SANITIZE) { ++ mutex_lock(&mds->mbox_mutex); + if (mds->security.sanitize_node) +- sysfs_notify_dirent(mds->security.sanitize_node); +- +- dev_dbg(cxlds->dev, "Sanitization operation ended\n"); ++ mod_delayed_work(system_wq, &mds->security.poll_dwork, 0); ++ mutex_unlock(&mds->mbox_mutex); + } else { + /* short-circuit the wait in __cxl_pci_mbox_send_cmd() */ + rcuwait_wake_up(&mds->mbox_wait); +@@ -152,18 +152,16 @@ static void cxl_mbox_sanitize_work(struct work_struct *work) + mutex_lock(&mds->mbox_mutex); + if (cxl_mbox_background_complete(cxlds)) { + mds->security.poll_tmo_secs = 0; +- put_device(cxlds->dev); +- + if (mds->security.sanitize_node) + sysfs_notify_dirent(mds->security.sanitize_node); ++ mds->security.sanitize_active = false; + + dev_dbg(cxlds->dev, "Sanitization operation ended\n"); + } else { + int timeout = mds->security.poll_tmo_secs + 10; + + mds->security.poll_tmo_secs = min(15 * 60, timeout); +- queue_delayed_work(system_wq, &mds->security.poll_dwork, +- timeout * HZ); ++ schedule_delayed_work(&mds->security.poll_dwork, timeout * HZ); + } + mutex_unlock(&mds->mbox_mutex); + } +@@ -295,18 +293,15 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_memdev_state *mds, + * and allow userspace to poll(2) for completion. + */ + if (mbox_cmd->opcode == CXL_MBOX_OP_SANITIZE) { +- if (mds->security.poll) { +- /* hold the device throughout */ +- get_device(cxlds->dev); +- +- /* give first timeout a second */ +- timeout = 1; +- mds->security.poll_tmo_secs = timeout; +- queue_delayed_work(system_wq, +- &mds->security.poll_dwork, +- timeout * HZ); +- } +- ++ if (mds->security.sanitize_active) ++ return -EBUSY; ++ ++ /* give first timeout a second */ ++ timeout = 1; ++ mds->security.poll_tmo_secs = timeout; ++ mds->security.sanitize_active = true; ++ schedule_delayed_work(&mds->security.poll_dwork, ++ timeout * HZ); + dev_dbg(dev, "Sanitization operation started\n"); + goto success; + } +@@ -389,7 +384,9 @@ static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds) + const int cap = readl(cxlds->regs.mbox + CXLDEV_MBOX_CAPS_OFFSET); + struct device *dev = cxlds->dev; + unsigned long timeout; ++ int irq, msgnum; + u64 md_status; ++ u32 ctrl; + + timeout = jiffies + mbox_ready_timeout * HZ; + do { +@@ -437,33 +434,26 @@ static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds) + dev_dbg(dev, "Mailbox payload sized %zu", mds->payload_size); + + rcuwait_init(&mds->mbox_wait); ++ INIT_DELAYED_WORK(&mds->security.poll_dwork, cxl_mbox_sanitize_work); + +- if (cap & CXLDEV_MBOX_CAP_BG_CMD_IRQ) { +- u32 ctrl; +- int irq, msgnum; +- struct pci_dev *pdev = to_pci_dev(cxlds->dev); +- +- msgnum = FIELD_GET(CXLDEV_MBOX_CAP_IRQ_MSGNUM_MASK, cap); +- irq = pci_irq_vector(pdev, msgnum); +- if (irq < 0) +- goto mbox_poll; +- +- if (cxl_request_irq(cxlds, irq, cxl_pci_mbox_irq, NULL)) +- goto mbox_poll; ++ /* background command interrupts are optional */ ++ if (!(cap & CXLDEV_MBOX_CAP_BG_CMD_IRQ)) ++ return 0; + +- /* enable background command mbox irq support */ +- ctrl = readl(cxlds->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET); +- ctrl |= CXLDEV_MBOX_CTRL_BG_CMD_IRQ; +- writel(ctrl, cxlds->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET); ++ msgnum = FIELD_GET(CXLDEV_MBOX_CAP_IRQ_MSGNUM_MASK, cap); ++ irq = pci_irq_vector(to_pci_dev(cxlds->dev), msgnum); ++ if (irq < 0) ++ return 0; + ++ if (cxl_request_irq(cxlds, irq, NULL, cxl_pci_mbox_irq)) + return 0; +- } + +-mbox_poll: +- mds->security.poll = true; +- INIT_DELAYED_WORK(&mds->security.poll_dwork, cxl_mbox_sanitize_work); ++ dev_dbg(cxlds->dev, "Mailbox interrupts enabled\n"); ++ /* enable background command mbox irq support */ ++ ctrl = readl(cxlds->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET); ++ ctrl |= CXLDEV_MBOX_CTRL_BG_CMD_IRQ; ++ writel(ctrl, cxlds->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET); + +- dev_dbg(cxlds->dev, "Mailbox interrupts are unsupported"); + return 0; + } + +@@ -484,7 +474,7 @@ static int cxl_rcrb_get_comp_regs(struct pci_dev *pdev, + resource_size_t component_reg_phys; + + *map = (struct cxl_register_map) { +- .dev = &pdev->dev, ++ .host = &pdev->dev, + .resource = CXL_RESOURCE_NONE, + }; + +@@ -882,11 +872,15 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) + if (rc) + return rc; + +- cxlmd = devm_cxl_add_memdev(cxlds); ++ cxlmd = devm_cxl_add_memdev(&pdev->dev, cxlds); + if (IS_ERR(cxlmd)) + return PTR_ERR(cxlmd); + +- rc = cxl_memdev_setup_fw_upload(mds); ++ rc = devm_cxl_setup_fw_upload(&pdev->dev, mds); ++ if (rc) ++ return rc; ++ ++ rc = devm_cxl_sanitize_setup_notifier(&pdev->dev, cxlmd); + if (rc) + return rc; + +diff --git a/drivers/dax/device.c b/drivers/dax/device.c +index 93ebedc5ec8ca3..01e89b7ac637f2 100644 +--- a/drivers/dax/device.c ++++ b/drivers/dax/device.c +@@ -86,7 +86,7 @@ static void dax_set_mapping(struct vm_fault *vmf, pfn_t pfn, + nr_pages = 1; + + pgoff = linear_page_index(vmf->vma, +- ALIGN(vmf->address, fault_size)); ++ ALIGN_DOWN(vmf->address, fault_size)); + + for (i = 0; i < nr_pages; i++) { + struct page *page = pfn_to_page(pfn_t_to_pfn(pfn) + i); +diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c +index 474d81831ad36b..49c542ecccde3b 100644 +--- a/drivers/devfreq/devfreq.c ++++ b/drivers/devfreq/devfreq.c +@@ -461,10 +461,14 @@ static void devfreq_monitor(struct work_struct *work) + if (err) + dev_err(&devfreq->dev, "dvfs failed with (%d) error\n", err); + ++ if (devfreq->stop_polling) ++ goto out; ++ + queue_delayed_work(devfreq_wq, &devfreq->work, + msecs_to_jiffies(devfreq->profile->polling_ms)); +- mutex_unlock(&devfreq->lock); + ++out: ++ mutex_unlock(&devfreq->lock); + trace_devfreq_monitor(devfreq); + } + +@@ -483,6 +487,10 @@ void devfreq_monitor_start(struct devfreq *devfreq) + if (IS_SUPPORTED_FLAG(devfreq->governor->flags, IRQ_DRIVEN)) + return; + ++ mutex_lock(&devfreq->lock); ++ if (delayed_work_pending(&devfreq->work)) ++ goto out; ++ + switch (devfreq->profile->timer) { + case DEVFREQ_TIMER_DEFERRABLE: + INIT_DEFERRABLE_WORK(&devfreq->work, devfreq_monitor); +@@ -491,12 +499,16 @@ void devfreq_monitor_start(struct devfreq *devfreq) + INIT_DELAYED_WORK(&devfreq->work, devfreq_monitor); + break; + default: +- return; ++ goto out; + } + + if (devfreq->profile->polling_ms) + queue_delayed_work(devfreq_wq, &devfreq->work, + msecs_to_jiffies(devfreq->profile->polling_ms)); ++ ++out: ++ devfreq->stop_polling = false; ++ mutex_unlock(&devfreq->lock); + } + EXPORT_SYMBOL(devfreq_monitor_start); + +@@ -513,6 +525,14 @@ void devfreq_monitor_stop(struct devfreq *devfreq) + if (IS_SUPPORTED_FLAG(devfreq->governor->flags, IRQ_DRIVEN)) + return; + ++ mutex_lock(&devfreq->lock); ++ if (devfreq->stop_polling) { ++ mutex_unlock(&devfreq->lock); ++ return; ++ } ++ ++ devfreq->stop_polling = true; ++ mutex_unlock(&devfreq->lock); + cancel_delayed_work_sync(&devfreq->work); + } + EXPORT_SYMBOL(devfreq_monitor_stop); +@@ -1688,7 +1708,7 @@ static ssize_t trans_stat_show(struct device *dev, + struct device_attribute *attr, char *buf) + { + struct devfreq *df = to_devfreq(dev); +- ssize_t len; ++ ssize_t len = 0; + int i, j; + unsigned int max_state; + +@@ -1697,7 +1717,7 @@ static ssize_t trans_stat_show(struct device *dev, + max_state = df->max_state; + + if (max_state == 0) +- return sprintf(buf, "Not Supported.\n"); ++ return scnprintf(buf, PAGE_SIZE, "Not Supported.\n"); + + mutex_lock(&df->lock); + if (!df->stop_polling && +@@ -1707,31 +1727,52 @@ static ssize_t trans_stat_show(struct device *dev, + } + mutex_unlock(&df->lock); + +- len = sprintf(buf, " From : To\n"); +- len += sprintf(buf + len, " :"); +- for (i = 0; i < max_state; i++) +- len += sprintf(buf + len, "%10lu", +- df->freq_table[i]); ++ len += scnprintf(buf + len, PAGE_SIZE - len, " From : To\n"); ++ len += scnprintf(buf + len, PAGE_SIZE - len, " :"); ++ for (i = 0; i < max_state; i++) { ++ if (len >= PAGE_SIZE - 1) ++ break; ++ len += scnprintf(buf + len, PAGE_SIZE - len, "%10lu", ++ df->freq_table[i]); ++ } ++ if (len >= PAGE_SIZE - 1) ++ return PAGE_SIZE - 1; + +- len += sprintf(buf + len, " time(ms)\n"); ++ len += scnprintf(buf + len, PAGE_SIZE - len, " time(ms)\n"); + + for (i = 0; i < max_state; i++) { ++ if (len >= PAGE_SIZE - 1) ++ break; + if (df->freq_table[i] == df->previous_freq) +- len += sprintf(buf + len, "*"); ++ len += scnprintf(buf + len, PAGE_SIZE - len, "*"); + else +- len += sprintf(buf + len, " "); ++ len += scnprintf(buf + len, PAGE_SIZE - len, " "); ++ if (len >= PAGE_SIZE - 1) ++ break; ++ ++ len += scnprintf(buf + len, PAGE_SIZE - len, "%10lu:", ++ df->freq_table[i]); ++ for (j = 0; j < max_state; j++) { ++ if (len >= PAGE_SIZE - 1) ++ break; ++ len += scnprintf(buf + len, PAGE_SIZE - len, "%10u", ++ df->stats.trans_table[(i * max_state) + j]); ++ } ++ if (len >= PAGE_SIZE - 1) ++ break; ++ len += scnprintf(buf + len, PAGE_SIZE - len, "%10llu\n", (u64) ++ jiffies64_to_msecs(df->stats.time_in_state[i])); ++ } + +- len += sprintf(buf + len, "%10lu:", df->freq_table[i]); +- for (j = 0; j < max_state; j++) +- len += sprintf(buf + len, "%10u", +- df->stats.trans_table[(i * max_state) + j]); ++ if (len < PAGE_SIZE - 1) ++ len += scnprintf(buf + len, PAGE_SIZE - len, "Total transition : %u\n", ++ df->stats.total_trans); + +- len += sprintf(buf + len, "%10llu\n", (u64) +- jiffies64_to_msecs(df->stats.time_in_state[i])); ++ if (len >= PAGE_SIZE - 1) { ++ pr_warn_once("devfreq transition table exceeds PAGE_SIZE. Disabling\n"); ++ return -EFBIG; + } + +- len += sprintf(buf + len, "Total transition : %u\n", +- df->stats.total_trans); + return len; + } + +diff --git a/drivers/devfreq/event/rockchip-dfi.c b/drivers/devfreq/event/rockchip-dfi.c +index 39ac069cabc756..74893c06aa087f 100644 +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -193,14 +193,15 @@ static int rockchip_dfi_probe(struct platform_device *pdev) + return dev_err_probe(dev, PTR_ERR(data->clk), + "Cannot get the clk pclk_ddr_mon\n"); + +- /* try to find the optional reference to the pmu syscon */ + node = of_parse_phandle(np, "rockchip,pmu", 0); +- if (node) { +- data->regmap_pmu = syscon_node_to_regmap(node); +- of_node_put(node); +- if (IS_ERR(data->regmap_pmu)) +- return PTR_ERR(data->regmap_pmu); +- } ++ if (!node) ++ return dev_err_probe(&pdev->dev, -ENODEV, "Can't find pmu_grf registers\n"); ++ ++ data->regmap_pmu = syscon_node_to_regmap(node); ++ of_node_put(node); ++ if (IS_ERR(data->regmap_pmu)) ++ return PTR_ERR(data->regmap_pmu); ++ + data->dev = dev; + + desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); +diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c +index 38b4110378de05..eb8b733065b24d 100644 +--- a/drivers/dma-buf/dma-resv.c ++++ b/drivers/dma-buf/dma-resv.c +@@ -301,7 +301,7 @@ void dma_resv_add_fence(struct dma_resv *obj, struct dma_fence *fence, + + dma_resv_list_entry(fobj, i, obj, &old, &old_usage); + if ((old->context == fence->context && old_usage >= usage && +- dma_fence_is_later(fence, old)) || ++ dma_fence_is_later_or_same(fence, old)) || + dma_fence_is_signaled(old)) { + dma_resv_list_set(fobj, i, fence, usage); + dma_fence_put(old); +diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c +index ee899f8e67215f..bea7e574f916e1 100644 +--- a/drivers/dma-buf/heaps/cma_heap.c ++++ b/drivers/dma-buf/heaps/cma_heap.c +@@ -165,7 +165,7 @@ static vm_fault_t cma_heap_vm_fault(struct vm_fault *vmf) + struct vm_area_struct *vma = vmf->vma; + struct cma_heap_buffer *buffer = vma->vm_private_data; + +- if (vmf->pgoff > buffer->pagecount) ++ if (vmf->pgoff >= buffer->pagecount) + return VM_FAULT_SIGBUS; + + vmf->page = buffer->pages[vmf->pgoff]; +diff --git a/drivers/dma-buf/st-dma-fence-chain.c b/drivers/dma-buf/st-dma-fence-chain.c +index c0979c8049b5a3..ed4b323886e430 100644 +--- a/drivers/dma-buf/st-dma-fence-chain.c ++++ b/drivers/dma-buf/st-dma-fence-chain.c +@@ -84,11 +84,11 @@ static int sanitycheck(void *arg) + return -ENOMEM; + + chain = mock_chain(NULL, f, 1); +- if (!chain) ++ if (chain) ++ dma_fence_enable_sw_signaling(chain); ++ else + err = -ENOMEM; + +- dma_fence_enable_sw_signaling(chain); +- + dma_fence_signal(f); + dma_fence_put(f); + +@@ -476,10 +476,9 @@ static int find_race(void *arg) + for (i = 0; i < ncpus; i++) { + int ret; + +- ret = kthread_stop(threads[i]); ++ ret = kthread_stop_put(threads[i]); + if (ret && !err) + err = ret; +- put_task_struct(threads[i]); + } + kfree(threads); + +@@ -591,8 +590,7 @@ static int wait_forward(void *arg) + for (i = 0; i < fc.chain_length; i++) + dma_fence_signal(fc.fences[i]); + +- err = kthread_stop(tsk); +- put_task_struct(tsk); ++ err = kthread_stop_put(tsk); + + err: + fence_chains_fini(&fc); +@@ -621,8 +619,7 @@ static int wait_backward(void *arg) + for (i = fc.chain_length; i--; ) + dma_fence_signal(fc.fences[i]); + +- err = kthread_stop(tsk); +- put_task_struct(tsk); ++ err = kthread_stop_put(tsk); + + err: + fence_chains_fini(&fc); +@@ -669,8 +666,7 @@ static int wait_random(void *arg) + for (i = 0; i < fc.chain_length; i++) + dma_fence_signal(fc.fences[i]); + +- err = kthread_stop(tsk); +- put_task_struct(tsk); ++ err = kthread_stop_put(tsk); + + err: + fence_chains_fini(&fc); +diff --git a/drivers/dma-buf/st-dma-fence.c b/drivers/dma-buf/st-dma-fence.c +index fb6e0a6ae2c96e..6a1bfcd0cc2108 100644 +--- a/drivers/dma-buf/st-dma-fence.c ++++ b/drivers/dma-buf/st-dma-fence.c +@@ -540,6 +540,12 @@ static int race_signal_callback(void *arg) + t[i].before = pass; + t[i].task = kthread_run(thread_signal_callback, &t[i], + "dma-fence:%d", i); ++ if (IS_ERR(t[i].task)) { ++ ret = PTR_ERR(t[i].task); ++ while (--i >= 0) ++ kthread_stop_put(t[i].task); ++ return ret; ++ } + get_task_struct(t[i].task); + } + +@@ -548,11 +554,9 @@ static int race_signal_callback(void *arg) + for (i = 0; i < ARRAY_SIZE(t); i++) { + int err; + +- err = kthread_stop(t[i].task); ++ err = kthread_stop_put(t[i].task); + if (err && !ret) + ret = err; +- +- put_task_struct(t[i].task); + } + } + +diff --git a/drivers/dma-buf/sync_debug.c b/drivers/dma-buf/sync_debug.c +index 101394f16930f8..237bce21d1e724 100644 +--- a/drivers/dma-buf/sync_debug.c ++++ b/drivers/dma-buf/sync_debug.c +@@ -110,12 +110,12 @@ static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj) + + seq_printf(s, "%s: %d\n", obj->name, obj->value); + +- spin_lock_irq(&obj->lock); ++ spin_lock(&obj->lock); /* Caller already disabled IRQ. */ + list_for_each(pos, &obj->pt_list) { + struct sync_pt *pt = container_of(pos, struct sync_pt, link); + sync_print_fence(s, &pt->base, false); + } +- spin_unlock_irq(&obj->lock); ++ spin_unlock(&obj->lock); + } + + static void sync_print_sync_file(struct seq_file *s, +diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig +index 4ccae1a3b88427..e36506471a4f67 100644 +--- a/drivers/dma/Kconfig ++++ b/drivers/dma/Kconfig +@@ -380,7 +380,7 @@ config LPC18XX_DMAMUX + + config MCF_EDMA + tristate "Freescale eDMA engine support, ColdFire mcf5441x SoCs" +- depends on M5441x || COMPILE_TEST ++ depends on M5441x || (COMPILE_TEST && FSL_EDMA=n) + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help +@@ -629,16 +629,16 @@ config TEGRA20_APB_DMA + + config TEGRA210_ADMA + tristate "NVIDIA Tegra210 ADMA support" +- depends on (ARCH_TEGRA_210_SOC || COMPILE_TEST) ++ depends on (ARCH_TEGRA || COMPILE_TEST) + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help +- Support for the NVIDIA Tegra210 ADMA controller driver. The +- DMA controller has multiple DMA channels and is used to service +- various audio clients in the Tegra210 audio processing engine +- (APE). This DMA controller transfers data from memory to +- peripheral and vice versa. It does not support memory to +- memory data transfer. ++ Support for the NVIDIA Tegra210/Tegra186/Tegra194/Tegra234 ADMA ++ controller driver. The DMA controller has multiple DMA channels ++ and is used to service various audio clients in the Tegra210 ++ audio processing engine (APE). This DMA controller transfers ++ data from memory to peripheral and vice versa. It does not ++ support memory to memory data transfer. + + config TIMB_DMA + tristate "Timberdale FPGA DMA support" +diff --git a/drivers/dma/altera-msgdma.c b/drivers/dma/altera-msgdma.c +index 4153c2edb04901..711e3756a39a52 100644 +--- a/drivers/dma/altera-msgdma.c ++++ b/drivers/dma/altera-msgdma.c +@@ -233,7 +233,7 @@ static void msgdma_free_descriptor(struct msgdma_device *mdev, + struct msgdma_sw_desc *child, *next; + + mdev->desc_free_cnt++; +- list_add_tail(&desc->node, &mdev->free_list); ++ list_move_tail(&desc->node, &mdev->free_list); + list_for_each_entry_safe(child, next, &desc->tx_list, node) { + mdev->desc_free_cnt++; + list_move_tail(&child->node, &mdev->free_list); +@@ -583,17 +583,16 @@ static void msgdma_issue_pending(struct dma_chan *chan) + static void msgdma_chan_desc_cleanup(struct msgdma_device *mdev) + { + struct msgdma_sw_desc *desc, *next; ++ unsigned long irqflags; + + list_for_each_entry_safe(desc, next, &mdev->done_list, node) { + struct dmaengine_desc_callback cb; + +- list_del(&desc->node); +- + dmaengine_desc_get_callback(&desc->async_tx, &cb); + if (dmaengine_desc_callback_valid(&cb)) { +- spin_unlock(&mdev->lock); ++ spin_unlock_irqrestore(&mdev->lock, irqflags); + dmaengine_desc_callback_invoke(&cb, NULL); +- spin_lock(&mdev->lock); ++ spin_lock_irqsave(&mdev->lock, irqflags); + } + + /* Run any dependencies, then free the descriptor */ +diff --git a/drivers/dma/apple-admac.c b/drivers/dma/apple-admac.c +index 3af795635c5ce6..356298e4dd22b3 100644 +--- a/drivers/dma/apple-admac.c ++++ b/drivers/dma/apple-admac.c +@@ -57,6 +57,8 @@ + + #define REG_BUS_WIDTH(ch) (0x8040 + (ch) * 0x200) + ++#define BUS_WIDTH_WORD_SIZE GENMASK(3, 0) ++#define BUS_WIDTH_FRAME_SIZE GENMASK(7, 4) + #define BUS_WIDTH_8BIT 0x00 + #define BUS_WIDTH_16BIT 0x01 + #define BUS_WIDTH_32BIT 0x02 +@@ -740,7 +742,8 @@ static int admac_device_config(struct dma_chan *chan, + struct admac_data *ad = adchan->host; + bool is_tx = admac_chan_direction(adchan->no) == DMA_MEM_TO_DEV; + int wordsize = 0; +- u32 bus_width = 0; ++ u32 bus_width = readl_relaxed(ad->base + REG_BUS_WIDTH(adchan->no)) & ++ ~(BUS_WIDTH_WORD_SIZE | BUS_WIDTH_FRAME_SIZE); + + switch (is_tx ? config->dst_addr_width : config->src_addr_width) { + case DMA_SLAVE_BUSWIDTH_1_BYTE: +diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c +index fc7cdad371616a..4f426be2868843 100644 +--- a/drivers/dma/dma-axi-dmac.c ++++ b/drivers/dma/dma-axi-dmac.c +@@ -1033,8 +1033,8 @@ static int axi_dmac_remove(struct platform_device *pdev) + { + struct axi_dmac *dmac = platform_get_drvdata(pdev); + +- of_dma_controller_free(pdev->dev.of_node); + free_irq(dmac->irq, dmac); ++ of_dma_controller_free(pdev->dev.of_node); + tasklet_kill(&dmac->chan.vchan.task); + dma_async_device_unregister(&dmac->dma_dev); + clk_disable_unprepare(dmac->clk); +diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c +index b7388ae62d7f1f..491b222402216a 100644 +--- a/drivers/dma/dmaengine.c ++++ b/drivers/dma/dmaengine.c +@@ -1103,6 +1103,9 @@ EXPORT_SYMBOL_GPL(dma_async_device_channel_register); + static void __dma_async_device_channel_unregister(struct dma_device *device, + struct dma_chan *chan) + { ++ if (chan->local == NULL) ++ return; ++ + WARN_ONCE(!device->device_release && chan->client_count, + "%s called while %d clients hold a reference\n", + __func__, chan->client_count); +diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +index dd02f84e404d08..72fb40de58b3f4 100644 +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +@@ -256,6 +256,7 @@ static struct axi_dma_desc *axi_desc_alloc(u32 num) + kfree(desc); + return NULL; + } ++ desc->nr_hw_descs = num; + + return desc; + } +@@ -282,7 +283,7 @@ static struct axi_dma_lli *axi_desc_get(struct axi_dma_chan *chan, + static void axi_desc_put(struct axi_dma_desc *desc) + { + struct axi_dma_chan *chan = desc->chan; +- int count = atomic_read(&chan->descs_allocated); ++ int count = desc->nr_hw_descs; + struct axi_dma_hw_desc *hw_desc; + int descs_put; + +@@ -1093,9 +1094,6 @@ static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan) + /* Remove the completed descriptor from issued list before completing */ + list_del(&vd->node); + vchan_cookie_complete(vd); +- +- /* Submit queued descriptors after processing the completed ones */ +- axi_chan_start_first_queued(chan); + } + + out: +diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +index eb267cb24f6702..8521530a34ec46 100644 +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +@@ -104,6 +104,7 @@ struct axi_dma_desc { + u32 completed_blocks; + u32 length; + u32 period_len; ++ u32 nr_hw_descs; + }; + + struct axi_dma_chan_config { +diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c +index b38786f0ad7995..b75fdaffad9a4e 100644 +--- a/drivers/dma/dw-edma/dw-edma-v0-core.c ++++ b/drivers/dma/dw-edma/dw-edma-v0-core.c +@@ -346,6 +346,20 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk) + dw_edma_v0_write_ll_link(chunk, i, control, chunk->ll_region.paddr); + } + ++static void dw_edma_v0_sync_ll_data(struct dw_edma_chunk *chunk) ++{ ++ /* ++ * In case of remote eDMA engine setup, the DW PCIe RP/EP internal ++ * configuration registers and application memory are normally accessed ++ * over different buses. Ensure LL-data reaches the memory before the ++ * doorbell register is toggled by issuing the dummy-read from the remote ++ * LL memory in a hope that the MRd TLP will return only after the ++ * last MWr TLP is completed ++ */ ++ if (!(chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL)) ++ readl(chunk->ll_region.vaddr.io); ++} ++ + static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first) + { + struct dw_edma_chan *chan = chunk->chan; +@@ -412,6 +426,9 @@ static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first) + SET_CH_32(dw, chan->dir, chan->id, llp.msb, + upper_32_bits(chunk->ll_region.paddr)); + } ++ ++ dw_edma_v0_sync_ll_data(chunk); ++ + /* Doorbell */ + SET_RW_32(dw, chan->dir, doorbell, + FIELD_PREP(EDMA_V0_DOORBELL_CH_MASK, chan->id)); +diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c +index 0745d9e7d259b1..406f169b09a75a 100644 +--- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c ++++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c +@@ -176,7 +176,7 @@ dw_edma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dent) + }; + struct dentry *regs_dent, *ch_dent; + int nr_entries, i; +- char name[16]; ++ char name[32]; + + regs_dent = debugfs_create_dir(WRITE_STR, dent); + +@@ -239,7 +239,7 @@ static noinline_for_stack void dw_edma_debugfs_regs_rd(struct dw_edma *dw, + }; + struct dentry *regs_dent, *ch_dent; + int nr_entries, i; +- char name[16]; ++ char name[32]; + + regs_dent = debugfs_create_dir(READ_STR, dent); + +diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c +index 00b735a0202ab2..e3f8db4fe909a1 100644 +--- a/drivers/dma/dw-edma/dw-hdma-v0-core.c ++++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c +@@ -17,8 +17,8 @@ enum dw_hdma_control { + DW_HDMA_V0_CB = BIT(0), + DW_HDMA_V0_TCB = BIT(1), + DW_HDMA_V0_LLP = BIT(2), +- DW_HDMA_V0_LIE = BIT(3), +- DW_HDMA_V0_RIE = BIT(4), ++ DW_HDMA_V0_LWIE = BIT(3), ++ DW_HDMA_V0_RWIE = BIT(4), + DW_HDMA_V0_CCS = BIT(8), + DW_HDMA_V0_LLE = BIT(9), + }; +@@ -65,18 +65,12 @@ static void dw_hdma_v0_core_off(struct dw_edma *dw) + + static u16 dw_hdma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir) + { +- u32 num_ch = 0; +- int id; +- +- for (id = 0; id < HDMA_V0_MAX_NR_CH; id++) { +- if (GET_CH_32(dw, id, dir, ch_en) & BIT(0)) +- num_ch++; +- } +- +- if (num_ch > HDMA_V0_MAX_NR_CH) +- num_ch = HDMA_V0_MAX_NR_CH; +- +- return (u16)num_ch; ++ /* ++ * The HDMA IP have no way to know the number of hardware channels ++ * available, we set it to maximum channels and let the platform ++ * set the right number of channels. ++ */ ++ return HDMA_V0_MAX_NR_CH; + } + + static enum dma_status dw_hdma_v0_core_ch_status(struct dw_edma_chan *chan) +@@ -201,25 +195,14 @@ static void dw_hdma_v0_write_ll_link(struct dw_edma_chunk *chunk, + static void dw_hdma_v0_core_write_chunk(struct dw_edma_chunk *chunk) + { + struct dw_edma_burst *child; +- struct dw_edma_chan *chan = chunk->chan; + u32 control = 0, i = 0; +- int j; + + if (chunk->cb) + control = DW_HDMA_V0_CB; + +- j = chunk->bursts_alloc; +- list_for_each_entry(child, &chunk->burst->list, list) { +- j--; +- if (!j) { +- control |= DW_HDMA_V0_LIE; +- if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL)) +- control |= DW_HDMA_V0_RIE; +- } +- ++ list_for_each_entry(child, &chunk->burst->list, list) + dw_hdma_v0_write_ll_data(chunk, i++, control, child->sz, + child->sar, child->dar); +- } + + control = DW_HDMA_V0_LLP | DW_HDMA_V0_TCB; + if (!chunk->cb) +@@ -228,6 +211,20 @@ static void dw_hdma_v0_core_write_chunk(struct dw_edma_chunk *chunk) + dw_hdma_v0_write_ll_link(chunk, i, control, chunk->ll_region.paddr); + } + ++static void dw_hdma_v0_sync_ll_data(struct dw_edma_chunk *chunk) ++{ ++ /* ++ * In case of remote HDMA engine setup, the DW PCIe RP/EP internal ++ * configuration registers and application memory are normally accessed ++ * over different buses. Ensure LL-data reaches the memory before the ++ * doorbell register is toggled by issuing the dummy-read from the remote ++ * LL memory in a hope that the MRd TLP will return only after the ++ * last MWr TLP is completed ++ */ ++ if (!(chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL)) ++ readl(chunk->ll_region.vaddr.io); ++} ++ + static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first) + { + struct dw_edma_chan *chan = chunk->chan; +@@ -239,10 +236,13 @@ static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first) + if (first) { + /* Enable engine */ + SET_CH_32(dw, chan->dir, chan->id, ch_en, BIT(0)); +- /* Interrupt enable&unmask - done, abort */ +- tmp = GET_CH_32(dw, chan->dir, chan->id, int_setup) | +- HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK | +- HDMA_V0_LOCAL_STOP_INT_EN | HDMA_V0_LOCAL_STOP_INT_EN; ++ /* Interrupt unmask - stop, abort */ ++ tmp = GET_CH_32(dw, chan->dir, chan->id, int_setup); ++ tmp &= ~(HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK); ++ /* Interrupt enable - stop, abort */ ++ tmp |= HDMA_V0_LOCAL_STOP_INT_EN | HDMA_V0_LOCAL_ABORT_INT_EN; ++ if (!(dw->chip->flags & DW_EDMA_CHIP_LOCAL)) ++ tmp |= HDMA_V0_REMOTE_STOP_INT_EN | HDMA_V0_REMOTE_ABORT_INT_EN; + SET_CH_32(dw, chan->dir, chan->id, int_setup, tmp); + /* Channel control */ + SET_CH_32(dw, chan->dir, chan->id, control1, HDMA_V0_LINKLIST_EN); +@@ -256,6 +256,9 @@ static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first) + /* Set consumer cycle */ + SET_CH_32(dw, chan->dir, chan->id, cycle_sync, + HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT); ++ ++ dw_hdma_v0_sync_ll_data(chunk); ++ + /* Doorbell */ + SET_CH_32(dw, chan->dir, chan->id, doorbell, HDMA_V0_DOORBELL_START); + } +diff --git a/drivers/dma/dw-edma/dw-hdma-v0-debugfs.c b/drivers/dma/dw-edma/dw-hdma-v0-debugfs.c +index 520c81978b085f..dcdc57fe976c13 100644 +--- a/drivers/dma/dw-edma/dw-hdma-v0-debugfs.c ++++ b/drivers/dma/dw-edma/dw-hdma-v0-debugfs.c +@@ -116,7 +116,7 @@ static void dw_hdma_debugfs_regs_ch(struct dw_edma *dw, enum dw_edma_dir dir, + static void dw_hdma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dent) + { + struct dentry *regs_dent, *ch_dent; +- char name[16]; ++ char name[32]; + int i; + + regs_dent = debugfs_create_dir(WRITE_STR, dent); +@@ -133,7 +133,7 @@ static void dw_hdma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dent) + static void dw_hdma_debugfs_regs_rd(struct dw_edma *dw, struct dentry *dent) + { + struct dentry *regs_dent, *ch_dent; +- char name[16]; ++ char name[32]; + int i; + + regs_dent = debugfs_create_dir(READ_STR, dent); +diff --git a/drivers/dma/dw-edma/dw-hdma-v0-regs.h b/drivers/dma/dw-edma/dw-hdma-v0-regs.h +index a974abdf8aaf5e..eab5fd7177e545 100644 +--- a/drivers/dma/dw-edma/dw-hdma-v0-regs.h ++++ b/drivers/dma/dw-edma/dw-hdma-v0-regs.h +@@ -15,7 +15,7 @@ + #define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6) + #define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5) + #define HDMA_V0_LOCAL_STOP_INT_EN BIT(4) +-#define HDMA_V0_REMOTEL_STOP_INT_EN BIT(3) ++#define HDMA_V0_REMOTE_STOP_INT_EN BIT(3) + #define HDMA_V0_ABORT_INT_MASK BIT(2) + #define HDMA_V0_STOP_INT_MASK BIT(0) + #define HDMA_V0_LINKLIST_EN BIT(0) +diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c +index 5f7d690e3dbae8..b341a6f1b04383 100644 +--- a/drivers/dma/dw/core.c ++++ b/drivers/dma/dw/core.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -621,12 +622,10 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, + struct dw_desc *prev; + struct dw_desc *first; + u32 ctllo, ctlhi; +- u8 m_master = dwc->dws.m_master; +- u8 lms = DWC_LLP_LMS(m_master); ++ u8 lms = DWC_LLP_LMS(dwc->dws.m_master); + dma_addr_t reg; + unsigned int reg_width; + unsigned int mem_width; +- unsigned int data_width = dw->pdata->data_width[m_master]; + unsigned int i; + struct scatterlist *sg; + size_t total_len = 0; +@@ -660,7 +659,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, + mem = sg_dma_address(sg); + len = sg_dma_len(sg); + +- mem_width = __ffs(data_width | mem | len); ++ mem_width = __ffs(sconfig->src_addr_width | mem | len); + + slave_sg_todev_fill_desc: + desc = dwc_desc_get(dwc); +@@ -720,7 +719,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, + lli_write(desc, sar, reg); + lli_write(desc, dar, mem); + lli_write(desc, ctlhi, ctlhi); +- mem_width = __ffs(data_width | mem); ++ mem_width = __ffs(sconfig->dst_addr_width | mem); + lli_write(desc, ctllo, ctllo | DWC_CTLL_DST_WIDTH(mem_width)); + desc->len = dlen; + +@@ -780,17 +779,93 @@ bool dw_dma_filter(struct dma_chan *chan, void *param) + } + EXPORT_SYMBOL_GPL(dw_dma_filter); + ++static int dwc_verify_p_buswidth(struct dma_chan *chan) ++{ ++ struct dw_dma_chan *dwc = to_dw_dma_chan(chan); ++ struct dw_dma *dw = to_dw_dma(chan->device); ++ u32 reg_width, max_width; ++ ++ if (dwc->dma_sconfig.direction == DMA_MEM_TO_DEV) ++ reg_width = dwc->dma_sconfig.dst_addr_width; ++ else if (dwc->dma_sconfig.direction == DMA_DEV_TO_MEM) ++ reg_width = dwc->dma_sconfig.src_addr_width; ++ else /* DMA_MEM_TO_MEM */ ++ return 0; ++ ++ max_width = dw->pdata->data_width[dwc->dws.p_master]; ++ ++ /* Fall-back to 1-byte transfer width if undefined */ ++ if (reg_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) ++ reg_width = DMA_SLAVE_BUSWIDTH_1_BYTE; ++ else if (!is_power_of_2(reg_width) || reg_width > max_width) ++ return -EINVAL; ++ else /* bus width is valid */ ++ return 0; ++ ++ /* Update undefined addr width value */ ++ if (dwc->dma_sconfig.direction == DMA_MEM_TO_DEV) ++ dwc->dma_sconfig.dst_addr_width = reg_width; ++ else /* DMA_DEV_TO_MEM */ ++ dwc->dma_sconfig.src_addr_width = reg_width; ++ ++ return 0; ++} ++ ++static int dwc_verify_m_buswidth(struct dma_chan *chan) ++{ ++ struct dw_dma_chan *dwc = to_dw_dma_chan(chan); ++ struct dw_dma *dw = to_dw_dma(chan->device); ++ u32 reg_width, reg_burst, mem_width; ++ ++ mem_width = dw->pdata->data_width[dwc->dws.m_master]; ++ ++ /* ++ * It's possible to have a data portion locked in the DMA FIFO in case ++ * of the channel suspension. Subsequent channel disabling will cause ++ * that data silent loss. In order to prevent that maintain the src and ++ * dst transfer widths coherency by means of the relation: ++ * (CTLx.SRC_TR_WIDTH * CTLx.SRC_MSIZE >= CTLx.DST_TR_WIDTH) ++ * Look for the details in the commit message that brings this change. ++ * ++ * Note the DMA configs utilized in the calculations below must have ++ * been verified to have correct values by this method call. ++ */ ++ if (dwc->dma_sconfig.direction == DMA_MEM_TO_DEV) { ++ reg_width = dwc->dma_sconfig.dst_addr_width; ++ if (mem_width < reg_width) ++ return -EINVAL; ++ ++ dwc->dma_sconfig.src_addr_width = mem_width; ++ } else if (dwc->dma_sconfig.direction == DMA_DEV_TO_MEM) { ++ reg_width = dwc->dma_sconfig.src_addr_width; ++ reg_burst = rounddown_pow_of_two(dwc->dma_sconfig.src_maxburst); ++ ++ dwc->dma_sconfig.dst_addr_width = min(mem_width, reg_width * reg_burst); ++ } ++ ++ return 0; ++} ++ + static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig) + { + struct dw_dma_chan *dwc = to_dw_dma_chan(chan); + struct dw_dma *dw = to_dw_dma(chan->device); ++ int ret; + + memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig)); + + dwc->dma_sconfig.src_maxburst = +- clamp(dwc->dma_sconfig.src_maxburst, 0U, dwc->max_burst); ++ clamp(dwc->dma_sconfig.src_maxburst, 1U, dwc->max_burst); + dwc->dma_sconfig.dst_maxburst = +- clamp(dwc->dma_sconfig.dst_maxburst, 0U, dwc->max_burst); ++ clamp(dwc->dma_sconfig.dst_maxburst, 1U, dwc->max_burst); ++ ++ ret = dwc_verify_p_buswidth(chan); ++ if (ret) ++ return ret; ++ ++ ret = dwc_verify_m_buswidth(chan); ++ if (ret) ++ return ret; + + dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst); + dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst); +diff --git a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c +index a42a37634881b2..da91bc9a8e6f0e 100644 +--- a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c ++++ b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c +@@ -38,15 +38,17 @@ static int dpaa2_qdma_alloc_chan_resources(struct dma_chan *chan) + if (!dpaa2_chan->fd_pool) + goto err; + +- dpaa2_chan->fl_pool = dma_pool_create("fl_pool", dev, +- sizeof(struct dpaa2_fl_entry), +- sizeof(struct dpaa2_fl_entry), 0); ++ dpaa2_chan->fl_pool = ++ dma_pool_create("fl_pool", dev, ++ sizeof(struct dpaa2_fl_entry) * 3, ++ sizeof(struct dpaa2_fl_entry), 0); ++ + if (!dpaa2_chan->fl_pool) + goto err_fd; + + dpaa2_chan->sdd_pool = + dma_pool_create("sdd_pool", dev, +- sizeof(struct dpaa2_qdma_sd_d), ++ sizeof(struct dpaa2_qdma_sd_d) * 2, + sizeof(struct dpaa2_qdma_sd_d), 0); + if (!dpaa2_chan->sdd_pool) + goto err_fl; +diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c +index 6a3abe5b17908d..53fdfd32a7e772 100644 +--- a/drivers/dma/fsl-edma-common.c ++++ b/drivers/dma/fsl-edma-common.c +@@ -3,6 +3,7 @@ + // Copyright (c) 2013-2014 Freescale Semiconductor, Inc + // Copyright (c) 2017 Sysam, Angelo Dureghello + ++#include + #include + #include + #include +@@ -74,18 +75,10 @@ static void fsl_edma3_enable_request(struct fsl_edma_chan *fsl_chan) + + flags = fsl_edma_drvflags(fsl_chan); + val = edma_readl_chreg(fsl_chan, ch_sbr); +- /* Remote/local swapped wrongly on iMX8 QM Audio edma */ +- if (flags & FSL_EDMA_DRV_QUIRK_SWAPPED) { +- if (!fsl_chan->is_rxchan) +- val |= EDMA_V3_CH_SBR_RD; +- else +- val |= EDMA_V3_CH_SBR_WR; +- } else { +- if (fsl_chan->is_rxchan) +- val |= EDMA_V3_CH_SBR_RD; +- else +- val |= EDMA_V3_CH_SBR_WR; +- } ++ if (fsl_chan->is_rxchan) ++ val |= EDMA_V3_CH_SBR_RD; ++ else ++ val |= EDMA_V3_CH_SBR_WR; + + if (fsl_chan->is_remote) + val &= ~(EDMA_V3_CH_SBR_RD | EDMA_V3_CH_SBR_WR); +@@ -97,8 +90,8 @@ static void fsl_edma3_enable_request(struct fsl_edma_chan *fsl_chan) + * ch_mux: With the exception of 0, attempts to write a value + * already in use will be forced to 0. + */ +- if (!edma_readl_chreg(fsl_chan, ch_mux)) +- edma_writel_chreg(fsl_chan, fsl_chan->srcid, ch_mux); ++ if (!edma_readl(fsl_chan->edma, fsl_chan->mux_addr)) ++ edma_writel(fsl_chan->edma, fsl_chan->srcid, fsl_chan->mux_addr); + } + + val = edma_readl_chreg(fsl_chan, ch_csr); +@@ -134,7 +127,7 @@ static void fsl_edma3_disable_request(struct fsl_edma_chan *fsl_chan) + flags = fsl_edma_drvflags(fsl_chan); + + if (flags & FSL_EDMA_DRV_HAS_CHMUX) +- edma_writel_chreg(fsl_chan, 0, ch_mux); ++ edma_writel(fsl_chan->edma, 0, fsl_chan->mux_addr); + + val &= ~EDMA_V3_CH_CSR_ERQ; + edma_writel_chreg(fsl_chan, val, ch_csr); +@@ -503,7 +496,7 @@ void fsl_edma_fill_tcd(struct fsl_edma_chan *fsl_chan, + if (fsl_chan->is_multi_fifo) { + /* set mloff to support multiple fifo */ + burst = cfg->direction == DMA_DEV_TO_MEM ? +- cfg->src_addr_width : cfg->dst_addr_width; ++ cfg->src_maxburst : cfg->dst_maxburst; + nbytes |= EDMA_V3_TCD_NBYTES_MLOFF(-(burst * 4)); + /* enable DMLOE/SMLOE */ + if (cfg->direction == DMA_MEM_TO_DEV) { +@@ -754,6 +747,8 @@ struct dma_async_tx_descriptor *fsl_edma_prep_memcpy(struct dma_chan *chan, + fsl_desc->iscyclic = false; + + fsl_chan->is_sw = true; ++ if (fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_MEM_REMOTE) ++ fsl_chan->is_remote = true; + + /* To match with copy_align and max_seg_size so 1 tcd is enough */ + fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[0].vtcd, dma_src, dma_dst, +@@ -802,6 +797,9 @@ int fsl_edma_alloc_chan_resources(struct dma_chan *chan) + { + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); + ++ if (fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_HAS_CHCLK) ++ clk_prepare_enable(fsl_chan->clk); ++ + fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev, + sizeof(struct fsl_edma_hw_tcd), + 32, 0); +@@ -828,6 +826,10 @@ void fsl_edma_free_chan_resources(struct dma_chan *chan) + dma_pool_destroy(fsl_chan->tcd_pool); + fsl_chan->tcd_pool = NULL; + fsl_chan->is_sw = false; ++ fsl_chan->srcid = 0; ++ fsl_chan->is_remote = false; ++ if (fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_HAS_CHCLK) ++ clk_disable_unprepare(fsl_chan->clk); + } + + void fsl_edma_cleanup_vchan(struct dma_device *dmadev) +diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h +index 40d50cc3d75a34..6028389de408b0 100644 +--- a/drivers/dma/fsl-edma-common.h ++++ b/drivers/dma/fsl-edma-common.h +@@ -30,8 +30,9 @@ + #define EDMA_TCD_ATTR_SSIZE(x) (((x) & GENMASK(2, 0)) << 8) + #define EDMA_TCD_ATTR_SMOD(x) (((x) & GENMASK(4, 0)) << 11) + +-#define EDMA_TCD_CITER_CITER(x) ((x) & GENMASK(14, 0)) +-#define EDMA_TCD_BITER_BITER(x) ((x) & GENMASK(14, 0)) ++#define EDMA_TCD_ITER_MASK GENMASK(14, 0) ++#define EDMA_TCD_CITER_CITER(x) ((x) & EDMA_TCD_ITER_MASK) ++#define EDMA_TCD_BITER_BITER(x) ((x) & EDMA_TCD_ITER_MASK) + + #define EDMA_TCD_CSR_START BIT(0) + #define EDMA_TCD_CSR_INT_MAJOR BIT(1) +@@ -145,6 +146,7 @@ struct fsl_edma_chan { + enum dma_data_direction dma_dir; + char chan_name[32]; + struct fsl_edma_hw_tcd __iomem *tcd; ++ void __iomem *mux_addr; + u32 real_count; + struct work_struct issue_worker; + struct platform_device *pdev; +@@ -176,8 +178,7 @@ struct fsl_edma_desc { + #define FSL_EDMA_DRV_HAS_PD BIT(5) + #define FSL_EDMA_DRV_HAS_CHCLK BIT(6) + #define FSL_EDMA_DRV_HAS_CHMUX BIT(7) +-/* imx8 QM audio edma remote local swapped */ +-#define FSL_EDMA_DRV_QUIRK_SWAPPED BIT(8) ++#define FSL_EDMA_DRV_MEM_REMOTE BIT(8) + /* control and status register is in tcd address space, edma3 reg layout */ + #define FSL_EDMA_DRV_SPLIT_REG BIT(9) + #define FSL_EDMA_DRV_BUS_8BYTE BIT(10) +@@ -206,6 +207,8 @@ struct fsl_edma_drvdata { + u32 chreg_off; + u32 chreg_space_sz; + u32 flags; ++ u32 mux_off; /* channel mux register offset */ ++ u32 mux_skip; /* how much skip for each channel */ + int (*setup_irq)(struct platform_device *pdev, + struct fsl_edma_engine *fsl_edma); + }; +diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c +index 8c4ed7012e232e..8a0ae90548997c 100644 +--- a/drivers/dma/fsl-edma-main.c ++++ b/drivers/dma/fsl-edma-main.c +@@ -9,6 +9,8 @@ + * Vybrid and Layerscape SoCs. + */ + ++#include ++#include + #include + #include + #include +@@ -23,10 +25,6 @@ + + #include "fsl-edma-common.h" + +-#define ARGS_RX BIT(0) +-#define ARGS_REMOTE BIT(1) +-#define ARGS_MULTI_FIFO BIT(2) +- + static void fsl_edma_synchronize(struct dma_chan *chan) + { + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); +@@ -155,9 +153,15 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec, + i = fsl_chan - fsl_edma->chans; + + fsl_chan->priority = dma_spec->args[1]; +- fsl_chan->is_rxchan = dma_spec->args[2] & ARGS_RX; +- fsl_chan->is_remote = dma_spec->args[2] & ARGS_REMOTE; +- fsl_chan->is_multi_fifo = dma_spec->args[2] & ARGS_MULTI_FIFO; ++ fsl_chan->is_rxchan = dma_spec->args[2] & FSL_EDMA_RX; ++ fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE; ++ fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO; ++ ++ if ((dma_spec->args[2] & FSL_EDMA_EVEN_CH) && (i & 0x1)) ++ continue; ++ ++ if ((dma_spec->args[2] & FSL_EDMA_ODD_CH) && !(i & 0x1)) ++ continue; + + if (!b_chmux && i == dma_spec->args[0]) { + chan = dma_get_slave_channel(chan); +@@ -336,16 +340,19 @@ static struct fsl_edma_drvdata imx7ulp_data = { + }; + + static struct fsl_edma_drvdata imx8qm_data = { +- .flags = FSL_EDMA_DRV_HAS_PD | FSL_EDMA_DRV_EDMA3, ++ .flags = FSL_EDMA_DRV_HAS_PD | FSL_EDMA_DRV_EDMA3 | FSL_EDMA_DRV_MEM_REMOTE, + .chreg_space_sz = 0x10000, + .chreg_off = 0x10000, + .setup_irq = fsl_edma3_irq_init, + }; + +-static struct fsl_edma_drvdata imx8qm_audio_data = { +- .flags = FSL_EDMA_DRV_QUIRK_SWAPPED | FSL_EDMA_DRV_HAS_PD | FSL_EDMA_DRV_EDMA3, ++static struct fsl_edma_drvdata imx8ulp_data = { ++ .flags = FSL_EDMA_DRV_HAS_CHMUX | FSL_EDMA_DRV_HAS_CHCLK | FSL_EDMA_DRV_HAS_DMACLK | ++ FSL_EDMA_DRV_EDMA3, + .chreg_space_sz = 0x10000, + .chreg_off = 0x10000, ++ .mux_off = 0x10000 + offsetof(struct fsl_edma3_ch_reg, ch_mux), ++ .mux_skip = 0x10000, + .setup_irq = fsl_edma3_irq_init, + }; + +@@ -360,6 +367,8 @@ static struct fsl_edma_drvdata imx93_data4 = { + .flags = FSL_EDMA_DRV_HAS_CHMUX | FSL_EDMA_DRV_HAS_DMACLK | FSL_EDMA_DRV_EDMA4, + .chreg_space_sz = 0x8000, + .chreg_off = 0x10000, ++ .mux_off = 0x10000 + offsetof(struct fsl_edma3_ch_reg, ch_mux), ++ .mux_skip = 0x8000, + .setup_irq = fsl_edma3_irq_init, + }; + +@@ -368,7 +377,7 @@ static const struct of_device_id fsl_edma_dt_ids[] = { + { .compatible = "fsl,ls1028a-edma", .data = &ls1028a_data}, + { .compatible = "fsl,imx7ulp-edma", .data = &imx7ulp_data}, + { .compatible = "fsl,imx8qm-edma", .data = &imx8qm_data}, +- { .compatible = "fsl,imx8qm-adma", .data = &imx8qm_audio_data}, ++ { .compatible = "fsl,imx8ulp-edma", .data = &imx8ulp_data}, + { .compatible = "fsl,imx93-edma3", .data = &imx93_data3}, + { .compatible = "fsl,imx93-edma4", .data = &imx93_data4}, + { /* sentinel */ } +@@ -400,9 +409,8 @@ static int fsl_edma3_attach_pd(struct platform_device *pdev, struct fsl_edma_eng + link = device_link_add(dev, pd_chan, DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); +- if (IS_ERR(link)) { +- dev_err(dev, "Failed to add device_link to %d: %ld\n", i, +- PTR_ERR(link)); ++ if (!link) { ++ dev_err(dev, "Failed to add device_link to %d\n", i); + return -EINVAL; + } + +@@ -424,6 +432,7 @@ static int fsl_edma_probe(struct platform_device *pdev) + struct fsl_edma_engine *fsl_edma; + const struct fsl_edma_drvdata *drvdata = NULL; + u32 chan_mask[2] = {0, 0}; ++ char clk_name[36]; + struct edma_regs *regs; + int chans; + int ret, i; +@@ -537,12 +546,23 @@ static int fsl_edma_probe(struct platform_device *pdev) + offsetof(struct fsl_edma3_ch_reg, tcd) : 0; + fsl_chan->tcd = fsl_edma->membase + + i * drvdata->chreg_space_sz + drvdata->chreg_off + len; ++ fsl_chan->mux_addr = fsl_edma->membase + drvdata->mux_off + i * drvdata->mux_skip; ++ ++ if (drvdata->flags & FSL_EDMA_DRV_HAS_CHCLK) { ++ snprintf(clk_name, sizeof(clk_name), "ch%02d", i); ++ fsl_chan->clk = devm_clk_get_enabled(&pdev->dev, ++ (const char *)clk_name); + ++ if (IS_ERR(fsl_chan->clk)) ++ return PTR_ERR(fsl_chan->clk); ++ } + fsl_chan->pdev = pdev; + vchan_init(&fsl_chan->vchan, &fsl_edma->dma_dev); + + edma_write_tcdreg(fsl_chan, 0, csr); + fsl_edma_chan_mux(fsl_chan, 0, false); ++ if (fsl_chan->edma->drvdata->flags & FSL_EDMA_DRV_HAS_CHCLK) ++ clk_disable_unprepare(fsl_chan->clk); + } + + ret = fsl_edma->drvdata->setup_irq(pdev, fsl_edma); +@@ -587,7 +607,8 @@ static int fsl_edma_probe(struct platform_device *pdev) + DMAENGINE_ALIGN_32_BYTES; + + /* Per worst case 'nbytes = 1' take CITER as the max_seg_size */ +- dma_set_max_seg_size(fsl_edma->dma_dev.dev, 0x3fff); ++ dma_set_max_seg_size(fsl_edma->dma_dev.dev, ++ FIELD_GET(EDMA_TCD_ITER_MASK, EDMA_TCD_ITER_MASK)); + + fsl_edma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; + +@@ -640,6 +661,8 @@ static int fsl_edma_suspend_late(struct device *dev) + + for (i = 0; i < fsl_edma->n_chans; i++) { + fsl_chan = &fsl_edma->chans[i]; ++ if (fsl_edma->chan_masked & BIT(i)) ++ continue; + spin_lock_irqsave(&fsl_chan->vchan.lock, flags); + /* Make sure chan is idle or will force disable. */ + if (unlikely(!fsl_chan->idle)) { +@@ -664,13 +687,16 @@ static int fsl_edma_resume_early(struct device *dev) + + for (i = 0; i < fsl_edma->n_chans; i++) { + fsl_chan = &fsl_edma->chans[i]; ++ if (fsl_edma->chan_masked & BIT(i)) ++ continue; + fsl_chan->pm_state = RUNNING; + edma_write_tcdreg(fsl_chan, 0, csr); + if (fsl_chan->slave_id != 0) + fsl_edma_chan_mux(fsl_chan, fsl_chan->slave_id, true); + } + +- edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr); ++ if (!(fsl_edma->drvdata->flags & FSL_EDMA_DRV_SPLIT_REG)) ++ edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr); + + return 0; + } +diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c +index a8cc8a4bc6102c..b7a2254b0de475 100644 +--- a/drivers/dma/fsl-qdma.c ++++ b/drivers/dma/fsl-qdma.c +@@ -109,6 +109,7 @@ + #define FSL_QDMA_CMD_WTHROTL_OFFSET 20 + #define FSL_QDMA_CMD_DSEN_OFFSET 19 + #define FSL_QDMA_CMD_LWC_OFFSET 16 ++#define FSL_QDMA_CMD_PF BIT(17) + + /* Field definition for Descriptor status */ + #define QDMA_CCDF_STATUS_RTE BIT(5) +@@ -384,7 +385,8 @@ static void fsl_qdma_comp_fill_memcpy(struct fsl_qdma_comp *fsl_comp, + qdma_csgf_set_f(csgf_dest, len); + /* Descriptor Buffer */ + cmd = cpu_to_le32(FSL_QDMA_CMD_RWTTYPE << +- FSL_QDMA_CMD_RWTTYPE_OFFSET); ++ FSL_QDMA_CMD_RWTTYPE_OFFSET) | ++ FSL_QDMA_CMD_PF; + sdf->data = QDMA_SDDF_CMD(cmd); + + cmd = cpu_to_le32(FSL_QDMA_CMD_RWTTYPE << +@@ -514,11 +516,11 @@ static struct fsl_qdma_queue + queue_temp = queue_head + i + (j * queue_num); + + queue_temp->cq = +- dma_alloc_coherent(&pdev->dev, +- sizeof(struct fsl_qdma_format) * +- queue_size[i], +- &queue_temp->bus_addr, +- GFP_KERNEL); ++ dmam_alloc_coherent(&pdev->dev, ++ sizeof(struct fsl_qdma_format) * ++ queue_size[i], ++ &queue_temp->bus_addr, ++ GFP_KERNEL); + if (!queue_temp->cq) + return NULL; + queue_temp->block_base = fsl_qdma->block_base + +@@ -563,11 +565,11 @@ static struct fsl_qdma_queue + /* + * Buffer for queue command + */ +- status_head->cq = dma_alloc_coherent(&pdev->dev, +- sizeof(struct fsl_qdma_format) * +- status_size, +- &status_head->bus_addr, +- GFP_KERNEL); ++ status_head->cq = dmam_alloc_coherent(&pdev->dev, ++ sizeof(struct fsl_qdma_format) * ++ status_size, ++ &status_head->bus_addr, ++ GFP_KERNEL); + if (!status_head->cq) { + devm_kfree(&pdev->dev, status_head); + return NULL; +@@ -805,7 +807,7 @@ fsl_qdma_irq_init(struct platform_device *pdev, + int i; + int cpu; + int ret; +- char irq_name[20]; ++ char irq_name[32]; + + fsl_qdma->error_irq = + platform_get_irq_byname(pdev, "qdma-error"); +@@ -1197,10 +1199,6 @@ static int fsl_qdma_probe(struct platform_device *pdev) + if (!fsl_qdma->queue) + return -ENOMEM; + +- ret = fsl_qdma_irq_init(pdev, fsl_qdma); +- if (ret) +- return ret; +- + fsl_qdma->irq_base = platform_get_irq_byname(pdev, "qdma-queue0"); + if (fsl_qdma->irq_base < 0) + return fsl_qdma->irq_base; +@@ -1239,16 +1237,19 @@ static int fsl_qdma_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, fsl_qdma); + +- ret = dma_async_device_register(&fsl_qdma->dma_dev); ++ ret = fsl_qdma_reg_init(fsl_qdma); + if (ret) { +- dev_err(&pdev->dev, +- "Can't register NXP Layerscape qDMA engine.\n"); ++ dev_err(&pdev->dev, "Can't Initialize the qDMA engine.\n"); + return ret; + } + +- ret = fsl_qdma_reg_init(fsl_qdma); ++ ret = fsl_qdma_irq_init(pdev, fsl_qdma); ++ if (ret) ++ return ret; ++ ++ ret = dma_async_device_register(&fsl_qdma->dma_dev); + if (ret) { +- dev_err(&pdev->dev, "Can't Initialize the qDMA engine.\n"); ++ dev_err(&pdev->dev, "Can't register NXP Layerscape qDMA engine.\n"); + return ret; + } + +@@ -1268,8 +1269,6 @@ static void fsl_qdma_cleanup_vchan(struct dma_device *dmadev) + + static int fsl_qdma_remove(struct platform_device *pdev) + { +- int i; +- struct fsl_qdma_queue *status; + struct device_node *np = pdev->dev.of_node; + struct fsl_qdma_engine *fsl_qdma = platform_get_drvdata(pdev); + +@@ -1278,11 +1277,6 @@ static int fsl_qdma_remove(struct platform_device *pdev) + of_dma_controller_free(np); + dma_async_device_unregister(&fsl_qdma->dma_dev); + +- for (i = 0; i < fsl_qdma->block_number; i++) { +- status = fsl_qdma->status[i]; +- dma_free_coherent(&pdev->dev, sizeof(struct fsl_qdma_format) * +- status->n_cq, status->cq, status->bus_addr); +- } + return 0; + } + +diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c +index 0ac634a51c5e35..6fa797fd85017d 100644 +--- a/drivers/dma/idma64.c ++++ b/drivers/dma/idma64.c +@@ -171,6 +171,10 @@ static irqreturn_t idma64_irq(int irq, void *dev) + u32 status_err; + unsigned short i; + ++ /* Since IRQ may be shared, check if DMA controller is powered on */ ++ if (status == GENMASK(31, 0)) ++ return IRQ_NONE; ++ + dev_vdbg(idma64->dma.dev, "%s: status=%#x\n", __func__, status); + + /* Check if we have any interrupt from the DMA controller */ +@@ -594,7 +598,9 @@ static int idma64_probe(struct idma64_chip *chip) + + idma64->dma.dev = chip->sysdev; + +- dma_set_max_seg_size(idma64->dma.dev, IDMA64C_CTLH_BLOCK_TS_MASK); ++ ret = dma_set_max_seg_size(idma64->dma.dev, IDMA64C_CTLH_BLOCK_TS_MASK); ++ if (ret) ++ return ret; + + ret = dma_async_device_register(&idma64->dma); + if (ret) +diff --git a/drivers/dma/idxd/Makefile b/drivers/dma/idxd/Makefile +index dc096839ac6374..c5e679070e4633 100644 +--- a/drivers/dma/idxd/Makefile ++++ b/drivers/dma/idxd/Makefile +@@ -1,12 +1,12 @@ + ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=IDXD + ++obj-$(CONFIG_INTEL_IDXD_BUS) += idxd_bus.o ++idxd_bus-y := bus.o ++ + obj-$(CONFIG_INTEL_IDXD) += idxd.o + idxd-y := init.o irq.o device.o sysfs.o submit.o dma.o cdev.o debugfs.o + + idxd-$(CONFIG_INTEL_IDXD_PERFMON) += perfmon.o + +-obj-$(CONFIG_INTEL_IDXD_BUS) += idxd_bus.o +-idxd_bus-y := bus.o +- + obj-$(CONFIG_INTEL_IDXD_COMPAT) += idxd_compat.o + idxd_compat-y := compat.o +diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c +index d32deb9b4e3dee..c18633ad8455fa 100644 +--- a/drivers/dma/idxd/cdev.c ++++ b/drivers/dma/idxd/cdev.c +@@ -342,10 +342,10 @@ static void idxd_cdev_evl_drain_pasid(struct idxd_wq *wq, u32 pasid) + if (!evl) + return; + +- spin_lock(&evl->lock); ++ mutex_lock(&evl->lock); + status.bits = ioread64(idxd->reg_base + IDXD_EVLSTATUS_OFFSET); + t = status.tail; +- h = evl->head; ++ h = status.head; + size = evl->size; + + while (h != t) { +@@ -354,9 +354,8 @@ static void idxd_cdev_evl_drain_pasid(struct idxd_wq *wq, u32 pasid) + set_bit(h, evl->bmap); + h = (h + 1) % size; + } +- spin_unlock(&evl->lock); +- + drain_workqueue(wq->wq); ++ mutex_unlock(&evl->lock); + } + + static int idxd_cdev_release(struct inode *node, struct file *filep) +@@ -401,6 +400,18 @@ static int idxd_cdev_mmap(struct file *filp, struct vm_area_struct *vma) + int rc; + + dev_dbg(&pdev->dev, "%s called\n", __func__); ++ ++ /* ++ * Due to an erratum in some of the devices supported by the driver, ++ * direct user submission to the device can be unsafe. ++ * (See the INTEL-SA-01084 security advisory) ++ * ++ * For the devices that exhibit this behavior, require that the user ++ * has CAP_SYS_RAWIO capabilities. ++ */ ++ if (!idxd->user_submission_safe && !capable(CAP_SYS_RAWIO)) ++ return -EPERM; ++ + rc = check_vma(wq, vma, __func__); + if (rc < 0) + return rc; +@@ -415,6 +426,70 @@ static int idxd_cdev_mmap(struct file *filp, struct vm_area_struct *vma) + vma->vm_page_prot); + } + ++static int idxd_submit_user_descriptor(struct idxd_user_context *ctx, ++ struct dsa_hw_desc __user *udesc) ++{ ++ struct idxd_wq *wq = ctx->wq; ++ struct idxd_dev *idxd_dev = &wq->idxd->idxd_dev; ++ const uint64_t comp_addr_align = is_dsa_dev(idxd_dev) ? 0x20 : 0x40; ++ void __iomem *portal = idxd_wq_portal_addr(wq); ++ struct dsa_hw_desc descriptor __aligned(64); ++ int rc; ++ ++ rc = copy_from_user(&descriptor, udesc, sizeof(descriptor)); ++ if (rc) ++ return -EFAULT; ++ ++ /* ++ * DSA devices are capable of indirect ("batch") command submission. ++ * On devices where direct user submissions are not safe, we cannot ++ * allow this since there is no good way for us to verify these ++ * indirect commands. ++ */ ++ if (is_dsa_dev(idxd_dev) && descriptor.opcode == DSA_OPCODE_BATCH && ++ !wq->idxd->user_submission_safe) ++ return -EINVAL; ++ /* ++ * As per the programming specification, the completion address must be ++ * aligned to 32 or 64 bytes. If this is violated the hardware ++ * engine can get very confused (security issue). ++ */ ++ if (!IS_ALIGNED(descriptor.completion_addr, comp_addr_align)) ++ return -EINVAL; ++ ++ if (wq_dedicated(wq)) ++ iosubmit_cmds512(portal, &descriptor, 1); ++ else { ++ descriptor.priv = 0; ++ descriptor.pasid = ctx->pasid; ++ rc = idxd_enqcmds(wq, portal, &descriptor); ++ if (rc < 0) ++ return rc; ++ } ++ ++ return 0; ++} ++ ++static ssize_t idxd_cdev_write(struct file *filp, const char __user *buf, size_t len, ++ loff_t *unused) ++{ ++ struct dsa_hw_desc __user *udesc = (struct dsa_hw_desc __user *)buf; ++ struct idxd_user_context *ctx = filp->private_data; ++ ssize_t written = 0; ++ int i; ++ ++ for (i = 0; i < len/sizeof(struct dsa_hw_desc); i++) { ++ int rc = idxd_submit_user_descriptor(ctx, udesc + i); ++ ++ if (rc) ++ return written ? written : rc; ++ ++ written += sizeof(struct dsa_hw_desc); ++ } ++ ++ return written; ++} ++ + static __poll_t idxd_cdev_poll(struct file *filp, + struct poll_table_struct *wait) + { +@@ -437,6 +512,7 @@ static const struct file_operations idxd_cdev_fops = { + .open = idxd_cdev_open, + .release = idxd_cdev_release, + .mmap = idxd_cdev_mmap, ++ .write = idxd_cdev_write, + .poll = idxd_cdev_poll, + }; + +@@ -501,7 +577,6 @@ void idxd_wq_del_cdev(struct idxd_wq *wq) + struct idxd_cdev *idxd_cdev; + + idxd_cdev = wq->idxd_cdev; +- ida_destroy(&file_ida); + wq->idxd_cdev = NULL; + cdev_device_del(&idxd_cdev->cdev, cdev_dev(idxd_cdev)); + put_device(cdev_dev(idxd_cdev)); +diff --git a/drivers/dma/idxd/debugfs.c b/drivers/dma/idxd/debugfs.c +index 9cfbd9b14c4c43..ad4245cb301d50 100644 +--- a/drivers/dma/idxd/debugfs.c ++++ b/drivers/dma/idxd/debugfs.c +@@ -66,11 +66,11 @@ static int debugfs_evl_show(struct seq_file *s, void *d) + if (!evl || !evl->log) + return 0; + +- spin_lock(&evl->lock); ++ mutex_lock(&evl->lock); + +- h = evl->head; + evl_status.bits = ioread64(idxd->reg_base + IDXD_EVLSTATUS_OFFSET); + t = evl_status.tail; ++ h = evl_status.head; + evl_size = evl->size; + + seq_printf(s, "Event Log head %u tail %u interrupt pending %u\n\n", +@@ -87,7 +87,7 @@ static int debugfs_evl_show(struct seq_file *s, void *d) + dump_event_entry(idxd, s, i, &count, processed); + } + +- spin_unlock(&evl->lock); ++ mutex_unlock(&evl->lock); + return 0; + } + +diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c +index 8f754f922217de..542d340552dd71 100644 +--- a/drivers/dma/idxd/device.c ++++ b/drivers/dma/idxd/device.c +@@ -770,7 +770,7 @@ static int idxd_device_evl_setup(struct idxd_device *idxd) + goto err_alloc; + } + +- spin_lock(&evl->lock); ++ mutex_lock(&evl->lock); + evl->log = addr; + evl->dma = dma_addr; + evl->log_size = size; +@@ -791,7 +791,7 @@ static int idxd_device_evl_setup(struct idxd_device *idxd) + gencfg.evl_en = 1; + iowrite32(gencfg.bits, idxd->reg_base + IDXD_GENCFG_OFFSET); + +- spin_unlock(&evl->lock); ++ mutex_unlock(&evl->lock); + return 0; + + err_alloc: +@@ -802,6 +802,9 @@ static int idxd_device_evl_setup(struct idxd_device *idxd) + + static void idxd_device_evl_free(struct idxd_device *idxd) + { ++ void *evl_log; ++ unsigned int evl_log_size; ++ dma_addr_t evl_dma; + union gencfg_reg gencfg; + union genctrl_reg genctrl; + struct device *dev = &idxd->pdev->dev; +@@ -811,7 +814,7 @@ static void idxd_device_evl_free(struct idxd_device *idxd) + if (!gencfg.evl_en) + return; + +- spin_lock(&evl->lock); ++ mutex_lock(&evl->lock); + gencfg.evl_en = 0; + iowrite32(gencfg.bits, idxd->reg_base + IDXD_GENCFG_OFFSET); + +@@ -822,11 +825,15 @@ static void idxd_device_evl_free(struct idxd_device *idxd) + iowrite64(0, idxd->reg_base + IDXD_EVLCFG_OFFSET); + iowrite64(0, idxd->reg_base + IDXD_EVLCFG_OFFSET + 8); + +- dma_free_coherent(dev, evl->log_size, evl->log, evl->dma); + bitmap_free(evl->bmap); ++ evl_log = evl->log; ++ evl_log_size = evl->log_size; ++ evl_dma = evl->dma; + evl->log = NULL; + evl->size = IDXD_EVL_SIZE_MIN; +- spin_unlock(&evl->lock); ++ mutex_unlock(&evl->lock); ++ ++ dma_free_coherent(dev, evl_log_size, evl_log, evl_dma); + } + + static void idxd_group_config_write(struct idxd_group *group) +diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h +index e269ca1f486255..bea10c5cdb76bb 100644 +--- a/drivers/dma/idxd/idxd.h ++++ b/drivers/dma/idxd/idxd.h +@@ -275,18 +275,18 @@ struct idxd_driver_data { + int evl_cr_off; + int cr_status_off; + int cr_result_off; ++ bool user_submission_safe; + }; + + struct idxd_evl { + /* Lock to protect event log access. */ +- spinlock_t lock; ++ struct mutex lock; + void *log; + dma_addr_t dma; + /* Total size of event log = number of entries * entry size. */ + unsigned int log_size; + /* The number of entries in the event log. */ + u16 size; +- u16 head; + unsigned long *bmap; + bool batch_fail[IDXD_MAX_BATCH_IDENT]; + }; +@@ -361,6 +361,8 @@ struct idxd_device { + + struct dentry *dbgfs_dir; + struct dentry *dbgfs_evl_file; ++ ++ bool user_submission_safe; + }; + + static inline unsigned int evl_ent_size(struct idxd_device *idxd) +diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c +index 0eb1c827a215f9..786afb256b6e0d 100644 +--- a/drivers/dma/idxd/init.c ++++ b/drivers/dma/idxd/init.c +@@ -47,6 +47,7 @@ static struct idxd_driver_data idxd_driver_data[] = { + .align = 32, + .dev_type = &dsa_device_type, + .evl_cr_off = offsetof(struct dsa_evl_entry, cr), ++ .user_submission_safe = false, /* See INTEL-SA-01084 security advisory */ + .cr_status_off = offsetof(struct dsa_completion_record, status), + .cr_result_off = offsetof(struct dsa_completion_record, result), + }, +@@ -57,6 +58,7 @@ static struct idxd_driver_data idxd_driver_data[] = { + .align = 64, + .dev_type = &iax_device_type, + .evl_cr_off = offsetof(struct iax_evl_entry, cr), ++ .user_submission_safe = false, /* See INTEL-SA-01084 security advisory */ + .cr_status_off = offsetof(struct iax_completion_record, status), + .cr_result_off = offsetof(struct iax_completion_record, error_code), + }, +@@ -342,7 +344,9 @@ static void idxd_cleanup_internals(struct idxd_device *idxd) + static int idxd_init_evl(struct idxd_device *idxd) + { + struct device *dev = &idxd->pdev->dev; ++ unsigned int evl_cache_size; + struct idxd_evl *evl; ++ const char *idxd_name; + + if (idxd->hw.gen_cap.evl_support == 0) + return 0; +@@ -351,12 +355,19 @@ static int idxd_init_evl(struct idxd_device *idxd) + if (!evl) + return -ENOMEM; + +- spin_lock_init(&evl->lock); ++ mutex_init(&evl->lock); + evl->size = IDXD_EVL_SIZE_MIN; + +- idxd->evl_cache = kmem_cache_create(dev_name(idxd_confdev(idxd)), +- sizeof(struct idxd_evl_fault) + evl_ent_size(idxd), +- 0, 0, NULL); ++ idxd_name = dev_name(idxd_confdev(idxd)); ++ evl_cache_size = sizeof(struct idxd_evl_fault) + evl_ent_size(idxd); ++ /* ++ * Since completion record in evl_cache will be copied to user ++ * when handling completion record page fault, need to create ++ * the cache suitable for user copy. ++ */ ++ idxd->evl_cache = kmem_cache_create_usercopy(idxd_name, evl_cache_size, ++ 0, 0, 0, evl_cache_size, ++ NULL); + if (!idxd->evl_cache) { + kfree(evl); + return -ENOMEM; +@@ -758,6 +769,8 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) + dev_info(&pdev->dev, "Intel(R) Accelerator Device (v%x)\n", + idxd->hw.version); + ++ idxd->user_submission_safe = data->user_submission_safe; ++ + return 0; + + err_dev_register: +diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c +index b501320a9c7ad0..7efc85b5bad9e9 100644 +--- a/drivers/dma/idxd/irq.c ++++ b/drivers/dma/idxd/irq.c +@@ -363,13 +363,13 @@ static void process_evl_entries(struct idxd_device *idxd) + evl_status.bits = 0; + evl_status.int_pending = 1; + +- spin_lock(&evl->lock); ++ mutex_lock(&evl->lock); + /* Clear interrupt pending bit */ + iowrite32(evl_status.bits_upper32, + idxd->reg_base + IDXD_EVLSTATUS_OFFSET + sizeof(u32)); +- h = evl->head; + evl_status.bits = ioread64(idxd->reg_base + IDXD_EVLSTATUS_OFFSET); + t = evl_status.tail; ++ h = evl_status.head; + size = idxd->evl->size; + + while (h != t) { +@@ -378,10 +378,9 @@ static void process_evl_entries(struct idxd_device *idxd) + h = (h + 1) % size; + } + +- evl->head = h; + evl_status.head = h; + iowrite32(evl_status.bits_lower32, idxd->reg_base + IDXD_EVLSTATUS_OFFSET); +- spin_unlock(&evl->lock); ++ mutex_unlock(&evl->lock); + } + + irqreturn_t idxd_misc_thread(int vec, void *data) +@@ -612,11 +611,13 @@ static void irq_process_work_list(struct idxd_irq_entry *irq_entry) + + spin_unlock(&irq_entry->list_lock); + +- list_for_each_entry(desc, &flist, list) { ++ list_for_each_entry_safe(desc, n, &flist, list) { + /* + * Check against the original status as ABORT is software defined + * and 0xff, which DSA_COMP_STATUS_MASK can mask out. + */ ++ list_del(&desc->list); ++ + if (unlikely(desc->completion->status == IDXD_COMP_DESC_ABORT)) { + idxd_dma_complete_txd(desc, IDXD_COMPLETE_ABORT, true); + continue; +diff --git a/drivers/dma/idxd/perfmon.c b/drivers/dma/idxd/perfmon.c +index fdda6d60426295..5e94247e1ea703 100644 +--- a/drivers/dma/idxd/perfmon.c ++++ b/drivers/dma/idxd/perfmon.c +@@ -528,14 +528,11 @@ static int perf_event_cpu_offline(unsigned int cpu, struct hlist_node *node) + return 0; + + target = cpumask_any_but(cpu_online_mask, cpu); +- + /* migrate events if there is a valid target */ +- if (target < nr_cpu_ids) ++ if (target < nr_cpu_ids) { + cpumask_set_cpu(target, &perfmon_dsa_cpu_mask); +- else +- target = -1; +- +- perf_pmu_migrate_context(&idxd_pmu->pmu, cpu, target); ++ perf_pmu_migrate_context(&idxd_pmu->pmu, cpu, target); ++ } + + return 0; + } +diff --git a/drivers/dma/idxd/registers.h b/drivers/dma/idxd/registers.h +index 7b54a3939ea135..cfbcd1adb1d1c2 100644 +--- a/drivers/dma/idxd/registers.h ++++ b/drivers/dma/idxd/registers.h +@@ -6,9 +6,6 @@ + #include + + /* PCI Config */ +-#define PCI_DEVICE_ID_INTEL_DSA_SPR0 0x0b25 +-#define PCI_DEVICE_ID_INTEL_IAX_SPR0 0x0cfe +- + #define DEVICE_VERSION_1 0x100 + #define DEVICE_VERSION_2 0x200 + +diff --git a/drivers/dma/idxd/submit.c b/drivers/dma/idxd/submit.c +index c01db23e3333f7..3f922518e3a525 100644 +--- a/drivers/dma/idxd/submit.c ++++ b/drivers/dma/idxd/submit.c +@@ -182,13 +182,6 @@ int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc) + + portal = idxd_wq_portal_addr(wq); + +- /* +- * The wmb() flushes writes to coherent DMA data before +- * possibly triggering a DMA read. The wmb() is necessary +- * even on UP because the recipient is a device. +- */ +- wmb(); +- + /* + * Pending the descriptor to the lockless list for the irq_entry + * that we designated the descriptor to. +@@ -199,6 +192,13 @@ int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc) + llist_add(&desc->llnode, &ie->pending_llist); + } + ++ /* ++ * The wmb() flushes writes to coherent DMA data before ++ * possibly triggering a DMA read. The wmb() is necessary ++ * even on UP because the recipient is a device. ++ */ ++ wmb(); ++ + if (wq_dedicated(wq)) { + iosubmit_cmds512(portal, desc->hw, 1); + } else { +diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c +index 7caba90d85b31e..1fd5a93045f79e 100644 +--- a/drivers/dma/idxd/sysfs.c ++++ b/drivers/dma/idxd/sysfs.c +@@ -1197,12 +1197,35 @@ static ssize_t wq_enqcmds_retries_store(struct device *dev, struct device_attrib + static struct device_attribute dev_attr_wq_enqcmds_retries = + __ATTR(enqcmds_retries, 0644, wq_enqcmds_retries_show, wq_enqcmds_retries_store); + ++static ssize_t op_cap_show_common(struct device *dev, char *buf, unsigned long *opcap_bmap) ++{ ++ ssize_t pos; ++ int i; ++ ++ pos = 0; ++ for (i = IDXD_MAX_OPCAP_BITS/64 - 1; i >= 0; i--) { ++ unsigned long val = opcap_bmap[i]; ++ ++ /* On systems where direct user submissions are not safe, we need to clear out ++ * the BATCH capability from the capability mask in sysfs since we cannot support ++ * that command on such systems. ++ */ ++ if (i == DSA_OPCODE_BATCH/64 && !confdev_to_idxd(dev)->user_submission_safe) ++ clear_bit(DSA_OPCODE_BATCH % 64, &val); ++ ++ pos += sysfs_emit_at(buf, pos, "%*pb", 64, &val); ++ pos += sysfs_emit_at(buf, pos, "%c", i == 0 ? '\n' : ','); ++ } ++ ++ return pos; ++} ++ + static ssize_t wq_op_config_show(struct device *dev, + struct device_attribute *attr, char *buf) + { + struct idxd_wq *wq = confdev_to_wq(dev); + +- return sysfs_emit(buf, "%*pb\n", IDXD_MAX_OPCAP_BITS, wq->opcap_bmap); ++ return op_cap_show_common(dev, buf, wq->opcap_bmap); + } + + static int idxd_verify_supported_opcap(struct idxd_device *idxd, unsigned long *opmask) +@@ -1421,7 +1444,7 @@ static ssize_t op_cap_show(struct device *dev, + { + struct idxd_device *idxd = confdev_to_idxd(dev); + +- return sysfs_emit(buf, "%*pb\n", IDXD_MAX_OPCAP_BITS, idxd->opcap_bmap); ++ return op_cap_show_common(dev, buf, idxd->opcap_bmap); + } + static DEVICE_ATTR_RO(op_cap); + +diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c +index 9c364e92cb828d..e8f45a7fded435 100644 +--- a/drivers/dma/ioat/init.c ++++ b/drivers/dma/ioat/init.c +@@ -534,18 +534,6 @@ static int ioat_probe(struct ioatdma_device *ioat_dma) + return err; + } + +-static int ioat_register(struct ioatdma_device *ioat_dma) +-{ +- int err = dma_async_device_register(&ioat_dma->dma_dev); +- +- if (err) { +- ioat_disable_interrupts(ioat_dma); +- dma_pool_destroy(ioat_dma->completion_pool); +- } +- +- return err; +-} +- + static void ioat_dma_remove(struct ioatdma_device *ioat_dma) + { + struct dma_device *dma = &ioat_dma->dma_dev; +@@ -1181,9 +1169,9 @@ static int ioat3_dma_probe(struct ioatdma_device *ioat_dma, int dca) + ioat_chan->reg_base + IOAT_DCACTRL_OFFSET); + } + +- err = ioat_register(ioat_dma); ++ err = dma_async_device_register(&ioat_dma->dma_dev); + if (err) +- return err; ++ goto err_disable_interrupts; + + ioat_kobject_add(ioat_dma, &ioat_ktype); + +@@ -1192,20 +1180,29 @@ static int ioat3_dma_probe(struct ioatdma_device *ioat_dma, int dca) + + /* disable relaxed ordering */ + err = pcie_capability_read_word(pdev, PCI_EXP_DEVCTL, &val16); +- if (err) +- return pcibios_err_to_errno(err); ++ if (err) { ++ err = pcibios_err_to_errno(err); ++ goto err_disable_interrupts; ++ } + + /* clear relaxed ordering enable */ + val16 &= ~PCI_EXP_DEVCTL_RELAX_EN; + err = pcie_capability_write_word(pdev, PCI_EXP_DEVCTL, val16); +- if (err) +- return pcibios_err_to_errno(err); ++ if (err) { ++ err = pcibios_err_to_errno(err); ++ goto err_disable_interrupts; ++ } + + if (ioat_dma->cap & IOAT_CAP_DPS) + writeb(ioat_pending_level + 1, + ioat_dma->reg_base + IOAT_PREFETCH_LIMIT_OFFSET); + + return 0; ++ ++err_disable_interrupts: ++ ioat_disable_interrupts(ioat_dma); ++ dma_pool_destroy(ioat_dma->completion_pool); ++ return err; + } + + static void ioat_shutdown(struct pci_dev *pdev) +@@ -1350,6 +1347,8 @@ static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) + void __iomem * const *iomap; + struct device *dev = &pdev->dev; + struct ioatdma_device *device; ++ unsigned int i; ++ u8 version; + int err; + + err = pcim_enable_device(pdev); +@@ -1363,6 +1362,10 @@ static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) + if (!iomap) + return -ENOMEM; + ++ version = readb(iomap[IOAT_MMIO_BAR] + IOAT_VER_OFFSET); ++ if (version < IOAT_VER_3_0) ++ return -ENODEV; ++ + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (err) + return err; +@@ -1373,17 +1376,18 @@ static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) + pci_set_master(pdev); + pci_set_drvdata(pdev, device); + +- device->version = readb(device->reg_base + IOAT_VER_OFFSET); ++ device->version = version; + if (device->version >= IOAT_VER_3_4) + ioat_dca_enabled = 0; +- if (device->version >= IOAT_VER_3_0) { +- if (is_skx_ioat(pdev)) +- device->version = IOAT_VER_3_2; +- err = ioat3_dma_probe(device, ioat_dca_enabled); +- } else +- return -ENODEV; + ++ if (is_skx_ioat(pdev)) ++ device->version = IOAT_VER_3_2; ++ ++ err = ioat3_dma_probe(device, ioat_dca_enabled); + if (err) { ++ for (i = 0; i < IOAT_MAX_CHANS; i++) ++ kfree(device->idx[i]); ++ kfree(device); + dev_err(dev, "Intel(R) I/OAT DMA Engine init failed\n"); + return -ENODEV; + } +@@ -1445,6 +1449,7 @@ module_init(ioat_init_module); + static void __exit ioat_exit_module(void) + { + pci_unregister_driver(&ioat_pci_driver); ++ kmem_cache_destroy(ioat_sed_cache); + kmem_cache_destroy(ioat_cache); + } + module_exit(ioat_exit_module); +diff --git a/drivers/dma/owl-dma.c b/drivers/dma/owl-dma.c +index 384476757c5e3a..3bcf73ef69dc7f 100644 +--- a/drivers/dma/owl-dma.c ++++ b/drivers/dma/owl-dma.c +@@ -250,7 +250,7 @@ static void pchan_update(struct owl_dma_pchan *pchan, u32 reg, + else + regval &= ~val; + +- writel(val, pchan->base + reg); ++ writel(regval, pchan->base + reg); + } + + static void pchan_writel(struct owl_dma_pchan *pchan, u32 reg, u32 data) +@@ -274,7 +274,7 @@ static void dma_update(struct owl_dma *od, u32 reg, u32 val, bool state) + else + regval &= ~val; + +- writel(val, od->base + reg); ++ writel(regval, od->base + reg); + } + + static void dma_writel(struct owl_dma *od, u32 reg, u32 data) +diff --git a/drivers/dma/ptdma/ptdma-dmaengine.c b/drivers/dma/ptdma/ptdma-dmaengine.c +index 1aa65e5de0f3ad..f792407348077d 100644 +--- a/drivers/dma/ptdma/ptdma-dmaengine.c ++++ b/drivers/dma/ptdma/ptdma-dmaengine.c +@@ -385,8 +385,6 @@ int pt_dmaengine_register(struct pt_device *pt) + chan->vc.desc_free = pt_do_cleanup; + vchan_init(&chan->vc, dma_dev); + +- dma_set_mask_and_coherent(pt->dev, DMA_BIT_MASK(64)); +- + ret = dma_async_device_register(dma_dev); + if (ret) + goto err_reg; +diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c +index 1b046d9a3a269a..16d342654da2bf 100644 +--- a/drivers/dma/pxa_dma.c ++++ b/drivers/dma/pxa_dma.c +@@ -722,7 +722,6 @@ static void pxad_free_desc(struct virt_dma_desc *vd) + dma_addr_t dma; + struct pxad_desc_sw *sw_desc = to_pxad_sw_desc(vd); + +- BUG_ON(sw_desc->nb_desc == 0); + for (i = sw_desc->nb_desc - 1; i >= 0; i--) { + if (i > 0) + dma = sw_desc->hw_desc[i - 1]->ddadr; +diff --git a/drivers/dma/sh/shdma.h b/drivers/dma/sh/shdma.h +index 9c121a4b33ad82..f97d80343aea42 100644 +--- a/drivers/dma/sh/shdma.h ++++ b/drivers/dma/sh/shdma.h +@@ -25,7 +25,7 @@ struct sh_dmae_chan { + const struct sh_dmae_slave_config *config; /* Slave DMA configuration */ + int xmit_shift; /* log_2(bytes_per_xfer) */ + void __iomem *base; +- char dev_id[16]; /* unique name per DMAC of channel */ ++ char dev_id[32]; /* unique name per DMAC of channel */ + int pm_error; + dma_addr_t slave_addr; + }; +diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c +index 0b30151fb45c4c..9840594a6aaa1f 100644 +--- a/drivers/dma/stm32-dma.c ++++ b/drivers/dma/stm32-dma.c +@@ -1249,8 +1249,8 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( + enum dma_slave_buswidth max_width; + struct stm32_dma_desc *desc; + size_t xfer_count, offset; +- u32 num_sgs, best_burst, dma_burst, threshold; +- int i; ++ u32 num_sgs, best_burst, threshold; ++ int dma_burst, i; + + num_sgs = DIV_ROUND_UP(len, STM32_DMA_ALIGNED_MAX_DATA_ITEMS); + desc = kzalloc(struct_size(desc, sg_req, num_sgs), GFP_NOWAIT); +@@ -1268,6 +1268,10 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( + best_burst = stm32_dma_get_best_burst(len, STM32_DMA_MAX_BURST, + threshold, max_width); + dma_burst = stm32_dma_get_burst(chan, best_burst); ++ if (dma_burst < 0) { ++ kfree(desc); ++ return NULL; ++ } + + stm32_dma_clear_reg(&desc->sg_req[i].chan_reg); + desc->sg_req[i].chan_reg.dma_scr = +diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c +index bae08b3f55c73f..f414efdbd809e1 100644 +--- a/drivers/dma/stm32-mdma.c ++++ b/drivers/dma/stm32-mdma.c +@@ -489,7 +489,7 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan, + src_maxburst = chan->dma_config.src_maxburst; + dst_maxburst = chan->dma_config.dst_maxburst; + +- ccr = stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)); ++ ccr = stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)) & ~STM32_MDMA_CCR_EN; + ctcr = stm32_mdma_read(dmadev, STM32_MDMA_CTCR(chan->id)); + ctbr = stm32_mdma_read(dmadev, STM32_MDMA_CTBR(chan->id)); + +@@ -965,7 +965,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src, + if (!desc) + return NULL; + +- ccr = stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)); ++ ccr = stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)) & ~STM32_MDMA_CCR_EN; + ctcr = stm32_mdma_read(dmadev, STM32_MDMA_CTCR(chan->id)); + ctbr = stm32_mdma_read(dmadev, STM32_MDMA_CTBR(chan->id)); + cbndtr = stm32_mdma_read(dmadev, STM32_MDMA_CBNDTR(chan->id)); +diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c +index 33b10100110096..674cf630528383 100644 +--- a/drivers/dma/tegra186-gpc-dma.c ++++ b/drivers/dma/tegra186-gpc-dma.c +@@ -746,6 +746,9 @@ static int tegra_dma_get_residual(struct tegra_dma_channel *tdc) + bytes_xfer = dma_desc->bytes_xfer + + sg_req[dma_desc->sg_idx].len - (wcount * 4); + ++ if (dma_desc->bytes_req == bytes_xfer) ++ return 0; ++ + residual = dma_desc->bytes_req - (bytes_xfer % dma_desc->bytes_req); + + return residual; +diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c +index aa8e2e8ac26098..155c409d2b434d 100644 +--- a/drivers/dma/ti/edma.c ++++ b/drivers/dma/ti/edma.c +@@ -2401,9 +2401,14 @@ static int edma_probe(struct platform_device *pdev) + if (irq < 0 && node) + irq = irq_of_parse_and_map(node, 0); + +- if (irq >= 0) { ++ if (irq > 0) { + irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccint", + dev_name(dev)); ++ if (!irq_name) { ++ ret = -ENOMEM; ++ goto err_disable_pm; ++ } ++ + ret = devm_request_irq(dev, irq, dma_irq_handler, 0, irq_name, + ecc); + if (ret) { +@@ -2417,9 +2422,14 @@ static int edma_probe(struct platform_device *pdev) + if (irq < 0 && node) + irq = irq_of_parse_and_map(node, 2); + +- if (irq >= 0) { ++ if (irq > 0) { + irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccerrint", + dev_name(dev)); ++ if (!irq_name) { ++ ret = -ENOMEM; ++ goto err_disable_pm; ++ } ++ + ret = devm_request_irq(dev, irq, dma_ccerr_handler, 0, irq_name, + ecc); + if (ret) { +diff --git a/drivers/dma/ti/k3-psil-am62.c b/drivers/dma/ti/k3-psil-am62.c +index 2b6fd6e37c6107..1272b1541f61e2 100644 +--- a/drivers/dma/ti/k3-psil-am62.c ++++ b/drivers/dma/ti/k3-psil-am62.c +@@ -74,7 +74,9 @@ static struct psil_ep am62_src_ep_map[] = { + PSIL_SAUL(0x7505, 21, 35, 8, 36, 0), + PSIL_SAUL(0x7506, 22, 43, 8, 43, 0), + PSIL_SAUL(0x7507, 23, 43, 8, 44, 0), +- /* PDMA_MAIN0 - SPI0-3 */ ++ /* PDMA_MAIN0 - SPI0-2 */ ++ PSIL_PDMA_XY_PKT(0x4300), ++ PSIL_PDMA_XY_PKT(0x4301), + PSIL_PDMA_XY_PKT(0x4302), + PSIL_PDMA_XY_PKT(0x4303), + PSIL_PDMA_XY_PKT(0x4304), +@@ -85,8 +87,6 @@ static struct psil_ep am62_src_ep_map[] = { + PSIL_PDMA_XY_PKT(0x4309), + PSIL_PDMA_XY_PKT(0x430a), + PSIL_PDMA_XY_PKT(0x430b), +- PSIL_PDMA_XY_PKT(0x430c), +- PSIL_PDMA_XY_PKT(0x430d), + /* PDMA_MAIN1 - UART0-6 */ + PSIL_PDMA_XY_PKT(0x4400), + PSIL_PDMA_XY_PKT(0x4401), +@@ -141,7 +141,9 @@ static struct psil_ep am62_dst_ep_map[] = { + /* SAUL */ + PSIL_SAUL(0xf500, 27, 83, 8, 83, 1), + PSIL_SAUL(0xf501, 28, 91, 8, 91, 1), +- /* PDMA_MAIN0 - SPI0-3 */ ++ /* PDMA_MAIN0 - SPI0-2 */ ++ PSIL_PDMA_XY_PKT(0xc300), ++ PSIL_PDMA_XY_PKT(0xc301), + PSIL_PDMA_XY_PKT(0xc302), + PSIL_PDMA_XY_PKT(0xc303), + PSIL_PDMA_XY_PKT(0xc304), +@@ -152,8 +154,6 @@ static struct psil_ep am62_dst_ep_map[] = { + PSIL_PDMA_XY_PKT(0xc309), + PSIL_PDMA_XY_PKT(0xc30a), + PSIL_PDMA_XY_PKT(0xc30b), +- PSIL_PDMA_XY_PKT(0xc30c), +- PSIL_PDMA_XY_PKT(0xc30d), + /* PDMA_MAIN1 - UART0-6 */ + PSIL_PDMA_XY_PKT(0xc400), + PSIL_PDMA_XY_PKT(0xc401), +diff --git a/drivers/dma/ti/k3-psil-am62a.c b/drivers/dma/ti/k3-psil-am62a.c +index ca9d71f914220a..4cf9123b0e9326 100644 +--- a/drivers/dma/ti/k3-psil-am62a.c ++++ b/drivers/dma/ti/k3-psil-am62a.c +@@ -84,7 +84,9 @@ static struct psil_ep am62a_src_ep_map[] = { + PSIL_SAUL(0x7505, 21, 35, 8, 36, 0), + PSIL_SAUL(0x7506, 22, 43, 8, 43, 0), + PSIL_SAUL(0x7507, 23, 43, 8, 44, 0), +- /* PDMA_MAIN0 - SPI0-3 */ ++ /* PDMA_MAIN0 - SPI0-2 */ ++ PSIL_PDMA_XY_PKT(0x4300), ++ PSIL_PDMA_XY_PKT(0x4301), + PSIL_PDMA_XY_PKT(0x4302), + PSIL_PDMA_XY_PKT(0x4303), + PSIL_PDMA_XY_PKT(0x4304), +@@ -95,8 +97,6 @@ static struct psil_ep am62a_src_ep_map[] = { + PSIL_PDMA_XY_PKT(0x4309), + PSIL_PDMA_XY_PKT(0x430a), + PSIL_PDMA_XY_PKT(0x430b), +- PSIL_PDMA_XY_PKT(0x430c), +- PSIL_PDMA_XY_PKT(0x430d), + /* PDMA_MAIN1 - UART0-6 */ + PSIL_PDMA_XY_PKT(0x4400), + PSIL_PDMA_XY_PKT(0x4401), +@@ -151,7 +151,9 @@ static struct psil_ep am62a_dst_ep_map[] = { + /* SAUL */ + PSIL_SAUL(0xf500, 27, 83, 8, 83, 1), + PSIL_SAUL(0xf501, 28, 91, 8, 91, 1), +- /* PDMA_MAIN0 - SPI0-3 */ ++ /* PDMA_MAIN0 - SPI0-2 */ ++ PSIL_PDMA_XY_PKT(0xc300), ++ PSIL_PDMA_XY_PKT(0xc301), + PSIL_PDMA_XY_PKT(0xc302), + PSIL_PDMA_XY_PKT(0xc303), + PSIL_PDMA_XY_PKT(0xc304), +@@ -162,8 +164,6 @@ static struct psil_ep am62a_dst_ep_map[] = { + PSIL_PDMA_XY_PKT(0xc309), + PSIL_PDMA_XY_PKT(0xc30a), + PSIL_PDMA_XY_PKT(0xc30b), +- PSIL_PDMA_XY_PKT(0xc30c), +- PSIL_PDMA_XY_PKT(0xc30d), + /* PDMA_MAIN1 - UART0-6 */ + PSIL_PDMA_XY_PKT(0xc400), + PSIL_PDMA_XY_PKT(0xc401), +diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c +index 30fd2f386f36a1..02a1ab04f498e5 100644 +--- a/drivers/dma/ti/k3-udma.c ++++ b/drivers/dma/ti/k3-udma.c +@@ -3968,6 +3968,7 @@ static void udma_desc_pre_callback(struct virt_dma_chan *vc, + { + struct udma_chan *uc = to_udma_chan(&vc->chan); + struct udma_desc *d; ++ u8 status; + + if (!vd) + return; +@@ -3977,12 +3978,12 @@ static void udma_desc_pre_callback(struct virt_dma_chan *vc, + if (d->metadata_size) + udma_fetch_epib(uc, d); + +- /* Provide residue information for the client */ + if (result) { + void *desc_vaddr = udma_curr_cppi5_desc_vaddr(d, d->desc_idx); + + if (cppi5_desc_get_type(desc_vaddr) == + CPPI5_INFO0_DESC_TYPE_VAL_HOST) { ++ /* Provide residue information for the client */ + result->residue = d->residue - + cppi5_hdesc_get_pktlen(desc_vaddr); + if (result->residue) +@@ -3991,7 +3992,12 @@ static void udma_desc_pre_callback(struct virt_dma_chan *vc, + result->result = DMA_TRANS_NOERROR; + } else { + result->residue = 0; +- result->result = DMA_TRANS_NOERROR; ++ /* Propagate TR Response errors to the client */ ++ status = d->hwdesc[0].tr_resp_base->status; ++ if (status) ++ result->result = DMA_TRANS_ABORTED; ++ else ++ result->result = DMA_TRANS_NOERROR; + } + } + } +@@ -4464,7 +4470,9 @@ static int udma_get_mmrs(struct platform_device *pdev, struct udma_dev *ud) + ud->rchan_cnt = UDMA_CAP2_RCHAN_CNT(cap2); + break; + case DMA_TYPE_BCDMA: +- ud->bchan_cnt = BCDMA_CAP2_BCHAN_CNT(cap2); ++ ud->bchan_cnt = BCDMA_CAP2_BCHAN_CNT(cap2) + ++ BCDMA_CAP3_HBCHAN_CNT(cap3) + ++ BCDMA_CAP3_UBCHAN_CNT(cap3); + ud->tchan_cnt = BCDMA_CAP2_TCHAN_CNT(cap2); + ud->rchan_cnt = BCDMA_CAP2_RCHAN_CNT(cap2); + ud->rflow_cnt = ud->rchan_cnt; +diff --git a/drivers/dma/xilinx/xilinx_dpdma.c b/drivers/dma/xilinx/xilinx_dpdma.c +index 84dc5240a8074a..93938ed80fc837 100644 +--- a/drivers/dma/xilinx/xilinx_dpdma.c ++++ b/drivers/dma/xilinx/xilinx_dpdma.c +@@ -214,7 +214,8 @@ struct xilinx_dpdma_tx_desc { + * @running: true if the channel is running + * @first_frame: flag for the first frame of stream + * @video_group: flag if multi-channel operation is needed for video channels +- * @lock: lock to access struct xilinx_dpdma_chan ++ * @lock: lock to access struct xilinx_dpdma_chan. Must be taken before ++ * @vchan.lock, if both are to be held. + * @desc_pool: descriptor allocation pool + * @err_task: error IRQ bottom half handler + * @desc: References to descriptors being processed +@@ -1097,12 +1098,14 @@ static void xilinx_dpdma_chan_vsync_irq(struct xilinx_dpdma_chan *chan) + * Complete the active descriptor, if any, promote the pending + * descriptor to active, and queue the next transfer, if any. + */ ++ spin_lock(&chan->vchan.lock); + if (chan->desc.active) + vchan_cookie_complete(&chan->desc.active->vdesc); + chan->desc.active = pending; + chan->desc.pending = NULL; + + xilinx_dpdma_chan_queue_transfer(chan); ++ spin_unlock(&chan->vchan.lock); + + out: + spin_unlock_irqrestore(&chan->lock, flags); +@@ -1264,10 +1267,12 @@ static void xilinx_dpdma_issue_pending(struct dma_chan *dchan) + struct xilinx_dpdma_chan *chan = to_xilinx_chan(dchan); + unsigned long flags; + +- spin_lock_irqsave(&chan->vchan.lock, flags); ++ spin_lock_irqsave(&chan->lock, flags); ++ spin_lock(&chan->vchan.lock); + if (vchan_issue_pending(&chan->vchan)) + xilinx_dpdma_chan_queue_transfer(chan); +- spin_unlock_irqrestore(&chan->vchan.lock, flags); ++ spin_unlock(&chan->vchan.lock); ++ spin_unlock_irqrestore(&chan->lock, flags); + } + + static int xilinx_dpdma_config(struct dma_chan *dchan, +@@ -1495,7 +1500,9 @@ static void xilinx_dpdma_chan_err_task(struct tasklet_struct *t) + XILINX_DPDMA_EINTR_CHAN_ERR_MASK << chan->id); + + spin_lock_irqsave(&chan->lock, flags); ++ spin_lock(&chan->vchan.lock); + xilinx_dpdma_chan_queue_transfer(chan); ++ spin_unlock(&chan->vchan.lock); + spin_unlock_irqrestore(&chan->lock, flags); + } + +diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile +index 61945d3113cc32..446364264e2b18 100644 +--- a/drivers/edac/Makefile ++++ b/drivers/edac/Makefile +@@ -54,11 +54,13 @@ obj-$(CONFIG_EDAC_MPC85XX) += mpc85xx_edac_mod.o + layerscape_edac_mod-y := fsl_ddr_edac.o layerscape_edac.o + obj-$(CONFIG_EDAC_LAYERSCAPE) += layerscape_edac_mod.o + +-skx_edac-y := skx_common.o skx_base.o +-obj-$(CONFIG_EDAC_SKX) += skx_edac.o ++skx_edac_common-y := skx_common.o + +-i10nm_edac-y := skx_common.o i10nm_base.o +-obj-$(CONFIG_EDAC_I10NM) += i10nm_edac.o ++skx_edac-y := skx_base.o ++obj-$(CONFIG_EDAC_SKX) += skx_edac.o skx_edac_common.o ++ ++i10nm_edac-y := i10nm_base.o ++obj-$(CONFIG_EDAC_I10NM) += i10nm_edac.o skx_edac_common.o + + obj-$(CONFIG_EDAC_CELL) += cell_edac.o + obj-$(CONFIG_EDAC_PPC4XX) += ppc4xx_edac.o +diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c +index 9b6642d0087130..b61c7f02a8c17c 100644 +--- a/drivers/edac/amd64_edac.c ++++ b/drivers/edac/amd64_edac.c +@@ -80,7 +80,7 @@ int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset, + amd64_warn("%s: error reading F%dx%03x.\n", + func, PCI_FUNC(pdev->devfn), offset); + +- return err; ++ return pcibios_err_to_errno(err); + } + + int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset, +@@ -93,7 +93,7 @@ int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset, + amd64_warn("%s: error writing to F%dx%03x.\n", + func, PCI_FUNC(pdev->devfn), offset); + +- return err; ++ return pcibios_err_to_errno(err); + } + + /* +@@ -1016,8 +1016,10 @@ static int gpu_get_node_map(void) + } + + ret = pci_read_config_dword(pdev, REG_LOCAL_NODE_TYPE_MAP, &tmp); +- if (ret) ++ if (ret) { ++ ret = pcibios_err_to_errno(ret); + goto out; ++ } + + gpu_node_map.node_count = FIELD_GET(LNTM_NODE_COUNT, tmp); + gpu_node_map.base_node_id = FIELD_GET(LNTM_BASE_NODE_ID, tmp); +diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c +index 1a18693294db48..a0edb61a5a01ac 100644 +--- a/drivers/edac/igen6_edac.c ++++ b/drivers/edac/igen6_edac.c +@@ -245,7 +245,7 @@ static u64 ehl_err_addr_to_imc_addr(u64 eaddr, int mc) + if (igen6_tom <= _4GB) + return eaddr + igen6_tolud - _4GB; + +- if (eaddr < _4GB) ++ if (eaddr >= igen6_tom) + return eaddr + igen6_tolud - igen6_tom; + + return eaddr; +@@ -627,7 +627,7 @@ static int errcmd_enable_error_reporting(bool enable) + + rc = pci_read_config_word(imc->pdev, ERRCMD_OFFSET, &errcmd); + if (rc) +- return rc; ++ return pcibios_err_to_errno(rc); + + if (enable) + errcmd |= ERRCMD_CE | ERRSTS_UE; +@@ -636,7 +636,7 @@ static int errcmd_enable_error_reporting(bool enable) + + rc = pci_write_config_word(imc->pdev, ERRCMD_OFFSET, errcmd); + if (rc) +- return rc; ++ return pcibios_err_to_errno(rc); + + return 0; + } +diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c +index ce3e0069e028d0..8d18099fd528cf 100644 +--- a/drivers/edac/skx_common.c ++++ b/drivers/edac/skx_common.c +@@ -48,7 +48,7 @@ static u64 skx_tolm, skx_tohm; + static LIST_HEAD(dev_edac_list); + static bool skx_mem_cfg_2lm; + +-int __init skx_adxl_get(void) ++int skx_adxl_get(void) + { + const char * const *names; + int i, j; +@@ -110,12 +110,14 @@ int __init skx_adxl_get(void) + + return -ENODEV; + } ++EXPORT_SYMBOL_GPL(skx_adxl_get); + +-void __exit skx_adxl_put(void) ++void skx_adxl_put(void) + { + kfree(adxl_values); + kfree(adxl_msg); + } ++EXPORT_SYMBOL_GPL(skx_adxl_put); + + static bool skx_adxl_decode(struct decoded_addr *res, bool error_in_1st_level_mem) + { +@@ -187,12 +189,14 @@ void skx_set_mem_cfg(bool mem_cfg_2lm) + { + skx_mem_cfg_2lm = mem_cfg_2lm; + } ++EXPORT_SYMBOL_GPL(skx_set_mem_cfg); + + void skx_set_decode(skx_decode_f decode, skx_show_retry_log_f show_retry_log) + { + driver_decode = decode; + skx_show_retry_rd_err_log = show_retry_log; + } ++EXPORT_SYMBOL_GPL(skx_set_decode); + + int skx_get_src_id(struct skx_dev *d, int off, u8 *id) + { +@@ -206,6 +210,7 @@ int skx_get_src_id(struct skx_dev *d, int off, u8 *id) + *id = GET_BITFIELD(reg, 12, 14); + return 0; + } ++EXPORT_SYMBOL_GPL(skx_get_src_id); + + int skx_get_node_id(struct skx_dev *d, u8 *id) + { +@@ -219,6 +224,7 @@ int skx_get_node_id(struct skx_dev *d, u8 *id) + *id = GET_BITFIELD(reg, 0, 2); + return 0; + } ++EXPORT_SYMBOL_GPL(skx_get_node_id); + + static int get_width(u32 mtr) + { +@@ -284,6 +290,7 @@ int skx_get_all_bus_mappings(struct res_config *cfg, struct list_head **list) + *list = &dev_edac_list; + return ndev; + } ++EXPORT_SYMBOL_GPL(skx_get_all_bus_mappings); + + int skx_get_hi_lo(unsigned int did, int off[], u64 *tolm, u64 *tohm) + { +@@ -323,6 +330,7 @@ int skx_get_hi_lo(unsigned int did, int off[], u64 *tolm, u64 *tohm) + pci_dev_put(pdev); + return -ENODEV; + } ++EXPORT_SYMBOL_GPL(skx_get_hi_lo); + + static int skx_get_dimm_attr(u32 reg, int lobit, int hibit, int add, + int minval, int maxval, const char *name) +@@ -394,6 +402,7 @@ int skx_get_dimm_info(u32 mtr, u32 mcmtr, u32 amap, struct dimm_info *dimm, + + return 1; + } ++EXPORT_SYMBOL_GPL(skx_get_dimm_info); + + int skx_get_nvdimm_info(struct dimm_info *dimm, struct skx_imc *imc, + int chan, int dimmno, const char *mod_str) +@@ -442,6 +451,7 @@ int skx_get_nvdimm_info(struct dimm_info *dimm, struct skx_imc *imc, + + return (size == 0 || size == ~0ull) ? 0 : 1; + } ++EXPORT_SYMBOL_GPL(skx_get_nvdimm_info); + + int skx_register_mci(struct skx_imc *imc, struct pci_dev *pdev, + const char *ctl_name, const char *mod_str, +@@ -512,6 +522,7 @@ int skx_register_mci(struct skx_imc *imc, struct pci_dev *pdev, + imc->mci = NULL; + return rc; + } ++EXPORT_SYMBOL_GPL(skx_register_mci); + + static void skx_unregister_mci(struct skx_imc *imc) + { +@@ -648,6 +659,10 @@ int skx_mce_check_error(struct notifier_block *nb, unsigned long val, + memset(&res, 0, sizeof(res)); + res.mce = mce; + res.addr = mce->addr & MCI_ADDR_PHYSADDR; ++ if (!pfn_to_online_page(res.addr >> PAGE_SHIFT) && !arch_is_platform_page(res.addr)) { ++ pr_err("Invalid address 0x%llx in IA32_MC%d_ADDR\n", mce->addr, mce->bank); ++ return NOTIFY_DONE; ++ } + + /* Try driver decoder first */ + if (!(driver_decode && driver_decode(&res))) { +@@ -684,6 +699,7 @@ int skx_mce_check_error(struct notifier_block *nb, unsigned long val, + mce->kflags |= MCE_HANDLED_EDAC; + return NOTIFY_DONE; + } ++EXPORT_SYMBOL_GPL(skx_mce_check_error); + + void skx_remove(void) + { +@@ -721,3 +737,8 @@ void skx_remove(void) + kfree(d); + } + } ++EXPORT_SYMBOL_GPL(skx_remove); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Tony Luck"); ++MODULE_DESCRIPTION("MC Driver for Intel server processors"); +diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h +index b6d3607dffe27b..11faf1db4fa482 100644 +--- a/drivers/edac/skx_common.h ++++ b/drivers/edac/skx_common.h +@@ -231,8 +231,8 @@ typedef int (*get_dimm_config_f)(struct mem_ctl_info *mci, + typedef bool (*skx_decode_f)(struct decoded_addr *res); + typedef void (*skx_show_retry_log_f)(struct decoded_addr *res, char *msg, int len, bool scrub_err); + +-int __init skx_adxl_get(void); +-void __exit skx_adxl_put(void); ++int skx_adxl_get(void); ++void skx_adxl_put(void); + void skx_set_decode(skx_decode_f decode, skx_show_retry_log_f show_retry_log); + void skx_set_mem_cfg(bool mem_cfg_2lm); + +diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c +index c4fc64cbecd0e6..6ddc90d7ba7c2a 100644 +--- a/drivers/edac/synopsys_edac.c ++++ b/drivers/edac/synopsys_edac.c +@@ -9,6 +9,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + +@@ -299,6 +301,7 @@ struct synps_ecc_status { + /** + * struct synps_edac_priv - DDR memory controller private instance data. + * @baseaddr: Base address of the DDR controller. ++ * @reglock: Concurrent CSRs access lock. + * @message: Buffer for framing the event specific info. + * @stat: ECC status information. + * @p_data: Platform data. +@@ -313,6 +316,7 @@ struct synps_ecc_status { + */ + struct synps_edac_priv { + void __iomem *baseaddr; ++ spinlock_t reglock; + char message[SYNPS_EDAC_MSG_SIZE]; + struct synps_ecc_status stat; + const struct synps_platform_data *p_data; +@@ -334,6 +338,7 @@ struct synps_edac_priv { + * @get_mtype: Get mtype. + * @get_dtype: Get dtype. + * @get_ecc_state: Get ECC state. ++ * @get_mem_info: Get EDAC memory info + * @quirks: To differentiate IPs. + */ + struct synps_platform_data { +@@ -341,6 +346,9 @@ struct synps_platform_data { + enum mem_type (*get_mtype)(const void __iomem *base); + enum dev_type (*get_dtype)(const void __iomem *base); + bool (*get_ecc_state)(void __iomem *base); ++#ifdef CONFIG_EDAC_DEBUG ++ u64 (*get_mem_info)(struct synps_edac_priv *priv); ++#endif + int quirks; + }; + +@@ -399,6 +407,25 @@ static int zynq_get_error_info(struct synps_edac_priv *priv) + return 0; + } + ++#ifdef CONFIG_EDAC_DEBUG ++/** ++ * zynqmp_get_mem_info - Get the current memory info. ++ * @priv: DDR memory controller private instance data. ++ * ++ * Return: host interface address. ++ */ ++static u64 zynqmp_get_mem_info(struct synps_edac_priv *priv) ++{ ++ u64 hif_addr = 0, linear_addr; ++ ++ linear_addr = priv->poison_addr; ++ if (linear_addr >= SZ_32G) ++ linear_addr = linear_addr - SZ_32G + SZ_2G; ++ hif_addr = linear_addr >> 3; ++ return hif_addr; ++} ++#endif ++ + /** + * zynqmp_get_error_info - Get the current ECC error info. + * @priv: DDR memory controller private instance data. +@@ -408,7 +435,8 @@ static int zynq_get_error_info(struct synps_edac_priv *priv) + static int zynqmp_get_error_info(struct synps_edac_priv *priv) + { + struct synps_ecc_status *p; +- u32 regval, clearval = 0; ++ u32 regval, clearval; ++ unsigned long flags; + void __iomem *base; + + base = priv->baseaddr; +@@ -452,10 +480,14 @@ static int zynqmp_get_error_info(struct synps_edac_priv *priv) + p->ueinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK); + p->ueinfo.data = readl(base + ECC_UESYND0_OFST); + out: +- clearval = ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT; +- clearval |= ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT; ++ spin_lock_irqsave(&priv->reglock, flags); ++ ++ clearval = readl(base + ECC_CLR_OFST) | ++ ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT | ++ ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT; + writel(clearval, base + ECC_CLR_OFST); +- writel(0x0, base + ECC_CLR_OFST); ++ ++ spin_unlock_irqrestore(&priv->reglock, flags); + + return 0; + } +@@ -515,24 +547,41 @@ static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p) + + static void enable_intr(struct synps_edac_priv *priv) + { ++ unsigned long flags; ++ + /* Enable UE/CE Interrupts */ +- if (priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR) +- writel(DDR_UE_MASK | DDR_CE_MASK, +- priv->baseaddr + ECC_CLR_OFST); +- else ++ if (!(priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR)) { + writel(DDR_QOSUE_MASK | DDR_QOSCE_MASK, + priv->baseaddr + DDR_QOS_IRQ_EN_OFST); + ++ return; ++ } ++ ++ spin_lock_irqsave(&priv->reglock, flags); ++ ++ writel(DDR_UE_MASK | DDR_CE_MASK, ++ priv->baseaddr + ECC_CLR_OFST); ++ ++ spin_unlock_irqrestore(&priv->reglock, flags); + } + + static void disable_intr(struct synps_edac_priv *priv) + { ++ unsigned long flags; ++ + /* Disable UE/CE Interrupts */ +- if (priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR) +- writel(0x0, priv->baseaddr + ECC_CLR_OFST); +- else ++ if (!(priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR)) { + writel(DDR_QOSUE_MASK | DDR_QOSCE_MASK, + priv->baseaddr + DDR_QOS_IRQ_DB_OFST); ++ ++ return; ++ } ++ ++ spin_lock_irqsave(&priv->reglock, flags); ++ ++ writel(0, priv->baseaddr + ECC_CLR_OFST); ++ ++ spin_unlock_irqrestore(&priv->reglock, flags); + } + + /** +@@ -576,8 +625,6 @@ static irqreturn_t intr_handler(int irq, void *dev_id) + /* v3.0 of the controller does not have this register */ + if (!(priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR)) + writel(regval, priv->baseaddr + DDR_QOS_IRQ_STAT_OFST); +- else +- enable_intr(priv); + + return IRQ_HANDLED; + } +@@ -899,6 +946,9 @@ static const struct synps_platform_data zynqmp_edac_def = { + .get_mtype = zynqmp_get_mtype, + .get_dtype = zynqmp_get_dtype, + .get_ecc_state = zynqmp_get_ecc_state, ++#ifdef CONFIG_EDAC_DEBUG ++ .get_mem_info = zynqmp_get_mem_info, ++#endif + .quirks = (DDR_ECC_INTR_SUPPORT + #ifdef CONFIG_EDAC_DEBUG + | DDR_ECC_DATA_POISON_SUPPORT +@@ -952,10 +1002,16 @@ MODULE_DEVICE_TABLE(of, synps_edac_match); + static void ddr_poison_setup(struct synps_edac_priv *priv) + { + int col = 0, row = 0, bank = 0, bankgrp = 0, rank = 0, regval; ++ const struct synps_platform_data *p_data; + int index; + ulong hif_addr = 0; + +- hif_addr = priv->poison_addr >> 3; ++ p_data = priv->p_data; ++ ++ if (p_data->get_mem_info) ++ hif_addr = p_data->get_mem_info(priv); ++ else ++ hif_addr = priv->poison_addr >> 3; + + for (index = 0; index < DDR_MAX_ROW_SHIFT; index++) { + if (priv->row_shift[index]) +@@ -1359,6 +1415,7 @@ static int mc_probe(struct platform_device *pdev) + priv = mci->pvt_info; + priv->baseaddr = baseaddr; + priv->p_data = p_data; ++ spin_lock_init(&priv->reglock); + + mc_init(mci, pdev); + +diff --git a/drivers/edac/thunderx_edac.c b/drivers/edac/thunderx_edac.c +index b9c5772da959cc..90d46e5c4ff069 100644 +--- a/drivers/edac/thunderx_edac.c ++++ b/drivers/edac/thunderx_edac.c +@@ -1133,7 +1133,7 @@ static irqreturn_t thunderx_ocx_com_threaded_isr(int irq, void *irq_id) + decode_register(other, OCX_OTHER_SIZE, + ocx_com_errors, ctx->reg_com_int); + +- strncat(msg, other, OCX_MESSAGE_SIZE); ++ strlcat(msg, other, OCX_MESSAGE_SIZE); + + for (lane = 0; lane < OCX_RX_LANES; lane++) + if (ctx->reg_com_int & BIT(lane)) { +@@ -1142,12 +1142,12 @@ static irqreturn_t thunderx_ocx_com_threaded_isr(int irq, void *irq_id) + lane, ctx->reg_lane_int[lane], + lane, ctx->reg_lane_stat11[lane]); + +- strncat(msg, other, OCX_MESSAGE_SIZE); ++ strlcat(msg, other, OCX_MESSAGE_SIZE); + + decode_register(other, OCX_OTHER_SIZE, + ocx_lane_errors, + ctx->reg_lane_int[lane]); +- strncat(msg, other, OCX_MESSAGE_SIZE); ++ strlcat(msg, other, OCX_MESSAGE_SIZE); + } + + if (ctx->reg_com_int & OCX_COM_INT_CE) +@@ -1217,7 +1217,7 @@ static irqreturn_t thunderx_ocx_lnk_threaded_isr(int irq, void *irq_id) + decode_register(other, OCX_OTHER_SIZE, + ocx_com_link_errors, ctx->reg_com_link_int); + +- strncat(msg, other, OCX_MESSAGE_SIZE); ++ strlcat(msg, other, OCX_MESSAGE_SIZE); + + if (ctx->reg_com_link_int & OCX_COM_LINK_INT_UE) + edac_device_handle_ue(ocx->edac_dev, 0, 0, msg); +@@ -1896,7 +1896,7 @@ static irqreturn_t thunderx_l2c_threaded_isr(int irq, void *irq_id) + + decode_register(other, L2C_OTHER_SIZE, l2_errors, ctx->reg_int); + +- strncat(msg, other, L2C_MESSAGE_SIZE); ++ strlcat(msg, other, L2C_MESSAGE_SIZE); + + if (ctx->reg_int & mask_ue) + edac_device_handle_ue(l2c->edac_dev, 0, 0, msg); +diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig +index 8de9023c2a3878..cf472e44c5ff90 100644 +--- a/drivers/extcon/Kconfig ++++ b/drivers/extcon/Kconfig +@@ -116,7 +116,8 @@ config EXTCON_MAX77843 + + config EXTCON_MAX8997 + tristate "Maxim MAX8997 EXTCON Support" +- depends on MFD_MAX8997 && IRQ_DOMAIN ++ depends on MFD_MAX8997 ++ select IRQ_DOMAIN + help + If you say yes here you get support for the MUIC device of + Maxim MAX8997 PMIC. The MAX8997 MUIC is a USB port accessory +diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c +index 6f7a60d2ed9161..e7f55c021e562f 100644 +--- a/drivers/extcon/extcon.c ++++ b/drivers/extcon/extcon.c +@@ -1280,8 +1280,6 @@ int extcon_dev_register(struct extcon_dev *edev) + + edev->id = ret; + +- dev_set_name(&edev->dev, "extcon%d", edev->id); +- + ret = extcon_alloc_cables(edev); + if (ret < 0) + goto err_alloc_cables; +@@ -1310,6 +1308,7 @@ int extcon_dev_register(struct extcon_dev *edev) + RAW_INIT_NOTIFIER_HEAD(&edev->nh_all); + + dev_set_drvdata(&edev->dev, edev); ++ dev_set_name(&edev->dev, "extcon%d", edev->id); + edev->state = 0; + + ret = device_register(&edev->dev); +diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c +index 6ac5ff20a2fe22..401a77e3b5fa8e 100644 +--- a/drivers/firewire/core-card.c ++++ b/drivers/firewire/core-card.c +@@ -429,7 +429,23 @@ static void bm_work(struct work_struct *work) + */ + card->bm_generation = generation; + +- if (root_device == NULL) { ++ if (card->gap_count == 0) { ++ /* ++ * If self IDs have inconsistent gap counts, do a ++ * bus reset ASAP. The config rom read might never ++ * complete, so don't wait for it. However, still ++ * send a PHY configuration packet prior to the ++ * bus reset. The PHY configuration packet might ++ * fail, but 1394-2008 8.4.5.2 explicitly permits ++ * it in this case, so it should be safe to try. ++ */ ++ new_root_id = local_id; ++ /* ++ * We must always send a bus reset if the gap count ++ * is inconsistent, so bypass the 5-reset limit. ++ */ ++ card->bm_retries = 0; ++ } else if (root_device == NULL) { + /* + * Either link_on is false, or we failed to read the + * config rom. In either case, pick another root. +@@ -484,7 +500,19 @@ static void bm_work(struct work_struct *work) + fw_notice(card, "phy config: new root=%x, gap_count=%d\n", + new_root_id, gap_count); + fw_send_phy_config(card, new_root_id, generation, gap_count); +- reset_bus(card, true); ++ /* ++ * Where possible, use a short bus reset to minimize ++ * disruption to isochronous transfers. But in the event ++ * of a gap count inconsistency, use a long bus reset. ++ * ++ * As noted in 1394a 8.4.6.2, nodes on a mixed 1394/1394a bus ++ * may set different gap counts after a bus reset. On a mixed ++ * 1394/1394a bus, a short bus reset can get doubled. Some ++ * nodes may treat the double reset as one bus reset and others ++ * may treat it as two, causing a gap count inconsistency ++ * again. Using a long bus reset prevents this. ++ */ ++ reset_bus(card, card->gap_count != 0); + /* Will allocate broadcast channel after the reset. */ + goto out; + } +diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c +index 6274b86eb94377..73cc2f2dcbf923 100644 +--- a/drivers/firewire/core-cdev.c ++++ b/drivers/firewire/core-cdev.c +@@ -598,11 +598,11 @@ static void complete_transaction(struct fw_card *card, int rcode, u32 request_ts + queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length, NULL, 0); + + break; ++ } + default: + WARN_ON(1); + break; + } +- } + + /* Drop the idr's reference */ + client_put(client); +diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c +index aa597cda0d8874..da8a4c8f287687 100644 +--- a/drivers/firewire/core-device.c ++++ b/drivers/firewire/core-device.c +@@ -100,10 +100,9 @@ static int textual_leaf_to_string(const u32 *block, char *buf, size_t size) + * @buf: where to put the string + * @size: size of @buf, in bytes + * +- * The string is taken from a minimal ASCII text descriptor leaf after +- * the immediate entry with @key. The string is zero-terminated. +- * An overlong string is silently truncated such that it and the +- * zero byte fit into @size. ++ * The string is taken from a minimal ASCII text descriptor leaf just after the entry with the ++ * @key. The string is zero-terminated. An overlong string is silently truncated such that it ++ * and the zero byte fit into @size. + * + * Returns strlen(buf) or a negative error code. + */ +@@ -717,14 +716,11 @@ static void create_units(struct fw_device *device) + fw_unit_attributes, + &unit->attribute_group); + +- if (device_register(&unit->device) < 0) +- goto skip_unit; +- + fw_device_get(device); +- continue; +- +- skip_unit: +- kfree(unit); ++ if (device_register(&unit->device) < 0) { ++ put_device(&unit->device); ++ continue; ++ } + } + } + +diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c +index b0d671db178a85..ea31ac7ac1ca93 100644 +--- a/drivers/firewire/nosy.c ++++ b/drivers/firewire/nosy.c +@@ -148,10 +148,12 @@ packet_buffer_get(struct client *client, char __user *data, size_t user_length) + if (atomic_read(&buffer->size) == 0) + return -ENODEV; + +- /* FIXME: Check length <= user_length. */ ++ length = buffer->head->length; ++ ++ if (length > user_length) ++ return 0; + + end = buffer->data + buffer->capacity; +- length = buffer->head->length; + + if (&buffer->head->data[length] < end) { + if (copy_to_user(data, buffer->head->data, length)) +diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c +index 7e88fd4897414b..b9ae0340b8a703 100644 +--- a/drivers/firewire/ohci.c ++++ b/drivers/firewire/ohci.c +@@ -279,6 +279,51 @@ static char ohci_driver_name[] = KBUILD_MODNAME; + #define QUIRK_TI_SLLZ059 0x20 + #define QUIRK_IR_WAKE 0x40 + ++// On PCI Express Root Complex in any type of AMD Ryzen machine, VIA VT6306/6307/6308 with Asmedia ++// ASM1083/1085 brings an inconvenience that the read accesses to 'Isochronous Cycle Timer' register ++// (at offset 0xf0 in PCI I/O space) often causes unexpected system reboot. The mechanism is not ++// clear, since the read access to the other registers is enough safe; e.g. 'Node ID' register, ++// while it is probable due to detection of any type of PCIe error. ++#define QUIRK_REBOOT_BY_CYCLE_TIMER_READ 0x80000000 ++ ++#if IS_ENABLED(CONFIG_X86) ++ ++static bool has_reboot_by_cycle_timer_read_quirk(const struct fw_ohci *ohci) ++{ ++ return !!(ohci->quirks & QUIRK_REBOOT_BY_CYCLE_TIMER_READ); ++} ++ ++#define PCI_DEVICE_ID_ASMEDIA_ASM108X 0x1080 ++ ++static bool detect_vt630x_with_asm1083_on_amd_ryzen_machine(const struct pci_dev *pdev) ++{ ++ const struct pci_dev *pcie_to_pci_bridge; ++ ++ // Detect any type of AMD Ryzen machine. ++ if (!static_cpu_has(X86_FEATURE_ZEN)) ++ return false; ++ ++ // Detect VIA VT6306/6307/6308. ++ if (pdev->vendor != PCI_VENDOR_ID_VIA) ++ return false; ++ if (pdev->device != PCI_DEVICE_ID_VIA_VT630X) ++ return false; ++ ++ // Detect Asmedia ASM1083/1085. ++ pcie_to_pci_bridge = pdev->bus->self; ++ if (pcie_to_pci_bridge->vendor != PCI_VENDOR_ID_ASMEDIA) ++ return false; ++ if (pcie_to_pci_bridge->device != PCI_DEVICE_ID_ASMEDIA_ASM108X) ++ return false; ++ ++ return true; ++} ++ ++#else ++#define has_reboot_by_cycle_timer_read_quirk(ohci) false ++#define detect_vt630x_with_asm1083_on_amd_ryzen_machine(pdev) false ++#endif ++ + /* In case of multiple matches in ohci_quirks[], only the first one is used. */ + static const struct { + unsigned short vendor, device, revision, flags; +@@ -1511,6 +1556,8 @@ static int handle_at_packet(struct context *context, + #define HEADER_GET_DATA_LENGTH(q) (((q) >> 16) & 0xffff) + #define HEADER_GET_EXTENDED_TCODE(q) (((q) >> 0) & 0xffff) + ++static u32 get_cycle_time(struct fw_ohci *ohci); ++ + static void handle_local_rom(struct fw_ohci *ohci, + struct fw_packet *packet, u32 csr) + { +@@ -1535,6 +1582,8 @@ static void handle_local_rom(struct fw_ohci *ohci, + (void *) ohci->config_rom + i, length); + } + ++ // Timestamping on behalf of the hardware. ++ response.timestamp = cycle_time_to_ohci_tstamp(get_cycle_time(ohci)); + fw_core_handle_response(&ohci->card, &response); + } + +@@ -1583,6 +1632,8 @@ static void handle_local_lock(struct fw_ohci *ohci, + fw_fill_response(&response, packet->header, RCODE_BUSY, NULL, 0); + + out: ++ // Timestamping on behalf of the hardware. ++ response.timestamp = cycle_time_to_ohci_tstamp(get_cycle_time(ohci)); + fw_core_handle_response(&ohci->card, &response); + } + +@@ -1625,8 +1676,6 @@ static void handle_local_request(struct context *ctx, struct fw_packet *packet) + } + } + +-static u32 get_cycle_time(struct fw_ohci *ohci); +- + static void at_context_transmit(struct context *ctx, struct fw_packet *packet) + { + unsigned long flags; +@@ -1724,6 +1773,9 @@ static u32 get_cycle_time(struct fw_ohci *ohci) + s32 diff01, diff12; + int i; + ++ if (has_reboot_by_cycle_timer_read_quirk(ohci)) ++ return 0; ++ + c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + + if (ohci->quirks & QUIRK_CYCLE_TIMER) { +@@ -2012,6 +2064,8 @@ static void bus_reset_work(struct work_struct *work) + + ohci->generation = generation; + reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); ++ if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS) ++ reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); + + if (ohci->quirks & QUIRK_RESET_PACKET) + ohci->request_generation = generation; +@@ -2077,12 +2131,14 @@ static irqreturn_t irq_handler(int irq, void *data) + return IRQ_NONE; + + /* +- * busReset and postedWriteErr must not be cleared yet ++ * busReset and postedWriteErr events must not be cleared yet + * (OHCI 1.1 clauses 7.2.3.2 and 13.2.8.1) + */ + reg_write(ohci, OHCI1394_IntEventClear, + event & ~(OHCI1394_busReset | OHCI1394_postedWriteErr)); + log_irqs(ohci, event); ++ if (event & OHCI1394_busReset) ++ reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset); + + if (event & OHCI1394_selfIDComplete) + queue_work(selfid_workqueue, &ohci->bus_reset_work); +@@ -3630,6 +3686,9 @@ static int pci_probe(struct pci_dev *dev, + if (param_quirks) + ohci->quirks = param_quirks; + ++ if (detect_vt630x_with_asm1083_on_amd_ryzen_machine(dev)) ++ ohci->quirks |= QUIRK_REBOOT_BY_CYCLE_TIMER_READ; ++ + /* + * Because dma_alloc_coherent() allocates at least one page, + * we save space by using a common buffer for the AR request/ +@@ -3722,6 +3781,7 @@ static int pci_probe(struct pci_dev *dev, + return 0; + + fail_msi: ++ devm_free_irq(&dev->dev, dev->irq, ohci); + pci_disable_msi(dev); + + return err; +@@ -3749,6 +3809,7 @@ static void pci_remove(struct pci_dev *dev) + + software_reset(ohci); + ++ devm_free_irq(&dev->dev, dev->irq, ohci); + pci_disable_msi(dev); + + dev_notice(&dev->dev, "removing fw-ohci device\n"); +diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c +index 7edf2c95282fa2..e779d866022b9f 100644 +--- a/drivers/firewire/sbp2.c ++++ b/drivers/firewire/sbp2.c +@@ -1519,9 +1519,9 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev) + sdev->use_10_for_rw = 1; + + if (sbp2_param_exclusive_login) { +- sdev->manage_system_start_stop = true; +- sdev->manage_runtime_start_stop = true; +- sdev->manage_shutdown = true; ++ sdev->manage_system_start_stop = 1; ++ sdev->manage_runtime_start_stop = 1; ++ sdev->manage_shutdown = 1; + } + + if (sdev->type == TYPE_ROM) +diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig +index b59e3041fd6275..f0e9f250669e2f 100644 +--- a/drivers/firmware/Kconfig ++++ b/drivers/firmware/Kconfig +@@ -229,6 +229,7 @@ config QCOM_SCM_DOWNLOAD_MODE_DEFAULT + config SYSFB + bool + select BOOT_VESA_SUPPORT ++ select SCREEN_INFO + + config SYSFB_SIMPLEFB + bool "Mark VGA/VBE/EFI FB as generic system framebuffer" +diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c +index 2b8bfcd010f5fd..7865438b36960d 100644 +--- a/drivers/firmware/arm_ffa/bus.c ++++ b/drivers/firmware/arm_ffa/bus.c +@@ -193,6 +193,7 @@ struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id, + dev->release = ffa_release_device; + dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id); + ++ ffa_dev->id = id; + ffa_dev->vm_id = vm_id; + ffa_dev->ops = ops; + uuid_copy(&ffa_dev->uuid, uuid); +diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c +index 121f4fc903cd57..7cd6b1564e8018 100644 +--- a/drivers/firmware/arm_ffa/driver.c ++++ b/drivers/firmware/arm_ffa/driver.c +@@ -587,17 +587,9 @@ static int ffa_partition_info_get(const char *uuid_str, + return 0; + } + +-static void _ffa_mode_32bit_set(struct ffa_device *dev) +-{ +- dev->mode_32bit = true; +-} +- + static void ffa_mode_32bit_set(struct ffa_device *dev) + { +- if (drv_info->version > FFA_VERSION_1_0) +- return; +- +- _ffa_mode_32bit_set(dev); ++ dev->mode_32bit = true; + } + + static int ffa_sync_send_receive(struct ffa_device *dev, +@@ -706,7 +698,7 @@ static void ffa_setup_partitions(void) + + if (drv_info->version > FFA_VERSION_1_0 && + !(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC)) +- _ffa_mode_32bit_set(ffa_dev); ++ ffa_mode_32bit_set(ffa_dev); + } + kfree(pbuf); + } +diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h +index c46dc5215af7a7..00b165d1f502df 100644 +--- a/drivers/firmware/arm_scmi/common.h ++++ b/drivers/firmware/arm_scmi/common.h +@@ -314,6 +314,7 @@ void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, + void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem); + bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, + struct scmi_xfer *xfer); ++bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem); + + /* declarations for message passing transports */ + struct scmi_msg_payld; +diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c +index 19246ed1f01ff7..b8d470417e8f99 100644 +--- a/drivers/firmware/arm_scmi/mailbox.c ++++ b/drivers/firmware/arm_scmi/mailbox.c +@@ -45,6 +45,20 @@ static void rx_callback(struct mbox_client *cl, void *m) + { + struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl); + ++ /* ++ * An A2P IRQ is NOT valid when received while the platform still has ++ * the ownership of the channel, because the platform at first releases ++ * the SMT channel and then sends the completion interrupt. ++ * ++ * This addresses a possible race condition in which a spurious IRQ from ++ * a previous timed-out reply which arrived late could be wrongly ++ * associated with the next pending transaction. ++ */ ++ if (cl->knows_txdone && !shmem_channel_free(smbox->shmem)) { ++ dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n"); ++ return; ++ } ++ + scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem), NULL); + } + +diff --git a/drivers/firmware/arm_scmi/optee.c b/drivers/firmware/arm_scmi/optee.c +index e123de6e8c67a9..aa02392265d326 100644 +--- a/drivers/firmware/arm_scmi/optee.c ++++ b/drivers/firmware/arm_scmi/optee.c +@@ -467,6 +467,13 @@ static int scmi_optee_chan_free(int id, void *p, void *data) + struct scmi_chan_info *cinfo = p; + struct scmi_optee_channel *channel = cinfo->transport_info; + ++ /* ++ * Different protocols might share the same chan info, so a previous ++ * call might have already freed the structure. ++ */ ++ if (!channel) ++ return 0; ++ + mutex_lock(&scmi_optee_private->mu); + list_del(&channel->link); + mutex_unlock(&scmi_optee_private->mu); +diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c +index 30dedd6ebfde61..dd344506b0a37d 100644 +--- a/drivers/firmware/arm_scmi/perf.c ++++ b/drivers/firmware/arm_scmi/perf.c +@@ -145,7 +145,6 @@ struct scmi_msg_resp_perf_describe_levels_v4 { + struct perf_dom_info { + u32 id; + bool set_limits; +- bool set_perf; + bool perf_limit_notify; + bool perf_level_notify; + bool perf_fastchannels; +@@ -153,8 +152,8 @@ struct perf_dom_info { + u32 opp_count; + u32 sustained_freq_khz; + u32 sustained_perf_level; +- u32 mult_factor; +- char name[SCMI_MAX_STR_SIZE]; ++ unsigned long mult_factor; ++ struct scmi_perf_domain_info info; + struct scmi_opp opp[MAX_OPPS]; + struct scmi_fc_info *fc_info; + struct xarray opps_by_idx; +@@ -257,7 +256,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph, + flags = le32_to_cpu(attr->flags); + + dom_info->set_limits = SUPPORTS_SET_LIMITS(flags); +- dom_info->set_perf = SUPPORTS_SET_PERF_LVL(flags); ++ dom_info->info.set_perf = SUPPORTS_SET_PERF_LVL(flags); + dom_info->perf_limit_notify = SUPPORTS_PERF_LIMIT_NOTIFY(flags); + dom_info->perf_level_notify = SUPPORTS_PERF_LEVEL_NOTIFY(flags); + dom_info->perf_fastchannels = SUPPORTS_PERF_FASTCHANNELS(flags); +@@ -269,14 +268,16 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph, + dom_info->sustained_perf_level = + le32_to_cpu(attr->sustained_perf_level); + if (!dom_info->sustained_freq_khz || +- !dom_info->sustained_perf_level) ++ !dom_info->sustained_perf_level || ++ dom_info->level_indexing_mode) + /* CPUFreq converts to kHz, hence default 1000 */ + dom_info->mult_factor = 1000; + else + dom_info->mult_factor = +- (dom_info->sustained_freq_khz * 1000) / +- dom_info->sustained_perf_level; +- strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE); ++ (dom_info->sustained_freq_khz * 1000UL) ++ / dom_info->sustained_perf_level; ++ strscpy(dom_info->info.name, attr->name, ++ SCMI_SHORT_NAME_MAX_SIZE); + } + + ph->xops->xfer_put(ph, t); +@@ -288,7 +289,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph, + if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 && + SUPPORTS_EXTENDED_NAMES(flags)) + ph->hops->extended_name_get(ph, PERF_DOMAIN_NAME_GET, +- dom_info->id, dom_info->name, ++ dom_info->id, dom_info->info.name, + SCMI_MAX_STR_SIZE); + + if (dom_info->level_indexing_mode) { +@@ -346,8 +347,8 @@ process_response_opp(struct scmi_opp *opp, unsigned int loop_idx, + } + + static inline void +-process_response_opp_v4(struct perf_dom_info *dom, struct scmi_opp *opp, +- unsigned int loop_idx, ++process_response_opp_v4(struct device *dev, struct perf_dom_info *dom, ++ struct scmi_opp *opp, unsigned int loop_idx, + const struct scmi_msg_resp_perf_describe_levels_v4 *r) + { + opp->perf = le32_to_cpu(r->opp[loop_idx].perf_val); +@@ -358,10 +359,23 @@ process_response_opp_v4(struct perf_dom_info *dom, struct scmi_opp *opp, + /* Note that PERF v4 reports always five 32-bit words */ + opp->indicative_freq = le32_to_cpu(r->opp[loop_idx].indicative_freq); + if (dom->level_indexing_mode) { ++ int ret; ++ + opp->level_index = le32_to_cpu(r->opp[loop_idx].level_index); + +- xa_store(&dom->opps_by_idx, opp->level_index, opp, GFP_KERNEL); +- xa_store(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL); ++ ret = xa_insert(&dom->opps_by_idx, opp->level_index, opp, ++ GFP_KERNEL); ++ if (ret) ++ dev_warn(dev, ++ "Failed to add opps_by_idx at %d - ret:%d\n", ++ opp->level_index, ret); ++ ++ ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL); ++ if (ret) ++ dev_warn(dev, ++ "Failed to add opps_by_lvl at %d - ret:%d\n", ++ opp->perf, ret); ++ + hash_add(dom->opps_by_freq, &opp->hash, opp->indicative_freq); + } + } +@@ -378,7 +392,7 @@ iter_perf_levels_process_response(const struct scmi_protocol_handle *ph, + if (PROTOCOL_REV_MAJOR(p->version) <= 0x3) + process_response_opp(opp, st->loop_idx, response); + else +- process_response_opp_v4(p->perf_dom, opp, st->loop_idx, ++ process_response_opp_v4(ph->dev, p->perf_dom, opp, st->loop_idx, + response); + p->perf_dom->opp_count++; + +@@ -423,6 +437,36 @@ scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph, + return ret; + } + ++static int scmi_perf_num_domains_get(const struct scmi_protocol_handle *ph) ++{ ++ struct scmi_perf_info *pi = ph->get_priv(ph); ++ ++ return pi->num_domains; ++} ++ ++static inline struct perf_dom_info * ++scmi_perf_domain_lookup(const struct scmi_protocol_handle *ph, u32 domain) ++{ ++ struct scmi_perf_info *pi = ph->get_priv(ph); ++ ++ if (domain >= pi->num_domains) ++ return ERR_PTR(-EINVAL); ++ ++ return pi->dom_info + domain; ++} ++ ++static const struct scmi_perf_domain_info * ++scmi_perf_info_get(const struct scmi_protocol_handle *ph, u32 domain) ++{ ++ struct perf_dom_info *dom; ++ ++ dom = scmi_perf_domain_lookup(ph, domain); ++ if (IS_ERR(dom)) ++ return ERR_PTR(-EINVAL); ++ ++ return &dom->info; ++} ++ + static int scmi_perf_msg_limits_set(const struct scmi_protocol_handle *ph, + u32 domain, u32 max_perf, u32 min_perf) + { +@@ -446,17 +490,6 @@ static int scmi_perf_msg_limits_set(const struct scmi_protocol_handle *ph, + return ret; + } + +-static inline struct perf_dom_info * +-scmi_perf_domain_lookup(const struct scmi_protocol_handle *ph, u32 domain) +-{ +- struct scmi_perf_info *pi = ph->get_priv(ph); +- +- if (domain >= pi->num_domains) +- return ERR_PTR(-EINVAL); +- +- return pi->dom_info + domain; +-} +- + static int __scmi_perf_limits_set(const struct scmi_protocol_handle *ph, + struct perf_dom_info *dom, u32 max_perf, + u32 min_perf) +@@ -780,7 +813,6 @@ static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph, + { + int idx, ret, domain; + unsigned long freq; +- struct scmi_opp *opp; + struct perf_dom_info *dom; + + domain = scmi_dev_domain_id(dev); +@@ -791,28 +823,21 @@ static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph, + if (IS_ERR(dom)) + return PTR_ERR(dom); + +- for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) { ++ for (idx = 0; idx < dom->opp_count; idx++) { + if (!dom->level_indexing_mode) +- freq = opp->perf * dom->mult_factor; ++ freq = dom->opp[idx].perf * dom->mult_factor; + else +- freq = opp->indicative_freq * 1000; ++ freq = dom->opp[idx].indicative_freq * dom->mult_factor; + + ret = dev_pm_opp_add(dev, freq, 0); + if (ret) { + dev_warn(dev, "failed to add opp %luHz\n", freq); +- +- while (idx-- > 0) { +- if (!dom->level_indexing_mode) +- freq = (--opp)->perf * dom->mult_factor; +- else +- freq = (--opp)->indicative_freq * 1000; +- dev_pm_opp_remove(dev, freq); +- } ++ dev_pm_opp_remove_all_dynamic(dev); + return ret; + } + + dev_dbg(dev, "[%d][%s]:: Registered OPP[%d] %lu\n", +- domain, dom->name, idx, freq); ++ domain, dom->info.name, idx, freq); + } + return 0; + } +@@ -851,7 +876,8 @@ static int scmi_dvfs_freq_set(const struct scmi_protocol_handle *ph, u32 domain, + } else { + struct scmi_opp *opp; + +- opp = LOOKUP_BY_FREQ(dom->opps_by_freq, freq / 1000); ++ opp = LOOKUP_BY_FREQ(dom->opps_by_freq, ++ freq / dom->mult_factor); + if (!opp) + return -EIO; + +@@ -885,7 +911,7 @@ static int scmi_dvfs_freq_get(const struct scmi_protocol_handle *ph, u32 domain, + if (!opp) + return -EIO; + +- *freq = opp->indicative_freq * 1000; ++ *freq = opp->indicative_freq * dom->mult_factor; + } + + return ret; +@@ -908,7 +934,7 @@ static int scmi_dvfs_est_power_get(const struct scmi_protocol_handle *ph, + if (!dom->level_indexing_mode) + opp_freq = opp->perf * dom->mult_factor; + else +- opp_freq = opp->indicative_freq * 1000; ++ opp_freq = opp->indicative_freq * dom->mult_factor; + + if (opp_freq < *freq) + continue; +@@ -948,6 +974,8 @@ scmi_power_scale_get(const struct scmi_protocol_handle *ph) + } + + static const struct scmi_perf_proto_ops perf_proto_ops = { ++ .num_domains_get = scmi_perf_num_domains_get, ++ .info_get = scmi_perf_info_get, + .limits_set = scmi_perf_limits_set, + .limits_get = scmi_perf_limits_get, + .level_set = scmi_perf_level_set, +diff --git a/drivers/firmware/arm_scmi/raw_mode.c b/drivers/firmware/arm_scmi/raw_mode.c +index 0493aa3c12bf53..130d13e9cd6beb 100644 +--- a/drivers/firmware/arm_scmi/raw_mode.c ++++ b/drivers/firmware/arm_scmi/raw_mode.c +@@ -921,7 +921,7 @@ static int scmi_dbg_raw_mode_open(struct inode *inode, struct file *filp) + rd->raw = raw; + filp->private_data = rd; + +- return 0; ++ return nonseekable_open(inode, filp); + } + + static int scmi_dbg_raw_mode_release(struct inode *inode, struct file *filp) +@@ -950,6 +950,7 @@ static const struct file_operations scmi_dbg_raw_mode_reset_fops = { + .open = scmi_dbg_raw_mode_open, + .release = scmi_dbg_raw_mode_release, + .write = scmi_dbg_raw_mode_reset_write, ++ .llseek = no_llseek, + .owner = THIS_MODULE, + }; + +@@ -959,6 +960,7 @@ static const struct file_operations scmi_dbg_raw_mode_message_fops = { + .read = scmi_dbg_raw_mode_message_read, + .write = scmi_dbg_raw_mode_message_write, + .poll = scmi_dbg_raw_mode_message_poll, ++ .llseek = no_llseek, + .owner = THIS_MODULE, + }; + +@@ -975,6 +977,7 @@ static const struct file_operations scmi_dbg_raw_mode_message_async_fops = { + .read = scmi_dbg_raw_mode_message_read, + .write = scmi_dbg_raw_mode_message_async_write, + .poll = scmi_dbg_raw_mode_message_poll, ++ .llseek = no_llseek, + .owner = THIS_MODULE, + }; + +@@ -998,6 +1001,7 @@ static const struct file_operations scmi_dbg_raw_mode_notification_fops = { + .release = scmi_dbg_raw_mode_release, + .read = scmi_test_dbg_raw_mode_notif_read, + .poll = scmi_test_dbg_raw_mode_notif_poll, ++ .llseek = no_llseek, + .owner = THIS_MODULE, + }; + +@@ -1021,6 +1025,7 @@ static const struct file_operations scmi_dbg_raw_mode_errors_fops = { + .release = scmi_dbg_raw_mode_release, + .read = scmi_test_dbg_raw_mode_errors_read, + .poll = scmi_test_dbg_raw_mode_errors_poll, ++ .llseek = no_llseek, + .owner = THIS_MODULE, + }; + +@@ -1111,7 +1116,6 @@ static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw, + int i; + + for (i = 0; i < num_chans; i++) { +- void *xret; + struct scmi_raw_queue *q; + + q = scmi_raw_queue_init(raw); +@@ -1120,13 +1124,12 @@ static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw, + goto err_xa; + } + +- xret = xa_store(&raw->chans_q, channels[i], q, ++ ret = xa_insert(&raw->chans_q, channels[i], q, + GFP_KERNEL); +- if (xa_err(xret)) { ++ if (ret) { + dev_err(dev, + "Fail to allocate Raw queue 0x%02X\n", + channels[i]); +- ret = xa_err(xret); + goto err_xa; + } + } +@@ -1322,6 +1325,12 @@ void scmi_raw_message_report(void *r, struct scmi_xfer *xfer, + dev = raw->handle->dev; + q = scmi_raw_queue_select(raw, idx, + SCMI_XFER_IS_CHAN_SET(xfer) ? chan_id : 0); ++ if (!q) { ++ dev_warn(dev, ++ "RAW[%d] - NO queue for chan 0x%X. Dropping report.\n", ++ idx, chan_id); ++ return; ++ } + + /* + * Grab the msg_q_lock upfront to avoid a possible race between +diff --git a/drivers/firmware/arm_scmi/shmem.c b/drivers/firmware/arm_scmi/shmem.c +index 87b4f4d35f0623..517d52fb3bcbbb 100644 +--- a/drivers/firmware/arm_scmi/shmem.c ++++ b/drivers/firmware/arm_scmi/shmem.c +@@ -122,3 +122,9 @@ bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, + (SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR | + SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); + } ++ ++bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem) ++{ ++ return (ioread32(&shmem->channel_status) & ++ SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); ++} +diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c +index c193516a254d9e..771797b6e26806 100644 +--- a/drivers/firmware/arm_scmi/smc.c ++++ b/drivers/firmware/arm_scmi/smc.c +@@ -196,6 +196,13 @@ static int smc_chan_free(int id, void *p, void *data) + struct scmi_chan_info *cinfo = p; + struct scmi_smc *scmi_info = cinfo->transport_info; + ++ /* ++ * Different protocols might share the same chan info, so a previous ++ * smc_chan_free call might have already freed the structure. ++ */ ++ if (!scmi_info) ++ return 0; ++ + /* Ignore any possible further reception on the IRQ path */ + if (scmi_info->irq > 0) + free_irq(scmi_info->irq, scmi_info); +diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c +index 79d4254d1f9bc5..e62ffffe5fb8d4 100644 +--- a/drivers/firmware/cirrus/cs_dsp.c ++++ b/drivers/firmware/cirrus/cs_dsp.c +@@ -522,7 +522,7 @@ void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp) + { + cs_dsp_debugfs_clear(dsp); + debugfs_remove_recursive(dsp->debugfs_root); +- dsp->debugfs_root = NULL; ++ dsp->debugfs_root = ERR_PTR(-ENODEV); + } + EXPORT_SYMBOL_NS_GPL(cs_dsp_cleanup_debugfs, FW_CS_DSP); + #else +@@ -796,6 +796,9 @@ int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, + + lockdep_assert_held(&ctl->dsp->pwr_lock); + ++ if (ctl->flags && !(ctl->flags & WMFW_CTL_FLAG_WRITEABLE)) ++ return -EPERM; ++ + if (len + off * sizeof(u32) > ctl->len) + return -EINVAL; + +@@ -1053,9 +1056,16 @@ struct cs_dsp_coeff_parsed_coeff { + int len; + }; + +-static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, const u8 **str) ++static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, unsigned int avail, ++ const u8 **str) + { +- int length; ++ int length, total_field_len; ++ ++ /* String fields are at least one __le32 */ ++ if (sizeof(__le32) > avail) { ++ *pos = NULL; ++ return 0; ++ } + + switch (bytes) { + case 1: +@@ -1068,10 +1078,16 @@ static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, const u8 **str) + return 0; + } + ++ total_field_len = ((length + bytes) + 3) & ~0x03; ++ if ((unsigned int)total_field_len > avail) { ++ *pos = NULL; ++ return 0; ++ } ++ + if (str) + *str = *pos + bytes; + +- *pos += ((length + bytes) + 3) & ~0x03; ++ *pos += total_field_len; + + return length; + } +@@ -1096,71 +1112,134 @@ static int cs_dsp_coeff_parse_int(int bytes, const u8 **pos) + return val; + } + +-static inline void cs_dsp_coeff_parse_alg(struct cs_dsp *dsp, const u8 **data, +- struct cs_dsp_coeff_parsed_alg *blk) ++static int cs_dsp_coeff_parse_alg(struct cs_dsp *dsp, ++ const struct wmfw_region *region, ++ struct cs_dsp_coeff_parsed_alg *blk) + { + const struct wmfw_adsp_alg_data *raw; ++ unsigned int data_len = le32_to_cpu(region->len); ++ unsigned int pos; ++ const u8 *tmp; ++ ++ raw = (const struct wmfw_adsp_alg_data *)region->data; + + switch (dsp->fw_ver) { + case 0: + case 1: +- raw = (const struct wmfw_adsp_alg_data *)*data; +- *data = raw->data; ++ if (sizeof(*raw) > data_len) ++ return -EOVERFLOW; + + blk->id = le32_to_cpu(raw->id); + blk->name = raw->name; +- blk->name_len = strlen(raw->name); ++ blk->name_len = strnlen(raw->name, ARRAY_SIZE(raw->name)); + blk->ncoeff = le32_to_cpu(raw->ncoeff); ++ ++ pos = sizeof(*raw); + break; + default: +- blk->id = cs_dsp_coeff_parse_int(sizeof(raw->id), data); +- blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), data, ++ if (sizeof(raw->id) > data_len) ++ return -EOVERFLOW; ++ ++ tmp = region->data; ++ blk->id = cs_dsp_coeff_parse_int(sizeof(raw->id), &tmp); ++ pos = tmp - region->data; ++ ++ tmp = ®ion->data[pos]; ++ blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp, data_len - pos, + &blk->name); +- cs_dsp_coeff_parse_string(sizeof(u16), data, NULL); +- blk->ncoeff = cs_dsp_coeff_parse_int(sizeof(raw->ncoeff), data); ++ if (!tmp) ++ return -EOVERFLOW; ++ ++ pos = tmp - region->data; ++ cs_dsp_coeff_parse_string(sizeof(u16), &tmp, data_len - pos, NULL); ++ if (!tmp) ++ return -EOVERFLOW; ++ ++ pos = tmp - region->data; ++ if (sizeof(raw->ncoeff) > (data_len - pos)) ++ return -EOVERFLOW; ++ ++ blk->ncoeff = cs_dsp_coeff_parse_int(sizeof(raw->ncoeff), &tmp); ++ pos += sizeof(raw->ncoeff); + break; + } + ++ if ((int)blk->ncoeff < 0) ++ return -EOVERFLOW; ++ + cs_dsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id); + cs_dsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name); + cs_dsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff); ++ ++ return pos; + } + +-static inline void cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, const u8 **data, +- struct cs_dsp_coeff_parsed_coeff *blk) ++static int cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, ++ const struct wmfw_region *region, ++ unsigned int pos, ++ struct cs_dsp_coeff_parsed_coeff *blk) + { + const struct wmfw_adsp_coeff_data *raw; ++ unsigned int data_len = le32_to_cpu(region->len); ++ unsigned int blk_len, blk_end_pos; + const u8 *tmp; +- int length; ++ ++ raw = (const struct wmfw_adsp_coeff_data *)®ion->data[pos]; ++ if (sizeof(raw->hdr) > (data_len - pos)) ++ return -EOVERFLOW; ++ ++ blk_len = le32_to_cpu(raw->hdr.size); ++ if (blk_len > S32_MAX) ++ return -EOVERFLOW; ++ ++ if (blk_len > (data_len - pos - sizeof(raw->hdr))) ++ return -EOVERFLOW; ++ ++ blk_end_pos = pos + sizeof(raw->hdr) + blk_len; ++ ++ blk->offset = le16_to_cpu(raw->hdr.offset); ++ blk->mem_type = le16_to_cpu(raw->hdr.type); + + switch (dsp->fw_ver) { + case 0: + case 1: +- raw = (const struct wmfw_adsp_coeff_data *)*data; +- *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size); ++ if (sizeof(*raw) > (data_len - pos)) ++ return -EOVERFLOW; + +- blk->offset = le16_to_cpu(raw->hdr.offset); +- blk->mem_type = le16_to_cpu(raw->hdr.type); + blk->name = raw->name; +- blk->name_len = strlen(raw->name); ++ blk->name_len = strnlen(raw->name, ARRAY_SIZE(raw->name)); + blk->ctl_type = le16_to_cpu(raw->ctl_type); + blk->flags = le16_to_cpu(raw->flags); + blk->len = le32_to_cpu(raw->len); + break; + default: +- tmp = *data; +- blk->offset = cs_dsp_coeff_parse_int(sizeof(raw->hdr.offset), &tmp); +- blk->mem_type = cs_dsp_coeff_parse_int(sizeof(raw->hdr.type), &tmp); +- length = cs_dsp_coeff_parse_int(sizeof(raw->hdr.size), &tmp); +- blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp, ++ pos += sizeof(raw->hdr); ++ tmp = ®ion->data[pos]; ++ blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp, data_len - pos, + &blk->name); +- cs_dsp_coeff_parse_string(sizeof(u8), &tmp, NULL); +- cs_dsp_coeff_parse_string(sizeof(u16), &tmp, NULL); ++ if (!tmp) ++ return -EOVERFLOW; ++ ++ pos = tmp - region->data; ++ cs_dsp_coeff_parse_string(sizeof(u8), &tmp, data_len - pos, NULL); ++ if (!tmp) ++ return -EOVERFLOW; ++ ++ pos = tmp - region->data; ++ cs_dsp_coeff_parse_string(sizeof(u16), &tmp, data_len - pos, NULL); ++ if (!tmp) ++ return -EOVERFLOW; ++ ++ pos = tmp - region->data; ++ if (sizeof(raw->ctl_type) + sizeof(raw->flags) + sizeof(raw->len) > ++ (data_len - pos)) ++ return -EOVERFLOW; ++ + blk->ctl_type = cs_dsp_coeff_parse_int(sizeof(raw->ctl_type), &tmp); ++ pos += sizeof(raw->ctl_type); + blk->flags = cs_dsp_coeff_parse_int(sizeof(raw->flags), &tmp); ++ pos += sizeof(raw->flags); + blk->len = cs_dsp_coeff_parse_int(sizeof(raw->len), &tmp); +- +- *data = *data + sizeof(raw->hdr) + length; + break; + } + +@@ -1170,6 +1249,8 @@ static inline void cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, const u8 **data, + cs_dsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags); + cs_dsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type); + cs_dsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len); ++ ++ return blk_end_pos; + } + + static int cs_dsp_check_coeff_flags(struct cs_dsp *dsp, +@@ -1193,12 +1274,16 @@ static int cs_dsp_parse_coeff(struct cs_dsp *dsp, + struct cs_dsp_alg_region alg_region = {}; + struct cs_dsp_coeff_parsed_alg alg_blk; + struct cs_dsp_coeff_parsed_coeff coeff_blk; +- const u8 *data = region->data; +- int i, ret; ++ int i, pos, ret; ++ ++ pos = cs_dsp_coeff_parse_alg(dsp, region, &alg_blk); ++ if (pos < 0) ++ return pos; + +- cs_dsp_coeff_parse_alg(dsp, &data, &alg_blk); + for (i = 0; i < alg_blk.ncoeff; i++) { +- cs_dsp_coeff_parse_coeff(dsp, &data, &coeff_blk); ++ pos = cs_dsp_coeff_parse_coeff(dsp, region, pos, &coeff_blk); ++ if (pos < 0) ++ return pos; + + switch (coeff_blk.ctl_type) { + case WMFW_CTL_TYPE_BYTES: +@@ -1267,6 +1352,10 @@ static unsigned int cs_dsp_adsp1_parse_sizes(struct cs_dsp *dsp, + const struct wmfw_adsp1_sizes *adsp1_sizes; + + adsp1_sizes = (void *)&firmware->data[pos]; ++ if (sizeof(*adsp1_sizes) > firmware->size - pos) { ++ cs_dsp_err(dsp, "%s: file truncated\n", file); ++ return 0; ++ } + + cs_dsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file, + le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm), +@@ -1283,6 +1372,10 @@ static unsigned int cs_dsp_adsp2_parse_sizes(struct cs_dsp *dsp, + const struct wmfw_adsp2_sizes *adsp2_sizes; + + adsp2_sizes = (void *)&firmware->data[pos]; ++ if (sizeof(*adsp2_sizes) > firmware->size - pos) { ++ cs_dsp_err(dsp, "%s: file truncated\n", file); ++ return 0; ++ } + + cs_dsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file, + le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym), +@@ -1322,7 +1415,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, + struct regmap *regmap = dsp->regmap; + unsigned int pos = 0; + const struct wmfw_header *header; +- const struct wmfw_adsp1_sizes *adsp1_sizes; + const struct wmfw_footer *footer; + const struct wmfw_region *region; + const struct cs_dsp_region *mem; +@@ -1338,10 +1430,8 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, + + ret = -EINVAL; + +- pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); +- if (pos >= firmware->size) { +- cs_dsp_err(dsp, "%s: file too short, %zu bytes\n", +- file, firmware->size); ++ if (sizeof(*header) >= firmware->size) { ++ ret = -EOVERFLOW; + goto out_fw; + } + +@@ -1369,22 +1459,36 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, + + pos = sizeof(*header); + pos = dsp->ops->parse_sizes(dsp, file, pos, firmware); ++ if ((pos == 0) || (sizeof(*footer) > firmware->size - pos)) { ++ ret = -EOVERFLOW; ++ goto out_fw; ++ } + + footer = (void *)&firmware->data[pos]; + pos += sizeof(*footer); + + if (le32_to_cpu(header->len) != pos) { +- cs_dsp_err(dsp, "%s: unexpected header length %d\n", +- file, le32_to_cpu(header->len)); ++ ret = -EOVERFLOW; + goto out_fw; + } + + cs_dsp_dbg(dsp, "%s: timestamp %llu\n", file, + le64_to_cpu(footer->timestamp)); + +- while (pos < firmware->size && +- sizeof(*region) < firmware->size - pos) { ++ while (pos < firmware->size) { ++ /* Is there enough data for a complete block header? */ ++ if (sizeof(*region) > firmware->size - pos) { ++ ret = -EOVERFLOW; ++ goto out_fw; ++ } ++ + region = (void *)&(firmware->data[pos]); ++ ++ if (le32_to_cpu(region->len) > firmware->size - pos - sizeof(*region)) { ++ ret = -EOVERFLOW; ++ goto out_fw; ++ } ++ + region_name = "Unknown"; + reg = 0; + text = NULL; +@@ -1441,16 +1545,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, + regions, le32_to_cpu(region->len), offset, + region_name); + +- if (le32_to_cpu(region->len) > +- firmware->size - pos - sizeof(*region)) { +- cs_dsp_err(dsp, +- "%s.%d: %s region len %d bytes exceeds file length %zu\n", +- file, regions, region_name, +- le32_to_cpu(region->len), firmware->size); +- ret = -EINVAL; +- goto out_fw; +- } +- + if (text) { + memcpy(text, region->data, le32_to_cpu(region->len)); + cs_dsp_info(dsp, "%s: %s\n", file, text); +@@ -1501,6 +1595,9 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, + cs_dsp_buf_free(&buf_list); + kfree(text); + ++ if (ret == -EOVERFLOW) ++ cs_dsp_err(dsp, "%s: file content overflows file data\n", file); ++ + return ret; + } + +@@ -2068,10 +2165,20 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware + pos = le32_to_cpu(hdr->len); + + blocks = 0; +- while (pos < firmware->size && +- sizeof(*blk) < firmware->size - pos) { ++ while (pos < firmware->size) { ++ /* Is there enough data for a complete block header? */ ++ if (sizeof(*blk) > firmware->size - pos) { ++ ret = -EOVERFLOW; ++ goto out_fw; ++ } ++ + blk = (void *)(&firmware->data[pos]); + ++ if (le32_to_cpu(blk->len) > firmware->size - pos - sizeof(*blk)) { ++ ret = -EOVERFLOW; ++ goto out_fw; ++ } ++ + type = le16_to_cpu(blk->type); + offset = le16_to_cpu(blk->offset); + version = le32_to_cpu(blk->ver) >> 8; +@@ -2168,17 +2275,6 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware + } + + if (reg) { +- if (le32_to_cpu(blk->len) > +- firmware->size - pos - sizeof(*blk)) { +- cs_dsp_err(dsp, +- "%s.%d: %s region len %d bytes exceeds file length %zu\n", +- file, blocks, region_name, +- le32_to_cpu(blk->len), +- firmware->size); +- ret = -EINVAL; +- goto out_fw; +- } +- + buf = cs_dsp_buf_alloc(blk->data, + le32_to_cpu(blk->len), + &buf_list); +@@ -2218,6 +2314,10 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware + regmap_async_complete(regmap); + cs_dsp_buf_free(&buf_list); + kfree(text); ++ ++ if (ret == -EOVERFLOW) ++ cs_dsp_err(dsp, "%s: file content overflows file data\n", file); ++ + return ret; + } + +@@ -2246,6 +2346,11 @@ static int cs_dsp_common_init(struct cs_dsp *dsp) + + mutex_init(&dsp->pwr_lock); + ++#ifdef CONFIG_DEBUG_FS ++ /* Ensure this is invalid if client never provides a debugfs root */ ++ dsp->debugfs_root = ERR_PTR(-ENODEV); ++#endif ++ + return 0; + } + +diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c +index 5f3a3e913d28fb..d19c78a78ae3ac 100644 +--- a/drivers/firmware/dmi-id.c ++++ b/drivers/firmware/dmi-id.c +@@ -169,9 +169,14 @@ static int dmi_dev_uevent(const struct device *dev, struct kobj_uevent_env *env) + return 0; + } + ++static void dmi_dev_release(struct device *dev) ++{ ++ kfree(dev); ++} ++ + static struct class dmi_class = { + .name = "dmi", +- .dev_release = (void(*)(struct device *)) kfree, ++ .dev_release = dmi_dev_release, + .dev_uevent = dmi_dev_uevent, + }; + +diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c +index 015c95a825d315..ac2a5d2d47463f 100644 +--- a/drivers/firmware/dmi_scan.c ++++ b/drivers/firmware/dmi_scan.c +@@ -101,6 +101,17 @@ static void dmi_decode_table(u8 *buf, + (data - buf + sizeof(struct dmi_header)) <= dmi_len) { + const struct dmi_header *dm = (const struct dmi_header *)data; + ++ /* ++ * If a short entry is found (less than 4 bytes), not only it ++ * is invalid, but we cannot reliably locate the next entry. ++ */ ++ if (dm->length < sizeof(struct dmi_header)) { ++ pr_warn(FW_BUG ++ "Corrupted DMI table, offset %zd (only %d entries processed)\n", ++ data - buf, i); ++ break; ++ } ++ + /* + * We want to know the total length (formatted area and + * strings) before decoding to make sure we won't run off the +diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c +index 83f5bb57fa4c46..83092d93f36a63 100644 +--- a/drivers/firmware/efi/arm-runtime.c ++++ b/drivers/firmware/efi/arm-runtime.c +@@ -107,7 +107,7 @@ static int __init arm_enable_runtime_services(void) + efi_memory_desc_t *md; + + for_each_efi_memory_desc(md) { +- int md_size = md->num_pages << EFI_PAGE_SHIFT; ++ u64 md_size = md->num_pages << EFI_PAGE_SHIFT; + struct resource *res; + + if (!(md->attribute & EFI_MEMORY_SP)) +diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c +index 3e8d4b51a8140c..97bafb5f703892 100644 +--- a/drivers/firmware/efi/capsule-loader.c ++++ b/drivers/firmware/efi/capsule-loader.c +@@ -292,7 +292,7 @@ static int efi_capsule_open(struct inode *inode, struct file *file) + return -ENOMEM; + } + +- cap_info->phys = kzalloc(sizeof(void *), GFP_KERNEL); ++ cap_info->phys = kzalloc(sizeof(phys_addr_t), GFP_KERNEL); + if (!cap_info->phys) { + kfree(cap_info->pages); + kfree(cap_info); +diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c +index ef0820f1a9246e..59b0d7197b6852 100644 +--- a/drivers/firmware/efi/efi-init.c ++++ b/drivers/firmware/efi/efi-init.c +@@ -134,15 +134,6 @@ static __init int is_usable_memory(efi_memory_desc_t *md) + case EFI_BOOT_SERVICES_DATA: + case EFI_CONVENTIONAL_MEMORY: + case EFI_PERSISTENT_MEMORY: +- /* +- * Special purpose memory is 'soft reserved', which means it +- * is set aside initially, but can be hotplugged back in or +- * be assigned to the dax driver after boot. +- */ +- if (efi_soft_reserve_enabled() && +- (md->attribute & EFI_MEMORY_SP)) +- return false; +- + /* + * According to the spec, these regions are no longer reserved + * after calling ExitBootServices(). However, we can only use +@@ -187,6 +178,16 @@ static __init void reserve_regions(void) + size = npages << PAGE_SHIFT; + + if (is_memory(md)) { ++ /* ++ * Special purpose memory is 'soft reserved', which ++ * means it is set aside initially. Don't add a memblock ++ * for it now so that it can be hotplugged back in or ++ * be assigned to the dax driver after boot. ++ */ ++ if (efi_soft_reserve_enabled() && ++ (md->attribute & EFI_MEMORY_SP)) ++ continue; ++ + early_init_dt_add_memory_arch(paddr, size); + + if (!is_usable_memory(md)) +diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c +index 1974f0ad32badb..2c1095dcc2f2f8 100644 +--- a/drivers/firmware/efi/efi.c ++++ b/drivers/firmware/efi/efi.c +@@ -199,6 +199,8 @@ static bool generic_ops_supported(void) + + name_size = sizeof(name); + ++ if (!efi.get_next_variable) ++ return false; + status = efi.get_next_variable(&name_size, &name, &guid); + if (status == EFI_UNSUPPORTED) + return false; +diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile +index a1157c2a717040..a0f1569b790da5 100644 +--- a/drivers/firmware/efi/libstub/Makefile ++++ b/drivers/firmware/efi/libstub/Makefile +@@ -28,7 +28,7 @@ cflags-$(CONFIG_ARM) += -DEFI_HAVE_STRLEN -DEFI_HAVE_STRNLEN \ + -DEFI_HAVE_MEMCHR -DEFI_HAVE_STRRCHR \ + -DEFI_HAVE_STRCMP -fno-builtin -fpic \ + $(call cc-option,-mno-single-pic-base) +-cflags-$(CONFIG_RISCV) += -fpic ++cflags-$(CONFIG_RISCV) += -fpic -mno-relax + cflags-$(CONFIG_LOONGARCH) += -fpie + + cflags-$(CONFIG_EFI_PARAMS_FROM_FDT) += -I$(srctree)/scripts/dtc/libfdt +@@ -108,13 +108,6 @@ lib-y := $(patsubst %.o,%.stub.o,$(lib-y)) + # https://bugs.llvm.org/show_bug.cgi?id=46480 + STUBCOPY_FLAGS-y += --remove-section=.note.gnu.property + +-# +-# For x86, bootloaders like systemd-boot or grub-efi do not zero-initialize the +-# .bss section, so the .bss section of the EFI stub needs to be included in the +-# .data section of the compressed kernel to ensure initialization. Rename the +-# .bss section here so it's easy to pick out in the linker script. +-# +-STUBCOPY_FLAGS-$(CONFIG_X86) += --rename-section .bss=.bss.efistub,load,alloc + STUBCOPY_RELOC-$(CONFIG_X86_32) := R_386_32 + STUBCOPY_RELOC-$(CONFIG_X86_64) := R_X86_64_64 + +diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c +index bfa30625f5d031..3dc2f9aaf08db0 100644 +--- a/drivers/firmware/efi/libstub/efi-stub-helper.c ++++ b/drivers/firmware/efi/libstub/efi-stub-helper.c +@@ -24,6 +24,8 @@ static bool efi_noinitrd; + static bool efi_nosoftreserve; + static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA); + ++int efi_mem_encrypt; ++ + bool __pure __efi_soft_reserve_enabled(void) + { + return !efi_nosoftreserve; +@@ -75,6 +77,12 @@ efi_status_t efi_parse_options(char const *cmdline) + efi_noinitrd = true; + } else if (IS_ENABLED(CONFIG_X86_64) && !strcmp(param, "no5lvl")) { + efi_no5lvl = true; ++ } else if (IS_ENABLED(CONFIG_ARCH_HAS_MEM_ENCRYPT) && ++ !strcmp(param, "mem_encrypt") && val) { ++ if (parse_option_str(val, "on")) ++ efi_mem_encrypt = 1; ++ else if (parse_option_str(val, "off")) ++ efi_mem_encrypt = -1; + } else if (!strcmp(param, "efi") && val) { + efi_nochunk = parse_option_str(val, "nochunk"); + efi_novamap |= parse_option_str(val, "novamap"); +diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h +index 212687c30d79c4..fc18fd649ed771 100644 +--- a/drivers/firmware/efi/libstub/efistub.h ++++ b/drivers/firmware/efi/libstub/efistub.h +@@ -37,8 +37,8 @@ extern bool efi_no5lvl; + extern bool efi_nochunk; + extern bool efi_nokaslr; + extern int efi_loglevel; ++extern int efi_mem_encrypt; + extern bool efi_novamap; +- + extern const efi_system_table_t *efi_system_table; + + typedef union efi_dxe_services_table efi_dxe_services_table_t; +@@ -956,7 +956,8 @@ efi_status_t efi_get_random_bytes(unsigned long size, u8 *out); + + efi_status_t efi_random_alloc(unsigned long size, unsigned long align, + unsigned long *addr, unsigned long random_seed, +- int memory_type, unsigned long alloc_limit); ++ int memory_type, unsigned long alloc_min, ++ unsigned long alloc_max); + + efi_status_t efi_random_get_seed(void); + +diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c +index 70e9789ff9de0a..6a337f1f8787b3 100644 +--- a/drivers/firmware/efi/libstub/fdt.c ++++ b/drivers/firmware/efi/libstub/fdt.c +@@ -335,8 +335,8 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle, + + fail: + efi_free(fdt_size, fdt_addr); +- +- efi_bs_call(free_pool, priv.runtime_map); ++ if (!efi_novamap) ++ efi_bs_call(free_pool, priv.runtime_map); + + return EFI_LOAD_ERROR; + } +diff --git a/drivers/firmware/efi/libstub/kaslr.c b/drivers/firmware/efi/libstub/kaslr.c +index 62d63f7a2645bf..1a9808012abd36 100644 +--- a/drivers/firmware/efi/libstub/kaslr.c ++++ b/drivers/firmware/efi/libstub/kaslr.c +@@ -119,7 +119,7 @@ efi_status_t efi_kaslr_relocate_kernel(unsigned long *image_addr, + */ + status = efi_random_alloc(*reserve_size, min_kimg_align, + reserve_addr, phys_seed, +- EFI_LOADER_CODE, EFI_ALLOC_LIMIT); ++ EFI_LOADER_CODE, 0, EFI_ALLOC_LIMIT); + if (status != EFI_SUCCESS) + efi_warn("efi_random_alloc() failed: 0x%lx\n", status); + } else { +diff --git a/drivers/firmware/efi/libstub/loongarch-stub.c b/drivers/firmware/efi/libstub/loongarch-stub.c +index 72c71ae201f0da..736b6aae323d35 100644 +--- a/drivers/firmware/efi/libstub/loongarch-stub.c ++++ b/drivers/firmware/efi/libstub/loongarch-stub.c +@@ -8,10 +8,10 @@ + #include + #include + #include "efistub.h" ++#include "loongarch-stub.h" + + extern int kernel_asize; + extern int kernel_fsize; +-extern int kernel_offset; + extern int kernel_entry; + + efi_status_t handle_kernel_image(unsigned long *image_addr, +@@ -24,7 +24,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, + efi_status_t status; + unsigned long kernel_addr = 0; + +- kernel_addr = (unsigned long)&kernel_offset - kernel_offset; ++ kernel_addr = (unsigned long)image->image_base; + + status = efi_relocate_kernel(&kernel_addr, kernel_fsize, kernel_asize, + EFI_KIMG_PREFERRED_ADDRESS, efi_get_kimg_min_align(), 0x0); +@@ -35,9 +35,10 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, + return status; + } + +-unsigned long kernel_entry_address(void) ++unsigned long kernel_entry_address(unsigned long kernel_addr, ++ efi_loaded_image_t *image) + { +- unsigned long base = (unsigned long)&kernel_offset - kernel_offset; ++ unsigned long base = (unsigned long)image->image_base; + +- return (unsigned long)&kernel_entry - base + VMLINUX_LOAD_ADDRESS; ++ return (unsigned long)&kernel_entry - base + kernel_addr; + } +diff --git a/drivers/firmware/efi/libstub/loongarch-stub.h b/drivers/firmware/efi/libstub/loongarch-stub.h +new file mode 100644 +index 00000000000000..cd015955a0152b +--- /dev/null ++++ b/drivers/firmware/efi/libstub/loongarch-stub.h +@@ -0,0 +1,4 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++ ++unsigned long kernel_entry_address(unsigned long kernel_addr, ++ efi_loaded_image_t *image); +diff --git a/drivers/firmware/efi/libstub/loongarch.c b/drivers/firmware/efi/libstub/loongarch.c +index 807cba2693fc17..d0ef93551c44f6 100644 +--- a/drivers/firmware/efi/libstub/loongarch.c ++++ b/drivers/firmware/efi/libstub/loongarch.c +@@ -8,6 +8,7 @@ + #include + #include + #include "efistub.h" ++#include "loongarch-stub.h" + + typedef void __noreturn (*kernel_entry_t)(bool efi, unsigned long cmdline, + unsigned long systab); +@@ -37,9 +38,10 @@ static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv) + return EFI_SUCCESS; + } + +-unsigned long __weak kernel_entry_address(void) ++unsigned long __weak kernel_entry_address(unsigned long kernel_addr, ++ efi_loaded_image_t *image) + { +- return *(unsigned long *)(PHYSADDR(VMLINUX_LOAD_ADDRESS) + 8); ++ return *(unsigned long *)(kernel_addr + 8) - PHYSADDR(VMLINUX_LOAD_ADDRESS) + kernel_addr; + } + + efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image, +@@ -73,7 +75,7 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image, + csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0); + csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1); + +- real_kernel_entry = (void *)kernel_entry_address(); ++ real_kernel_entry = (void *)kernel_entry_address(kernel_addr, image); + + real_kernel_entry(true, (unsigned long)cmdline_ptr, + (unsigned long)efi_system_table); +diff --git a/drivers/firmware/efi/libstub/randomalloc.c b/drivers/firmware/efi/libstub/randomalloc.c +index 674a064b8f7adc..c41e7b2091cdd1 100644 +--- a/drivers/firmware/efi/libstub/randomalloc.c ++++ b/drivers/firmware/efi/libstub/randomalloc.c +@@ -17,7 +17,7 @@ + static unsigned long get_entry_num_slots(efi_memory_desc_t *md, + unsigned long size, + unsigned long align_shift, +- u64 alloc_limit) ++ u64 alloc_min, u64 alloc_max) + { + unsigned long align = 1UL << align_shift; + u64 first_slot, last_slot, region_end; +@@ -30,11 +30,11 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md, + return 0; + + region_end = min(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - 1, +- alloc_limit); ++ alloc_max); + if (region_end < size) + return 0; + +- first_slot = round_up(md->phys_addr, align); ++ first_slot = round_up(max(md->phys_addr, alloc_min), align); + last_slot = round_down(region_end - size + 1, align); + + if (first_slot > last_slot) +@@ -56,7 +56,8 @@ efi_status_t efi_random_alloc(unsigned long size, + unsigned long *addr, + unsigned long random_seed, + int memory_type, +- unsigned long alloc_limit) ++ unsigned long alloc_min, ++ unsigned long alloc_max) + { + unsigned long total_slots = 0, target_slot; + unsigned long total_mirrored_slots = 0; +@@ -78,7 +79,8 @@ efi_status_t efi_random_alloc(unsigned long size, + efi_memory_desc_t *md = (void *)map->map + map_offset; + unsigned long slots; + +- slots = get_entry_num_slots(md, size, ilog2(align), alloc_limit); ++ slots = get_entry_num_slots(md, size, ilog2(align), alloc_min, ++ alloc_max); + MD_NUM_SLOTS(md) = slots; + total_slots += slots; + if (md->attribute & EFI_MEMORY_MORE_RELIABLE) +@@ -118,7 +120,7 @@ efi_status_t efi_random_alloc(unsigned long size, + continue; + } + +- target = round_up(md->phys_addr, align) + target_slot * align; ++ target = round_up(max_t(u64, md->phys_addr, alloc_min), align) + target_slot * align; + pages = size / EFI_PAGE_SIZE; + + status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS, +diff --git a/drivers/firmware/efi/libstub/screen_info.c b/drivers/firmware/efi/libstub/screen_info.c +index a51ec201ca3cbe..5d3a1e32d1776b 100644 +--- a/drivers/firmware/efi/libstub/screen_info.c ++++ b/drivers/firmware/efi/libstub/screen_info.c +@@ -32,6 +32,8 @@ struct screen_info *__alloc_screen_info(void) + if (status != EFI_SUCCESS) + return NULL; + ++ memset(si, 0, sizeof(*si)); ++ + status = efi_bs_call(install_configuration_table, + &screen_info_guid, si); + if (status == EFI_SUCCESS) +diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c +index 7acbac16eae0b2..95da291c3083ef 100644 +--- a/drivers/firmware/efi/libstub/tpm.c ++++ b/drivers/firmware/efi/libstub/tpm.c +@@ -115,7 +115,7 @@ void efi_retrieve_tpm2_eventlog(void) + } + + /* Allocate space for the logs and copy them. */ +- status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, ++ status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY, + sizeof(*log_tbl) + log_size, (void **)&log_tbl); + + if (status != EFI_SUCCESS) { +diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c +index 9d5df683f8821c..b2b06d18b7b4a7 100644 +--- a/drivers/firmware/efi/libstub/x86-stub.c ++++ b/drivers/firmware/efi/libstub/x86-stub.c +@@ -21,6 +21,8 @@ + #include "efistub.h" + #include "x86-stub.h" + ++extern char _bss[], _ebss[]; ++ + const efi_system_table_t *efi_system_table; + const efi_dxe_services_table_t *efi_dxe_table; + static efi_loaded_image_t *image = NULL; +@@ -223,8 +225,8 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params) + } + } + +-void efi_adjust_memory_range_protection(unsigned long start, +- unsigned long size) ++efi_status_t efi_adjust_memory_range_protection(unsigned long start, ++ unsigned long size) + { + efi_status_t status; + efi_gcd_memory_space_desc_t desc; +@@ -236,13 +238,26 @@ void efi_adjust_memory_range_protection(unsigned long start, + rounded_end = roundup(start + size, EFI_PAGE_SIZE); + + if (memattr != NULL) { +- efi_call_proto(memattr, clear_memory_attributes, rounded_start, +- rounded_end - rounded_start, EFI_MEMORY_XP); +- return; ++ status = efi_call_proto(memattr, set_memory_attributes, ++ rounded_start, ++ rounded_end - rounded_start, ++ EFI_MEMORY_RO); ++ if (status != EFI_SUCCESS) { ++ efi_warn("Failed to set EFI_MEMORY_RO attribute\n"); ++ return status; ++ } ++ ++ status = efi_call_proto(memattr, clear_memory_attributes, ++ rounded_start, ++ rounded_end - rounded_start, ++ EFI_MEMORY_XP); ++ if (status != EFI_SUCCESS) ++ efi_warn("Failed to clear EFI_MEMORY_XP attribute\n"); ++ return status; + } + + if (efi_dxe_table == NULL) +- return; ++ return EFI_SUCCESS; + + /* + * Don't modify memory region attributes, they are +@@ -255,7 +270,7 @@ void efi_adjust_memory_range_protection(unsigned long start, + status = efi_dxe_call(get_memory_space_descriptor, start, &desc); + + if (status != EFI_SUCCESS) +- return; ++ break; + + next = desc.base_address + desc.length; + +@@ -280,8 +295,10 @@ void efi_adjust_memory_range_protection(unsigned long start, + unprotect_start, + unprotect_start + unprotect_size, + status); ++ break; + } + } ++ return EFI_SUCCESS; + } + + static void setup_unaccepted_memory(void) +@@ -307,17 +324,20 @@ static void setup_unaccepted_memory(void) + efi_err("Memory acceptance protocol failed\n"); + } + ++static efi_char16_t *efistub_fw_vendor(void) ++{ ++ unsigned long vendor = efi_table_attr(efi_system_table, fw_vendor); ++ ++ return (efi_char16_t *)vendor; ++} ++ + static const efi_char16_t apple[] = L"Apple"; + + static void setup_quirks(struct boot_params *boot_params) + { +- efi_char16_t *fw_vendor = (efi_char16_t *)(unsigned long) +- efi_table_attr(efi_system_table, fw_vendor); +- +- if (!memcmp(fw_vendor, apple, sizeof(apple))) { +- if (IS_ENABLED(CONFIG_APPLE_PROPERTIES)) +- retrieve_apple_device_properties(boot_params); +- } ++ if (IS_ENABLED(CONFIG_APPLE_PROPERTIES) && ++ !memcmp(efistub_fw_vendor(), apple, sizeof(apple))) ++ retrieve_apple_device_properties(boot_params); + } + + /* +@@ -449,14 +469,17 @@ void __noreturn efi_stub_entry(efi_handle_t handle, + efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, + efi_system_table_t *sys_table_arg) + { ++ efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; + struct boot_params *boot_params; + struct setup_header *hdr; +- void *image_base; +- efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; + int options_size = 0; + efi_status_t status; ++ unsigned long alloc; + char *cmdline_ptr; + ++ if (efi_is_native()) ++ memset(_bss, 0, _ebss - _bss); ++ + efi_system_table = sys_table_arg; + + /* Check if we were booted by the EFI firmware */ +@@ -469,58 +492,32 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, + efi_exit(handle, status); + } + +- image_base = efi_table_attr(image, image_base); +- +- status = efi_allocate_pages(sizeof(struct boot_params), +- (unsigned long *)&boot_params, ULONG_MAX); +- if (status != EFI_SUCCESS) { +- efi_err("Failed to allocate lowmem for boot params\n"); ++ status = efi_allocate_pages(PARAM_SIZE, &alloc, ULONG_MAX); ++ if (status != EFI_SUCCESS) + efi_exit(handle, status); +- } +- +- memset(boot_params, 0x0, sizeof(struct boot_params)); + +- hdr = &boot_params->hdr; ++ boot_params = memset((void *)alloc, 0x0, PARAM_SIZE); ++ hdr = &boot_params->hdr; + +- /* Copy the setup header from the second sector to boot_params */ +- memcpy(&hdr->jump, image_base + 512, +- sizeof(struct setup_header) - offsetof(struct setup_header, jump)); +- +- /* +- * Fill out some of the header fields ourselves because the +- * EFI firmware loader doesn't load the first sector. +- */ ++ /* Assign the setup_header fields that the kernel actually cares about */ + hdr->root_flags = 1; + hdr->vid_mode = 0xffff; +- hdr->boot_flag = 0xAA55; + + hdr->type_of_loader = 0x21; ++ hdr->initrd_addr_max = INT_MAX; + + /* Convert unicode cmdline to ascii */ + cmdline_ptr = efi_convert_cmdline(image, &options_size); +- if (!cmdline_ptr) +- goto fail; +- +- efi_set_u64_split((unsigned long)cmdline_ptr, +- &hdr->cmd_line_ptr, &boot_params->ext_cmd_line_ptr); +- +- hdr->ramdisk_image = 0; +- hdr->ramdisk_size = 0; ++ if (!cmdline_ptr) { ++ efi_free(PARAM_SIZE, alloc); ++ efi_exit(handle, EFI_OUT_OF_RESOURCES); ++ } + +- /* +- * Disregard any setup data that was provided by the bootloader: +- * setup_data could be pointing anywhere, and we have no way of +- * authenticating or validating the payload. +- */ +- hdr->setup_data = 0; ++ efi_set_u64_split((unsigned long)cmdline_ptr, &hdr->cmd_line_ptr, ++ &boot_params->ext_cmd_line_ptr); + + efi_stub_entry(handle, sys_table_arg, boot_params); + /* not reached */ +- +-fail: +- efi_free(sizeof(struct boot_params), (unsigned long)boot_params); +- +- efi_exit(handle, status); + } + + static void add_e820ext(struct boot_params *params, +@@ -786,6 +783,26 @@ static void error(char *str) + efi_warn("Decompression failed: %s\n", str); + } + ++static const char *cmdline_memmap_override; ++ ++static efi_status_t parse_options(const char *cmdline) ++{ ++ static const char opts[][14] = { ++ "mem=", "memmap=", "efi_fake_mem=", "hugepages=" ++ }; ++ ++ for (int i = 0; i < ARRAY_SIZE(opts); i++) { ++ const char *p = strstr(cmdline, opts[i]); ++ ++ if (p == cmdline || (p > cmdline && isspace(p[-1]))) { ++ cmdline_memmap_override = opts[i]; ++ break; ++ } ++ } ++ ++ return efi_parse_options(cmdline); ++} ++ + static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry) + { + unsigned long virt_addr = LOAD_PHYSICAL_ADDR; +@@ -799,15 +816,34 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry) + + if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && !efi_nokaslr) { + u64 range = KERNEL_IMAGE_SIZE - LOAD_PHYSICAL_ADDR - kernel_total_size; ++ static const efi_char16_t ami[] = L"American Megatrends"; + + efi_get_seed(seed, sizeof(seed)); + + virt_addr += (range * seed[1]) >> 32; + virt_addr &= ~(CONFIG_PHYSICAL_ALIGN - 1); ++ ++ /* ++ * Older Dell systems with AMI UEFI firmware v2.0 may hang ++ * while decompressing the kernel if physical address ++ * randomization is enabled. ++ * ++ * https://bugzilla.kernel.org/show_bug.cgi?id=218173 ++ */ ++ if (efi_system_table->hdr.revision <= EFI_2_00_SYSTEM_TABLE_REVISION && ++ !memcmp(efistub_fw_vendor(), ami, sizeof(ami))) { ++ efi_debug("AMI firmware v2.0 or older detected - disabling physical KASLR\n"); ++ seed[0] = 0; ++ } else if (cmdline_memmap_override) { ++ efi_info("%s detected on the kernel command line - disabling physical KASLR\n", ++ cmdline_memmap_override); ++ seed[0] = 0; ++ } + } + + status = efi_random_alloc(alloc_size, CONFIG_PHYSICAL_ALIGN, &addr, + seed[0], EFI_LOADER_CODE, ++ LOAD_PHYSICAL_ADDR, + EFI_X86_KERNEL_ALLOC_LIMIT); + if (status != EFI_SUCCESS) + return status; +@@ -820,9 +856,7 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry) + + *kernel_entry = addr + entry; + +- efi_adjust_memory_range_protection(addr, kernel_total_size); +- +- return EFI_SUCCESS; ++ return efi_adjust_memory_range_protection(addr, kernel_text_size); + } + + static void __noreturn enter_kernel(unsigned long kernel_addr, +@@ -878,7 +912,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle, + } + + #ifdef CONFIG_CMDLINE_BOOL +- status = efi_parse_options(CONFIG_CMDLINE); ++ status = parse_options(CONFIG_CMDLINE); + if (status != EFI_SUCCESS) { + efi_err("Failed to parse options\n"); + goto fail; +@@ -887,13 +921,16 @@ void __noreturn efi_stub_entry(efi_handle_t handle, + if (!IS_ENABLED(CONFIG_CMDLINE_OVERRIDE)) { + unsigned long cmdline_paddr = ((u64)hdr->cmd_line_ptr | + ((u64)boot_params->ext_cmd_line_ptr << 32)); +- status = efi_parse_options((char *)cmdline_paddr); ++ status = parse_options((char *)cmdline_paddr); + if (status != EFI_SUCCESS) { + efi_err("Failed to parse options\n"); + goto fail; + } + } + ++ if (efi_mem_encrypt > 0) ++ hdr->xloadflags |= XLF_MEM_ENCRYPTION; ++ + status = efi_decompress_kernel(&kernel_entry); + if (status != EFI_SUCCESS) { + efi_err("Failed to decompress kernel\n"); +@@ -968,8 +1005,6 @@ void __noreturn efi_stub_entry(efi_handle_t handle, + void efi_handover_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg, + struct boot_params *boot_params) + { +- extern char _bss[], _ebss[]; +- + memset(_bss, 0, _ebss - _bss); + efi_stub_entry(handle, sys_table_arg, boot_params); + } +diff --git a/drivers/firmware/efi/libstub/x86-stub.h b/drivers/firmware/efi/libstub/x86-stub.h +index 2748bca192dfb2..4433d0f97441ca 100644 +--- a/drivers/firmware/efi/libstub/x86-stub.h ++++ b/drivers/firmware/efi/libstub/x86-stub.h +@@ -7,8 +7,8 @@ extern struct boot_params *boot_params_pointer asm("boot_params"); + extern void trampoline_32bit_src(void *, bool); + extern const u16 trampoline_ljmp_imm_offset; + +-void efi_adjust_memory_range_protection(unsigned long start, +- unsigned long size); ++efi_status_t efi_adjust_memory_range_protection(unsigned long start, ++ unsigned long size); + + #ifdef CONFIG_X86_64 + efi_status_t efi_setup_5level_paging(void); +diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c +index bdb17eac0cb401..1ceace95675868 100644 +--- a/drivers/firmware/efi/libstub/zboot.c ++++ b/drivers/firmware/efi/libstub/zboot.c +@@ -119,7 +119,7 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) + } + + status = efi_random_alloc(alloc_size, min_kimg_align, &image_base, +- seed, EFI_LOADER_CODE, EFI_ALLOC_LIMIT); ++ seed, EFI_LOADER_CODE, 0, EFI_ALLOC_LIMIT); + if (status != EFI_SUCCESS) { + efi_err("Failed to allocate memory\n"); + goto free_cmdline; +diff --git a/drivers/firmware/efi/libstub/zboot.lds b/drivers/firmware/efi/libstub/zboot.lds +index ac8c0ef851581f..af2c82f7bd9024 100644 +--- a/drivers/firmware/efi/libstub/zboot.lds ++++ b/drivers/firmware/efi/libstub/zboot.lds +@@ -41,6 +41,7 @@ SECTIONS + } + + /DISCARD/ : { ++ *(.discard .discard.*) + *(.modinfo .init.modinfo) + } + } +diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c +index a1180461a445cf..77dd20f9df312c 100644 +--- a/drivers/firmware/efi/memmap.c ++++ b/drivers/firmware/efi/memmap.c +@@ -15,10 +15,6 @@ + #include + #include + +-#ifndef __efi_memmap_free +-#define __efi_memmap_free(phys, size, flags) do { } while (0) +-#endif +- + /** + * __efi_memmap_init - Common code for mapping the EFI memory map + * @data: EFI memory map data +@@ -51,11 +47,6 @@ int __init __efi_memmap_init(struct efi_memory_map_data *data) + return -ENOMEM; + } + +- if (efi.memmap.flags & (EFI_MEMMAP_MEMBLOCK | EFI_MEMMAP_SLAB)) +- __efi_memmap_free(efi.memmap.phys_map, +- efi.memmap.desc_size * efi.memmap.nr_map, +- efi.memmap.flags); +- + map.phys_map = data->phys_map; + map.nr_map = data->size / data->desc_size; + map.map_end = map.map + data->size; +diff --git a/drivers/firmware/efi/riscv-runtime.c b/drivers/firmware/efi/riscv-runtime.c +index 09525fb5c240e6..01f0f90ea41831 100644 +--- a/drivers/firmware/efi/riscv-runtime.c ++++ b/drivers/firmware/efi/riscv-runtime.c +@@ -85,7 +85,7 @@ static int __init riscv_enable_runtime_services(void) + efi_memory_desc_t *md; + + for_each_efi_memory_desc(md) { +- int md_size = md->num_pages << EFI_PAGE_SHIFT; ++ u64 md_size = md->num_pages << EFI_PAGE_SHIFT; + struct resource *res; + + if (!(md->attribute & EFI_MEMORY_SP)) +diff --git a/drivers/firmware/efi/unaccepted_memory.c b/drivers/firmware/efi/unaccepted_memory.c +index 135278ddaf627b..6c3d84d9bcc16f 100644 +--- a/drivers/firmware/efi/unaccepted_memory.c ++++ b/drivers/firmware/efi/unaccepted_memory.c +@@ -3,6 +3,7 @@ + #include + #include + #include ++#include + #include + + /* Protects unaccepted memory bitmap and accepting_list */ +@@ -100,7 +101,7 @@ void accept_memory(phys_addr_t start, phys_addr_t end) + * overlap on physical address level. + */ + list_for_each_entry(entry, &accepting_list, list) { +- if (entry->end < range.start) ++ if (entry->end <= range.start) + continue; + if (entry->start >= range.end) + continue; +@@ -148,6 +149,9 @@ void accept_memory(phys_addr_t start, phys_addr_t end) + } + + list_del(&range.list); ++ ++ touch_softlockup_watchdog(); ++ + spin_unlock_irqrestore(&unaccepted_memory_lock, flags); + } + +diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c +index d9629ff8786199..2328ca58bba61f 100644 +--- a/drivers/firmware/psci/psci.c ++++ b/drivers/firmware/psci/psci.c +@@ -497,10 +497,12 @@ int psci_cpu_suspend_enter(u32 state) + + static int psci_system_suspend(unsigned long unused) + { ++ int err; + phys_addr_t pa_cpu_resume = __pa_symbol(cpu_resume); + +- return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), ++ err = invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), + pa_cpu_resume, 0, 0); ++ return psci_to_linux_errno(err); + } + + static int psci_system_suspend_enter(suspend_state_t state) +diff --git a/drivers/firmware/qcom_scm-smc.c b/drivers/firmware/qcom_scm-smc.c +index 16cf88acfa8ee0..0a2a2c794d0eda 100644 +--- a/drivers/firmware/qcom_scm-smc.c ++++ b/drivers/firmware/qcom_scm-smc.c +@@ -71,7 +71,7 @@ int scm_get_wq_ctx(u32 *wq_ctx, u32 *flags, u32 *more_pending) + struct arm_smccc_res get_wq_res; + struct arm_smccc_args get_wq_ctx = {0}; + +- get_wq_ctx.args[0] = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ++ get_wq_ctx.args[0] = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, + ARM_SMCCC_SMC_64, ARM_SMCCC_OWNER_SIP, + SCM_SMC_FNID(QCOM_SCM_SVC_WAITQ, QCOM_SCM_WAITQ_GET_WQ_CTX)); + +diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c +index 06fe8aca870d7b..7af59985f1c1f9 100644 +--- a/drivers/firmware/qcom_scm.c ++++ b/drivers/firmware/qcom_scm.c +@@ -167,6 +167,12 @@ static enum qcom_scm_convention __get_convention(void) + if (likely(qcom_scm_convention != SMC_CONVENTION_UNKNOWN)) + return qcom_scm_convention; + ++ /* ++ * Per the "SMC calling convention specification", the 64-bit calling ++ * convention can only be used when the client is 64-bit, otherwise ++ * system will encounter the undefined behaviour. ++ */ ++#if IS_ENABLED(CONFIG_ARM64) + /* + * Device isn't required as there is only one argument - no device + * needed to dma_map_single to secure world +@@ -187,6 +193,7 @@ static enum qcom_scm_convention __get_convention(void) + forced = true; + goto found; + } ++#endif + + probed_convention = SMC_CONVENTION_ARM_32; + ret = __scm_smc_call(NULL, &desc, probed_convention, &res, true); +@@ -491,13 +498,14 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, + + ret = qcom_scm_bw_enable(); + if (ret) +- return ret; ++ goto disable_clk; + + desc.args[1] = mdata_phys; + + ret = qcom_scm_call(__scm->dev, &desc, &res); +- + qcom_scm_bw_disable(); ++ ++disable_clk: + qcom_scm_clk_disable(); + + out: +@@ -559,10 +567,12 @@ int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size) + + ret = qcom_scm_bw_enable(); + if (ret) +- return ret; ++ goto disable_clk; + + ret = qcom_scm_call(__scm->dev, &desc, &res); + qcom_scm_bw_disable(); ++ ++disable_clk: + qcom_scm_clk_disable(); + + return ret ? : res.result[0]; +@@ -594,10 +604,12 @@ int qcom_scm_pas_auth_and_reset(u32 peripheral) + + ret = qcom_scm_bw_enable(); + if (ret) +- return ret; ++ goto disable_clk; + + ret = qcom_scm_call(__scm->dev, &desc, &res); + qcom_scm_bw_disable(); ++ ++disable_clk: + qcom_scm_clk_disable(); + + return ret ? : res.result[0]; +@@ -628,11 +640,12 @@ int qcom_scm_pas_shutdown(u32 peripheral) + + ret = qcom_scm_bw_enable(); + if (ret) +- return ret; ++ goto disable_clk; + + ret = qcom_scm_call(__scm->dev, &desc, &res); +- + qcom_scm_bw_disable(); ++ ++disable_clk: + qcom_scm_clk_disable(); + + return ret ? : res.result[0]; +@@ -1326,7 +1339,7 @@ static int qcom_scm_find_dload_address(struct device *dev, u64 *addr) + */ + bool qcom_scm_is_available(void) + { +- return !!__scm; ++ return !!READ_ONCE(__scm); + } + EXPORT_SYMBOL_GPL(qcom_scm_is_available); + +@@ -1407,10 +1420,12 @@ static int qcom_scm_probe(struct platform_device *pdev) + if (!scm) + return -ENOMEM; + ++ scm->dev = &pdev->dev; + ret = qcom_scm_find_dload_address(&pdev->dev, &scm->dload_mode_addr); + if (ret < 0) + return ret; + ++ init_completion(&scm->waitq_comp); + mutex_init(&scm->scm_bw_lock); + + scm->path = devm_of_icc_get(&pdev->dev, NULL); +@@ -1442,10 +1457,8 @@ static int qcom_scm_probe(struct platform_device *pdev) + if (ret) + return ret; + +- __scm = scm; +- __scm->dev = &pdev->dev; +- +- init_completion(&__scm->waitq_comp); ++ /* Let all above stores be available after this */ ++ smp_store_release(&__scm, scm); + + irq = platform_get_irq_optional(pdev, 0); + if (irq < 0) { +diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c +index f66efaa5196d9d..428ae54d3196c2 100644 +--- a/drivers/firmware/raspberrypi.c ++++ b/drivers/firmware/raspberrypi.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -97,8 +98,8 @@ int rpi_firmware_property_list(struct rpi_firmware *fw, + if (size & 3) + return -EINVAL; + +- buf = dma_alloc_coherent(fw->cl.dev, PAGE_ALIGN(size), &bus_addr, +- GFP_ATOMIC); ++ buf = dma_alloc_coherent(fw->chan->mbox->dev, PAGE_ALIGN(size), ++ &bus_addr, GFP_ATOMIC); + if (!buf) + return -ENOMEM; + +@@ -126,7 +127,7 @@ int rpi_firmware_property_list(struct rpi_firmware *fw, + ret = -EINVAL; + } + +- dma_free_coherent(fw->cl.dev, PAGE_ALIGN(size), buf, bus_addr); ++ dma_free_coherent(fw->chan->mbox->dev, PAGE_ALIGN(size), buf, bus_addr); + + return ret; + } +diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c +index 82fcfd29bc4d29..defd7a36cb08a4 100644 +--- a/drivers/firmware/sysfb.c ++++ b/drivers/firmware/sysfb.c +@@ -77,6 +77,8 @@ static __init int sysfb_init(void) + bool compatible; + int ret = 0; + ++ screen_info_apply_fixups(); ++ + mutex_lock(&disable_lock); + if (disabled) + goto unlock_mutex; +@@ -128,4 +130,4 @@ static __init int sysfb_init(void) + } + + /* must execute after PCI subsystem for EFI quirks */ +-subsys_initcall_sync(sysfb_init); ++device_initcall(sysfb_init); +diff --git a/drivers/firmware/tegra/bpmp-debugfs.c b/drivers/firmware/tegra/bpmp-debugfs.c +index 6dfe3d34109ee9..b20d04950d99b3 100644 +--- a/drivers/firmware/tegra/bpmp-debugfs.c ++++ b/drivers/firmware/tegra/bpmp-debugfs.c +@@ -77,7 +77,7 @@ static const char *get_filename(struct tegra_bpmp *bpmp, + + root_path_buf = kzalloc(root_path_buf_len, GFP_KERNEL); + if (!root_path_buf) +- goto out; ++ return NULL; + + root_path = dentry_path(bpmp->debugfs_mirror, root_path_buf, + root_path_buf_len); +diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c +index 51d062e0c3f129..c3a1dc3449617f 100644 +--- a/drivers/firmware/tegra/bpmp.c ++++ b/drivers/firmware/tegra/bpmp.c +@@ -24,12 +24,6 @@ + #define MSG_RING BIT(1) + #define TAG_SZ 32 + +-static inline struct tegra_bpmp * +-mbox_client_to_bpmp(struct mbox_client *client) +-{ +- return container_of(client, struct tegra_bpmp, mbox.client); +-} +- + static inline const struct tegra_bpmp_ops * + channel_to_ops(struct tegra_bpmp_channel *channel) + { +@@ -313,6 +307,8 @@ static ssize_t tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel, + return __tegra_bpmp_channel_write(channel, mrq, flags, data, size); + } + ++static int __maybe_unused tegra_bpmp_resume(struct device *dev); ++ + int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp, + struct tegra_bpmp_message *msg) + { +@@ -325,6 +321,14 @@ int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp, + if (!tegra_bpmp_message_valid(msg)) + return -EINVAL; + ++ if (bpmp->suspended) { ++ /* Reset BPMP IPC channels during resume based on flags passed */ ++ if (msg->flags & TEGRA_BPMP_MESSAGE_RESET) ++ tegra_bpmp_resume(bpmp->dev); ++ else ++ return -EAGAIN; ++ } ++ + channel = bpmp->tx_channel; + + spin_lock(&bpmp->atomic_tx_lock); +@@ -364,6 +368,14 @@ int tegra_bpmp_transfer(struct tegra_bpmp *bpmp, + if (!tegra_bpmp_message_valid(msg)) + return -EINVAL; + ++ if (bpmp->suspended) { ++ /* Reset BPMP IPC channels during resume based on flags passed */ ++ if (msg->flags & TEGRA_BPMP_MESSAGE_RESET) ++ tegra_bpmp_resume(bpmp->dev); ++ else ++ return -EAGAIN; ++ } ++ + channel = tegra_bpmp_write_threaded(bpmp, msg->mrq, msg->tx.data, + msg->tx.size); + if (IS_ERR(channel)) +@@ -796,10 +808,21 @@ static int tegra_bpmp_probe(struct platform_device *pdev) + return err; + } + ++static int __maybe_unused tegra_bpmp_suspend(struct device *dev) ++{ ++ struct tegra_bpmp *bpmp = dev_get_drvdata(dev); ++ ++ bpmp->suspended = true; ++ ++ return 0; ++} ++ + static int __maybe_unused tegra_bpmp_resume(struct device *dev) + { + struct tegra_bpmp *bpmp = dev_get_drvdata(dev); + ++ bpmp->suspended = false; ++ + if (bpmp->soc->ops->resume) + return bpmp->soc->ops->resume(bpmp); + else +@@ -807,6 +830,7 @@ static int __maybe_unused tegra_bpmp_resume(struct device *dev) + } + + static const struct dev_pm_ops tegra_bpmp_pm_ops = { ++ .suspend_noirq = tegra_bpmp_suspend, + .resume_noirq = tegra_bpmp_resume, + }; + +diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c +index 26a37f47f4ca54..3b4c9355cb60f6 100644 +--- a/drivers/firmware/ti_sci.c ++++ b/drivers/firmware/ti_sci.c +@@ -161,7 +161,7 @@ static int ti_sci_debugfs_create(struct platform_device *pdev, + { + struct device *dev = &pdev->dev; + struct resource *res; +- char debug_name[50] = "ti_sci_debug@"; ++ char debug_name[50]; + + /* Debug region is optional */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, +@@ -178,10 +178,10 @@ static int ti_sci_debugfs_create(struct platform_device *pdev, + /* Setup NULL termination */ + info->debug_buffer[info->debug_region_size] = 0; + +- info->d = debugfs_create_file(strncat(debug_name, dev_name(dev), +- sizeof(debug_name) - +- sizeof("ti_sci_debug@")), +- 0444, NULL, info, &ti_sci_debug_fops); ++ snprintf(debug_name, sizeof(debug_name), "ti_sci_debug@%s", ++ dev_name(dev)); ++ info->d = debugfs_create_file(debug_name, 0444, NULL, info, ++ &ti_sci_debug_fops); + if (IS_ERR(info->d)) + return PTR_ERR(info->d); + +@@ -190,19 +190,6 @@ static int ti_sci_debugfs_create(struct platform_device *pdev, + return 0; + } + +-/** +- * ti_sci_debugfs_destroy() - clean up log debug file +- * @pdev: platform device pointer +- * @info: Pointer to SCI entity information +- */ +-static void ti_sci_debugfs_destroy(struct platform_device *pdev, +- struct ti_sci_info *info) +-{ +- if (IS_ERR(info->debug_region)) +- return; +- +- debugfs_remove(info->d); +-} + #else /* CONFIG_DEBUG_FS */ + static inline int ti_sci_debugfs_create(struct platform_device *dev, + struct ti_sci_info *info) +@@ -3449,43 +3436,12 @@ static int ti_sci_probe(struct platform_device *pdev) + return ret; + } + +-static int ti_sci_remove(struct platform_device *pdev) +-{ +- struct ti_sci_info *info; +- struct device *dev = &pdev->dev; +- int ret = 0; +- +- of_platform_depopulate(dev); +- +- info = platform_get_drvdata(pdev); +- +- if (info->nb.notifier_call) +- unregister_restart_handler(&info->nb); +- +- mutex_lock(&ti_sci_list_mutex); +- if (info->users) +- ret = -EBUSY; +- else +- list_del(&info->node); +- mutex_unlock(&ti_sci_list_mutex); +- +- if (!ret) { +- ti_sci_debugfs_destroy(pdev, info); +- +- /* Safe to free channels since no more users */ +- mbox_free_channel(info->chan_tx); +- mbox_free_channel(info->chan_rx); +- } +- +- return ret; +-} +- + static struct platform_driver ti_sci_driver = { + .probe = ti_sci_probe, +- .remove = ti_sci_remove, + .driver = { + .name = "ti-sci", + .of_match_table = of_match_ptr(ti_sci_of_match), ++ .suppress_bind_attrs = true, + }, + }; + module_platform_driver(ti_sci_driver); +diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c +index 2de0fb139ce176..3d354ebd38c285 100644 +--- a/drivers/firmware/turris-mox-rwtm.c ++++ b/drivers/firmware/turris-mox-rwtm.c +@@ -2,7 +2,7 @@ + /* + * Turris Mox rWTM firmware driver + * +- * Copyright (C) 2019 Marek Behún ++ * Copyright (C) 2019, 2024 Marek Behún + */ + + #include +@@ -174,6 +174,9 @@ static void mox_rwtm_rx_callback(struct mbox_client *cl, void *data) + struct mox_rwtm *rwtm = dev_get_drvdata(cl->dev); + struct armada_37xx_rwtm_rx_msg *msg = data; + ++ if (completion_done(&rwtm->cmd_done)) ++ return; ++ + rwtm->reply = *msg; + complete(&rwtm->cmd_done); + } +@@ -199,9 +202,8 @@ static int mox_get_board_info(struct mox_rwtm *rwtm) + if (ret < 0) + return ret; + +- ret = wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2); +- if (ret < 0) +- return ret; ++ if (!wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2)) ++ return -ETIMEDOUT; + + ret = mox_get_status(MBOX_CMD_BOARD_INFO, reply->retval); + if (ret == -ENODATA) { +@@ -235,9 +237,8 @@ static int mox_get_board_info(struct mox_rwtm *rwtm) + if (ret < 0) + return ret; + +- ret = wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2); +- if (ret < 0) +- return ret; ++ if (!wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2)) ++ return -ETIMEDOUT; + + ret = mox_get_status(MBOX_CMD_ECDSA_PUB_KEY, reply->retval); + if (ret == -ENODATA) { +@@ -274,9 +275,8 @@ static int check_get_random_support(struct mox_rwtm *rwtm) + if (ret < 0) + return ret; + +- ret = wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2); +- if (ret < 0) +- return ret; ++ if (!wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2)) ++ return -ETIMEDOUT; + + return mox_get_status(MBOX_CMD_GET_RANDOM, rwtm->reply.retval); + } +@@ -499,6 +499,7 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) + platform_set_drvdata(pdev, rwtm); + + mutex_init(&rwtm->busy); ++ init_completion(&rwtm->cmd_done); + + rwtm->mbox_client.dev = dev; + rwtm->mbox_client.rx_callback = mox_rwtm_rx_callback; +@@ -512,8 +513,6 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) + goto remove_files; + } + +- init_completion(&rwtm->cmd_done); +- + ret = mox_get_board_info(rwtm); + if (ret < 0) + dev_warn(dev, "Cannot read board information: %i\n", ret); +diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c +index 98b8fd16183e41..80cac3a5f97678 100644 +--- a/drivers/fpga/dfl-pci.c ++++ b/drivers/fpga/dfl-pci.c +@@ -78,6 +78,7 @@ static void cci_pci_free_irq(struct pci_dev *pcidev) + #define PCIE_DEVICE_ID_SILICOM_PAC_N5011 0x1001 + #define PCIE_DEVICE_ID_INTEL_DFL 0xbcce + /* PCI Subdevice ID for PCIE_DEVICE_ID_INTEL_DFL */ ++#define PCIE_SUBDEVICE_ID_INTEL_D5005 0x138d + #define PCIE_SUBDEVICE_ID_INTEL_N6000 0x1770 + #define PCIE_SUBDEVICE_ID_INTEL_N6001 0x1771 + #define PCIE_SUBDEVICE_ID_INTEL_C6100 0x17d4 +@@ -101,6 +102,8 @@ static struct pci_device_id cci_pcie_id_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005_VF),}, + {PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5010),}, + {PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5011),}, ++ {PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_DFL, ++ PCI_VENDOR_ID_INTEL, PCIE_SUBDEVICE_ID_INTEL_D5005),}, + {PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_DFL, + PCI_VENDOR_ID_INTEL, PCIE_SUBDEVICE_ID_INTEL_N6000),}, + {PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_DFL_VF, +diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c +index a024be2b84e291..83d35fbb824505 100644 +--- a/drivers/fpga/fpga-bridge.c ++++ b/drivers/fpga/fpga-bridge.c +@@ -55,33 +55,26 @@ int fpga_bridge_disable(struct fpga_bridge *bridge) + } + EXPORT_SYMBOL_GPL(fpga_bridge_disable); + +-static struct fpga_bridge *__fpga_bridge_get(struct device *dev, ++static struct fpga_bridge *__fpga_bridge_get(struct device *bridge_dev, + struct fpga_image_info *info) + { + struct fpga_bridge *bridge; +- int ret = -ENODEV; + +- bridge = to_fpga_bridge(dev); ++ bridge = to_fpga_bridge(bridge_dev); + + bridge->info = info; + +- if (!mutex_trylock(&bridge->mutex)) { +- ret = -EBUSY; +- goto err_dev; +- } ++ if (!mutex_trylock(&bridge->mutex)) ++ return ERR_PTR(-EBUSY); + +- if (!try_module_get(dev->parent->driver->owner)) +- goto err_ll_mod; ++ if (!try_module_get(bridge->br_ops_owner)) { ++ mutex_unlock(&bridge->mutex); ++ return ERR_PTR(-ENODEV); ++ } + + dev_dbg(&bridge->dev, "get\n"); + + return bridge; +- +-err_ll_mod: +- mutex_unlock(&bridge->mutex); +-err_dev: +- put_device(dev); +- return ERR_PTR(ret); + } + + /** +@@ -98,13 +91,18 @@ static struct fpga_bridge *__fpga_bridge_get(struct device *dev, + struct fpga_bridge *of_fpga_bridge_get(struct device_node *np, + struct fpga_image_info *info) + { +- struct device *dev; ++ struct fpga_bridge *bridge; ++ struct device *bridge_dev; + +- dev = class_find_device_by_of_node(&fpga_bridge_class, np); +- if (!dev) ++ bridge_dev = class_find_device_by_of_node(&fpga_bridge_class, np); ++ if (!bridge_dev) + return ERR_PTR(-ENODEV); + +- return __fpga_bridge_get(dev, info); ++ bridge = __fpga_bridge_get(bridge_dev, info); ++ if (IS_ERR(bridge)) ++ put_device(bridge_dev); ++ ++ return bridge; + } + EXPORT_SYMBOL_GPL(of_fpga_bridge_get); + +@@ -125,6 +123,7 @@ static int fpga_bridge_dev_match(struct device *dev, const void *data) + struct fpga_bridge *fpga_bridge_get(struct device *dev, + struct fpga_image_info *info) + { ++ struct fpga_bridge *bridge; + struct device *bridge_dev; + + bridge_dev = class_find_device(&fpga_bridge_class, NULL, dev, +@@ -132,7 +131,11 @@ struct fpga_bridge *fpga_bridge_get(struct device *dev, + if (!bridge_dev) + return ERR_PTR(-ENODEV); + +- return __fpga_bridge_get(bridge_dev, info); ++ bridge = __fpga_bridge_get(bridge_dev, info); ++ if (IS_ERR(bridge)) ++ put_device(bridge_dev); ++ ++ return bridge; + } + EXPORT_SYMBOL_GPL(fpga_bridge_get); + +@@ -146,7 +149,7 @@ void fpga_bridge_put(struct fpga_bridge *bridge) + dev_dbg(&bridge->dev, "put\n"); + + bridge->info = NULL; +- module_put(bridge->dev.parent->driver->owner); ++ module_put(bridge->br_ops_owner); + mutex_unlock(&bridge->mutex); + put_device(&bridge->dev); + } +@@ -316,18 +319,19 @@ static struct attribute *fpga_bridge_attrs[] = { + ATTRIBUTE_GROUPS(fpga_bridge); + + /** +- * fpga_bridge_register - create and register an FPGA Bridge device ++ * __fpga_bridge_register - create and register an FPGA Bridge device + * @parent: FPGA bridge device from pdev + * @name: FPGA bridge name + * @br_ops: pointer to structure of fpga bridge ops + * @priv: FPGA bridge private data ++ * @owner: owner module containing the br_ops + * + * Return: struct fpga_bridge pointer or ERR_PTR() + */ + struct fpga_bridge * +-fpga_bridge_register(struct device *parent, const char *name, +- const struct fpga_bridge_ops *br_ops, +- void *priv) ++__fpga_bridge_register(struct device *parent, const char *name, ++ const struct fpga_bridge_ops *br_ops, ++ void *priv, struct module *owner) + { + struct fpga_bridge *bridge; + int id, ret; +@@ -357,6 +361,7 @@ fpga_bridge_register(struct device *parent, const char *name, + + bridge->name = name; + bridge->br_ops = br_ops; ++ bridge->br_ops_owner = owner; + bridge->priv = priv; + + bridge->dev.groups = br_ops->groups; +@@ -386,7 +391,7 @@ fpga_bridge_register(struct device *parent, const char *name, + + return ERR_PTR(ret); + } +-EXPORT_SYMBOL_GPL(fpga_bridge_register); ++EXPORT_SYMBOL_GPL(__fpga_bridge_register); + + /** + * fpga_bridge_unregister - unregister an FPGA bridge +diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c +index 06651389c59262..0f4035b089a2ea 100644 +--- a/drivers/fpga/fpga-mgr.c ++++ b/drivers/fpga/fpga-mgr.c +@@ -664,20 +664,16 @@ static struct attribute *fpga_mgr_attrs[] = { + }; + ATTRIBUTE_GROUPS(fpga_mgr); + +-static struct fpga_manager *__fpga_mgr_get(struct device *dev) ++static struct fpga_manager *__fpga_mgr_get(struct device *mgr_dev) + { + struct fpga_manager *mgr; + +- mgr = to_fpga_manager(dev); ++ mgr = to_fpga_manager(mgr_dev); + +- if (!try_module_get(dev->parent->driver->owner)) +- goto err_dev; ++ if (!try_module_get(mgr->mops_owner)) ++ mgr = ERR_PTR(-ENODEV); + + return mgr; +- +-err_dev: +- put_device(dev); +- return ERR_PTR(-ENODEV); + } + + static int fpga_mgr_dev_match(struct device *dev, const void *data) +@@ -693,12 +689,18 @@ static int fpga_mgr_dev_match(struct device *dev, const void *data) + */ + struct fpga_manager *fpga_mgr_get(struct device *dev) + { +- struct device *mgr_dev = class_find_device(&fpga_mgr_class, NULL, dev, +- fpga_mgr_dev_match); ++ struct fpga_manager *mgr; ++ struct device *mgr_dev; ++ ++ mgr_dev = class_find_device(&fpga_mgr_class, NULL, dev, fpga_mgr_dev_match); + if (!mgr_dev) + return ERR_PTR(-ENODEV); + +- return __fpga_mgr_get(mgr_dev); ++ mgr = __fpga_mgr_get(mgr_dev); ++ if (IS_ERR(mgr)) ++ put_device(mgr_dev); ++ ++ return mgr; + } + EXPORT_SYMBOL_GPL(fpga_mgr_get); + +@@ -711,13 +713,18 @@ EXPORT_SYMBOL_GPL(fpga_mgr_get); + */ + struct fpga_manager *of_fpga_mgr_get(struct device_node *node) + { +- struct device *dev; ++ struct fpga_manager *mgr; ++ struct device *mgr_dev; + +- dev = class_find_device_by_of_node(&fpga_mgr_class, node); +- if (!dev) ++ mgr_dev = class_find_device_by_of_node(&fpga_mgr_class, node); ++ if (!mgr_dev) + return ERR_PTR(-ENODEV); + +- return __fpga_mgr_get(dev); ++ mgr = __fpga_mgr_get(mgr_dev); ++ if (IS_ERR(mgr)) ++ put_device(mgr_dev); ++ ++ return mgr; + } + EXPORT_SYMBOL_GPL(of_fpga_mgr_get); + +@@ -727,7 +734,7 @@ EXPORT_SYMBOL_GPL(of_fpga_mgr_get); + */ + void fpga_mgr_put(struct fpga_manager *mgr) + { +- module_put(mgr->dev.parent->driver->owner); ++ module_put(mgr->mops_owner); + put_device(&mgr->dev); + } + EXPORT_SYMBOL_GPL(fpga_mgr_put); +@@ -766,9 +773,10 @@ void fpga_mgr_unlock(struct fpga_manager *mgr) + EXPORT_SYMBOL_GPL(fpga_mgr_unlock); + + /** +- * fpga_mgr_register_full - create and register an FPGA Manager device ++ * __fpga_mgr_register_full - create and register an FPGA Manager device + * @parent: fpga manager device from pdev + * @info: parameters for fpga manager ++ * @owner: owner module containing the ops + * + * The caller of this function is responsible for calling fpga_mgr_unregister(). + * Using devm_fpga_mgr_register_full() instead is recommended. +@@ -776,7 +784,8 @@ EXPORT_SYMBOL_GPL(fpga_mgr_unlock); + * Return: pointer to struct fpga_manager pointer or ERR_PTR() + */ + struct fpga_manager * +-fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info) ++__fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, ++ struct module *owner) + { + const struct fpga_manager_ops *mops = info->mops; + struct fpga_manager *mgr; +@@ -804,6 +813,8 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in + + mutex_init(&mgr->ref_mutex); + ++ mgr->mops_owner = owner; ++ + mgr->name = info->name; + mgr->mops = info->mops; + mgr->priv = info->priv; +@@ -841,14 +852,15 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in + + return ERR_PTR(ret); + } +-EXPORT_SYMBOL_GPL(fpga_mgr_register_full); ++EXPORT_SYMBOL_GPL(__fpga_mgr_register_full); + + /** +- * fpga_mgr_register - create and register an FPGA Manager device ++ * __fpga_mgr_register - create and register an FPGA Manager device + * @parent: fpga manager device from pdev + * @name: fpga manager name + * @mops: pointer to structure of fpga manager ops + * @priv: fpga manager private data ++ * @owner: owner module containing the ops + * + * The caller of this function is responsible for calling fpga_mgr_unregister(). + * Using devm_fpga_mgr_register() instead is recommended. This simple +@@ -859,8 +871,8 @@ EXPORT_SYMBOL_GPL(fpga_mgr_register_full); + * Return: pointer to struct fpga_manager pointer or ERR_PTR() + */ + struct fpga_manager * +-fpga_mgr_register(struct device *parent, const char *name, +- const struct fpga_manager_ops *mops, void *priv) ++__fpga_mgr_register(struct device *parent, const char *name, ++ const struct fpga_manager_ops *mops, void *priv, struct module *owner) + { + struct fpga_manager_info info = { 0 }; + +@@ -868,9 +880,9 @@ fpga_mgr_register(struct device *parent, const char *name, + info.mops = mops; + info.priv = priv; + +- return fpga_mgr_register_full(parent, &info); ++ return __fpga_mgr_register_full(parent, &info, owner); + } +-EXPORT_SYMBOL_GPL(fpga_mgr_register); ++EXPORT_SYMBOL_GPL(__fpga_mgr_register); + + /** + * fpga_mgr_unregister - unregister an FPGA manager +@@ -900,9 +912,10 @@ static void devm_fpga_mgr_unregister(struct device *dev, void *res) + } + + /** +- * devm_fpga_mgr_register_full - resource managed variant of fpga_mgr_register() ++ * __devm_fpga_mgr_register_full - resource managed variant of fpga_mgr_register() + * @parent: fpga manager device from pdev + * @info: parameters for fpga manager ++ * @owner: owner module containing the ops + * + * Return: fpga manager pointer on success, negative error code otherwise. + * +@@ -910,7 +923,8 @@ static void devm_fpga_mgr_unregister(struct device *dev, void *res) + * function will be called automatically when the managing device is detached. + */ + struct fpga_manager * +-devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info) ++__devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, ++ struct module *owner) + { + struct fpga_mgr_devres *dr; + struct fpga_manager *mgr; +@@ -919,7 +933,7 @@ devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_inf + if (!dr) + return ERR_PTR(-ENOMEM); + +- mgr = fpga_mgr_register_full(parent, info); ++ mgr = __fpga_mgr_register_full(parent, info, owner); + if (IS_ERR(mgr)) { + devres_free(dr); + return mgr; +@@ -930,14 +944,15 @@ devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_inf + + return mgr; + } +-EXPORT_SYMBOL_GPL(devm_fpga_mgr_register_full); ++EXPORT_SYMBOL_GPL(__devm_fpga_mgr_register_full); + + /** +- * devm_fpga_mgr_register - resource managed variant of fpga_mgr_register() ++ * __devm_fpga_mgr_register - resource managed variant of fpga_mgr_register() + * @parent: fpga manager device from pdev + * @name: fpga manager name + * @mops: pointer to structure of fpga manager ops + * @priv: fpga manager private data ++ * @owner: owner module containing the ops + * + * Return: fpga manager pointer on success, negative error code otherwise. + * +@@ -946,8 +961,9 @@ EXPORT_SYMBOL_GPL(devm_fpga_mgr_register_full); + * device is detached. + */ + struct fpga_manager * +-devm_fpga_mgr_register(struct device *parent, const char *name, +- const struct fpga_manager_ops *mops, void *priv) ++__devm_fpga_mgr_register(struct device *parent, const char *name, ++ const struct fpga_manager_ops *mops, void *priv, ++ struct module *owner) + { + struct fpga_manager_info info = { 0 }; + +@@ -955,9 +971,9 @@ devm_fpga_mgr_register(struct device *parent, const char *name, + info.mops = mops; + info.priv = priv; + +- return devm_fpga_mgr_register_full(parent, &info); ++ return __devm_fpga_mgr_register_full(parent, &info, owner); + } +-EXPORT_SYMBOL_GPL(devm_fpga_mgr_register); ++EXPORT_SYMBOL_GPL(__devm_fpga_mgr_register); + + static void fpga_mgr_dev_release(struct device *dev) + { +diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c +index b364a929425ce9..753cd142503e0e 100644 +--- a/drivers/fpga/fpga-region.c ++++ b/drivers/fpga/fpga-region.c +@@ -53,7 +53,7 @@ static struct fpga_region *fpga_region_get(struct fpga_region *region) + } + + get_device(dev); +- if (!try_module_get(dev->parent->driver->owner)) { ++ if (!try_module_get(region->ops_owner)) { + put_device(dev); + mutex_unlock(®ion->mutex); + return ERR_PTR(-ENODEV); +@@ -75,7 +75,7 @@ static void fpga_region_put(struct fpga_region *region) + + dev_dbg(dev, "put\n"); + +- module_put(dev->parent->driver->owner); ++ module_put(region->ops_owner); + put_device(dev); + mutex_unlock(®ion->mutex); + } +@@ -181,14 +181,16 @@ static struct attribute *fpga_region_attrs[] = { + ATTRIBUTE_GROUPS(fpga_region); + + /** +- * fpga_region_register_full - create and register an FPGA Region device ++ * __fpga_region_register_full - create and register an FPGA Region device + * @parent: device parent + * @info: parameters for FPGA Region ++ * @owner: module containing the get_bridges function + * + * Return: struct fpga_region or ERR_PTR() + */ + struct fpga_region * +-fpga_region_register_full(struct device *parent, const struct fpga_region_info *info) ++__fpga_region_register_full(struct device *parent, const struct fpga_region_info *info, ++ struct module *owner) + { + struct fpga_region *region; + int id, ret = 0; +@@ -213,6 +215,7 @@ fpga_region_register_full(struct device *parent, const struct fpga_region_info * + region->compat_id = info->compat_id; + region->priv = info->priv; + region->get_bridges = info->get_bridges; ++ region->ops_owner = owner; + + mutex_init(®ion->mutex); + INIT_LIST_HEAD(®ion->bridge_list); +@@ -241,13 +244,14 @@ fpga_region_register_full(struct device *parent, const struct fpga_region_info * + + return ERR_PTR(ret); + } +-EXPORT_SYMBOL_GPL(fpga_region_register_full); ++EXPORT_SYMBOL_GPL(__fpga_region_register_full); + + /** +- * fpga_region_register - create and register an FPGA Region device ++ * __fpga_region_register - create and register an FPGA Region device + * @parent: device parent + * @mgr: manager that programs this region + * @get_bridges: optional function to get bridges to a list ++ * @owner: module containing the get_bridges function + * + * This simple version of the register function should be sufficient for most users. + * The fpga_region_register_full() function is available for users that need to +@@ -256,17 +260,17 @@ EXPORT_SYMBOL_GPL(fpga_region_register_full); + * Return: struct fpga_region or ERR_PTR() + */ + struct fpga_region * +-fpga_region_register(struct device *parent, struct fpga_manager *mgr, +- int (*get_bridges)(struct fpga_region *)) ++__fpga_region_register(struct device *parent, struct fpga_manager *mgr, ++ int (*get_bridges)(struct fpga_region *), struct module *owner) + { + struct fpga_region_info info = { 0 }; + + info.mgr = mgr; + info.get_bridges = get_bridges; + +- return fpga_region_register_full(parent, &info); ++ return __fpga_region_register_full(parent, &info, owner); + } +-EXPORT_SYMBOL_GPL(fpga_region_register); ++EXPORT_SYMBOL_GPL(__fpga_region_register); + + /** + * fpga_region_unregister - unregister an FPGA region +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index 673bafb8be5887..ebd4e113dc2654 100644 +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -691,7 +691,8 @@ config GPIO_UNIPHIER + Say yes here to support UniPhier GPIOs. + + config GPIO_VF610 +- def_bool y ++ bool "VF610 GPIO support" ++ default y if SOC_VF610 + depends on ARCH_MXC + select GPIOLIB_IRQCHIP + help +@@ -1506,7 +1507,7 @@ config GPIO_TPS68470 + are "output only" GPIOs. + + config GPIO_TQMX86 +- tristate "TQ-Systems QTMX86 GPIO" ++ tristate "TQ-Systems TQMx86 GPIO" + depends on MFD_TQMX86 || COMPILE_TEST + depends on HAS_IOPORT_MAP + select GPIOLIB_IRQCHIP +diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c +index e00c333105170f..753e7be039e4d9 100644 +--- a/drivers/gpio/gpio-74x164.c ++++ b/drivers/gpio/gpio-74x164.c +@@ -127,8 +127,6 @@ static int gen_74x164_probe(struct spi_device *spi) + if (IS_ERR(chip->gpiod_oe)) + return PTR_ERR(chip->gpiod_oe); + +- gpiod_set_value_cansleep(chip->gpiod_oe, 1); +- + spi_set_drvdata(spi, chip); + + chip->gpio_chip.label = spi->modalias; +@@ -153,6 +151,8 @@ static int gen_74x164_probe(struct spi_device *spi) + goto exit_destroy; + } + ++ gpiod_set_value_cansleep(chip->gpiod_oe, 1); ++ + ret = gpiochip_add_data(&chip->gpio_chip, chip); + if (!ret) + return 0; +diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c +index 58f107194fdafd..76468e6a2899a8 100644 +--- a/drivers/gpio/gpio-aspeed.c ++++ b/drivers/gpio/gpio-aspeed.c +@@ -406,6 +406,8 @@ static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, + gpio->dcache[GPIO_BANK(offset)] = reg; + + iowrite32(reg, addr); ++ /* Flush write */ ++ ioread32(addr); + } + + static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, +@@ -1191,7 +1193,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) + if (!gpio_id) + return -EINVAL; + +- gpio->clk = of_clk_get(pdev->dev.of_node, 0); ++ gpio->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(gpio->clk)) { + dev_warn(&pdev->dev, + "Failed to get clock from devicetree, debouncing disabled\n"); +diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c +index 1ee62cd58582b6..25db014494a4de 100644 +--- a/drivers/gpio/gpio-crystalcove.c ++++ b/drivers/gpio/gpio-crystalcove.c +@@ -92,7 +92,7 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type) + case 0x5e: + return GPIOPANELCTL; + default: +- return -EOPNOTSUPP; ++ return -ENOTSUPP; + } + } + +diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c +index 8db5717bdabe56..75107ede3bf8f4 100644 +--- a/drivers/gpio/gpio-davinci.c ++++ b/drivers/gpio/gpio-davinci.c +@@ -225,6 +225,11 @@ static int davinci_gpio_probe(struct platform_device *pdev) + else + nirq = DIV_ROUND_UP(ngpio, 16); + ++ if (nirq > MAX_INT_PER_BANK) { ++ dev_err(dev, "Too many IRQs!\n"); ++ return -EINVAL; ++ } ++ + chips = devm_kzalloc(dev, sizeof(*chips), GFP_KERNEL); + if (!chips) + return -ENOMEM; +@@ -284,7 +289,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) + * serve as EDMA event triggers. + */ + +-static void gpio_irq_disable(struct irq_data *d) ++static void gpio_irq_mask(struct irq_data *d) + { + struct davinci_gpio_regs __iomem *g = irq2regs(d); + uintptr_t mask = (uintptr_t)irq_data_get_irq_handler_data(d); +@@ -293,7 +298,7 @@ static void gpio_irq_disable(struct irq_data *d) + writel_relaxed(mask, &g->clr_rising); + } + +-static void gpio_irq_enable(struct irq_data *d) ++static void gpio_irq_unmask(struct irq_data *d) + { + struct davinci_gpio_regs __iomem *g = irq2regs(d); + uintptr_t mask = (uintptr_t)irq_data_get_irq_handler_data(d); +@@ -319,8 +324,8 @@ static int gpio_irq_type(struct irq_data *d, unsigned trigger) + + static struct irq_chip gpio_irqchip = { + .name = "GPIO", +- .irq_enable = gpio_irq_enable, +- .irq_disable = gpio_irq_disable, ++ .irq_unmask = gpio_irq_unmask, ++ .irq_mask = gpio_irq_mask, + .irq_set_type = gpio_irq_type, + .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_SKIP_SET_WAKE, + }; +diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c +index c22fcaa44a614c..6b7d47a52b10a1 100644 +--- a/drivers/gpio/gpio-dwapb.c ++++ b/drivers/gpio/gpio-dwapb.c +@@ -283,13 +283,15 @@ static void dwapb_irq_enable(struct irq_data *d) + { + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = to_dwapb_gpio(gc); ++ irq_hw_number_t hwirq = irqd_to_hwirq(d); + unsigned long flags; + u32 val; + + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); +- val = dwapb_read(gpio, GPIO_INTEN); +- val |= BIT(irqd_to_hwirq(d)); ++ val = dwapb_read(gpio, GPIO_INTEN) | BIT(hwirq); + dwapb_write(gpio, GPIO_INTEN, val); ++ val = dwapb_read(gpio, GPIO_INTMASK) & ~BIT(hwirq); ++ dwapb_write(gpio, GPIO_INTMASK, val); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); + } + +@@ -297,12 +299,14 @@ static void dwapb_irq_disable(struct irq_data *d) + { + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = to_dwapb_gpio(gc); ++ irq_hw_number_t hwirq = irqd_to_hwirq(d); + unsigned long flags; + u32 val; + + raw_spin_lock_irqsave(&gc->bgpio_lock, flags); +- val = dwapb_read(gpio, GPIO_INTEN); +- val &= ~BIT(irqd_to_hwirq(d)); ++ val = dwapb_read(gpio, GPIO_INTMASK) | BIT(hwirq); ++ dwapb_write(gpio, GPIO_INTMASK, val); ++ val = dwapb_read(gpio, GPIO_INTEN) & ~BIT(hwirq); + dwapb_write(gpio, GPIO_INTEN, val); + raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); + } +diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c +index 5320cf1de89c46..b24e349deed5eb 100644 +--- a/drivers/gpio/gpio-eic-sprd.c ++++ b/drivers/gpio/gpio-eic-sprd.c +@@ -321,20 +321,27 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) + switch (flow_type) { + case IRQ_TYPE_LEVEL_HIGH: + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 1); ++ sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1); + break; + case IRQ_TYPE_LEVEL_LOW: + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0); ++ sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1); + break; + case IRQ_TYPE_EDGE_RISING: + case IRQ_TYPE_EDGE_FALLING: + case IRQ_TYPE_EDGE_BOTH: + state = sprd_eic_get(chip, offset); +- if (state) ++ if (state) { + sprd_eic_update(chip, offset, + SPRD_EIC_DBNC_IEV, 0); +- else ++ sprd_eic_update(chip, offset, ++ SPRD_EIC_DBNC_IC, 1); ++ } else { + sprd_eic_update(chip, offset, + SPRD_EIC_DBNC_IEV, 1); ++ sprd_eic_update(chip, offset, ++ SPRD_EIC_DBNC_IC, 1); ++ } + break; + default: + return -ENOTSUPP; +@@ -346,20 +353,27 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) + switch (flow_type) { + case IRQ_TYPE_LEVEL_HIGH: + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0); ++ sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1); + break; + case IRQ_TYPE_LEVEL_LOW: + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1); ++ sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1); + break; + case IRQ_TYPE_EDGE_RISING: + case IRQ_TYPE_EDGE_FALLING: + case IRQ_TYPE_EDGE_BOTH: + state = sprd_eic_get(chip, offset); +- if (state) ++ if (state) { + sprd_eic_update(chip, offset, + SPRD_EIC_LATCH_INTPOL, 0); +- else ++ sprd_eic_update(chip, offset, ++ SPRD_EIC_LATCH_INTCLR, 1); ++ } else { + sprd_eic_update(chip, offset, + SPRD_EIC_LATCH_INTPOL, 1); ++ sprd_eic_update(chip, offset, ++ SPRD_EIC_LATCH_INTCLR, 1); ++ } + break; + default: + return -ENOTSUPP; +@@ -373,29 +387,34 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1); ++ sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); + irq_set_handler_locked(data, handle_edge_irq); + break; + case IRQ_TYPE_EDGE_FALLING: + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0); ++ sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); + irq_set_handler_locked(data, handle_edge_irq); + break; + case IRQ_TYPE_EDGE_BOTH: + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 1); ++ sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); + irq_set_handler_locked(data, handle_edge_irq); + break; + case IRQ_TYPE_LEVEL_HIGH: + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1); ++ sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); + irq_set_handler_locked(data, handle_level_irq); + break; + case IRQ_TYPE_LEVEL_LOW: + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0); ++ sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); + irq_set_handler_locked(data, handle_level_irq); + break; + default: +@@ -408,29 +427,34 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1); ++ sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); + irq_set_handler_locked(data, handle_edge_irq); + break; + case IRQ_TYPE_EDGE_FALLING: + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0); ++ sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); + irq_set_handler_locked(data, handle_edge_irq); + break; + case IRQ_TYPE_EDGE_BOTH: + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 1); ++ sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); + irq_set_handler_locked(data, handle_edge_irq); + break; + case IRQ_TYPE_LEVEL_HIGH: + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1); ++ sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); + irq_set_handler_locked(data, handle_level_irq); + break; + case IRQ_TYPE_LEVEL_LOW: + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0); ++ sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); + irq_set_handler_locked(data, handle_level_irq); + break; + default: +diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c +index 5ef8af8249806a..c097e310c9e841 100644 +--- a/drivers/gpio/gpio-lpc32xx.c ++++ b/drivers/gpio/gpio-lpc32xx.c +@@ -529,6 +529,7 @@ static const struct of_device_id lpc32xx_gpio_of_match[] = { + { .compatible = "nxp,lpc3220-gpio", }, + { }, + }; ++MODULE_DEVICE_TABLE(of, lpc32xx_gpio_of_match); + + static struct platform_driver lpc32xx_gpio_driver = { + .driver = { +diff --git a/drivers/gpio/gpio-mlxbf3.c b/drivers/gpio/gpio-mlxbf3.c +index 7a3e1760fc5b7d..10ea71273c8915 100644 +--- a/drivers/gpio/gpio-mlxbf3.c ++++ b/drivers/gpio/gpio-mlxbf3.c +@@ -39,6 +39,8 @@ + #define MLXBF_GPIO_CAUSE_OR_EVTEN0 0x14 + #define MLXBF_GPIO_CAUSE_OR_CLRCAUSE 0x18 + ++#define MLXBF_GPIO_CLR_ALL_INTS GENMASK(31, 0) ++ + struct mlxbf3_gpio_context { + struct gpio_chip gc; + +@@ -82,6 +84,8 @@ static void mlxbf3_gpio_irq_disable(struct irq_data *irqd) + val = readl(gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0); + val &= ~BIT(offset); + writel(val, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0); ++ ++ writel(BIT(offset), gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_CLRCAUSE); + raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); + + gpiochip_disable_irq(gc, offset); +@@ -215,6 +219,8 @@ static int mlxbf3_gpio_probe(struct platform_device *pdev) + gs->gpio_clr_io + MLXBF_GPIO_FW_DATA_OUT_CLEAR, + gs->gpio_set_io + MLXBF_GPIO_FW_OUTPUT_ENABLE_SET, + gs->gpio_clr_io + MLXBF_GPIO_FW_OUTPUT_ENABLE_CLEAR, 0); ++ if (ret) ++ return dev_err_probe(dev, ret, "%s: bgpio_init() failed", __func__); + + gc->request = gpiochip_generic_request; + gc->free = gpiochip_generic_free; +@@ -251,6 +257,15 @@ static int mlxbf3_gpio_probe(struct platform_device *pdev) + return 0; + } + ++static void mlxbf3_gpio_shutdown(struct platform_device *pdev) ++{ ++ struct mlxbf3_gpio_context *gs = platform_get_drvdata(pdev); ++ ++ /* Disable and clear all interrupts */ ++ writel(0, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0); ++ writel(MLXBF_GPIO_CLR_ALL_INTS, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_CLRCAUSE); ++} ++ + static const struct acpi_device_id mlxbf3_gpio_acpi_match[] = { + { "MLNXBF33", 0 }, + {} +@@ -263,6 +278,7 @@ static struct platform_driver mlxbf3_gpio_driver = { + .acpi_match_table = mlxbf3_gpio_acpi_match, + }, + .probe = mlxbf3_gpio_probe, ++ .shutdown = mlxbf3_gpio_shutdown, + }; + module_platform_driver(mlxbf3_gpio_driver); + +diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c +index 74fdf0d87b2c8e..c9f9f4e36c89b5 100644 +--- a/drivers/gpio/gpio-mmio.c ++++ b/drivers/gpio/gpio-mmio.c +@@ -622,8 +622,6 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev, + ret = gpiochip_get_ngpios(gc, dev); + if (ret) + gc->ngpio = gc->bgpio_bits; +- else +- gc->bgpio_bits = roundup_pow_of_two(round_up(gc->ngpio, 8)); + + ret = bgpio_setup_io(gc, dat, set, clr, flags); + if (ret) +diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c +index bdd50a78e4142d..ce9a94e332801f 100644 +--- a/drivers/gpio/gpio-pca953x.c ++++ b/drivers/gpio/gpio-pca953x.c +@@ -766,6 +766,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) + int level; + + if (chip->driver_data & PCA_PCAL) { ++ guard(mutex)(&chip->i2c_lock); ++ + /* Enable latch on interrupt-enabled inputs */ + pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask); + +diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c +index b35b9604413f08..caeb3bdc78f8db 100644 +--- a/drivers/gpio/gpio-rockchip.c ++++ b/drivers/gpio/gpio-rockchip.c +@@ -713,6 +713,7 @@ static int rockchip_gpio_probe(struct platform_device *pdev) + return -ENODEV; + + pctldev = of_pinctrl_get(pctlnp); ++ of_node_put(pctlnp); + if (!pctldev) + return -EPROBE_DEFER; + +diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c +index 44bf1709a6488c..a8e5ac95cf1702 100644 +--- a/drivers/gpio/gpio-sim.c ++++ b/drivers/gpio/gpio-sim.c +@@ -1438,10 +1438,10 @@ static const struct config_item_type gpio_sim_device_config_group_type = { + static struct config_group * + gpio_sim_config_make_device_group(struct config_group *group, const char *name) + { +- struct gpio_sim_device *dev __free(kfree) = NULL; + int id; + +- dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ struct gpio_sim_device *dev __free(kfree) = kzalloc(sizeof(*dev), ++ GFP_KERNEL); + if (!dev) + return ERR_PTR(-ENOMEM); + +diff --git a/drivers/gpio/gpio-tangier.c b/drivers/gpio/gpio-tangier.c +index 7ce3eddaed2572..1ce40b7673b114 100644 +--- a/drivers/gpio/gpio-tangier.c ++++ b/drivers/gpio/gpio-tangier.c +@@ -205,7 +205,8 @@ static int tng_gpio_set_config(struct gpio_chip *chip, unsigned int offset, + + static void tng_irq_ack(struct irq_data *d) + { +- struct tng_gpio *priv = irq_data_get_irq_chip_data(d); ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); ++ struct tng_gpio *priv = gpiochip_get_data(gc); + irq_hw_number_t gpio = irqd_to_hwirq(d); + unsigned long flags; + void __iomem *gisr; +@@ -241,7 +242,8 @@ static void tng_irq_unmask_mask(struct tng_gpio *priv, u32 gpio, bool unmask) + + static void tng_irq_mask(struct irq_data *d) + { +- struct tng_gpio *priv = irq_data_get_irq_chip_data(d); ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); ++ struct tng_gpio *priv = gpiochip_get_data(gc); + irq_hw_number_t gpio = irqd_to_hwirq(d); + + tng_irq_unmask_mask(priv, gpio, false); +@@ -250,7 +252,8 @@ static void tng_irq_mask(struct irq_data *d) + + static void tng_irq_unmask(struct irq_data *d) + { +- struct tng_gpio *priv = irq_data_get_irq_chip_data(d); ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(d); ++ struct tng_gpio *priv = gpiochip_get_data(gc); + irq_hw_number_t gpio = irqd_to_hwirq(d); + + gpiochip_enable_irq(&priv->chip, gpio); +diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c +index d87dd06db40d07..9130c691a2dd32 100644 +--- a/drivers/gpio/gpio-tegra186.c ++++ b/drivers/gpio/gpio-tegra186.c +@@ -36,12 +36,6 @@ + #define TEGRA186_GPIO_SCR_SEC_REN BIT(27) + #define TEGRA186_GPIO_SCR_SEC_G1W BIT(9) + #define TEGRA186_GPIO_SCR_SEC_G1R BIT(1) +-#define TEGRA186_GPIO_FULL_ACCESS (TEGRA186_GPIO_SCR_SEC_WEN | \ +- TEGRA186_GPIO_SCR_SEC_REN | \ +- TEGRA186_GPIO_SCR_SEC_G1R | \ +- TEGRA186_GPIO_SCR_SEC_G1W) +-#define TEGRA186_GPIO_SCR_SEC_ENABLE (TEGRA186_GPIO_SCR_SEC_WEN | \ +- TEGRA186_GPIO_SCR_SEC_REN) + + /* control registers */ + #define TEGRA186_GPIO_ENABLE_CONFIG 0x00 +@@ -177,10 +171,18 @@ static inline bool tegra186_gpio_is_accessible(struct tegra_gpio *gpio, unsigned + + value = __raw_readl(secure + TEGRA186_GPIO_SCR); + +- if ((value & TEGRA186_GPIO_SCR_SEC_ENABLE) == 0) +- return true; ++ /* ++ * When SCR_SEC_[R|W]EN is unset, then we have full read/write access to all the ++ * registers for given GPIO pin. ++ * When SCR_SEC[R|W]EN is set, then there is need to further check the accompanying ++ * SCR_SEC_G1[R|W] bit to determine read/write access to all the registers for given ++ * GPIO pin. ++ */ + +- if ((value & TEGRA186_GPIO_FULL_ACCESS) == TEGRA186_GPIO_FULL_ACCESS) ++ if (((value & TEGRA186_GPIO_SCR_SEC_REN) == 0 || ++ ((value & TEGRA186_GPIO_SCR_SEC_REN) && (value & TEGRA186_GPIO_SCR_SEC_G1R))) && ++ ((value & TEGRA186_GPIO_SCR_SEC_WEN) == 0 || ++ ((value & TEGRA186_GPIO_SCR_SEC_WEN) && (value & TEGRA186_GPIO_SCR_SEC_G1W)))) + return true; + + return false; +diff --git a/drivers/gpio/gpio-tqmx86.c b/drivers/gpio/gpio-tqmx86.c +index 3a28c1f273c396..f2e7e8754d95d6 100644 +--- a/drivers/gpio/gpio-tqmx86.c ++++ b/drivers/gpio/gpio-tqmx86.c +@@ -6,6 +6,7 @@ + * Vadim V.Vlasov + */ + ++#include + #include + #include + #include +@@ -28,16 +29,25 @@ + #define TQMX86_GPIIC 3 /* GPI Interrupt Configuration Register */ + #define TQMX86_GPIIS 4 /* GPI Interrupt Status Register */ + ++#define TQMX86_GPII_NONE 0 + #define TQMX86_GPII_FALLING BIT(0) + #define TQMX86_GPII_RISING BIT(1) ++/* Stored in irq_type as a trigger type, but not actually valid as a register ++ * value, so the name doesn't use "GPII" ++ */ ++#define TQMX86_INT_BOTH (BIT(0) | BIT(1)) + #define TQMX86_GPII_MASK (BIT(0) | BIT(1)) + #define TQMX86_GPII_BITS 2 ++/* Stored in irq_type with GPII bits */ ++#define TQMX86_INT_UNMASKED BIT(2) + + struct tqmx86_gpio_data { + struct gpio_chip chip; + void __iomem *io_base; + int irq; ++ /* Lock must be held for accessing output and irq_type fields */ + raw_spinlock_t spinlock; ++ DECLARE_BITMAP(output, TQMX86_NGPIO); + u8 irq_type[TQMX86_NGPI]; + }; + +@@ -64,15 +74,10 @@ static void tqmx86_gpio_set(struct gpio_chip *chip, unsigned int offset, + { + struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip); + unsigned long flags; +- u8 val; + + raw_spin_lock_irqsave(&gpio->spinlock, flags); +- val = tqmx86_gpio_read(gpio, TQMX86_GPIOD); +- if (value) +- val |= BIT(offset); +- else +- val &= ~BIT(offset); +- tqmx86_gpio_write(gpio, val, TQMX86_GPIOD); ++ __assign_bit(offset, gpio->output, value); ++ tqmx86_gpio_write(gpio, bitmap_get_value8(gpio->output, 0), TQMX86_GPIOD); + raw_spin_unlock_irqrestore(&gpio->spinlock, flags); + } + +@@ -107,21 +112,38 @@ static int tqmx86_gpio_get_direction(struct gpio_chip *chip, + return GPIO_LINE_DIRECTION_OUT; + } + ++static void tqmx86_gpio_irq_config(struct tqmx86_gpio_data *gpio, int offset) ++ __must_hold(&gpio->spinlock) ++{ ++ u8 type = TQMX86_GPII_NONE, gpiic; ++ ++ if (gpio->irq_type[offset] & TQMX86_INT_UNMASKED) { ++ type = gpio->irq_type[offset] & TQMX86_GPII_MASK; ++ ++ if (type == TQMX86_INT_BOTH) ++ type = tqmx86_gpio_get(&gpio->chip, offset + TQMX86_NGPO) ++ ? TQMX86_GPII_FALLING ++ : TQMX86_GPII_RISING; ++ } ++ ++ gpiic = tqmx86_gpio_read(gpio, TQMX86_GPIIC); ++ gpiic &= ~(TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS)); ++ gpiic |= type << (offset * TQMX86_GPII_BITS); ++ tqmx86_gpio_write(gpio, gpiic, TQMX86_GPIIC); ++} ++ + static void tqmx86_gpio_irq_mask(struct irq_data *data) + { + unsigned int offset = (data->hwirq - TQMX86_NGPO); + struct tqmx86_gpio_data *gpio = gpiochip_get_data( + irq_data_get_irq_chip_data(data)); + unsigned long flags; +- u8 gpiic, mask; +- +- mask = TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS); + + raw_spin_lock_irqsave(&gpio->spinlock, flags); +- gpiic = tqmx86_gpio_read(gpio, TQMX86_GPIIC); +- gpiic &= ~mask; +- tqmx86_gpio_write(gpio, gpiic, TQMX86_GPIIC); ++ gpio->irq_type[offset] &= ~TQMX86_INT_UNMASKED; ++ tqmx86_gpio_irq_config(gpio, offset); + raw_spin_unlock_irqrestore(&gpio->spinlock, flags); ++ + gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(data)); + } + +@@ -131,16 +153,12 @@ static void tqmx86_gpio_irq_unmask(struct irq_data *data) + struct tqmx86_gpio_data *gpio = gpiochip_get_data( + irq_data_get_irq_chip_data(data)); + unsigned long flags; +- u8 gpiic, mask; +- +- mask = TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS); + + gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(data)); ++ + raw_spin_lock_irqsave(&gpio->spinlock, flags); +- gpiic = tqmx86_gpio_read(gpio, TQMX86_GPIIC); +- gpiic &= ~mask; +- gpiic |= gpio->irq_type[offset] << (offset * TQMX86_GPII_BITS); +- tqmx86_gpio_write(gpio, gpiic, TQMX86_GPIIC); ++ gpio->irq_type[offset] |= TQMX86_INT_UNMASKED; ++ tqmx86_gpio_irq_config(gpio, offset); + raw_spin_unlock_irqrestore(&gpio->spinlock, flags); + } + +@@ -151,7 +169,7 @@ static int tqmx86_gpio_irq_set_type(struct irq_data *data, unsigned int type) + unsigned int offset = (data->hwirq - TQMX86_NGPO); + unsigned int edge_type = type & IRQF_TRIGGER_MASK; + unsigned long flags; +- u8 new_type, gpiic; ++ u8 new_type; + + switch (edge_type) { + case IRQ_TYPE_EDGE_RISING: +@@ -161,19 +179,16 @@ static int tqmx86_gpio_irq_set_type(struct irq_data *data, unsigned int type) + new_type = TQMX86_GPII_FALLING; + break; + case IRQ_TYPE_EDGE_BOTH: +- new_type = TQMX86_GPII_FALLING | TQMX86_GPII_RISING; ++ new_type = TQMX86_INT_BOTH; + break; + default: + return -EINVAL; /* not supported */ + } + +- gpio->irq_type[offset] = new_type; +- + raw_spin_lock_irqsave(&gpio->spinlock, flags); +- gpiic = tqmx86_gpio_read(gpio, TQMX86_GPIIC); +- gpiic &= ~((TQMX86_GPII_MASK) << (offset * TQMX86_GPII_BITS)); +- gpiic |= new_type << (offset * TQMX86_GPII_BITS); +- tqmx86_gpio_write(gpio, gpiic, TQMX86_GPIIC); ++ gpio->irq_type[offset] &= ~TQMX86_GPII_MASK; ++ gpio->irq_type[offset] |= new_type; ++ tqmx86_gpio_irq_config(gpio, offset); + raw_spin_unlock_irqrestore(&gpio->spinlock, flags); + + return 0; +@@ -184,8 +199,8 @@ static void tqmx86_gpio_irq_handler(struct irq_desc *desc) + struct gpio_chip *chip = irq_desc_get_handler_data(desc); + struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip); + struct irq_chip *irq_chip = irq_desc_get_chip(desc); +- unsigned long irq_bits; +- int i = 0; ++ unsigned long irq_bits, flags; ++ int i; + u8 irq_status; + + chained_irq_enter(irq_chip, desc); +@@ -194,6 +209,34 @@ static void tqmx86_gpio_irq_handler(struct irq_desc *desc) + tqmx86_gpio_write(gpio, irq_status, TQMX86_GPIIS); + + irq_bits = irq_status; ++ ++ raw_spin_lock_irqsave(&gpio->spinlock, flags); ++ for_each_set_bit(i, &irq_bits, TQMX86_NGPI) { ++ /* ++ * Edge-both triggers are implemented by flipping the edge ++ * trigger after each interrupt, as the controller only supports ++ * either rising or falling edge triggers, but not both. ++ * ++ * Internally, the TQMx86 GPIO controller has separate status ++ * registers for rising and falling edge interrupts. GPIIC ++ * configures which bits from which register are visible in the ++ * interrupt status register GPIIS and defines what triggers the ++ * parent IRQ line. Writing to GPIIS always clears both rising ++ * and falling interrupt flags internally, regardless of the ++ * currently configured trigger. ++ * ++ * In consequence, we can cleanly implement the edge-both ++ * trigger in software by first clearing the interrupt and then ++ * setting the new trigger based on the current GPIO input in ++ * tqmx86_gpio_irq_config() - even if an edge arrives between ++ * reading the input and setting the trigger, we will have a new ++ * interrupt pending. ++ */ ++ if ((gpio->irq_type[i] & TQMX86_GPII_MASK) == TQMX86_INT_BOTH) ++ tqmx86_gpio_irq_config(gpio, i); ++ } ++ raw_spin_unlock_irqrestore(&gpio->spinlock, flags); ++ + for_each_set_bit(i, &irq_bits, TQMX86_NGPI) + generic_handle_domain_irq(gpio->chip.irq.domain, + i + TQMX86_NGPO); +@@ -277,6 +320,13 @@ static int tqmx86_gpio_probe(struct platform_device *pdev) + + tqmx86_gpio_write(gpio, (u8)~TQMX86_DIR_INPUT_MASK, TQMX86_GPIODD); + ++ /* ++ * Reading the previous output state is not possible with TQMx86 hardware. ++ * Initialize all outputs to 0 to have a defined state that matches the ++ * shadow register. ++ */ ++ tqmx86_gpio_write(gpio, 0, TQMX86_GPIOD); ++ + chip = &gpio->chip; + chip->label = "gpio-tqmx86"; + chip->owner = THIS_MODULE; +diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c +index c18b6b47384f1b..94ca9d03c09494 100644 +--- a/drivers/gpio/gpio-wcove.c ++++ b/drivers/gpio/gpio-wcove.c +@@ -104,7 +104,7 @@ static inline int to_reg(int gpio, enum ctrl_register type) + unsigned int reg = type == CTRL_IN ? GPIO_IN_CTRL_BASE : GPIO_OUT_CTRL_BASE; + + if (gpio >= WCOVE_GPIO_NUM) +- return -EOPNOTSUPP; ++ return -ENOTSUPP; + + return reg + gpio; + } +diff --git a/drivers/gpio/gpio-zynqmp-modepin.c b/drivers/gpio/gpio-zynqmp-modepin.c +index a0d69387c1532d..2f3c9ebfa78d1d 100644 +--- a/drivers/gpio/gpio-zynqmp-modepin.c ++++ b/drivers/gpio/gpio-zynqmp-modepin.c +@@ -146,6 +146,7 @@ static const struct of_device_id modepin_platform_id[] = { + { .compatible = "xlnx,zynqmp-gpio-modepin", }, + { } + }; ++MODULE_DEVICE_TABLE(of, modepin_platform_id); + + static struct platform_driver modepin_platform_driver = { + .driver = { +diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c +index 51e41676de0b8d..b366b4ca4c40e9 100644 +--- a/drivers/gpio/gpiolib-acpi.c ++++ b/drivers/gpio/gpiolib-acpi.c +@@ -128,7 +128,24 @@ static bool acpi_gpio_deferred_req_irqs_done; + + static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) + { +- return device_match_acpi_handle(&gc->gpiodev->dev, data); ++ /* First check the actual GPIO device */ ++ if (device_match_acpi_handle(&gc->gpiodev->dev, data)) ++ return true; ++ ++ /* ++ * When the ACPI device is artificially split to the banks of GPIOs, ++ * where each of them is represented by a separate GPIO device, ++ * the firmware node of the physical device may not be shared among ++ * the banks as they may require different values for the same property, ++ * e.g., number of GPIOs in a certain bank. In such case the ACPI handle ++ * of a GPIO device is NULL and can not be used. Hence we have to check ++ * the parent device to be sure that there is no match before bailing ++ * out. ++ */ ++ if (gc->parent) ++ return device_match_acpi_handle(gc->parent, data); ++ ++ return false; + } + + /** +@@ -1655,6 +1672,40 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = { + .ignore_wake = "SYNA1202:00@16", + }, + }, ++ { ++ /* ++ * On the Peaq C1010 2-in-1 INT33FC:00 pin 3 is connected to ++ * a "dolby" button. At the ACPI level an _AEI event-handler ++ * is connected which sets an ACPI variable to 1 on both ++ * edges. This variable can be polled + cleared to 0 using ++ * WMI. But since the variable is set on both edges the WMI ++ * interface is pretty useless even when polling. ++ * So instead the x86-android-tablets code instantiates ++ * a gpio-keys platform device for it. ++ * Ignore the _AEI handler for the pin, so that it is not busy. ++ */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "PEAQ"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "PEAQ PMM C1010 MD99187"), ++ }, ++ .driver_data = &(struct acpi_gpiolib_dmi_quirk) { ++ .ignore_interrupt = "INT33FC:00@3", ++ }, ++ }, ++ { ++ /* ++ * Spurious wakeups from TP_ATTN# pin ++ * Found in BIOS 0.35 ++ * https://gitlab.freedesktop.org/drm/amd/-/issues/3073 ++ */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "GPD"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "G1619-04"), ++ }, ++ .driver_data = &(struct acpi_gpiolib_dmi_quirk) { ++ .ignore_wake = "PNP0C50:00@8", ++ }, ++ }, + {} /* Terminating entry */ + }; + +diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c +index e39d344feb2899..545998e9f6ad21 100644 +--- a/drivers/gpio/gpiolib-cdev.c ++++ b/drivers/gpio/gpiolib-cdev.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -21,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -130,6 +132,10 @@ struct linehandle_state { + GPIOHANDLE_REQUEST_OPEN_DRAIN | \ + GPIOHANDLE_REQUEST_OPEN_SOURCE) + ++#define GPIOHANDLE_REQUEST_DIRECTION_FLAGS \ ++ (GPIOHANDLE_REQUEST_INPUT | \ ++ GPIOHANDLE_REQUEST_OUTPUT) ++ + static int linehandle_validate_flags(u32 flags) + { + /* Return an error if an unknown flag is set */ +@@ -210,21 +216,21 @@ static long linehandle_set_config(struct linehandle_state *lh, + if (ret) + return ret; + ++ /* Lines must be reconfigured explicitly as input or output. */ ++ if (!(lflags & GPIOHANDLE_REQUEST_DIRECTION_FLAGS)) ++ return -EINVAL; ++ + for (i = 0; i < lh->num_descs; i++) { + desc = lh->descs[i]; +- linehandle_flags_to_desc_flags(gcnf.flags, &desc->flags); ++ linehandle_flags_to_desc_flags(lflags, &desc->flags); + +- /* +- * Lines have to be requested explicitly for input +- * or output, else the line will be treated "as is". +- */ + if (lflags & GPIOHANDLE_REQUEST_OUTPUT) { + int val = !!gcnf.default_values[i]; + + ret = gpiod_direction_output(desc, val); + if (ret) + return ret; +- } else if (lflags & GPIOHANDLE_REQUEST_INPUT) { ++ } else { + ret = gpiod_direction_input(desc); + if (ret) + return ret; +@@ -461,6 +467,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) + + /** + * struct line - contains the state of a requested line ++ * @node: to store the object in supinfo_tree if supplemental + * @desc: the GPIO descriptor for this line. + * @req: the corresponding line request + * @irq: the interrupt triggered in response to events on this GPIO +@@ -473,6 +480,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) + * @line_seqno: the seqno for the current edge event in the sequence of + * events for this line. + * @work: the worker that implements software debouncing ++ * @debounce_period_us: the debounce period in microseconds + * @sw_debounced: flag indicating if the software debouncer is active + * @level: the current debounced physical level of the line + * @hdesc: the Hardware Timestamp Engine (HTE) descriptor +@@ -481,6 +489,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) + * @last_seqno: the last sequence number before debounce period expires + */ + struct line { ++ struct rb_node node; + struct gpio_desc *desc; + /* + * -- edge detector specific fields -- +@@ -514,6 +523,15 @@ struct line { + * -- debouncer specific fields -- + */ + struct delayed_work work; ++ /* ++ * debounce_period_us is accessed by debounce_irq_handler() and ++ * process_hw_ts() which are disabled when modified by ++ * debounce_setup(), edge_detector_setup() or edge_detector_stop() ++ * or can live with a stale version when updated by ++ * edge_detector_update(). ++ * The modifying functions are themselves mutually exclusive. ++ */ ++ unsigned int debounce_period_us; + /* + * sw_debounce is accessed by linereq_set_config(), which is the + * only setter, and linereq_get_values(), which can live with a +@@ -546,6 +564,17 @@ struct line { + #endif /* CONFIG_HTE */ + }; + ++/* ++ * a rbtree of the struct lines containing supplemental info. ++ * Used to populate gpio_v2_line_info with cdev specific fields not contained ++ * in the struct gpio_desc. ++ * A line is determined to contain supplemental information by ++ * line_has_supinfo(). ++ */ ++static struct rb_root supinfo_tree = RB_ROOT; ++/* covers supinfo_tree */ ++static DEFINE_SPINLOCK(supinfo_lock); ++ + /** + * struct linereq - contains the state of a userspace line request + * @gdev: the GPIO device the line request pertains to +@@ -559,7 +588,8 @@ struct line { + * this line request. Note that this is not used when @num_lines is 1, as + * the line_seqno is then the same and is cheaper to calculate. + * @config_mutex: mutex for serializing ioctl() calls to ensure consistency +- * of configuration, particularly multi-step accesses to desc flags. ++ * of configuration, particularly multi-step accesses to desc flags and ++ * changes to supinfo status. + * @lines: the lines held by this line request, with @num_lines elements. + */ + struct linereq { +@@ -575,6 +605,103 @@ struct linereq { + struct line lines[]; + }; + ++static void supinfo_insert(struct line *line) ++{ ++ struct rb_node **new = &(supinfo_tree.rb_node), *parent = NULL; ++ struct line *entry; ++ ++ guard(spinlock)(&supinfo_lock); ++ ++ while (*new) { ++ entry = container_of(*new, struct line, node); ++ ++ parent = *new; ++ if (line->desc < entry->desc) { ++ new = &((*new)->rb_left); ++ } else if (line->desc > entry->desc) { ++ new = &((*new)->rb_right); ++ } else { ++ /* this should never happen */ ++ WARN(1, "duplicate line inserted"); ++ return; ++ } ++ } ++ ++ rb_link_node(&line->node, parent, new); ++ rb_insert_color(&line->node, &supinfo_tree); ++} ++ ++static void supinfo_erase(struct line *line) ++{ ++ guard(spinlock)(&supinfo_lock); ++ ++ rb_erase(&line->node, &supinfo_tree); ++} ++ ++static struct line *supinfo_find(struct gpio_desc *desc) ++{ ++ struct rb_node *node = supinfo_tree.rb_node; ++ struct line *line; ++ ++ while (node) { ++ line = container_of(node, struct line, node); ++ if (desc < line->desc) ++ node = node->rb_left; ++ else if (desc > line->desc) ++ node = node->rb_right; ++ else ++ return line; ++ } ++ return NULL; ++} ++ ++static void supinfo_to_lineinfo(struct gpio_desc *desc, ++ struct gpio_v2_line_info *info) ++{ ++ struct gpio_v2_line_attribute *attr; ++ struct line *line; ++ ++ guard(spinlock)(&supinfo_lock); ++ ++ line = supinfo_find(desc); ++ if (!line) ++ return; ++ ++ attr = &info->attrs[info->num_attrs]; ++ attr->id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE; ++ attr->debounce_period_us = READ_ONCE(line->debounce_period_us); ++ info->num_attrs++; ++} ++ ++static inline bool line_has_supinfo(struct line *line) ++{ ++ return READ_ONCE(line->debounce_period_us); ++} ++ ++/* ++ * Checks line_has_supinfo() before and after the change to avoid unnecessary ++ * supinfo_tree access. ++ * Called indirectly by linereq_create() or linereq_set_config() so line ++ * is already protected from concurrent changes. ++ */ ++static void line_set_debounce_period(struct line *line, ++ unsigned int debounce_period_us) ++{ ++ bool was_suppl = line_has_supinfo(line); ++ ++ WRITE_ONCE(line->debounce_period_us, debounce_period_us); ++ ++ /* if supinfo status is unchanged then we're done */ ++ if (line_has_supinfo(line) == was_suppl) ++ return; ++ ++ /* supinfo status has changed, so update the tree */ ++ if (was_suppl) ++ supinfo_erase(line); ++ else ++ supinfo_insert(line); ++} ++ + #define GPIO_V2_LINE_BIAS_FLAGS \ + (GPIO_V2_LINE_FLAG_BIAS_PULL_UP | \ + GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN | \ +@@ -655,6 +782,25 @@ static u32 line_event_id(int level) + GPIO_V2_LINE_EVENT_FALLING_EDGE; + } + ++static inline char *make_irq_label(const char *orig) ++{ ++ char *new; ++ ++ if (!orig) ++ return NULL; ++ ++ new = kstrdup_and_replace(orig, '/', ':', GFP_KERNEL); ++ if (!new) ++ return ERR_PTR(-ENOMEM); ++ ++ return new; ++} ++ ++static inline void free_irq_label(const char *label) ++{ ++ kfree(label); ++} ++ + #ifdef CONFIG_HTE + + static enum hte_return process_hw_ts_thread(void *p) +@@ -723,7 +869,7 @@ static enum hte_return process_hw_ts(struct hte_ts_data *ts, void *p) + line->total_discard_seq++; + line->last_seqno = ts->seq; + mod_delayed_work(system_wq, &line->work, +- usecs_to_jiffies(READ_ONCE(line->desc->debounce_period_us))); ++ usecs_to_jiffies(READ_ONCE(line->debounce_period_us))); + } else { + if (unlikely(ts->seq < line->line_seqno)) + return HTE_CB_HANDLED; +@@ -864,7 +1010,7 @@ static irqreturn_t debounce_irq_handler(int irq, void *p) + struct line *line = p; + + mod_delayed_work(system_wq, &line->work, +- usecs_to_jiffies(READ_ONCE(line->desc->debounce_period_us))); ++ usecs_to_jiffies(READ_ONCE(line->debounce_period_us))); + + return IRQ_HANDLED; + } +@@ -942,11 +1088,12 @@ static int debounce_setup(struct line *line, unsigned int debounce_period_us) + { + unsigned long irqflags; + int ret, level, irq; ++ char *label; + + /* try hardware */ + ret = gpiod_set_debounce(line->desc, debounce_period_us); + if (!ret) { +- WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); ++ line_set_debounce_period(line, debounce_period_us); + return ret; + } + if (ret != -ENOTSUPP) +@@ -964,11 +1111,17 @@ static int debounce_setup(struct line *line, unsigned int debounce_period_us) + if (irq < 0) + return -ENXIO; + ++ label = make_irq_label(line->req->label); ++ if (IS_ERR(label)) ++ return -ENOMEM; ++ + irqflags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING; + ret = request_irq(irq, debounce_irq_handler, irqflags, +- line->req->label, line); +- if (ret) ++ label, line); ++ if (ret) { ++ free_irq_label(label); + return ret; ++ } + line->irq = irq; + } else { + ret = hte_edge_setup(line, GPIO_V2_LINE_FLAG_EDGE_BOTH); +@@ -1013,7 +1166,7 @@ static u32 gpio_v2_line_config_debounce_period(struct gpio_v2_line_config *lc, + static void edge_detector_stop(struct line *line) + { + if (line->irq) { +- free_irq(line->irq, line); ++ free_irq_label(free_irq(line->irq, line)); + line->irq = 0; + } + +@@ -1025,8 +1178,7 @@ static void edge_detector_stop(struct line *line) + cancel_delayed_work_sync(&line->work); + WRITE_ONCE(line->sw_debounced, 0); + WRITE_ONCE(line->edflags, 0); +- if (line->desc) +- WRITE_ONCE(line->desc->debounce_period_us, 0); ++ line_set_debounce_period(line, 0); + /* do not change line->level - see comment in debounced_value() */ + } + +@@ -1038,6 +1190,7 @@ static int edge_detector_setup(struct line *line, + unsigned long irqflags = 0; + u64 eflags; + int irq, ret; ++ char *label; + + eflags = edflags & GPIO_V2_LINE_EDGE_FLAGS; + if (eflags && !kfifo_initialized(&line->req->events)) { +@@ -1051,7 +1204,7 @@ static int edge_detector_setup(struct line *line, + ret = debounce_setup(line, debounce_period_us); + if (ret) + return ret; +- WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); ++ line_set_debounce_period(line, debounce_period_us); + } + + /* detection disabled or sw debouncer will provide edge detection */ +@@ -1074,11 +1227,17 @@ static int edge_detector_setup(struct line *line, + IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; + irqflags |= IRQF_ONESHOT; + ++ label = make_irq_label(line->req->label); ++ if (IS_ERR(label)) ++ return PTR_ERR(label); ++ + /* Request a thread to read the events */ + ret = request_threaded_irq(irq, edge_irq_handler, edge_irq_thread, +- irqflags, line->req->label, line); +- if (ret) ++ irqflags, label, line); ++ if (ret) { ++ free_irq_label(label); + return ret; ++ } + + line->irq = irq; + return 0; +@@ -1088,17 +1247,31 @@ static int edge_detector_update(struct line *line, + struct gpio_v2_line_config *lc, + unsigned int line_idx, u64 edflags) + { ++ u64 eflags; ++ int ret; + u64 active_edflags = READ_ONCE(line->edflags); + unsigned int debounce_period_us = + gpio_v2_line_config_debounce_period(lc, line_idx); + + if ((active_edflags == edflags) && +- (READ_ONCE(line->desc->debounce_period_us) == debounce_period_us)) ++ (READ_ONCE(line->debounce_period_us) == debounce_period_us)) + return 0; + + /* sw debounced and still will be...*/ + if (debounce_period_us && READ_ONCE(line->sw_debounced)) { +- WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); ++ line_set_debounce_period(line, debounce_period_us); ++ /* ++ * ensure event fifo is initialised if edge detection ++ * is now enabled. ++ */ ++ eflags = edflags & GPIO_V2_LINE_EDGE_FLAGS; ++ if (eflags && !kfifo_initialized(&line->req->events)) { ++ ret = kfifo_alloc(&line->req->events, ++ line->req->event_buffer_size, ++ GFP_KERNEL); ++ if (ret) ++ return ret; ++ } + return 0; + } + +@@ -1392,12 +1565,14 @@ static long linereq_set_config_unlocked(struct linereq *lr, + line = &lr->lines[i]; + desc = lr->lines[i].desc; + flags = gpio_v2_line_config_flags(lc, i); +- gpio_v2_line_config_flags_to_desc_flags(flags, &desc->flags); +- edflags = flags & GPIO_V2_LINE_EDGE_DETECTOR_FLAGS; + /* +- * Lines have to be requested explicitly for input +- * or output, else the line will be treated "as is". ++ * Lines not explicitly reconfigured as input or output ++ * are left unchanged. + */ ++ if (!(flags & GPIO_V2_LINE_DIRECTION_FLAGS)) ++ continue; ++ gpio_v2_line_config_flags_to_desc_flags(flags, &desc->flags); ++ edflags = flags & GPIO_V2_LINE_EDGE_DETECTOR_FLAGS; + if (flags & GPIO_V2_LINE_FLAG_OUTPUT) { + int val = gpio_v2_line_config_output_value(lc, i); + +@@ -1405,7 +1580,7 @@ static long linereq_set_config_unlocked(struct linereq *lr, + ret = gpiod_direction_output(desc, val); + if (ret) + return ret; +- } else if (flags & GPIO_V2_LINE_FLAG_INPUT) { ++ } else { + ret = gpiod_direction_input(desc); + if (ret) + return ret; +@@ -1573,6 +1748,7 @@ static ssize_t linereq_read(struct file *file, char __user *buf, + + static void linereq_free(struct linereq *lr) + { ++ struct line *line; + unsigned int i; + + if (lr->device_unregistered_nb.notifier_call) +@@ -1580,10 +1756,14 @@ static void linereq_free(struct linereq *lr) + &lr->device_unregistered_nb); + + for (i = 0; i < lr->num_lines; i++) { +- if (lr->lines[i].desc) { +- edge_detector_stop(&lr->lines[i]); +- gpiod_free(lr->lines[i].desc); +- } ++ line = &lr->lines[i]; ++ if (!line->desc) ++ continue; ++ ++ edge_detector_stop(line); ++ if (line_has_supinfo(line)) ++ supinfo_erase(line); ++ gpiod_free(line->desc); + } + kfifo_free(&lr->events); + kfree(lr->label); +@@ -1943,7 +2123,7 @@ static void lineevent_free(struct lineevent_state *le) + blocking_notifier_chain_unregister(&le->gdev->device_notifier, + &le->device_unregistered_nb); + if (le->irq) +- free_irq(le->irq, le); ++ free_irq_label(free_irq(le->irq, le)); + if (le->desc) + gpiod_free(le->desc); + kfree(le->label); +@@ -2091,6 +2271,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) + int fd; + int ret; + int irq, irqflags = 0; ++ char *label; + + if (copy_from_user(&eventreq, ip, sizeof(eventreq))) + return -EFAULT; +@@ -2175,15 +2356,23 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) + if (ret) + goto out_free_le; + ++ label = make_irq_label(le->label); ++ if (IS_ERR(label)) { ++ ret = PTR_ERR(label); ++ goto out_free_le; ++ } ++ + /* Request a thread to read the events */ + ret = request_threaded_irq(irq, + lineevent_irq_handler, + lineevent_irq_thread, + irqflags, +- le->label, ++ label, + le); +- if (ret) ++ if (ret) { ++ free_irq_label(label); + goto out_free_le; ++ } + + le->irq = irq; + +@@ -2274,8 +2463,6 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, + struct gpio_chip *gc = desc->gdev->chip; + bool ok_for_pinctrl; + unsigned long flags; +- u32 debounce_period_us; +- unsigned int num_attrs = 0; + + memset(info, 0, sizeof(*info)); + info->offset = gpio_chip_hwgpio(desc); +@@ -2342,14 +2529,6 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, + else if (test_bit(FLAG_EVENT_CLOCK_HTE, &desc->flags)) + info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE; + +- debounce_period_us = READ_ONCE(desc->debounce_period_us); +- if (debounce_period_us) { +- info->attrs[num_attrs].id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE; +- info->attrs[num_attrs].debounce_period_us = debounce_period_us; +- num_attrs++; +- } +- info->num_attrs = num_attrs; +- + spin_unlock_irqrestore(&gpio_lock, flags); + } + +@@ -2456,6 +2635,7 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip, + return -EBUSY; + } + gpio_desc_to_lineinfo(desc, &lineinfo); ++ supinfo_to_lineinfo(desc, &lineinfo); + + if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) { + if (watch) +@@ -2482,10 +2662,7 @@ static int lineinfo_unwatch(struct gpio_chardev_data *cdev, void __user *ip) + return 0; + } + +-/* +- * gpio_ioctl() - ioctl handler for the GPIO chardev +- */ +-static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++static long gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) + { + struct gpio_chardev_data *cdev = file->private_data; + struct gpio_device *gdev = cdev->gdev; +@@ -2522,6 +2699,17 @@ static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + } + } + ++/* ++ * gpio_ioctl() - ioctl handler for the GPIO chardev ++ */ ++static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct gpio_chardev_data *cdev = file->private_data; ++ ++ return call_ioctl_locked(file, cmd, arg, cdev->gdev, ++ gpio_ioctl_unlocked); ++} ++ + #ifdef CONFIG_COMPAT + static long gpio_ioctl_compat(struct file *file, unsigned int cmd, + unsigned long arg) +@@ -2546,6 +2734,7 @@ static int lineinfo_changed_notify(struct notifier_block *nb, + chg.event_type = action; + chg.timestamp_ns = ktime_get_ns(); + gpio_desc_to_lineinfo(desc, &chg.info); ++ supinfo_to_lineinfo(desc, &chg.info); + + ret = kfifo_in_spinlocked(&cdev->events, &chg, 1, &cdev->wait.lock); + if (ret) +@@ -2766,11 +2955,11 @@ static int gpio_chrdev_release(struct inode *inode, struct file *file) + struct gpio_chardev_data *cdev = file->private_data; + struct gpio_device *gdev = cdev->gdev; + +- bitmap_free(cdev->watched_lines); + blocking_notifier_chain_unregister(&gdev->device_notifier, + &cdev->device_unregistered_nb); + blocking_notifier_chain_unregister(&gdev->line_state_notifier, + &cdev->lineinfo_changed_nb); ++ bitmap_free(cdev->watched_lines); + gpio_device_put(gdev); + kfree(cdev); + +diff --git a/drivers/gpio/gpiolib-devres.c b/drivers/gpio/gpiolib-devres.c +index fe9ce6b19f15c5..4987e62dcb3d15 100644 +--- a/drivers/gpio/gpiolib-devres.c ++++ b/drivers/gpio/gpiolib-devres.c +@@ -158,7 +158,7 @@ struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, + if (!dr) + return ERR_PTR(-ENOMEM); + +- desc = fwnode_gpiod_get_index(fwnode, con_id, index, flags, label); ++ desc = gpiod_find_and_request(dev, fwnode, con_id, index, flags, label, false); + if (IS_ERR(desc)) { + devres_free(dr); + return desc; +diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c +index 531faabead0f40..cec9e8f29bbdfe 100644 +--- a/drivers/gpio/gpiolib-of.c ++++ b/drivers/gpio/gpiolib-of.c +@@ -192,6 +192,24 @@ static void of_gpio_try_fixup_polarity(const struct device_node *np, + */ + { "himax,hx8357", "gpios-reset", false }, + { "himax,hx8369", "gpios-reset", false }, ++#endif ++#if IS_ENABLED(CONFIG_PCI_LANTIQ) ++ /* ++ * According to the PCI specification, the RST# pin is an ++ * active-low signal. However, most of the device trees that ++ * have been widely used for a long time incorrectly describe ++ * reset GPIO as active-high, and were also using wrong name ++ * for the property. ++ */ ++ { "lantiq,pci-xway", "gpio-reset", false }, ++#endif ++#if IS_ENABLED(CONFIG_TOUCHSCREEN_TSC2005) ++ /* ++ * DTS for Nokia N900 incorrectly specified "active high" ++ * polarity for the reset line, while the chip actually ++ * treats it as "active low". ++ */ ++ { "ti,tsc2005", "reset-gpios", false }, + #endif + }; + unsigned int i; +@@ -491,9 +509,9 @@ static struct gpio_desc *of_find_gpio_rename(struct device_node *np, + { "reset", "reset-n-io", "marvell,nfc-uart" }, + { "reset", "reset-n-io", "mrvl,nfc-uart" }, + #endif +-#if !IS_ENABLED(CONFIG_PCI_LANTIQ) ++#if IS_ENABLED(CONFIG_PCI_LANTIQ) + /* MIPS Lantiq PCI */ +- { "reset", "gpios-reset", "lantiq,pci-xway" }, ++ { "reset", "gpio-reset", "lantiq,pci-xway" }, + #endif + + /* +@@ -512,6 +530,10 @@ static struct gpio_desc *of_find_gpio_rename(struct device_node *np, + #if IS_ENABLED(CONFIG_SND_SOC_CS42L56) + { "reset", "cirrus,gpio-nreset", "cirrus,cs42l56" }, + #endif ++#if IS_ENABLED(CONFIG_SND_SOC_MT2701_CS42448) ++ { "i2s1-in-sel-gpio1", NULL, "mediatek,mt2701-cs42448-machine" }, ++ { "i2s1-in-sel-gpio2", NULL, "mediatek,mt2701-cs42448-machine" }, ++#endif + #if IS_ENABLED(CONFIG_SND_SOC_TLV320AIC3X) + { "reset", "gpio-reset", "ti,tlv320aic3x" }, + { "reset", "gpio-reset", "ti,tlv320aic33" }, +diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c +index 50503a4525eb03..6c27312c627883 100644 +--- a/drivers/gpio/gpiolib-sysfs.c ++++ b/drivers/gpio/gpiolib-sysfs.c +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + + #include ++#include + #include + #include + #include +@@ -474,14 +475,17 @@ static ssize_t export_store(const struct class *class, + goto done; + + status = gpiod_set_transitory(desc, false); +- if (!status) { +- status = gpiod_export(desc, true); +- if (status < 0) +- gpiod_free(desc); +- else +- set_bit(FLAG_SYSFS, &desc->flags); ++ if (status) { ++ gpiod_free(desc); ++ goto done; + } + ++ status = gpiod_export(desc, true); ++ if (status < 0) ++ gpiod_free(desc); ++ else ++ set_bit(FLAG_SYSFS, &desc->flags); ++ + done: + if (status) + pr_debug("%s: status %d\n", __func__, status); +@@ -771,15 +775,15 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev) + struct gpio_desc *desc; + struct gpio_chip *chip = gdev->chip; + +- if (!gdev->mockdev) +- return; ++ scoped_guard(mutex, &sysfs_lock) { ++ if (!gdev->mockdev) ++ return; + +- device_unregister(gdev->mockdev); ++ device_unregister(gdev->mockdev); + +- /* prevent further gpiod exports */ +- mutex_lock(&sysfs_lock); +- gdev->mockdev = NULL; +- mutex_unlock(&sysfs_lock); ++ /* prevent further gpiod exports */ ++ gdev->mockdev = NULL; ++ } + + /* unregister gpiod class devices owned by sysfs */ + for_each_gpio_desc_with_flag(chip, desc, FLAG_SYSFS) { +@@ -814,7 +818,7 @@ static int __init gpiolib_sysfs_init(void) + * gpiochip_sysfs_register() acquires a mutex. This is unsafe + * and needs to be fixed. + * +- * Also it would be nice to use gpiochip_find() here so we ++ * Also it would be nice to use gpio_device_find() here so we + * can keep gpio_chips local to gpiolib.c, but the yield of + * gpio_lock prevents us from doing this. + */ +diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c +index 40a0022ea71909..5c0016c77d2abe 100644 +--- a/drivers/gpio/gpiolib.c ++++ b/drivers/gpio/gpiolib.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -164,7 +165,7 @@ struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc, + if (hwnum >= gdev->ngpio) + return ERR_PTR(-EINVAL); + +- return &gdev->descs[hwnum]; ++ return &gdev->descs[array_index_nospec(hwnum, gdev->ngpio)]; + } + EXPORT_SYMBOL_GPL(gpiochip_get_desc); + +@@ -894,11 +895,11 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, + + ret = gpiochip_irqchip_init_valid_mask(gc); + if (ret) +- goto err_remove_acpi_chip; ++ goto err_free_hogs; + + ret = gpiochip_irqchip_init_hw(gc); + if (ret) +- goto err_remove_acpi_chip; ++ goto err_remove_irqchip_mask; + + ret = gpiochip_add_irqchip(gc, lock_key, request_key); + if (ret) +@@ -923,13 +924,13 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, + gpiochip_irqchip_remove(gc); + err_remove_irqchip_mask: + gpiochip_irqchip_free_valid_mask(gc); +-err_remove_acpi_chip: ++err_free_hogs: ++ gpiochip_free_hogs(gc); + acpi_gpiochip_remove(gc); ++ gpiochip_remove_pin_ranges(gc); + err_remove_of_chip: +- gpiochip_free_hogs(gc); + of_gpiochip_remove(gc); + err_free_gpiochip_mask: +- gpiochip_remove_pin_ranges(gc); + gpiochip_free_valid_mask(gc); + if (gdev->dev.release) { + /* release() has been registered by gpiochip_setup_dev() */ +@@ -1014,16 +1015,10 @@ void gpiochip_remove(struct gpio_chip *gc) + } + EXPORT_SYMBOL_GPL(gpiochip_remove); + +-/** +- * gpiochip_find() - iterator for locating a specific gpio_chip +- * @data: data to pass to match function +- * @match: Callback function to check gpio_chip ++/* ++ * FIXME: This will be removed soon. + * +- * Similar to bus_find_device. It returns a reference to a gpio_chip as +- * determined by a user supplied @match callback. The callback should return +- * 0 if the device doesn't match and non-zero if it does. If the callback is +- * non-zero, this function will return to the caller and not iterate over any +- * more gpio_chips. ++ * This function is depracated, don't use. + */ + struct gpio_chip *gpiochip_find(void *data, + int (*match)(struct gpio_chip *gc, +@@ -1031,21 +1026,62 @@ struct gpio_chip *gpiochip_find(void *data, + { + struct gpio_device *gdev; + struct gpio_chip *gc = NULL; +- unsigned long flags; +- +- spin_lock_irqsave(&gpio_lock, flags); +- list_for_each_entry(gdev, &gpio_devices, list) +- if (gdev->chip && match(gdev->chip, data)) { +- gc = gdev->chip; +- break; +- } + +- spin_unlock_irqrestore(&gpio_lock, flags); ++ gdev = gpio_device_find(data, match); ++ if (gdev) { ++ gc = gdev->chip; ++ gpio_device_put(gdev); ++ } + + return gc; + } + EXPORT_SYMBOL_GPL(gpiochip_find); + ++/** ++ * gpio_device_find() - find a specific GPIO device ++ * @data: data to pass to match function ++ * @match: Callback function to check gpio_chip ++ * ++ * Returns: ++ * New reference to struct gpio_device. ++ * ++ * Similar to bus_find_device(). It returns a reference to a gpio_device as ++ * determined by a user supplied @match callback. The callback should return ++ * 0 if the device doesn't match and non-zero if it does. If the callback ++ * returns non-zero, this function will return to the caller and not iterate ++ * over any more gpio_devices. ++ * ++ * The callback takes the GPIO chip structure as argument. During the execution ++ * of the callback function the chip is protected from being freed. TODO: This ++ * actually has yet to be implemented. ++ * ++ * If the function returns non-NULL, the returned reference must be freed by ++ * the caller using gpio_device_put(). ++ */ ++struct gpio_device *gpio_device_find(void *data, ++ int (*match)(struct gpio_chip *gc, ++ void *data)) ++{ ++ struct gpio_device *gdev; ++ ++ /* ++ * Not yet but in the future the spinlock below will become a mutex. ++ * Annotate this function before anyone tries to use it in interrupt ++ * context like it happened with gpiochip_find(). ++ */ ++ might_sleep(); ++ ++ guard(spinlock_irqsave)(&gpio_lock); ++ ++ list_for_each_entry(gdev, &gpio_devices, list) { ++ if (gdev->chip && match(gdev->chip, data)) ++ return gpio_device_get(gdev); ++ } ++ ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(gpio_device_find); ++ + static int gpiochip_match_name(struct gpio_chip *gc, void *data) + { + const char *name = data; +@@ -1058,6 +1094,30 @@ static struct gpio_chip *find_chip_by_name(const char *name) + return gpiochip_find((void *)name, gpiochip_match_name); + } + ++/** ++ * gpio_device_get() - Increase the reference count of this GPIO device ++ * @gdev: GPIO device to increase the refcount for ++ * ++ * Returns: ++ * Pointer to @gdev. ++ */ ++struct gpio_device *gpio_device_get(struct gpio_device *gdev) ++{ ++ return to_gpio_device(get_device(&gdev->dev)); ++} ++EXPORT_SYMBOL_GPL(gpio_device_get); ++ ++/** ++ * gpio_device_put() - Decrease the reference count of this GPIO device and ++ * possibly free all resources associated with it. ++ * @gdev: GPIO device to decrease the reference count for ++ */ ++void gpio_device_put(struct gpio_device *gdev) ++{ ++ put_device(&gdev->dev); ++} ++EXPORT_SYMBOL_GPL(gpio_device_put); ++ + #ifdef CONFIG_GPIOLIB_IRQCHIP + + /* +@@ -3962,13 +4022,13 @@ static struct gpio_desc *gpiod_find_by_fwnode(struct fwnode_handle *fwnode, + return desc; + } + +-static struct gpio_desc *gpiod_find_and_request(struct device *consumer, +- struct fwnode_handle *fwnode, +- const char *con_id, +- unsigned int idx, +- enum gpiod_flags flags, +- const char *label, +- bool platform_lookup_allowed) ++struct gpio_desc *gpiod_find_and_request(struct device *consumer, ++ struct fwnode_handle *fwnode, ++ const char *con_id, ++ unsigned int idx, ++ enum gpiod_flags flags, ++ const char *label, ++ bool platform_lookup_allowed) + { + unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT; + struct gpio_desc *desc; +diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h +index a0a67569300b98..9bbde38238d33a 100644 +--- a/drivers/gpio/gpiolib.h ++++ b/drivers/gpio/gpiolib.h +@@ -86,16 +86,6 @@ static inline struct gpio_device *to_gpio_device(struct device *dev) + return container_of(dev, struct gpio_device, dev); + } + +-static inline struct gpio_device *gpio_device_get(struct gpio_device *gdev) +-{ +- return to_gpio_device(get_device(&gdev->dev)); +-} +- +-static inline void gpio_device_put(struct gpio_device *gdev) +-{ +- put_device(&gdev->dev); +-} +- + /* gpio suffixes used for ACPI and device tree lookup */ + static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" }; + +@@ -217,6 +207,14 @@ static inline int gpiod_request_user(struct gpio_desc *desc, const char *label) + return ret; + } + ++struct gpio_desc *gpiod_find_and_request(struct device *consumer, ++ struct fwnode_handle *fwnode, ++ const char *con_id, ++ unsigned int idx, ++ enum gpiod_flags flags, ++ const char *label, ++ bool platform_lookup_allowed); ++ + int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, + unsigned long lflags, enum gpiod_flags dflags); + int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce); +diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig +index 3caa020391c752..ec4abf9ff47b5f 100644 +--- a/drivers/gpu/drm/Kconfig ++++ b/drivers/gpu/drm/Kconfig +@@ -198,7 +198,7 @@ config DRM_TTM + config DRM_TTM_KUNIT_TEST + tristate "KUnit tests for TTM" if !KUNIT_ALL_TESTS + default n +- depends on DRM && KUNIT && MMU ++ depends on DRM && KUNIT && MMU && (UML || COMPILE_TEST) + select DRM_TTM + select DRM_EXPORT_FOR_TESTS if m + select DRM_KUNIT_TEST_HELPERS +@@ -206,7 +206,8 @@ config DRM_TTM_KUNIT_TEST + help + Enables unit tests for TTM, a GPU memory manager subsystem used + to manage memory buffers. This option is mostly useful for kernel +- developers. ++ developers. It depends on (UML || COMPILE_TEST) since no other driver ++ which uses TTM can be loaded while running the tests. + + If in doubt, say "N". + +diff --git a/drivers/gpu/drm/amd/amdgpu/aldebaran.c b/drivers/gpu/drm/amd/amdgpu/aldebaran.c +index 2b97b8a96fb494..7fea4f0f495a39 100644 +--- a/drivers/gpu/drm/amd/amdgpu/aldebaran.c ++++ b/drivers/gpu/drm/amd/amdgpu/aldebaran.c +@@ -100,7 +100,7 @@ static int aldebaran_mode2_suspend_ip(struct amdgpu_device *adev) + adev->ip_blocks[i].status.hw = false; + } + +- return r; ++ return 0; + } + + static int +@@ -333,6 +333,7 @@ aldebaran_mode2_restore_hwcontext(struct amdgpu_reset_control *reset_ctl, + { + struct list_head *reset_device_list = reset_context->reset_device_list; + struct amdgpu_device *tmp_adev = NULL; ++ struct amdgpu_ras *con; + int r; + + if (reset_device_list == NULL) +@@ -358,7 +359,30 @@ aldebaran_mode2_restore_hwcontext(struct amdgpu_reset_control *reset_ctl, + */ + amdgpu_register_gpu_instance(tmp_adev); + +- /* Resume RAS */ ++ /* Resume RAS, ecc_irq */ ++ con = amdgpu_ras_get_context(tmp_adev); ++ if (!amdgpu_sriov_vf(tmp_adev) && con) { ++ if (tmp_adev->sdma.ras && ++ tmp_adev->sdma.ras->ras_block.ras_late_init) { ++ r = tmp_adev->sdma.ras->ras_block.ras_late_init(tmp_adev, ++ &tmp_adev->sdma.ras->ras_block.ras_comm); ++ if (r) { ++ dev_err(tmp_adev->dev, "SDMA failed to execute ras_late_init! ret:%d\n", r); ++ goto end; ++ } ++ } ++ ++ if (tmp_adev->gfx.ras && ++ tmp_adev->gfx.ras->ras_block.ras_late_init) { ++ r = tmp_adev->gfx.ras->ras_block.ras_late_init(tmp_adev, ++ &tmp_adev->gfx.ras->ras_block.ras_comm); ++ if (r) { ++ dev_err(tmp_adev->dev, "GFX failed to execute ras_late_init! ret:%d\n", r); ++ goto end; ++ } ++ } ++ } ++ + amdgpu_ras_resume(tmp_adev); + + /* Update PSP FW topology after reset */ +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +index a79d53bdbe136a..d59e8536192ca9 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +@@ -1009,6 +1009,8 @@ struct amdgpu_device { + bool in_s3; + bool in_s4; + bool in_s0ix; ++ /* indicate amdgpu suspension status */ ++ bool suspend_complete; + + enum pp_mp1_state mp1_state; + struct amdgpu_doorbell_index doorbell_index; +@@ -1367,6 +1369,7 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, + void amdgpu_driver_release_kms(struct drm_device *dev); + + int amdgpu_device_ip_suspend(struct amdgpu_device *adev); ++int amdgpu_device_prepare(struct drm_device *dev); + int amdgpu_device_suspend(struct drm_device *dev, bool fbcon); + int amdgpu_device_resume(struct drm_device *dev, bool fbcon); + u32 amdgpu_get_vblank_counter_kms(struct drm_crtc *crtc); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_afmt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_afmt.c +index a4d65973bf7cf4..80771b1480fff5 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_afmt.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_afmt.c +@@ -100,6 +100,7 @@ struct amdgpu_afmt_acr amdgpu_afmt_acr(uint32_t clock) + amdgpu_afmt_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000); + amdgpu_afmt_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100); + amdgpu_afmt_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000); ++ res.clock = clock; + + return res; + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +index 25d5fda5b243e3..af6c6d89e63afb 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +@@ -335,15 +335,15 @@ int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size, + return r; + } + +-void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void *mem_obj) ++void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void **mem_obj) + { +- struct amdgpu_bo *bo = (struct amdgpu_bo *) mem_obj; ++ struct amdgpu_bo **bo = (struct amdgpu_bo **) mem_obj; + +- amdgpu_bo_reserve(bo, true); +- amdgpu_bo_kunmap(bo); +- amdgpu_bo_unpin(bo); +- amdgpu_bo_unreserve(bo); +- amdgpu_bo_unref(&(bo)); ++ amdgpu_bo_reserve(*bo, true); ++ amdgpu_bo_kunmap(*bo); ++ amdgpu_bo_unpin(*bo); ++ amdgpu_bo_unreserve(*bo); ++ amdgpu_bo_unref(bo); + } + + int amdgpu_amdkfd_alloc_gws(struct amdgpu_device *adev, size_t size, +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +index 2fe9860725bd94..3134e6ad81d1d4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +@@ -221,7 +221,7 @@ int amdgpu_amdkfd_evict_userptr(struct mmu_interval_notifier *mni, + int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size, + void **mem_obj, uint64_t *gpu_addr, + void **cpu_ptr, bool mqd_gfx9); +-void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void *mem_obj); ++void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void **mem_obj); + int amdgpu_amdkfd_alloc_gws(struct amdgpu_device *adev, size_t size, + void **mem_obj); + void amdgpu_amdkfd_free_gws(struct amdgpu_device *adev, void *mem_obj); +@@ -303,6 +303,7 @@ int amdgpu_amdkfd_gpuvm_map_memory_to_gpu(struct amdgpu_device *adev, + struct kgd_mem *mem, void *drm_priv); + int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu( + struct amdgpu_device *adev, struct kgd_mem *mem, void *drm_priv); ++int amdgpu_amdkfd_gpuvm_dmaunmap_mem(struct kgd_mem *mem, void *drm_priv); + int amdgpu_amdkfd_gpuvm_sync_memory( + struct amdgpu_device *adev, struct kgd_mem *mem, bool intr); + int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_mem *mem, +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c +index 469785d337911a..1ef758ac5076ef 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c +@@ -90,7 +90,7 @@ struct amdgpu_amdkfd_fence *to_amdgpu_amdkfd_fence(struct dma_fence *f) + return NULL; + + fence = container_of(f, struct amdgpu_amdkfd_fence, base); +- if (fence && f->ops == &amdkfd_fence_ops) ++ if (f->ops == &amdkfd_fence_ops) + return fence; + + return NULL; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +index e036011137aa22..a1f35510d53955 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +@@ -213,7 +213,7 @@ int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev, + (kfd_mem_limit.ttm_mem_used + ttm_mem_needed > + kfd_mem_limit.max_ttm_mem_limit) || + (adev && xcp_id >= 0 && adev->kfd.vram_used[xcp_id] + vram_needed > +- vram_size - reserved_for_pt)) { ++ vram_size - reserved_for_pt - atomic64_read(&adev->vram_pin_size))) { + ret = -ENOMEM; + goto release; + } +@@ -407,6 +407,10 @@ static int amdgpu_amdkfd_bo_validate(struct amdgpu_bo *bo, uint32_t domain, + "Called with userptr BO")) + return -EINVAL; + ++ /* bo has been pinned, not need validate it */ ++ if (bo->tbo.pin_count) ++ return 0; ++ + amdgpu_bo_placement_from_domain(bo, domain); + + ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); +@@ -733,7 +737,7 @@ kfd_mem_dmaunmap_sg_bo(struct kgd_mem *mem, + enum dma_data_direction dir; + + if (unlikely(!ttm->sg)) { +- pr_err("SG Table of BO is UNEXPECTEDLY NULL"); ++ pr_debug("SG Table of BO is NULL"); + return; + } + +@@ -1135,7 +1139,8 @@ static int reserve_bo_and_cond_vms(struct kgd_mem *mem, + int ret; + + ctx->sync = &mem->sync; +- drm_exec_init(&ctx->exec, DRM_EXEC_INTERRUPTIBLE_WAIT); ++ drm_exec_init(&ctx->exec, DRM_EXEC_INTERRUPTIBLE_WAIT | ++ DRM_EXEC_IGNORE_DUPLICATES); + drm_exec_until_all_locked(&ctx->exec) { + ctx->n_vms = 0; + list_for_each_entry(entry, &mem->attachments, list) { +@@ -1201,8 +1206,6 @@ static void unmap_bo_from_gpuvm(struct kgd_mem *mem, + amdgpu_vm_clear_freed(adev, vm, &bo_va->last_pt_update); + + amdgpu_sync_fence(sync, bo_va->last_pt_update); +- +- kfd_mem_dmaunmap_attachment(mem, entry); + } + + static int update_gpuvm_pte(struct kgd_mem *mem, +@@ -1257,6 +1260,7 @@ static int map_bo_to_gpuvm(struct kgd_mem *mem, + + update_gpuvm_pte_failed: + unmap_bo_from_gpuvm(mem, entry, sync); ++ kfd_mem_dmaunmap_attachment(mem, entry); + return ret; + } + +@@ -1785,6 +1789,7 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( + err_bo_create: + amdgpu_amdkfd_unreserve_mem_limit(adev, aligned_size, flags, xcp_id); + err_reserve_limit: ++ amdgpu_sync_free(&(*mem)->sync); + mutex_destroy(&(*mem)->lock); + if (gobj) + drm_gem_object_put(gobj); +@@ -1860,8 +1865,10 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu( + mem->va + bo_size * (1 + mem->aql_queue)); + + /* Remove from VM internal data structures */ +- list_for_each_entry_safe(entry, tmp, &mem->attachments, list) ++ list_for_each_entry_safe(entry, tmp, &mem->attachments, list) { ++ kfd_mem_dmaunmap_attachment(mem, entry); + kfd_mem_detach(entry); ++ } + + ret = unreserve_bo_and_vms(&ctx, false, false); + +@@ -2035,6 +2042,37 @@ int amdgpu_amdkfd_gpuvm_map_memory_to_gpu( + return ret; + } + ++int amdgpu_amdkfd_gpuvm_dmaunmap_mem(struct kgd_mem *mem, void *drm_priv) ++{ ++ struct kfd_mem_attachment *entry; ++ struct amdgpu_vm *vm; ++ int ret; ++ ++ vm = drm_priv_to_vm(drm_priv); ++ ++ mutex_lock(&mem->lock); ++ ++ ret = amdgpu_bo_reserve(mem->bo, true); ++ if (ret) ++ goto out; ++ ++ list_for_each_entry(entry, &mem->attachments, list) { ++ if (entry->bo_va->base.vm != vm) ++ continue; ++ if (entry->bo_va->base.bo->tbo.ttm && ++ !entry->bo_va->base.bo->tbo.ttm->sg) ++ continue; ++ ++ kfd_mem_dmaunmap_attachment(mem, entry); ++ } ++ ++ amdgpu_bo_unreserve(mem->bo); ++out: ++ mutex_unlock(&mem->lock); ++ ++ return ret; ++} ++ + int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu( + struct amdgpu_device *adev, struct kgd_mem *mem, void *drm_priv) + { +@@ -2597,7 +2635,7 @@ static int confirm_valid_user_pages_locked(struct amdkfd_process_info *process_i + + /* keep mem without hmm range at userptr_inval_list */ + if (!mem->range) +- continue; ++ continue; + + /* Only check mem with hmm range associated */ + valid = amdgpu_ttm_tt_get_user_pages_done( +@@ -2814,9 +2852,6 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef) + if (!attachment->is_mapped) + continue; + +- if (attachment->bo_va->base.bo->tbo.pin_count) +- continue; +- + kfd_mem_dmaunmap_attachment(mem, attachment); + ret = update_gpuvm_pte(mem, attachment, &sync_obj); + if (ret) { +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +index dce9e7d5e4ec67..a14a54a734c128 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +@@ -1476,6 +1476,8 @@ int amdgpu_atombios_init_mc_reg_table(struct amdgpu_device *adev, + (u32)le32_to_cpu(*((u32 *)reg_data + j)); + j++; + } else if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_EQU_PREV) { ++ if (i == 0) ++ continue; + reg_table->mc_reg_table_entry[num_ranges].mc_data[i] = + reg_table->mc_reg_table_entry[num_ranges].mc_data[i - 1]; + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c +index fb2681dd6b338c..6521d06c7e4e72 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c +@@ -211,6 +211,7 @@ union igp_info { + struct atom_integrated_system_info_v1_11 v11; + struct atom_integrated_system_info_v1_12 v12; + struct atom_integrated_system_info_v2_1 v21; ++ struct atom_integrated_system_info_v2_3 v23; + }; + + union umc_info { +@@ -359,6 +360,20 @@ amdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev, + if (vram_type) + *vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type); + break; ++ case 3: ++ mem_channel_number = igp_info->v23.umachannelnumber; ++ if (!mem_channel_number) ++ mem_channel_number = 1; ++ mem_type = igp_info->v23.memorytype; ++ if (mem_type == LpDdr5MemType) ++ mem_channel_width = 32; ++ else ++ mem_channel_width = 64; ++ if (vram_width) ++ *vram_width = mem_channel_number * mem_channel_width; ++ if (vram_type) ++ *vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type); ++ break; + default: + return -EINVAL; + } +@@ -384,7 +399,7 @@ amdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev, + mem_channel_number = vram_info->v30.channel_num; + mem_channel_width = vram_info->v30.channel_width; + if (vram_width) +- *vram_width = mem_channel_number * (1 << mem_channel_width); ++ *vram_width = mem_channel_number * 16; + break; + default: + return -EINVAL; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +index 38ccec913f0097..f3a09ecb76992b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +@@ -29,6 +29,7 @@ + #include "amdgpu.h" + #include "atom.h" + ++#include + #include + #include + #include +@@ -287,6 +288,10 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev) + if (adev->flags & AMD_IS_APU) + return false; + ++ /* ATRM is for on-platform devices only */ ++ if (dev_is_removable(&adev->pdev->dev)) ++ return false; ++ + while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { + dhandle = ACPI_HANDLE(&pdev->dev); + if (!dhandle) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +index b6298e901cbd4f..9a53ca555e7088 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +@@ -183,6 +183,7 @@ int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id, + } + + rcu_read_unlock(); ++ *result = NULL; + return -ENOENT; + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +index b8280be6225d9f..c3d89088123dbd 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +@@ -213,6 +213,9 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device, + struct amdgpu_firmware_info *ucode; + + id = fw_type_convert(cgs_device, type); ++ if (id >= AMDGPU_UCODE_ID_MAXIMUM) ++ return -EINVAL; ++ + ucode = &adev->firmware.ucode[id]; + if (ucode->fw == NULL) + return -EINVAL; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +index d93a8961274c6a..13c97ba7a820b4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +@@ -207,7 +207,7 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p, + } + + for (i = 0; i < p->nchunks; i++) { +- struct drm_amdgpu_cs_chunk __user **chunk_ptr = NULL; ++ struct drm_amdgpu_cs_chunk __user *chunk_ptr = NULL; + struct drm_amdgpu_cs_chunk user_chunk; + uint32_t __user *cdata; + +@@ -263,6 +263,10 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p, + if (size < sizeof(struct drm_amdgpu_bo_list_in)) + goto free_partial_kdata; + ++ /* Only a single BO list is allowed to simplify handling. */ ++ if (p->bo_list) ++ goto free_partial_kdata; ++ + ret = amdgpu_cs_p1_bo_handles(p, p->chunks[i].kdata); + if (ret) + goto free_partial_kdata; +@@ -819,7 +823,7 @@ static int amdgpu_cs_bo_validate(void *param, struct amdgpu_bo *bo) + + p->bytes_moved += ctx.bytes_moved; + if (!amdgpu_gmc_vram_full_visible(&adev->gmc) && +- amdgpu_bo_in_cpu_visible_vram(bo)) ++ amdgpu_res_cpu_visible(adev, bo->tbo.resource)) + p->bytes_moved_vis += ctx.bytes_moved; + + if (unlikely(r == -ENOMEM) && domain != bo->allowed_domains) { +@@ -1057,6 +1061,9 @@ static int amdgpu_cs_patch_ibs(struct amdgpu_cs_parser *p, + r = amdgpu_ring_parse_cs(ring, p, job, ib); + if (r) + return r; ++ ++ if (ib->sa_bo) ++ ib->gpu_addr = amdgpu_sa_bo_gpu_addr(ib->sa_bo); + } else { + ib->ptr = (uint32_t *)kptr; + r = amdgpu_ring_patch_cs_in_place(ring, p, job, ib); +@@ -1093,6 +1100,21 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) + unsigned int i; + int r; + ++ /* ++ * We can't use gang submit on with reserved VMIDs when the VM changes ++ * can't be invalidated by more than one engine at the same time. ++ */ ++ if (p->gang_size > 1 && !p->adev->vm_manager.concurrent_flush) { ++ for (i = 0; i < p->gang_size; ++i) { ++ struct drm_sched_entity *entity = p->entities[i]; ++ struct drm_gpu_scheduler *sched = entity->rq->sched; ++ struct amdgpu_ring *ring = to_amdgpu_ring(sched); ++ ++ if (amdgpu_vmid_uses_reserved(vm, ring->vm_hub)) ++ return -EINVAL; ++ } ++ } ++ + r = amdgpu_vm_clear_freed(adev, vm, NULL); + if (r) + return r; +@@ -1411,7 +1433,7 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + if (r == -ENOMEM) + DRM_ERROR("Not enough memory for command submission!\n"); + else if (r != -ERESTARTSYS && r != -EAGAIN) +- DRM_ERROR("Failed to process the buffer list %d!\n", r); ++ DRM_DEBUG("Failed to process the buffer list %d!\n", r); + goto error_fini; + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +index 76549c2cffebe1..cf8804fa7e9716 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +@@ -684,16 +684,24 @@ int amdgpu_ctx_ioctl(struct drm_device *dev, void *data, + + switch (args->in.op) { + case AMDGPU_CTX_OP_ALLOC_CTX: ++ if (args->in.flags) ++ return -EINVAL; + r = amdgpu_ctx_alloc(adev, fpriv, filp, priority, &id); + args->out.alloc.ctx_id = id; + break; + case AMDGPU_CTX_OP_FREE_CTX: ++ if (args->in.flags) ++ return -EINVAL; + r = amdgpu_ctx_free(fpriv, id); + break; + case AMDGPU_CTX_OP_QUERY_STATE: ++ if (args->in.flags) ++ return -EINVAL; + r = amdgpu_ctx_query(adev, fpriv, id, &args->out); + break; + case AMDGPU_CTX_OP_QUERY_STATE2: ++ if (args->in.flags) ++ return -EINVAL; + r = amdgpu_ctx_query2(adev, fpriv, id, &args->out); + break; + case AMDGPU_CTX_OP_GET_STABLE_PSTATE: +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +index a4faea4fa0b592..1c2c9ff9d39df0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +@@ -638,6 +638,9 @@ static ssize_t amdgpu_debugfs_regs_didt_read(struct file *f, char __user *buf, + if (size & 0x3 || *pos & 0x3) + return -EINVAL; + ++ if (!adev->didt_rreg) ++ return -EOPNOTSUPP; ++ + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); + if (r < 0) { + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); +@@ -694,6 +697,9 @@ static ssize_t amdgpu_debugfs_regs_didt_write(struct file *f, const char __user + if (size & 0x3 || *pos & 0x3) + return -EINVAL; + ++ if (!adev->didt_wreg) ++ return -EOPNOTSUPP; ++ + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); + if (r < 0) { + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); +@@ -748,6 +754,9 @@ static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf, + ssize_t result = 0; + int r; + ++ if (!adev->smc_rreg) ++ return -EOPNOTSUPP; ++ + if (size & 0x3 || *pos & 0x3) + return -EINVAL; + +@@ -804,6 +813,9 @@ static ssize_t amdgpu_debugfs_regs_smc_write(struct file *f, const char __user * + ssize_t result = 0; + int r; + ++ if (!adev->smc_wreg) ++ return -EOPNOTSUPP; ++ + if (size & 0x3 || *pos & 0x3) + return -EINVAL; + +@@ -2040,12 +2052,13 @@ static ssize_t amdgpu_reset_dump_register_list_write(struct file *f, + struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(f)->i_private; + char reg_offset[11]; + uint32_t *new = NULL, *tmp = NULL; +- int ret, i = 0, len = 0; ++ unsigned int len = 0; ++ int ret, i = 0; + + do { + memset(reg_offset, 0, 11); + if (copy_from_user(reg_offset, buf + len, +- min(10, ((int)size-len)))) { ++ min(10, (size-len)))) { + ret = -EFAULT; + goto error_free; + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index 2b8356699f235d..9c99d69b4b083e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1217,6 +1218,7 @@ bool amdgpu_device_need_post(struct amdgpu_device *adev) + return true; + + fw_ver = *((uint32_t *)adev->pm.fw->data + 69); ++ release_firmware(adev->pm.fw); + if (fw_ver < 0x00160e00) + return true; + } +@@ -1547,6 +1549,7 @@ static void amdgpu_switcheroo_set_state(struct pci_dev *pdev, + } else { + pr_info("switched off\n"); + dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; ++ amdgpu_device_prepare(dev); + amdgpu_device_suspend(dev, true); + amdgpu_device_cache_pci_state(pdev); + /* Shut down the device */ +@@ -1895,15 +1898,8 @@ static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev) + + adev->firmware.gpu_info_fw = NULL; + +- if (adev->mman.discovery_bin) { +- /* +- * FIXME: The bounding box is still needed by Navi12, so +- * temporarily read it from gpu_info firmware. Should be dropped +- * when DAL no longer needs it. +- */ +- if (adev->asic_type != CHIP_NAVI12) +- return 0; +- } ++ if (adev->mman.discovery_bin) ++ return 0; + + switch (adev->asic_type) { + default: +@@ -2018,7 +2014,6 @@ static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev) + */ + static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) + { +- struct drm_device *dev = adev_to_drm(adev); + struct pci_dev *parent; + int i, r; + bool total; +@@ -2089,7 +2084,7 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) + (amdgpu_is_atpx_hybrid() || + amdgpu_has_atpx_dgpu_power_cntl()) && + ((adev->flags & AMD_IS_APU) == 0) && +- !pci_is_thunderbolt_attached(to_pci_dev(dev->dev))) ++ !dev_is_removable(&adev->pdev->dev)) + adev->flags |= AMD_IS_PX; + + if (!(adev->flags & AMD_IS_APU)) { +@@ -2103,6 +2098,8 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) + adev->pm.pp_feature &= ~PP_GFXOFF_MASK; + if (amdgpu_sriov_vf(adev) && adev->asic_type == CHIP_SIENNA_CICHLID) + adev->pm.pp_feature &= ~PP_OVERDRIVE_MASK; ++ if (!amdgpu_device_pcie_dynamic_switching_supported()) ++ adev->pm.pp_feature &= ~PP_PCIE_DPM_MASK; + + total = true; + for (i = 0; i < adev->num_ip_blocks; i++) { +@@ -3476,10 +3473,6 @@ static void amdgpu_device_set_mcbp(struct amdgpu_device *adev) + adev->gfx.mcbp = true; + else if (amdgpu_mcbp == 0) + adev->gfx.mcbp = false; +- else if ((adev->ip_versions[GC_HWIP][0] >= IP_VERSION(9, 0, 0)) && +- (adev->ip_versions[GC_HWIP][0] < IP_VERSION(10, 0, 0)) && +- adev->gfx.num_gfx_rings) +- adev->gfx.mcbp = true; + + if (amdgpu_sriov_vf(adev)) + adev->gfx.mcbp = true; +@@ -3568,6 +3561,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, + mutex_init(&adev->grbm_idx_mutex); + mutex_init(&adev->mn_lock); + mutex_init(&adev->virt.vf_errors.lock); ++ mutex_init(&adev->virt.rlcg_reg_lock); + hash_init(adev->mn_hash); + mutex_init(&adev->psp.mutex); + mutex_init(&adev->notifier_lock); +@@ -3901,7 +3895,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, + + px = amdgpu_device_supports_px(ddev); + +- if (px || (!pci_is_thunderbolt_attached(adev->pdev) && ++ if (px || (!dev_is_removable(&adev->pdev->dev) && + apple_gmux_detect(NULL, NULL))) + vga_switcheroo_register_client(adev->pdev, + &amdgpu_switcheroo_ops, px); +@@ -4046,7 +4040,7 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev) + + px = amdgpu_device_supports_px(adev_to_drm(adev)); + +- if (px || (!pci_is_thunderbolt_attached(adev->pdev) && ++ if (px || (!dev_is_removable(&adev->pdev->dev) && + apple_gmux_detect(NULL, NULL))) + vga_switcheroo_unregister_client(adev->pdev); + +@@ -4102,6 +4096,43 @@ static int amdgpu_device_evict_resources(struct amdgpu_device *adev) + /* + * Suspend & resume. + */ ++/** ++ * amdgpu_device_prepare - prepare for device suspend ++ * ++ * @dev: drm dev pointer ++ * ++ * Prepare to put the hw in the suspend state (all asics). ++ * Returns 0 for success or an error on failure. ++ * Called at driver suspend. ++ */ ++int amdgpu_device_prepare(struct drm_device *dev) ++{ ++ struct amdgpu_device *adev = drm_to_adev(dev); ++ int i, r; ++ ++ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) ++ return 0; ++ ++ /* Evict the majority of BOs before starting suspend sequence */ ++ r = amdgpu_device_evict_resources(adev); ++ if (r) ++ return r; ++ ++ flush_delayed_work(&adev->gfx.gfx_off_delay_work); ++ ++ for (i = 0; i < adev->num_ip_blocks; i++) { ++ if (!adev->ip_blocks[i].status.valid) ++ continue; ++ if (!adev->ip_blocks[i].version->funcs->prepare_suspend) ++ continue; ++ r = adev->ip_blocks[i].version->funcs->prepare_suspend((void *)adev); ++ if (r) ++ return r; ++ } ++ ++ return 0; ++} ++ + /** + * amdgpu_device_suspend - initiate device suspend + * +@@ -4122,11 +4153,6 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) + + adev->in_suspend = true; + +- /* Evict the majority of BOs before grabbing the full access */ +- r = amdgpu_device_evict_resources(adev); +- if (r) +- return r; +- + if (amdgpu_sriov_vf(adev)) { + amdgpu_virt_fini_data_exchange(adev); + r = amdgpu_virt_request_full_gpu(adev, false); +@@ -4141,7 +4167,6 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) + drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, true); + + cancel_delayed_work_sync(&adev->delayed_init_work); +- flush_delayed_work(&adev->gfx.gfx_off_delay_work); + + amdgpu_ras_suspend(adev); + +@@ -4455,7 +4480,8 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev) + shadow = vmbo->shadow; + + /* No need to recover an evicted BO */ +- if (shadow->tbo.resource->mem_type != TTM_PL_TT || ++ if (!shadow->tbo.resource || ++ shadow->tbo.resource->mem_type != TTM_PL_TT || + shadow->tbo.resource->start == AMDGPU_BO_INVALID_OFFSET || + shadow->parent->tbo.resource->mem_type != TTM_PL_VRAM) + continue; +@@ -4661,11 +4687,14 @@ int amdgpu_device_mode1_reset(struct amdgpu_device *adev) + + dev_info(adev->dev, "GPU mode1 reset\n"); + ++ /* Cache the state before bus master disable. The saved config space ++ * values are used in other cases like restore after mode-2 reset. ++ */ ++ amdgpu_device_cache_pci_state(adev->pdev); ++ + /* disable BM */ + pci_clear_master(adev->pdev); + +- amdgpu_device_cache_pci_state(adev->pdev); +- + if (amdgpu_dpm_is_mode1_reset_supported(adev)) { + dev_info(adev->dev, "GPU smu mode1 reset\n"); + ret = amdgpu_dpm_mode1_reset(adev); +@@ -5183,7 +5212,8 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, + * Flush RAM to disk so that after reboot + * the user can read log and see why the system rebooted. + */ +- if (need_emergency_restart && amdgpu_ras_get_context(adev)->reboot) { ++ if (need_emergency_restart && amdgpu_ras_get_context(adev) && ++ amdgpu_ras_get_context(adev)->reboot) { + DRM_WARN("Emergency reboot."); + + ksys_sync_helper(); +@@ -5206,7 +5236,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, + * to put adev in the 1st position. + */ + INIT_LIST_HEAD(&device_list); +- if (!amdgpu_sriov_vf(adev) && (adev->gmc.xgmi.num_physical_nodes > 1)) { ++ if (!amdgpu_sriov_vf(adev) && (adev->gmc.xgmi.num_physical_nodes > 1) && hive) { + list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { + list_add_tail(&tmp_adev->reset_list, &device_list); + if (gpu_reset_for_dev_remove && adev->shutdown) +@@ -5617,7 +5647,7 @@ int amdgpu_device_baco_exit(struct drm_device *dev) + adev->nbio.funcs->enable_doorbell_interrupt) + adev->nbio.funcs->enable_doorbell_interrupt(adev, true); + +- if (amdgpu_passthrough(adev) && ++ if (amdgpu_passthrough(adev) && adev->nbio.funcs && + adev->nbio.funcs->clear_doorbell_interrupt) + adev->nbio.funcs->clear_doorbell_interrupt(adev); + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +index 7d5e7ad28ba82a..b04d789bfd1005 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +@@ -93,6 +93,7 @@ + MODULE_FIRMWARE(FIRMWARE_IP_DISCOVERY); + + #define mmRCC_CONFIG_MEMSIZE 0xde3 ++#define mmMP0_SMN_C2PMSG_33 0x16061 + #define mmMM_INDEX 0x0 + #define mmMM_INDEX_HI 0x6 + #define mmMM_DATA 0x1 +@@ -231,8 +232,26 @@ static int amdgpu_discovery_read_binary_from_sysmem(struct amdgpu_device *adev, + static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev, + uint8_t *binary) + { +- uint64_t vram_size = (uint64_t)RREG32(mmRCC_CONFIG_MEMSIZE) << 20; +- int ret = 0; ++ uint64_t vram_size; ++ u32 msg; ++ int i, ret = 0; ++ ++ /* It can take up to a second for IFWI init to complete on some dGPUs, ++ * but generally it should be in the 60-100ms range. Normally this starts ++ * as soon as the device gets power so by the time the OS loads this has long ++ * completed. However, when a card is hotplugged via e.g., USB4, we need to ++ * wait for this to complete. Once the C2PMSG is updated, we can ++ * continue. ++ */ ++ if (dev_is_removable(&adev->pdev->dev)) { ++ for (i = 0; i < 1000; i++) { ++ msg = RREG32(mmMP0_SMN_C2PMSG_33); ++ if (msg & 0x80000000) ++ break; ++ msleep(1); ++ } ++ } ++ vram_size = (uint64_t)RREG32(mmRCC_CONFIG_MEMSIZE) << 20; + + if (vram_size) { + uint64_t pos = vram_size - DISCOVERY_TMR_OFFSET; +@@ -1251,11 +1270,10 @@ static int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev) + * 0b10 : encode is disabled + * 0b01 : decode is disabled + */ +- adev->vcn.vcn_config[adev->vcn.num_vcn_inst] = +- ip->revision & 0xc0; +- ip->revision &= ~0xc0; + if (adev->vcn.num_vcn_inst < + AMDGPU_MAX_VCN_INSTANCES) { ++ adev->vcn.vcn_config[adev->vcn.num_vcn_inst] = ++ ip->revision & 0xc0; + adev->vcn.num_vcn_inst++; + adev->vcn.inst_mask |= + (1U << ip->instance_number); +@@ -1266,6 +1284,7 @@ static int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev) + adev->vcn.num_vcn_inst + 1, + AMDGPU_MAX_VCN_INSTANCES); + } ++ ip->revision &= ~0xc0; + } + if (le16_to_cpu(ip->hw_id) == SDMA0_HWID || + le16_to_cpu(ip->hw_id) == SDMA1_HWID || +@@ -1531,7 +1550,7 @@ static int amdgpu_discovery_get_mall_info(struct amdgpu_device *adev) + break; + case 2: + mall_size_per_umc = le32_to_cpu(mall_info->v2.mall_size_per_umc); +- adev->gmc.mall_size = mall_size_per_umc * adev->gmc.num_umc; ++ adev->gmc.mall_size = (uint64_t)mall_size_per_umc * adev->gmc.num_umc; + break; + default: + dev_err(adev->dev, +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +index 363e6a2cad8c20..5fbb9caa7415fd 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +@@ -340,14 +340,11 @@ int amdgpu_display_crtc_set_config(struct drm_mode_set *set, + adev->have_disp_power_ref = true; + return ret; + } +- /* if we have no active crtcs, then drop the power ref +- * we got before ++ /* if we have no active crtcs, then go to ++ * drop the power ref we got before + */ +- if (!active && adev->have_disp_power_ref) { +- pm_runtime_put_autosuspend(dev->dev); ++ if (!active && adev->have_disp_power_ref) + adev->have_disp_power_ref = false; +- } +- + out: + /* drop the power reference we got coming in here */ + pm_runtime_put_autosuspend(dev->dev); +@@ -912,8 +909,7 @@ static int check_tiling_flags_gfx6(struct amdgpu_framebuffer *afb) + { + u64 micro_tile_mode; + +- /* Zero swizzle mode means linear */ +- if (AMDGPU_TILING_GET(afb->tiling_flags, SWIZZLE_MODE) == 0) ++ if (AMDGPU_TILING_GET(afb->tiling_flags, ARRAY_MODE) == 1) /* LINEAR_ALIGNED */ + return 0; + + micro_tile_mode = AMDGPU_TILING_GET(afb->tiling_flags, MICRO_TILE_MODE); +@@ -1037,6 +1033,30 @@ static int amdgpu_display_verify_sizes(struct amdgpu_framebuffer *rfb) + block_width = 256 / format_info->cpp[i]; + block_height = 1; + block_size_log2 = 8; ++ } else if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) >= AMD_FMT_MOD_TILE_VER_GFX12) { ++ int swizzle = AMD_FMT_MOD_GET(TILE, modifier); ++ ++ switch (swizzle) { ++ case AMD_FMT_MOD_TILE_GFX12_256B_2D: ++ block_size_log2 = 8; ++ break; ++ case AMD_FMT_MOD_TILE_GFX12_4K_2D: ++ block_size_log2 = 12; ++ break; ++ case AMD_FMT_MOD_TILE_GFX12_64K_2D: ++ block_size_log2 = 16; ++ break; ++ case AMD_FMT_MOD_TILE_GFX12_256K_2D: ++ block_size_log2 = 18; ++ break; ++ default: ++ drm_dbg_kms(rfb->base.dev, ++ "Gfx12 swizzle mode with unknown block size: %d\n", swizzle); ++ return -EINVAL; ++ } ++ ++ get_block_dimensions(block_size_log2, format_info->cpp[i], ++ &block_width, &block_height); + } else { + int swizzle = AMD_FMT_MOD_GET(TILE, modifier); + +@@ -1072,7 +1092,8 @@ static int amdgpu_display_verify_sizes(struct amdgpu_framebuffer *rfb) + return ret; + } + +- if (AMD_FMT_MOD_GET(DCC, modifier)) { ++ if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) <= AMD_FMT_MOD_TILE_VER_GFX11 && ++ AMD_FMT_MOD_GET(DCC, modifier)) { + if (AMD_FMT_MOD_GET(DCC_RETILE, modifier)) { + block_size_log2 = get_dcc_block_size(modifier, false, false); + get_block_dimensions(block_size_log2 + 8, format_info->cpp[0], +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h +index 09f6727e7c73ae..4a8b33f55f6bc3 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell.h +@@ -357,8 +357,9 @@ int amdgpu_doorbell_init(struct amdgpu_device *adev); + void amdgpu_doorbell_fini(struct amdgpu_device *adev); + int amdgpu_doorbell_create_kernel_doorbells(struct amdgpu_device *adev); + uint32_t amdgpu_doorbell_index_on_bar(struct amdgpu_device *adev, +- struct amdgpu_bo *db_bo, +- uint32_t doorbell_index); ++ struct amdgpu_bo *db_bo, ++ uint32_t doorbell_index, ++ uint32_t db_size); + + #define RDOORBELL32(index) amdgpu_mm_rdoorbell(adev, (index)) + #define WDOORBELL32(index, v) amdgpu_mm_wdoorbell(adev, (index), (v)) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell_mgr.c +index 8eee5d783a92bd..3f3662e8b87103 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell_mgr.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_doorbell_mgr.c +@@ -113,20 +113,25 @@ void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v) + * + * @adev: amdgpu_device pointer + * @db_bo: doorbell object's bo +- * @db_index: doorbell relative index in this doorbell object ++ * @doorbell_index: doorbell relative index in this doorbell object ++ * @db_size: doorbell size is in byte + * + * returns doorbell's absolute index in BAR + */ + uint32_t amdgpu_doorbell_index_on_bar(struct amdgpu_device *adev, +- struct amdgpu_bo *db_bo, +- uint32_t doorbell_index) ++ struct amdgpu_bo *db_bo, ++ uint32_t doorbell_index, ++ uint32_t db_size) + { + int db_bo_offset; + + db_bo_offset = amdgpu_bo_gpu_offset_no_check(db_bo); + +- /* doorbell index is 32 bit but doorbell's size is 64-bit, so *2 */ +- return db_bo_offset / sizeof(u32) + doorbell_index * 2; ++ /* doorbell index is 32 bit but doorbell's size can be 32 bit ++ * or 64 bit, so *db_size(in byte)/4 for alignment. ++ */ ++ return db_bo_offset / sizeof(u32) + doorbell_index * ++ DIV_ROUND_UP(db_size, 4); + } + + /** +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +index 81edf66dbea8bd..f9bc38d20ce3ee 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +@@ -2195,6 +2195,8 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, + pm_runtime_mark_last_busy(ddev->dev); + pm_runtime_put_autosuspend(ddev->dev); + ++ pci_wake_from_d3(pdev, TRUE); ++ + /* + * For runpm implemented via BACO, PMFW will handle the + * timing for BACO in and out: +@@ -2384,8 +2386,9 @@ static int amdgpu_pmops_prepare(struct device *dev) + /* Return a positive number here so + * DPM_FLAG_SMART_SUSPEND works properly + */ +- if (amdgpu_device_supports_boco(drm_dev)) +- return pm_runtime_suspended(dev); ++ if (amdgpu_device_supports_boco(drm_dev) && ++ pm_runtime_suspended(dev)) ++ return 1; + + /* if we will not support s3 or s2i for the device + * then skip suspend +@@ -2394,7 +2397,7 @@ static int amdgpu_pmops_prepare(struct device *dev) + !amdgpu_acpi_is_s3_active(adev)) + return 1; + +- return 0; ++ return amdgpu_device_prepare(drm_dev); + } + + static void amdgpu_pmops_complete(struct device *dev) +@@ -2407,6 +2410,7 @@ static int amdgpu_pmops_suspend(struct device *dev) + struct drm_device *drm_dev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(drm_dev); + ++ adev->suspend_complete = false; + if (amdgpu_acpi_is_s0ix_active(adev)) + adev->in_s0ix = true; + else if (amdgpu_acpi_is_s3_active(adev)) +@@ -2421,6 +2425,7 @@ static int amdgpu_pmops_suspend_noirq(struct device *dev) + struct drm_device *drm_dev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(drm_dev); + ++ adev->suspend_complete = true; + if (amdgpu_acpi_should_gpu_reset(adev)) + return amdgpu_asic_reset(adev); + +@@ -2594,6 +2599,9 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev) + if (amdgpu_device_supports_boco(drm_dev)) + adev->mp1_state = PP_MP1_STATE_UNLOAD; + ++ ret = amdgpu_device_prepare(drm_dev); ++ if (ret) ++ return ret; + ret = amdgpu_device_suspend(drm_dev, false); + if (ret) { + adev->in_runpm = false; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c +index e71768661ca8d2..09a34c7258e226 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c +@@ -179,7 +179,7 @@ static int __amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, + * Returns the number of bytes read/written; -errno on error. + */ + static int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, +- u8 *eeprom_buf, u16 buf_size, bool read) ++ u8 *eeprom_buf, u32 buf_size, bool read) + { + const struct i2c_adapter_quirks *quirks = i2c_adap->quirks; + u16 limit; +@@ -225,7 +225,7 @@ static int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, + + int amdgpu_eeprom_read(struct i2c_adapter *i2c_adap, + u32 eeprom_addr, u8 *eeprom_buf, +- u16 bytes) ++ u32 bytes) + { + return amdgpu_eeprom_xfer(i2c_adap, eeprom_addr, eeprom_buf, bytes, + true); +@@ -233,7 +233,7 @@ int amdgpu_eeprom_read(struct i2c_adapter *i2c_adap, + + int amdgpu_eeprom_write(struct i2c_adapter *i2c_adap, + u32 eeprom_addr, u8 *eeprom_buf, +- u16 bytes) ++ u32 bytes) + { + return amdgpu_eeprom_xfer(i2c_adap, eeprom_addr, eeprom_buf, bytes, + false); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h +index 6935adb2be1f1c..8083b8253ef433 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.h +@@ -28,10 +28,10 @@ + + int amdgpu_eeprom_read(struct i2c_adapter *i2c_adap, + u32 eeprom_addr, u8 *eeprom_buf, +- u16 bytes); ++ u32 bytes); + + int amdgpu_eeprom_write(struct i2c_adapter *i2c_adap, + u32 eeprom_addr, u8 *eeprom_buf, +- u16 bytes); ++ u32 bytes); + + #endif +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c +index 6038b5021b27be..792c059ff7b352 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c +@@ -105,6 +105,10 @@ void amdgpu_show_fdinfo(struct drm_printer *p, struct drm_file *file) + stats.requested_visible_vram/1024UL); + drm_printf(p, "amd-requested-gtt:\t%llu KiB\n", + stats.requested_gtt/1024UL); ++ drm_printf(p, "drm-shared-vram:\t%llu KiB\n", stats.vram_shared/1024UL); ++ drm_printf(p, "drm-shared-gtt:\t%llu KiB\n", stats.gtt_shared/1024UL); ++ drm_printf(p, "drm-shared-cpu:\t%llu KiB\n", stats.cpu_shared/1024UL); ++ + for (hw_ip = 0; hw_ip < AMDGPU_HW_IP_NUM; ++hw_ip) { + if (!usage[hw_ip]) + continue; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +index 73b8cca35bab87..eace2c9d0c3624 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +@@ -34,6 +34,7 @@ + #include + #endif + #include "amdgpu.h" ++#include "amdgpu_reset.h" + #include + #include + +@@ -400,7 +401,10 @@ void amdgpu_gart_invalidate_tlb(struct amdgpu_device *adev) + return; + + mb(); +- amdgpu_device_flush_hdp(adev, NULL); ++ if (down_read_trylock(&adev->reset_domain->sem)) { ++ amdgpu_device_flush_hdp(adev, NULL); ++ up_read(&adev->reset_domain->sem); ++ } + for_each_set_bit(i, adev->vmhubs_mask, AMDGPU_MAX_VMHUBS) + amdgpu_gmc_flush_gpu_tlb(adev, 0, i, 0); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +index ca4d2d430e28c8..a1b15d0d6c4893 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +@@ -962,6 +962,7 @@ static int amdgpu_debugfs_gem_info_show(struct seq_file *m, void *unused) + list_for_each_entry(file, &dev->filelist, lhead) { + struct task_struct *task; + struct drm_gem_object *gobj; ++ struct pid *pid; + int id; + + /* +@@ -971,8 +972,9 @@ static int amdgpu_debugfs_gem_info_show(struct seq_file *m, void *unused) + * Therefore, we need to protect this ->comm access using RCU. + */ + rcu_read_lock(); +- task = pid_task(file->pid, PIDTYPE_TGID); +- seq_printf(m, "pid %8d command %s:\n", pid_nr(file->pid), ++ pid = rcu_dereference(file->pid); ++ task = pid_task(pid, PIDTYPE_TGID); ++ seq_printf(m, "pid %8d command %s:\n", pid_nr(pid), + task ? task->comm : ""); + rcu_read_unlock(); + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +index 2382921710ece7..e7b053898f9e90 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +@@ -384,9 +384,11 @@ int amdgpu_gfx_mqd_sw_init(struct amdgpu_device *adev, + struct amdgpu_ring *ring = &kiq->ring; + u32 domain = AMDGPU_GEM_DOMAIN_GTT; + ++#if !defined(CONFIG_ARM) && !defined(CONFIG_ARM64) + /* Only enable on gfx10 and 11 for now to avoid changing behavior on older chips */ + if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 0, 0)) + domain |= AMDGPU_GEM_DOMAIN_VRAM; ++#endif + + /* create MQD for KIQ */ + if (!adev->enable_mes_kiq && !ring->mqd_obj) { +@@ -700,8 +702,15 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable) + + if (adev->gfx.gfx_off_req_count == 0 && + !adev->gfx.gfx_off_state) { +- schedule_delayed_work(&adev->gfx.gfx_off_delay_work, ++ /* If going to s2idle, no need to wait */ ++ if (adev->in_s0ix) { ++ if (!amdgpu_dpm_set_powergating_by_smu(adev, ++ AMD_IP_BLOCK_TYPE_GFX, true)) ++ adev->gfx.gfx_off_state = true; ++ } else { ++ schedule_delayed_work(&adev->gfx.gfx_off_delay_work, + delay); ++ } + } + } else { + if (adev->gfx.gfx_off_req_count == 0) { +@@ -784,8 +793,11 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r + int r; + + if (amdgpu_ras_is_supported(adev, ras_block->block)) { +- if (!amdgpu_persistent_edc_harvesting_supported(adev)) +- amdgpu_ras_reset_error_status(adev, AMDGPU_RAS_BLOCK__GFX); ++ if (!amdgpu_persistent_edc_harvesting_supported(adev)) { ++ r = amdgpu_ras_reset_error_status(adev, AMDGPU_RAS_BLOCK__GFX); ++ if (r) ++ return r; ++ } + + r = amdgpu_ras_block_late_init(adev, ras_block); + if (r) +@@ -929,7 +941,10 @@ uint32_t amdgpu_kiq_rreg(struct amdgpu_device *adev, uint32_t reg) + pr_err("critical bug! too many kiq readers\n"); + goto failed_unlock; + } +- amdgpu_ring_alloc(ring, 32); ++ r = amdgpu_ring_alloc(ring, 32); ++ if (r) ++ goto failed_unlock; ++ + amdgpu_ring_emit_rreg(ring, reg, reg_val_offs); + r = amdgpu_fence_emit_polling(ring, &seq, MAX_KIQ_REG_WAIT); + if (r) +@@ -995,7 +1010,10 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v) + } + + spin_lock_irqsave(&kiq->ring_lock, flags); +- amdgpu_ring_alloc(ring, 32); ++ r = amdgpu_ring_alloc(ring, 32); ++ if (r) ++ goto failed_unlock; ++ + amdgpu_ring_emit_wreg(ring, reg, v); + r = amdgpu_fence_emit_polling(ring, &seq, MAX_KIQ_REG_WAIT); + if (r) +@@ -1031,6 +1049,7 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v) + + failed_undo: + amdgpu_ring_undo(ring); ++failed_unlock: + spin_unlock_irqrestore(&kiq->ring_lock, flags); + failed_kiq_write: + dev_err(adev->dev, "failed to write reg:%x\n", reg); +@@ -1175,7 +1194,8 @@ void amdgpu_gfx_cp_init_microcode(struct amdgpu_device *adev, + fw_size = le32_to_cpu(cp_hdr_v2_0->data_size_bytes); + break; + default: +- break; ++ dev_err(adev->dev, "Invalid ucode id %u\n", ucode_id); ++ return; + } + + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +index d78bd97325434f..0b6a0e149f1c4c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +@@ -650,7 +650,6 @@ void amdgpu_gmc_noretry_set(struct amdgpu_device *adev) + struct amdgpu_gmc *gmc = &adev->gmc; + uint32_t gc_ver = adev->ip_versions[GC_HWIP][0]; + bool noretry_default = (gc_ver == IP_VERSION(9, 0, 1) || +- gc_ver == IP_VERSION(9, 3, 0) || + gc_ver == IP_VERSION(9, 4, 0) || + gc_ver == IP_VERSION(9, 4, 1) || + gc_ver == IP_VERSION(9, 4, 2) || +@@ -876,21 +875,28 @@ int amdgpu_gmc_vram_checking(struct amdgpu_device *adev) + * seconds, so here, we just pick up three parts for emulation. + */ + ret = memcmp(vram_ptr, cptr, 10); +- if (ret) +- return ret; ++ if (ret) { ++ ret = -EIO; ++ goto release_buffer; ++ } + + ret = memcmp(vram_ptr + (size / 2), cptr, 10); +- if (ret) +- return ret; ++ if (ret) { ++ ret = -EIO; ++ goto release_buffer; ++ } + + ret = memcmp(vram_ptr + size - 10, cptr, 10); +- if (ret) +- return ret; ++ if (ret) { ++ ret = -EIO; ++ goto release_buffer; ++ } + ++release_buffer: + amdgpu_bo_free_kernel(&vram_bo, &vram_gpu, + &vram_ptr); + +- return 0; ++ return ret; + } + + static ssize_t current_memory_partition_show( +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c +index 081267161d4018..57516a8c5db347 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c +@@ -129,13 +129,25 @@ static const struct mmu_interval_notifier_ops amdgpu_hmm_hsa_ops = { + */ + int amdgpu_hmm_register(struct amdgpu_bo *bo, unsigned long addr) + { ++ int r; ++ + if (bo->kfd_bo) +- return mmu_interval_notifier_insert(&bo->notifier, current->mm, ++ r = mmu_interval_notifier_insert(&bo->notifier, current->mm, + addr, amdgpu_bo_size(bo), + &amdgpu_hmm_hsa_ops); +- return mmu_interval_notifier_insert(&bo->notifier, current->mm, addr, +- amdgpu_bo_size(bo), +- &amdgpu_hmm_gfx_ops); ++ else ++ r = mmu_interval_notifier_insert(&bo->notifier, current->mm, addr, ++ amdgpu_bo_size(bo), ++ &amdgpu_hmm_gfx_ops); ++ if (r) ++ /* ++ * Make sure amdgpu_hmm_unregister() doesn't call ++ * mmu_interval_notifier_remove() when the notifier isn't properly ++ * initialized. ++ */ ++ bo->notifier.mm = NULL; ++ ++ return r; + } + + /** +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +index ff1ea99292fbf0..69dfc699d78b07 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +@@ -409,7 +409,7 @@ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring, + if (r || !idle) + goto error; + +- if (vm->reserved_vmid[vmhub] || (enforce_isolation && (vmhub == AMDGPU_GFXHUB(0)))) { ++ if (amdgpu_vmid_uses_reserved(vm, vmhub)) { + r = amdgpu_vmid_grab_reserved(vm, ring, job, &id, fence); + if (r || !id) + goto error; +@@ -459,6 +459,19 @@ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring, + return r; + } + ++/* ++ * amdgpu_vmid_uses_reserved - check if a VM will use a reserved VMID ++ * @vm: the VM to check ++ * @vmhub: the VMHUB which will be used ++ * ++ * Returns: True if the VM will use a reserved VMID. ++ */ ++bool amdgpu_vmid_uses_reserved(struct amdgpu_vm *vm, unsigned int vmhub) ++{ ++ return vm->reserved_vmid[vmhub] || ++ (enforce_isolation && (vmhub == AMDGPU_GFXHUB(0))); ++} ++ + int amdgpu_vmid_alloc_reserved(struct amdgpu_device *adev, + unsigned vmhub) + { +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h +index fa8c42c83d5d26..240fa675126029 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h +@@ -78,6 +78,7 @@ void amdgpu_pasid_free_delayed(struct dma_resv *resv, + + bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev, + struct amdgpu_vmid *id); ++bool amdgpu_vmid_uses_reserved(struct amdgpu_vm *vm, unsigned int vmhub); + int amdgpu_vmid_alloc_reserved(struct amdgpu_device *adev, + unsigned vmhub); + void amdgpu_vmid_free_reserved(struct amdgpu_device *adev, +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h +index 6c6184f0dbc17e..508f02eb0cf8f9 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h +@@ -28,7 +28,7 @@ + #define AMDGPU_IH_MAX_NUM_IVS 32 + + #define IH_RING_SIZE (256 * 1024) +-#define IH_SW_RING_SIZE (8 * 1024) /* enough for 256 CAM entries */ ++#define IH_SW_RING_SIZE (16 * 1024) /* enough for 512 CAM entries */ + + struct amdgpu_device; + struct amdgpu_iv_entry; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c +index fa6d0adcec206c..5978edf7ea71e4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c +@@ -438,6 +438,14 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev, + + entry.ih = ih; + entry.iv_entry = (const uint32_t *)&ih->ring[ring_index]; ++ ++ /* ++ * timestamp is not supported on some legacy SOCs (cik, cz, iceland, ++ * si and tonga), so initialize timestamp and timestamp_src to 0 ++ */ ++ entry.timestamp = 0; ++ entry.timestamp_src = 0; ++ + amdgpu_ih_decode_iv(adev, &entry); + + trace_amdgpu_iv(ih - &adev->irq.ih, &entry); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +index 78476bc75b4e1d..99dd86337e8412 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +@@ -258,9 +258,8 @@ amdgpu_job_prepare_job(struct drm_sched_job *sched_job, + struct dma_fence *fence = NULL; + int r; + +- /* Ignore soft recovered fences here */ + r = drm_sched_entity_error(s_entity); +- if (r && r != -ENODATA) ++ if (r) + goto error; + + if (!fence && job->gang_submit) +@@ -300,12 +299,15 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job) + dma_fence_set_error(finished, -ECANCELED); + + if (finished->error < 0) { +- DRM_INFO("Skip scheduling IBs!\n"); ++ dev_dbg(adev->dev, "Skip scheduling IBs in ring(%s)", ++ ring->name); + } else { + r = amdgpu_ib_schedule(ring, job->num_ibs, job->ibs, job, + &fence); + if (r) +- DRM_ERROR("Error scheduling IBs (%d)\n", r); ++ dev_err(adev->dev, ++ "Error scheduling IBs (%d) in ring(%s)", r, ++ ring->name); + } + + job->job_run_counter++; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +index d30dc0b718c73e..5797055b1148f7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +@@ -43,6 +43,7 @@ + #include "amdgpu_gem.h" + #include "amdgpu_display.h" + #include "amdgpu_ras.h" ++#include "amdgpu_reset.h" + #include "amd_pcie.h" + + void amdgpu_unregister_gpu_instance(struct amdgpu_device *adev) +@@ -722,6 +723,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + ? -EFAULT : 0; + } + case AMDGPU_INFO_READ_MMR_REG: { ++ int ret = 0; + unsigned int n, alloc_size; + uint32_t *regs; + unsigned int se_num = (info->read_mmr_reg.instance >> +@@ -731,24 +733,37 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + AMDGPU_INFO_MMR_SH_INDEX_SHIFT) & + AMDGPU_INFO_MMR_SH_INDEX_MASK; + ++ if (!down_read_trylock(&adev->reset_domain->sem)) ++ return -ENOENT; ++ + /* set full masks if the userspace set all bits + * in the bitfields + */ +- if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) ++ if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) { + se_num = 0xffffffff; +- else if (se_num >= AMDGPU_GFX_MAX_SE) +- return -EINVAL; +- if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) ++ } else if (se_num >= AMDGPU_GFX_MAX_SE) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) { + sh_num = 0xffffffff; +- else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) +- return -EINVAL; ++ } else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) { ++ ret = -EINVAL; ++ goto out; ++ } + +- if (info->read_mmr_reg.count > 128) +- return -EINVAL; ++ if (info->read_mmr_reg.count > 128) { ++ ret = -EINVAL; ++ goto out; ++ } + + regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL); +- if (!regs) +- return -ENOMEM; ++ if (!regs) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ + alloc_size = info->read_mmr_reg.count * sizeof(*regs); + + amdgpu_gfx_off_ctrl(adev, false); +@@ -760,13 +775,17 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + info->read_mmr_reg.dword_offset + i); + kfree(regs); + amdgpu_gfx_off_ctrl(adev, true); +- return -EFAULT; ++ ret = -EFAULT; ++ goto out; + } + } + amdgpu_gfx_off_ctrl(adev, true); + n = copy_to_user(out, regs, min(size, alloc_size)); + kfree(regs); +- return n ? -EFAULT : 0; ++ ret = (n ? -EFAULT : 0); ++out: ++ up_read(&adev->reset_domain->sem); ++ return ret; + } + case AMDGPU_INFO_DEV_INFO: { + struct drm_amdgpu_info_device *dev_info; +@@ -1026,7 +1045,12 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + if (amdgpu_dpm_read_sensor(adev, + AMDGPU_PP_SENSOR_GPU_AVG_POWER, + (void *)&ui32, &ui32_size)) { +- return -EINVAL; ++ /* fall back to input power for backwards compat */ ++ if (amdgpu_dpm_read_sensor(adev, ++ AMDGPU_PP_SENSOR_GPU_INPUT_POWER, ++ (void *)&ui32, &ui32_size)) { ++ return -EINVAL; ++ } + } + ui32 >>= 8; + break; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +index b6015157763af8..c5c55e132af21d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +@@ -556,8 +556,20 @@ static void amdgpu_mes_queue_init_mqd(struct amdgpu_device *adev, + mqd_prop.hqd_queue_priority = p->hqd_queue_priority; + mqd_prop.hqd_active = false; + ++ if (p->queue_type == AMDGPU_RING_TYPE_GFX || ++ p->queue_type == AMDGPU_RING_TYPE_COMPUTE) { ++ mutex_lock(&adev->srbm_mutex); ++ amdgpu_gfx_select_me_pipe_q(adev, p->ring->me, p->ring->pipe, 0, 0, 0); ++ } ++ + mqd_mgr->init_mqd(adev, q->mqd_cpu_ptr, &mqd_prop); + ++ if (p->queue_type == AMDGPU_RING_TYPE_GFX || ++ p->queue_type == AMDGPU_RING_TYPE_COMPUTE) { ++ amdgpu_gfx_select_me_pipe_q(adev, 0, 0, 0, 0, 0); ++ mutex_unlock(&adev->srbm_mutex); ++ } ++ + amdgpu_bo_unreserve(q->mqd_obj); + } + +@@ -873,6 +885,11 @@ int amdgpu_mes_set_shader_debugger(struct amdgpu_device *adev, + op_input.op = MES_MISC_OP_SET_SHADER_DEBUGGER; + op_input.set_shader_debugger.process_context_addr = process_context_addr; + op_input.set_shader_debugger.flags.u32all = flags; ++ ++ /* use amdgpu mes_flush_shader_debugger instead */ ++ if (op_input.set_shader_debugger.flags.process_ctx_flush) ++ return -EINVAL; ++ + op_input.set_shader_debugger.spi_gdbg_per_vmid_cntl = spi_gdbg_per_vmid_cntl; + memcpy(op_input.set_shader_debugger.tcp_watch_cntl, tcp_watch_cntl, + sizeof(op_input.set_shader_debugger.tcp_watch_cntl)); +@@ -892,6 +909,32 @@ int amdgpu_mes_set_shader_debugger(struct amdgpu_device *adev, + return r; + } + ++int amdgpu_mes_flush_shader_debugger(struct amdgpu_device *adev, ++ uint64_t process_context_addr) ++{ ++ struct mes_misc_op_input op_input = {0}; ++ int r; ++ ++ if (!adev->mes.funcs->misc_op) { ++ DRM_ERROR("mes flush shader debugger is not supported!\n"); ++ return -EINVAL; ++ } ++ ++ op_input.op = MES_MISC_OP_SET_SHADER_DEBUGGER; ++ op_input.set_shader_debugger.process_context_addr = process_context_addr; ++ op_input.set_shader_debugger.flags.process_ctx_flush = true; ++ ++ amdgpu_mes_lock(&adev->mes); ++ ++ r = adev->mes.funcs->misc_op(&adev->mes, &op_input); ++ if (r) ++ DRM_ERROR("failed to set_shader_debugger\n"); ++ ++ amdgpu_mes_unlock(&adev->mes); ++ ++ return r; ++} ++ + static void + amdgpu_mes_ring_to_queue_props(struct amdgpu_device *adev, + struct amdgpu_ring *ring, +@@ -993,9 +1036,13 @@ int amdgpu_mes_add_ring(struct amdgpu_device *adev, int gang_id, + switch (queue_type) { + case AMDGPU_RING_TYPE_GFX: + ring->funcs = adev->gfx.gfx_ring[0].funcs; ++ ring->me = adev->gfx.gfx_ring[0].me; ++ ring->pipe = adev->gfx.gfx_ring[0].pipe; + break; + case AMDGPU_RING_TYPE_COMPUTE: + ring->funcs = adev->gfx.compute_ring[0].funcs; ++ ring->me = adev->gfx.compute_ring[0].me; ++ ring->pipe = adev->gfx.compute_ring[0].pipe; + break; + case AMDGPU_RING_TYPE_SDMA: + ring->funcs = adev->sdma.instance[0].ring.funcs; +@@ -1051,6 +1098,7 @@ void amdgpu_mes_remove_ring(struct amdgpu_device *adev, + return; + + amdgpu_mes_remove_hw_queue(adev, ring->hw_queue_id); ++ del_timer_sync(&ring->fence_drv.fallback_timer); + amdgpu_ring_fini(ring); + kfree(ring); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +index a27b424ffe0056..c2c88b772361d7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +@@ -291,9 +291,10 @@ struct mes_misc_op_input { + uint64_t process_context_addr; + union { + struct { +- uint64_t single_memop : 1; +- uint64_t single_alu_op : 1; +- uint64_t reserved: 30; ++ uint32_t single_memop : 1; ++ uint32_t single_alu_op : 1; ++ uint32_t reserved: 29; ++ uint32_t process_ctx_flush: 1; + }; + uint32_t u32all; + } flags; +@@ -369,7 +370,8 @@ int amdgpu_mes_set_shader_debugger(struct amdgpu_device *adev, + const uint32_t *tcp_watch_cntl, + uint32_t flags, + bool trap_en); +- ++int amdgpu_mes_flush_shader_debugger(struct amdgpu_device *adev, ++ uint64_t process_context_addr); + int amdgpu_mes_add_ring(struct amdgpu_device *adev, int gang_id, + int queue_type, int idx, + struct amdgpu_mes_ctx_data *ctx_data, +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +index ace837cfa0a6bc..4e9ae52ef9fdbf 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +@@ -613,6 +613,8 @@ int amdgpu_bo_create(struct amdgpu_device *adev, + else + amdgpu_bo_placement_from_domain(bo, bp->domain); + if (bp->type == ttm_bo_type_kernel) ++ bo->tbo.priority = 2; ++ else if (!(bp->flags & AMDGPU_GEM_CREATE_DISCARDABLE)) + bo->tbo.priority = 1; + + if (!bp->destroy) +@@ -625,8 +627,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev, + return r; + + if (!amdgpu_gmc_vram_full_visible(&adev->gmc) && +- bo->tbo.resource->mem_type == TTM_PL_VRAM && +- amdgpu_bo_in_cpu_visible_vram(bo)) ++ amdgpu_res_cpu_visible(adev, bo->tbo.resource)) + amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved, + ctx.bytes_moved); + else +@@ -1250,7 +1251,7 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, + * amdgpu_bo_move_notify - notification about a memory move + * @bo: pointer to a buffer object + * @evict: if this move is evicting the buffer from the graphics address space +- * @new_mem: new information of the bufer object ++ * @new_mem: new resource for backing the BO + * + * Marks the corresponding &amdgpu_bo buffer object as invalid, also performs + * bookkeeping. +@@ -1261,8 +1262,8 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, + struct ttm_resource *new_mem) + { + struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); +- struct amdgpu_bo *abo; + struct ttm_resource *old_mem = bo->resource; ++ struct amdgpu_bo *abo; + + if (!amdgpu_bo_is_amdgpu_bo(bo)) + return; +@@ -1273,44 +1274,50 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, + amdgpu_bo_kunmap(abo); + + if (abo->tbo.base.dma_buf && !abo->tbo.base.import_attach && +- bo->resource->mem_type != TTM_PL_SYSTEM) ++ old_mem && old_mem->mem_type != TTM_PL_SYSTEM) + dma_buf_move_notify(abo->tbo.base.dma_buf); + +- /* remember the eviction */ +- if (evict) +- atomic64_inc(&adev->num_evictions); +- +- /* update statistics */ +- if (!new_mem) +- return; +- + /* move_notify is called before move happens */ +- trace_amdgpu_bo_move(abo, new_mem->mem_type, old_mem->mem_type); ++ trace_amdgpu_bo_move(abo, new_mem ? new_mem->mem_type : -1, ++ old_mem ? old_mem->mem_type : -1); + } + + void amdgpu_bo_get_memory(struct amdgpu_bo *bo, + struct amdgpu_mem_stats *stats) + { ++ struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); ++ struct ttm_resource *res = bo->tbo.resource; + uint64_t size = amdgpu_bo_size(bo); ++ struct drm_gem_object *obj; + unsigned int domain; ++ bool shared; + + /* Abort if the BO doesn't currently have a backing store */ +- if (!bo->tbo.resource) ++ if (!res) + return; + +- domain = amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type); ++ obj = &bo->tbo.base; ++ shared = drm_gem_object_is_shared_for_memory_stats(obj); ++ ++ domain = amdgpu_mem_type_to_domain(res->mem_type); + switch (domain) { + case AMDGPU_GEM_DOMAIN_VRAM: + stats->vram += size; +- if (amdgpu_bo_in_cpu_visible_vram(bo)) ++ if (amdgpu_res_cpu_visible(adev, bo->tbo.resource)) + stats->visible_vram += size; ++ if (shared) ++ stats->vram_shared += size; + break; + case AMDGPU_GEM_DOMAIN_GTT: + stats->gtt += size; ++ if (shared) ++ stats->gtt_shared += size; + break; + case AMDGPU_GEM_DOMAIN_CPU: + default: + stats->cpu += size; ++ if (shared) ++ stats->cpu_shared += size; + break; + } + +@@ -1395,10 +1402,7 @@ vm_fault_t amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) + /* Remember that this BO was accessed by the CPU */ + abo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; + +- if (bo->resource->mem_type != TTM_PL_VRAM) +- return 0; +- +- if (amdgpu_bo_in_cpu_visible_vram(abo)) ++ if (amdgpu_res_cpu_visible(adev, bo->resource)) + return 0; + + /* Can't move a pinned BO to visible VRAM */ +@@ -1422,7 +1426,7 @@ vm_fault_t amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) + + /* this should never happen */ + if (bo->resource->mem_type == TTM_PL_VRAM && +- !amdgpu_bo_in_cpu_visible_vram(abo)) ++ !amdgpu_res_cpu_visible(adev, bo->resource)) + return VM_FAULT_SIGBUS; + + ttm_bo_move_to_lru_tail_unlocked(bo); +@@ -1582,6 +1586,7 @@ uint32_t amdgpu_bo_get_preferred_domain(struct amdgpu_device *adev, + */ + u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m) + { ++ struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); + struct dma_buf_attachment *attachment; + struct dma_buf *dma_buf; + const char *placement; +@@ -1590,10 +1595,11 @@ u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m) + + if (dma_resv_trylock(bo->tbo.base.resv)) { + unsigned int domain; ++ + domain = amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type); + switch (domain) { + case AMDGPU_GEM_DOMAIN_VRAM: +- if (amdgpu_bo_in_cpu_visible_vram(bo)) ++ if (amdgpu_res_cpu_visible(adev, bo->tbo.resource)) + placement = "VRAM VISIBLE"; + else + placement = "VRAM"; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +index d28e21baef16ee..bc42ccbde659ac 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +@@ -138,12 +138,18 @@ struct amdgpu_bo_vm { + struct amdgpu_mem_stats { + /* current VRAM usage, includes visible VRAM */ + uint64_t vram; ++ /* current shared VRAM usage, includes visible VRAM */ ++ uint64_t vram_shared; + /* current visible VRAM usage */ + uint64_t visible_vram; + /* current GTT usage */ + uint64_t gtt; ++ /* current shared GTT usage */ ++ uint64_t gtt_shared; + /* current system memory usage */ + uint64_t cpu; ++ /* current shared system memory usage */ ++ uint64_t cpu_shared; + /* sum of evicted buffers, includes visible VRAM */ + uint64_t evicted_vram; + /* sum of evicted buffers due to CPU access */ +@@ -244,28 +250,6 @@ static inline u64 amdgpu_bo_mmap_offset(struct amdgpu_bo *bo) + return drm_vma_node_offset_addr(&bo->tbo.base.vma_node); + } + +-/** +- * amdgpu_bo_in_cpu_visible_vram - check if BO is (partly) in visible VRAM +- */ +-static inline bool amdgpu_bo_in_cpu_visible_vram(struct amdgpu_bo *bo) +-{ +- struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); +- struct amdgpu_res_cursor cursor; +- +- if (!bo->tbo.resource || bo->tbo.resource->mem_type != TTM_PL_VRAM) +- return false; +- +- amdgpu_res_first(bo->tbo.resource, 0, amdgpu_bo_size(bo), &cursor); +- while (cursor.remaining) { +- if (cursor.start < adev->gmc.visible_vram_size) +- return true; +- +- amdgpu_res_next(&cursor, cursor.size); +- } +- +- return false; +-} +- + /** + * amdgpu_bo_explicit_sync - return whether the bo is explicitly synced + */ +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +index 429ef212c1f25b..a4f9015345ccb5 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +@@ -1336,6 +1336,9 @@ static void psp_xgmi_reflect_topology_info(struct psp_context *psp, + uint8_t dst_num_links = node_info.num_links; + + hive = amdgpu_get_xgmi_hive(psp->adev); ++ if (WARN_ON(!hive)) ++ return; ++ + list_for_each_entry(mirror_adev, &hive->device_list, gmc.xgmi.head) { + struct psp_xgmi_topology_info *mirror_top_info; + int j; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c +index 468a67b302d4c1..9aff579c6abf54 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c +@@ -166,6 +166,9 @@ static ssize_t ta_if_load_debugfs_write(struct file *fp, const char *buf, size_t + if (ret) + return -EFAULT; + ++ if (ta_bin_len > PSP_1_MEG) ++ return -EINVAL; ++ + copy_pos += sizeof(uint32_t); + + ta_bin = kzalloc(ta_bin_len, GFP_KERNEL); +@@ -334,7 +337,7 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size + + set_ta_context_funcs(psp, ta_type, &context); + +- if (!context->initialized) { ++ if (!context || !context->initialized) { + dev_err(adev->dev, "TA is not initialized\n"); + ret = -EINVAL; + goto err_free_shared_buf; +@@ -362,7 +365,7 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size + } + } + +- if (copy_to_user((char *)buf, context->mem_context.shared_buf, shared_buf_len)) ++ if (copy_to_user((char *)&buf[copy_pos], context->mem_context.shared_buf, shared_buf_len)) + ret = -EFAULT; + + err_free_shared_buf: +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +index 163445baa4fc80..7cba98f8bbdca8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +@@ -1025,6 +1025,9 @@ int amdgpu_ras_query_error_status(struct amdgpu_device *adev, + if (!obj) + return -EINVAL; + ++ if (!info || info->head.block == AMDGPU_RAS_BLOCK_COUNT) ++ return -EINVAL; ++ + if (info->head.block == AMDGPU_RAS_BLOCK__UMC) { + amdgpu_ras_get_ecc_info(adev, &err_data); + } else { +@@ -1373,7 +1376,8 @@ static void amdgpu_ras_sysfs_remove_bad_page_node(struct amdgpu_device *adev) + { + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + +- sysfs_remove_file_from_group(&adev->dev->kobj, ++ if (adev->dev->kobj.sd) ++ sysfs_remove_file_from_group(&adev->dev->kobj, + &con->badpages_attr.attr, + RAS_FS_NAME); + } +@@ -1390,7 +1394,8 @@ static int amdgpu_ras_sysfs_remove_feature_node(struct amdgpu_device *adev) + .attrs = attrs, + }; + +- sysfs_remove_group(&adev->dev->kobj, &group); ++ if (adev->dev->kobj.sd) ++ sysfs_remove_group(&adev->dev->kobj, &group); + + return 0; + } +@@ -1437,7 +1442,8 @@ int amdgpu_ras_sysfs_remove(struct amdgpu_device *adev, + if (!obj || !obj->attr_inuse) + return -EINVAL; + +- sysfs_remove_file_from_group(&adev->dev->kobj, ++ if (adev->dev->kobj.sd) ++ sysfs_remove_file_from_group(&adev->dev->kobj, + &obj->sysfs_attr.attr, + RAS_FS_NAME); + obj->attr_inuse = 0; +@@ -1774,12 +1780,15 @@ static void amdgpu_ras_interrupt_process_handler(struct work_struct *work) + int amdgpu_ras_interrupt_dispatch(struct amdgpu_device *adev, + struct ras_dispatch_if *info) + { +- struct ras_manager *obj = amdgpu_ras_find_obj(adev, &info->head); +- struct ras_ih_data *data = &obj->ih_data; ++ struct ras_manager *obj; ++ struct ras_ih_data *data; + ++ obj = amdgpu_ras_find_obj(adev, &info->head); + if (!obj) + return -EINVAL; + ++ data = &obj->ih_data; ++ + if (data->inuse == 0) + return 0; + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +index 595d5e535aca63..9d82701d365bbe 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +@@ -214,6 +214,12 @@ static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev, + control->i2c_address = EEPROM_I2C_MADDR_0; + return true; + case IP_VERSION(13, 0, 0): ++ if (strnstr(atom_ctx->vbios_pn, "D707", ++ sizeof(atom_ctx->vbios_pn))) ++ control->i2c_address = EEPROM_I2C_MADDR_0; ++ else ++ control->i2c_address = EEPROM_I2C_MADDR_4; ++ return true; + case IP_VERSION(13, 0, 6): + case IP_VERSION(13, 0, 10): + control->i2c_address = EEPROM_I2C_MADDR_4; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +index 80d6e132e4095d..f44b303ae287a7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +@@ -352,7 +352,7 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring, + ring->max_dw = max_dw; + ring->hw_prio = hw_prio; + +- if (!ring->no_scheduler) { ++ if (!ring->no_scheduler && ring->funcs->type < AMDGPU_HW_IP_NUM) { + hw_ip = ring->funcs->type; + num_sched = &adev->gpu_sched[hw_ip][hw_prio].num_scheds; + adev->gpu_sched[hw_ip][hw_prio].sched[(*num_sched)++] = +@@ -469,8 +469,9 @@ static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) + { + struct amdgpu_ring *ring = file_inode(f)->i_private; +- int r, i; + uint32_t value, result, early[3]; ++ loff_t i; ++ int r; + + if (*pos & 3 || size & 3) + return -EINVAL; +@@ -520,46 +521,58 @@ static ssize_t amdgpu_debugfs_mqd_read(struct file *f, char __user *buf, + { + struct amdgpu_ring *ring = file_inode(f)->i_private; + volatile u32 *mqd; +- int r; ++ u32 *kbuf; ++ int r, i; + uint32_t value, result; + + if (*pos & 3 || size & 3) + return -EINVAL; + +- result = 0; ++ kbuf = kmalloc(ring->mqd_size, GFP_KERNEL); ++ if (!kbuf) ++ return -ENOMEM; + + r = amdgpu_bo_reserve(ring->mqd_obj, false); + if (unlikely(r != 0)) +- return r; ++ goto err_free; + + r = amdgpu_bo_kmap(ring->mqd_obj, (void **)&mqd); +- if (r) { +- amdgpu_bo_unreserve(ring->mqd_obj); +- return r; +- } ++ if (r) ++ goto err_unreserve; ++ ++ /* ++ * Copy to local buffer to avoid put_user(), which might fault ++ * and acquire mmap_sem, under reservation_ww_class_mutex. ++ */ ++ for (i = 0; i < ring->mqd_size/sizeof(u32); i++) ++ kbuf[i] = mqd[i]; + ++ amdgpu_bo_kunmap(ring->mqd_obj); ++ amdgpu_bo_unreserve(ring->mqd_obj); ++ ++ result = 0; + while (size) { + if (*pos >= ring->mqd_size) +- goto done; ++ break; + +- value = mqd[*pos/4]; ++ value = kbuf[*pos/4]; + r = put_user(value, (uint32_t *)buf); + if (r) +- goto done; ++ goto err_free; + buf += 4; + result += 4; + size -= 4; + *pos += 4; + } + +-done: +- amdgpu_bo_kunmap(ring->mqd_obj); +- mqd = NULL; +- amdgpu_bo_unreserve(ring->mqd_obj); +- if (r) +- return r; +- ++ kfree(kbuf); + return result; ++ ++err_unreserve: ++ amdgpu_bo_unreserve(ring->mqd_obj); ++err_free: ++ kfree(kbuf); ++ return r; + } + + static const struct file_operations amdgpu_debugfs_mqd_fops = { +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c +index 8ed0e073656f88..41ebe690eeffa7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c +@@ -135,6 +135,10 @@ static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __u + mutex_unlock(&psp->securedisplay_context.mutex); + break; + case 2: ++ if (size < 3 || phy_id >= TA_SECUREDISPLAY_MAX_PHY) { ++ dev_err(adev->dev, "Invalid input: %s\n", str); ++ return -EINVAL; ++ } + mutex_lock(&psp->securedisplay_context.mutex); + psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd, + TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +index dcd8c066bc1f50..1b013a44ca99af 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +@@ -191,7 +191,8 @@ static bool amdgpu_sync_test_fence(struct amdgpu_device *adev, + + /* Never sync to VM updates either. */ + if (fence_owner == AMDGPU_FENCE_OWNER_VM && +- owner != AMDGPU_FENCE_OWNER_UNDEFINED) ++ owner != AMDGPU_FENCE_OWNER_UNDEFINED && ++ owner != AMDGPU_FENCE_OWNER_KFD) + return false; + + /* Ignore fences depending on the sync mode */ +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +index 4e51dce3aab5d6..8c3fb1562ffef9 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +@@ -137,7 +137,7 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo, + amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU); + } else if (!amdgpu_gmc_vram_full_visible(&adev->gmc) && + !(abo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) && +- amdgpu_bo_in_cpu_visible_vram(abo)) { ++ amdgpu_res_cpu_visible(adev, bo->resource)) { + + /* Try evicting to the CPU inaccessible part of VRAM + * first, but only set GTT as busy placement, so this +@@ -408,40 +408,55 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo, + return r; + } + +-/* +- * amdgpu_mem_visible - Check that memory can be accessed by ttm_bo_move_memcpy ++/** ++ * amdgpu_res_cpu_visible - Check that resource can be accessed by CPU ++ * @adev: amdgpu device ++ * @res: the resource to check + * +- * Called by amdgpu_bo_move() ++ * Returns: true if the full resource is CPU visible, false otherwise. + */ +-static bool amdgpu_mem_visible(struct amdgpu_device *adev, +- struct ttm_resource *mem) ++bool amdgpu_res_cpu_visible(struct amdgpu_device *adev, ++ struct ttm_resource *res) + { +- u64 mem_size = (u64)mem->size; + struct amdgpu_res_cursor cursor; +- u64 end; + +- if (mem->mem_type == TTM_PL_SYSTEM || +- mem->mem_type == TTM_PL_TT) ++ if (!res) ++ return false; ++ ++ if (res->mem_type == TTM_PL_SYSTEM || res->mem_type == TTM_PL_TT || ++ res->mem_type == AMDGPU_PL_PREEMPT || res->mem_type == AMDGPU_PL_DOORBELL) + return true; +- if (mem->mem_type != TTM_PL_VRAM) ++ ++ if (res->mem_type != TTM_PL_VRAM) + return false; + +- amdgpu_res_first(mem, 0, mem_size, &cursor); +- end = cursor.start + cursor.size; ++ amdgpu_res_first(res, 0, res->size, &cursor); + while (cursor.remaining) { ++ if ((cursor.start + cursor.size) > adev->gmc.visible_vram_size) ++ return false; + amdgpu_res_next(&cursor, cursor.size); ++ } + +- if (!cursor.remaining) +- break; ++ return true; ++} + +- /* ttm_resource_ioremap only supports contiguous memory */ +- if (end != cursor.start) +- return false; ++/* ++ * amdgpu_res_copyable - Check that memory can be accessed by ttm_bo_move_memcpy ++ * ++ * Called by amdgpu_bo_move() ++ */ ++static bool amdgpu_res_copyable(struct amdgpu_device *adev, ++ struct ttm_resource *mem) ++{ ++ if (!amdgpu_res_cpu_visible(adev, mem)) ++ return false; + +- end = cursor.start + cursor.size; +- } ++ /* ttm_resource_ioremap only supports contiguous memory */ ++ if (mem->mem_type == TTM_PL_VRAM && ++ !(mem->placement & TTM_PL_FLAG_CONTIGUOUS)) ++ return false; + +- return end <= adev->gmc.visible_vram_size; ++ return true; + } + + /* +@@ -471,14 +486,16 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict, + + if (!old_mem || (old_mem->mem_type == TTM_PL_SYSTEM && + bo->ttm == NULL)) { ++ amdgpu_bo_move_notify(bo, evict, new_mem); + ttm_bo_move_null(bo, new_mem); +- goto out; ++ return 0; + } + if (old_mem->mem_type == TTM_PL_SYSTEM && + (new_mem->mem_type == TTM_PL_TT || + new_mem->mem_type == AMDGPU_PL_PREEMPT)) { ++ amdgpu_bo_move_notify(bo, evict, new_mem); + ttm_bo_move_null(bo, new_mem); +- goto out; ++ return 0; + } + if ((old_mem->mem_type == TTM_PL_TT || + old_mem->mem_type == AMDGPU_PL_PREEMPT) && +@@ -488,9 +505,10 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict, + return r; + + amdgpu_ttm_backend_unbind(bo->bdev, bo->ttm); ++ amdgpu_bo_move_notify(bo, evict, new_mem); + ttm_resource_free(bo, &bo->resource); + ttm_bo_assign_mem(bo, new_mem); +- goto out; ++ return 0; + } + + if (old_mem->mem_type == AMDGPU_PL_GDS || +@@ -502,8 +520,9 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict, + new_mem->mem_type == AMDGPU_PL_OA || + new_mem->mem_type == AMDGPU_PL_DOORBELL) { + /* Nothing to save here */ ++ amdgpu_bo_move_notify(bo, evict, new_mem); + ttm_bo_move_null(bo, new_mem); +- goto out; ++ return 0; + } + + if (bo->type == ttm_bo_type_device && +@@ -515,27 +534,28 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict, + abo->flags &= ~AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; + } + +- if (adev->mman.buffer_funcs_enabled) { +- if (((old_mem->mem_type == TTM_PL_SYSTEM && +- new_mem->mem_type == TTM_PL_VRAM) || +- (old_mem->mem_type == TTM_PL_VRAM && +- new_mem->mem_type == TTM_PL_SYSTEM))) { +- hop->fpfn = 0; +- hop->lpfn = 0; +- hop->mem_type = TTM_PL_TT; +- hop->flags = TTM_PL_FLAG_TEMPORARY; +- return -EMULTIHOP; +- } ++ if (adev->mman.buffer_funcs_enabled && ++ ((old_mem->mem_type == TTM_PL_SYSTEM && ++ new_mem->mem_type == TTM_PL_VRAM) || ++ (old_mem->mem_type == TTM_PL_VRAM && ++ new_mem->mem_type == TTM_PL_SYSTEM))) { ++ hop->fpfn = 0; ++ hop->lpfn = 0; ++ hop->mem_type = TTM_PL_TT; ++ hop->flags = TTM_PL_FLAG_TEMPORARY; ++ return -EMULTIHOP; ++ } + ++ amdgpu_bo_move_notify(bo, evict, new_mem); ++ if (adev->mman.buffer_funcs_enabled) + r = amdgpu_move_blit(bo, evict, new_mem, old_mem); +- } else { ++ else + r = -ENODEV; +- } + + if (r) { + /* Check that all memory is CPU accessible */ +- if (!amdgpu_mem_visible(adev, old_mem) || +- !amdgpu_mem_visible(adev, new_mem)) { ++ if (!amdgpu_res_copyable(adev, old_mem) || ++ !amdgpu_res_copyable(adev, new_mem)) { + pr_err("Move buffer fallback to memcpy unavailable\n"); + return r; + } +@@ -545,10 +565,10 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict, + return r; + } + +-out: +- /* update statistics */ ++ /* update statistics after the move */ ++ if (evict) ++ atomic64_inc(&adev->num_evictions); + atomic64_add(bo->base.size, &adev->num_bytes_moved); +- amdgpu_bo_move_notify(bo, evict, new_mem); + return 0; + } + +@@ -561,7 +581,6 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_device *bdev, + struct ttm_resource *mem) + { + struct amdgpu_device *adev = amdgpu_ttm_adev(bdev); +- size_t bus_size = (size_t)mem->size; + + switch (mem->mem_type) { + case TTM_PL_SYSTEM: +@@ -572,9 +591,6 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_device *bdev, + break; + case TTM_PL_VRAM: + mem->bus.offset = mem->start << PAGE_SHIFT; +- /* check if it's visible */ +- if ((mem->bus.offset + bus_size) > adev->gmc.visible_vram_size) +- return -EINVAL; + + if (adev->mman.aper_base_kaddr && + mem->placement & TTM_PL_FLAG_CONTIGUOUS) +@@ -868,6 +884,7 @@ static void amdgpu_ttm_gart_bind(struct amdgpu_device *adev, + amdgpu_gart_bind(adev, gtt->offset, ttm->num_pages, + gtt->ttm.dma_address, flags); + } ++ gtt->bound = true; + } + + /* +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +index 65ec82141a8e01..32cf6b6f6efd96 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +@@ -139,6 +139,9 @@ int amdgpu_vram_mgr_reserve_range(struct amdgpu_vram_mgr *mgr, + int amdgpu_vram_mgr_query_page_status(struct amdgpu_vram_mgr *mgr, + uint64_t start); + ++bool amdgpu_res_cpu_visible(struct amdgpu_device *adev, ++ struct ttm_resource *res); ++ + int amdgpu_ttm_init(struct amdgpu_device *adev); + void amdgpu_ttm_fini(struct amdgpu_device *adev); + void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c +index 8beefc045e1451..bef7541770641c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c +@@ -1326,9 +1326,13 @@ int amdgpu_ucode_request(struct amdgpu_device *adev, const struct firmware **fw, + + if (err) + return -ENODEV; ++ + err = amdgpu_ucode_validate(*fw); +- if (err) ++ if (err) { + dev_dbg(adev->dev, "\"%s\" failed to validate\n", fw_name); ++ release_firmware(*fw); ++ *fw = NULL; ++ } + + return err; + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +index 1904edf6840716..88a3aa36b41d77 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +@@ -742,7 +742,8 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, + uint32_t created = 0; + uint32_t allocated = 0; + uint32_t tmp, handle = 0; +- uint32_t *size = &tmp; ++ uint32_t dummy = 0xffffffff; ++ uint32_t *size = &dummy; + unsigned int idx; + int i, r = 0; + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +index 36b55d2bd51a91..111350ef1b742a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +@@ -135,6 +135,10 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev) + } + } + ++ /* from vcn4 and above, only unified queue is used */ ++ adev->vcn.using_unified_queue = ++ adev->ip_versions[UVD_HWIP][0] >= IP_VERSION(4, 0, 0); ++ + hdr = (const struct common_firmware_header *)adev->vcn.fw->data; + adev->vcn.fw_version = le32_to_cpu(hdr->ucode_version); + +@@ -259,18 +263,6 @@ int amdgpu_vcn_sw_fini(struct amdgpu_device *adev) + return 0; + } + +-/* from vcn4 and above, only unified queue is used */ +-static bool amdgpu_vcn_using_unified_queue(struct amdgpu_ring *ring) +-{ +- struct amdgpu_device *adev = ring->adev; +- bool ret = false; +- +- if (adev->ip_versions[UVD_HWIP][0] >= IP_VERSION(4, 0, 0)) +- ret = true; +- +- return ret; +-} +- + bool amdgpu_vcn_is_disabled_vcn(struct amdgpu_device *adev, enum vcn_ring_type type, uint32_t vcn_instance) + { + bool ret = false; +@@ -292,8 +284,15 @@ int amdgpu_vcn_suspend(struct amdgpu_device *adev) + void *ptr; + int i, idx; + ++ bool in_ras_intr = amdgpu_ras_intr_triggered(); ++ + cancel_delayed_work_sync(&adev->vcn.idle_work); + ++ /* err_event_athub will corrupt VCPU buffer, so we need to ++ * restore fw data and clear buffer in amdgpu_vcn_resume() */ ++ if (in_ras_intr) ++ return 0; ++ + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { + if (adev->vcn.harvest_config & (1 << i)) + continue; +@@ -373,7 +372,9 @@ static void amdgpu_vcn_idle_work_handler(struct work_struct *work) + for (i = 0; i < adev->vcn.num_enc_rings; ++i) + fence[j] += amdgpu_fence_count_emitted(&adev->vcn.inst[j].ring_enc[i]); + +- if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) { ++ /* Only set DPG pause for VCN3 or below, VCN4 and above will be handled by FW */ ++ if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG && ++ !adev->vcn.using_unified_queue) { + struct dpg_pause_state new_state; + + if (fence[j] || +@@ -419,7 +420,9 @@ void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring) + amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN, + AMD_PG_STATE_UNGATE); + +- if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) { ++ /* Only set DPG pause for VCN3 or below, VCN4 and above will be handled by FW */ ++ if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG && ++ !adev->vcn.using_unified_queue) { + struct dpg_pause_state new_state; + + if (ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC) { +@@ -445,8 +448,12 @@ void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring) + + void amdgpu_vcn_ring_end_use(struct amdgpu_ring *ring) + { ++ struct amdgpu_device *adev = ring->adev; ++ ++ /* Only set DPG pause for VCN3 or below, VCN4 and above will be handled by FW */ + if (ring->adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG && +- ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC) ++ ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC && ++ !adev->vcn.using_unified_queue) + atomic_dec(&ring->adev->vcn.inst[ring->me].dpg_enc_submission_cnt); + + atomic_dec(&ring->adev->vcn.total_submission_cnt); +@@ -700,12 +707,11 @@ static int amdgpu_vcn_dec_sw_send_msg(struct amdgpu_ring *ring, + struct amdgpu_job *job; + struct amdgpu_ib *ib; + uint64_t addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr); +- bool sq = amdgpu_vcn_using_unified_queue(ring); + uint32_t *ib_checksum; + uint32_t ib_pack_in_dw; + int i, r; + +- if (sq) ++ if (adev->vcn.using_unified_queue) + ib_size_dw += 8; + + r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, +@@ -718,7 +724,7 @@ static int amdgpu_vcn_dec_sw_send_msg(struct amdgpu_ring *ring, + ib->length_dw = 0; + + /* single queue headers */ +- if (sq) { ++ if (adev->vcn.using_unified_queue) { + ib_pack_in_dw = sizeof(struct amdgpu_vcn_decode_buffer) / sizeof(uint32_t) + + 4 + 2; /* engine info + decoding ib in dw */ + ib_checksum = amdgpu_vcn_unified_ring_ib_header(ib, ib_pack_in_dw, false); +@@ -737,7 +743,7 @@ static int amdgpu_vcn_dec_sw_send_msg(struct amdgpu_ring *ring, + for (i = ib->length_dw; i < ib_size_dw; ++i) + ib->ptr[i] = 0x0; + +- if (sq) ++ if (adev->vcn.using_unified_queue) + amdgpu_vcn_unified_ring_ib_checksum(&ib_checksum, ib_pack_in_dw); + + r = amdgpu_job_submit_direct(job, ring, &f); +@@ -827,15 +833,15 @@ static int amdgpu_vcn_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t hand + struct dma_fence **fence) + { + unsigned int ib_size_dw = 16; ++ struct amdgpu_device *adev = ring->adev; + struct amdgpu_job *job; + struct amdgpu_ib *ib; + struct dma_fence *f = NULL; + uint32_t *ib_checksum = NULL; + uint64_t addr; +- bool sq = amdgpu_vcn_using_unified_queue(ring); + int i, r; + +- if (sq) ++ if (adev->vcn.using_unified_queue) + ib_size_dw += 8; + + r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, +@@ -849,7 +855,7 @@ static int amdgpu_vcn_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t hand + + ib->length_dw = 0; + +- if (sq) ++ if (adev->vcn.using_unified_queue) + ib_checksum = amdgpu_vcn_unified_ring_ib_header(ib, 0x11, true); + + ib->ptr[ib->length_dw++] = 0x00000018; +@@ -871,7 +877,7 @@ static int amdgpu_vcn_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t hand + for (i = ib->length_dw; i < ib_size_dw; ++i) + ib->ptr[i] = 0x0; + +- if (sq) ++ if (adev->vcn.using_unified_queue) + amdgpu_vcn_unified_ring_ib_checksum(&ib_checksum, 0x11); + + r = amdgpu_job_submit_direct(job, ring, &f); +@@ -894,15 +900,15 @@ static int amdgpu_vcn_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t han + struct dma_fence **fence) + { + unsigned int ib_size_dw = 16; ++ struct amdgpu_device *adev = ring->adev; + struct amdgpu_job *job; + struct amdgpu_ib *ib; + struct dma_fence *f = NULL; + uint32_t *ib_checksum = NULL; + uint64_t addr; +- bool sq = amdgpu_vcn_using_unified_queue(ring); + int i, r; + +- if (sq) ++ if (adev->vcn.using_unified_queue) + ib_size_dw += 8; + + r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, +@@ -916,7 +922,7 @@ static int amdgpu_vcn_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t han + + ib->length_dw = 0; + +- if (sq) ++ if (adev->vcn.using_unified_queue) + ib_checksum = amdgpu_vcn_unified_ring_ib_header(ib, 0x11, true); + + ib->ptr[ib->length_dw++] = 0x00000018; +@@ -938,7 +944,7 @@ static int amdgpu_vcn_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t han + for (i = ib->length_dw; i < ib_size_dw; ++i) + ib->ptr[i] = 0x0; + +- if (sq) ++ if (adev->vcn.using_unified_queue) + amdgpu_vcn_unified_ring_ib_checksum(&ib_checksum, 0x11); + + r = amdgpu_job_submit_direct(job, ring, &f); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +index a3eed90b6af090..3dc2cffdae4fca 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +@@ -284,6 +284,7 @@ struct amdgpu_vcn { + + uint16_t inst_mask; + uint8_t num_inst_per_aid; ++ bool using_unified_queue; + }; + + struct amdgpu_fw_shared_rb_ptrs_struct { +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +index 96857ae7fb5bc6..22575422ca7ec1 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +@@ -137,8 +137,10 @@ int amdgpu_virt_request_full_gpu(struct amdgpu_device *adev, bool init) + + if (virt->ops && virt->ops->req_full_gpu) { + r = virt->ops->req_full_gpu(adev, init); +- if (r) ++ if (r) { ++ adev->no_hw_access = true; + return r; ++ } + + adev->virt.caps &= ~AMDGPU_SRIOV_CAPS_RUNTIME; + } +@@ -615,7 +617,7 @@ static int amdgpu_virt_write_vf2pf_data(struct amdgpu_device *adev) + vf2pf_info->dummy_page_addr = (uint64_t)adev->dummy_page_addr; + vf2pf_info->checksum = + amd_sriov_msg_checksum( +- vf2pf_info, vf2pf_info->header.size, 0, 0); ++ vf2pf_info, sizeof(*vf2pf_info), 0, 0); + + return 0; + } +@@ -998,11 +1000,17 @@ static u32 amdgpu_virt_rlcg_reg_rw(struct amdgpu_device *adev, u32 offset, u32 v + return 0; + } + ++ if (amdgpu_device_skip_hw_access(adev)) ++ return 0; ++ + reg_access_ctrl = &adev->gfx.rlc.reg_access_ctrl[xcc_id]; + scratch_reg0 = (void __iomem *)adev->rmmio + 4 * reg_access_ctrl->scratch_reg0; + scratch_reg1 = (void __iomem *)adev->rmmio + 4 * reg_access_ctrl->scratch_reg1; + scratch_reg2 = (void __iomem *)adev->rmmio + 4 * reg_access_ctrl->scratch_reg2; + scratch_reg3 = (void __iomem *)adev->rmmio + 4 * reg_access_ctrl->scratch_reg3; ++ ++ mutex_lock(&adev->virt.rlcg_reg_lock); ++ + if (reg_access_ctrl->spare_int) + spare_int = (void __iomem *)adev->rmmio + 4 * reg_access_ctrl->spare_int; + +@@ -1058,6 +1066,9 @@ static u32 amdgpu_virt_rlcg_reg_rw(struct amdgpu_device *adev, u32 offset, u32 v + } + + ret = readl(scratch_reg0); ++ ++ mutex_unlock(&adev->virt.rlcg_reg_lock); ++ + return ret; + } + +@@ -1067,6 +1078,9 @@ void amdgpu_sriov_wreg(struct amdgpu_device *adev, + { + u32 rlcg_flag; + ++ if (amdgpu_device_skip_hw_access(adev)) ++ return; ++ + if (!amdgpu_sriov_runtime(adev) && + amdgpu_virt_get_rlcg_reg_access_flag(adev, acc_flags, hwip, true, &rlcg_flag)) { + amdgpu_virt_rlcg_reg_rw(adev, offset, value, rlcg_flag, xcc_id); +@@ -1084,6 +1098,9 @@ u32 amdgpu_sriov_rreg(struct amdgpu_device *adev, + { + u32 rlcg_flag; + ++ if (amdgpu_device_skip_hw_access(adev)) ++ return 0; ++ + if (!amdgpu_sriov_runtime(adev) && + amdgpu_virt_get_rlcg_reg_access_flag(adev, acc_flags, hwip, false, &rlcg_flag)) + return amdgpu_virt_rlcg_reg_rw(adev, offset, 0, rlcg_flag, xcc_id); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +index fabb83e9d9aec7..23b6efa9d25df8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +@@ -263,6 +263,8 @@ struct amdgpu_virt { + + /* the ucode id to signal the autoload */ + uint32_t autoload_ucode_id; ++ ++ struct mutex rlcg_reg_lock; + }; + + struct amdgpu_video_codec_info; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c +index 7148a216ae2fe4..f417c3393a0904 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c +@@ -2,6 +2,7 @@ + + #include + #include ++#include + #include + + #include "amdgpu.h" +@@ -239,6 +240,8 @@ static int amdgpu_vkms_conn_get_modes(struct drm_connector *connector) + + for (i = 0; i < ARRAY_SIZE(common_modes); i++) { + mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false); ++ if (!mode) ++ continue; + drm_mode_probed_add(connector, mode); + } + +@@ -311,7 +314,13 @@ static int amdgpu_vkms_prepare_fb(struct drm_plane *plane, + return 0; + } + afb = to_amdgpu_framebuffer(new_state->fb); +- obj = new_state->fb->obj[0]; ++ ++ obj = drm_gem_fb_get_obj(new_state->fb, 0); ++ if (!obj) { ++ DRM_ERROR("Failed to get obj from framebuffer\n"); ++ return -EINVAL; ++ } ++ + rbo = gem_to_amdgpu_bo(obj); + adev = amdgpu_ttm_adev(rbo->tbo.bdev); + +@@ -365,12 +374,19 @@ static void amdgpu_vkms_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state) + { + struct amdgpu_bo *rbo; ++ struct drm_gem_object *obj; + int r; + + if (!old_state->fb) + return; + +- rbo = gem_to_amdgpu_bo(old_state->fb->obj[0]); ++ obj = drm_gem_fb_get_obj(old_state->fb, 0); ++ if (!obj) { ++ DRM_ERROR("Failed to get obj from framebuffer\n"); ++ return; ++ } ++ ++ rbo = gem_to_amdgpu_bo(obj); + r = amdgpu_bo_reserve(rbo, false); + if (unlikely(r)) { + DRM_ERROR("failed to reserve rbo before unpin\n"); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +index 82f25996ff5ef6..f02b6232680f33 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +@@ -285,6 +285,7 @@ static void amdgpu_vm_bo_reset_state_machine(struct amdgpu_vm *vm) + list_for_each_entry_safe(vm_bo, tmp, &vm->idle, vm_status) { + struct amdgpu_bo *bo = vm_bo->bo; + ++ vm_bo->moved = true; + if (!bo || bo->tbo.type != ttm_bo_type_kernel) + list_move(&vm_bo->vm_status, &vm_bo->vm->moved); + else if (bo->parent) +@@ -417,7 +418,7 @@ uint64_t amdgpu_vm_generation(struct amdgpu_device *adev, struct amdgpu_vm *vm) + if (!vm) + return result; + +- result += vm->generation; ++ result += lower_32_bits(vm->generation); + /* Add one if the page tables will be re-generated on next CS */ + if (drm_sched_entity_error(&vm->delayed)) + ++result; +@@ -442,13 +443,14 @@ int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm, + int (*validate)(void *p, struct amdgpu_bo *bo), + void *param) + { ++ uint64_t new_vm_generation = amdgpu_vm_generation(adev, vm); + struct amdgpu_vm_bo_base *bo_base; + struct amdgpu_bo *shadow; + struct amdgpu_bo *bo; + int r; + +- if (drm_sched_entity_error(&vm->delayed)) { +- ++vm->generation; ++ if (vm->generation != new_vm_generation) { ++ vm->generation = new_vm_generation; + amdgpu_vm_bo_reset_state_machine(vm); + amdgpu_vm_fini_entities(vm); + r = amdgpu_vm_init_entities(adev, vm); +@@ -1095,8 +1097,8 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, + bo = gem_to_amdgpu_bo(gobj); + } + mem = bo->tbo.resource; +- if (mem->mem_type == TTM_PL_TT || +- mem->mem_type == AMDGPU_PL_PREEMPT) ++ if (mem && (mem->mem_type == TTM_PL_TT || ++ mem->mem_type == AMDGPU_PL_PREEMPT)) + pages_addr = bo->tbo.ttm->dma_address; + } + +@@ -1499,6 +1501,37 @@ static void amdgpu_vm_bo_insert_map(struct amdgpu_device *adev, + trace_amdgpu_vm_bo_map(bo_va, mapping); + } + ++/* Validate operation parameters to prevent potential abuse */ ++static int amdgpu_vm_verify_parameters(struct amdgpu_device *adev, ++ struct amdgpu_bo *bo, ++ uint64_t saddr, ++ uint64_t offset, ++ uint64_t size) ++{ ++ uint64_t tmp, lpfn; ++ ++ if (saddr & AMDGPU_GPU_PAGE_MASK ++ || offset & AMDGPU_GPU_PAGE_MASK ++ || size & AMDGPU_GPU_PAGE_MASK) ++ return -EINVAL; ++ ++ if (check_add_overflow(saddr, size, &tmp) ++ || check_add_overflow(offset, size, &tmp) ++ || size == 0 /* which also leads to end < begin */) ++ return -EINVAL; ++ ++ /* make sure object fit at this offset */ ++ if (bo && offset + size > amdgpu_bo_size(bo)) ++ return -EINVAL; ++ ++ /* Ensure last pfn not exceed max_pfn */ ++ lpfn = (saddr + size - 1) >> AMDGPU_GPU_PAGE_SHIFT; ++ if (lpfn >= adev->vm_manager.max_pfn) ++ return -EINVAL; ++ ++ return 0; ++} ++ + /** + * amdgpu_vm_bo_map - map bo inside a vm + * +@@ -1525,21 +1558,14 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, + struct amdgpu_bo *bo = bo_va->base.bo; + struct amdgpu_vm *vm = bo_va->base.vm; + uint64_t eaddr; ++ int r; + +- /* validate the parameters */ +- if (saddr & ~PAGE_MASK || offset & ~PAGE_MASK || size & ~PAGE_MASK) +- return -EINVAL; +- if (saddr + size <= saddr || offset + size <= offset) +- return -EINVAL; +- +- /* make sure object fit at this offset */ +- eaddr = saddr + size - 1; +- if ((bo && offset + size > amdgpu_bo_size(bo)) || +- (eaddr >= adev->vm_manager.max_pfn << AMDGPU_GPU_PAGE_SHIFT)) +- return -EINVAL; ++ r = amdgpu_vm_verify_parameters(adev, bo, saddr, offset, size); ++ if (r) ++ return r; + + saddr /= AMDGPU_GPU_PAGE_SIZE; +- eaddr /= AMDGPU_GPU_PAGE_SIZE; ++ eaddr = saddr + (size - 1) / AMDGPU_GPU_PAGE_SIZE; + + tmp = amdgpu_vm_it_iter_first(&vm->va, saddr, eaddr); + if (tmp) { +@@ -1592,17 +1618,9 @@ int amdgpu_vm_bo_replace_map(struct amdgpu_device *adev, + uint64_t eaddr; + int r; + +- /* validate the parameters */ +- if (saddr & ~PAGE_MASK || offset & ~PAGE_MASK || size & ~PAGE_MASK) +- return -EINVAL; +- if (saddr + size <= saddr || offset + size <= offset) +- return -EINVAL; +- +- /* make sure object fit at this offset */ +- eaddr = saddr + size - 1; +- if ((bo && offset + size > amdgpu_bo_size(bo)) || +- (eaddr >= adev->vm_manager.max_pfn << AMDGPU_GPU_PAGE_SHIFT)) +- return -EINVAL; ++ r = amdgpu_vm_verify_parameters(adev, bo, saddr, offset, size); ++ if (r) ++ return r; + + /* Allocate all the needed memory */ + mapping = kmalloc(sizeof(*mapping), GFP_KERNEL); +@@ -1616,7 +1634,7 @@ int amdgpu_vm_bo_replace_map(struct amdgpu_device *adev, + } + + saddr /= AMDGPU_GPU_PAGE_SIZE; +- eaddr /= AMDGPU_GPU_PAGE_SIZE; ++ eaddr = saddr + (size - 1) / AMDGPU_GPU_PAGE_SIZE; + + mapping->start = saddr; + mapping->last = eaddr; +@@ -1703,10 +1721,14 @@ int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev, + struct amdgpu_bo_va_mapping *before, *after, *tmp, *next; + LIST_HEAD(removed); + uint64_t eaddr; ++ int r; ++ ++ r = amdgpu_vm_verify_parameters(adev, NULL, saddr, 0, size); ++ if (r) ++ return r; + +- eaddr = saddr + size - 1; + saddr /= AMDGPU_GPU_PAGE_SIZE; +- eaddr /= AMDGPU_GPU_PAGE_SIZE; ++ eaddr = saddr + (size - 1) / AMDGPU_GPU_PAGE_SIZE; + + /* Allocate all the needed memory */ + before = kzalloc(sizeof(*before), GFP_KERNEL); +@@ -2125,7 +2147,8 @@ long amdgpu_vm_wait_idle(struct amdgpu_vm *vm, long timeout) + * Returns: + * 0 for success, error for failure. + */ +-int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, int32_t xcp_id) ++int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, ++ int32_t xcp_id) + { + struct amdgpu_bo *root_bo; + struct amdgpu_bo_vm *root; +@@ -2144,6 +2167,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, int32_t xcp + INIT_LIST_HEAD(&vm->done); + INIT_LIST_HEAD(&vm->pt_freed); + INIT_WORK(&vm->pt_free_work, amdgpu_vm_pt_free_work); ++ INIT_KFIFO(vm->faults); + + r = amdgpu_vm_init_entities(adev, vm); + if (r) +@@ -2169,7 +2193,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, int32_t xcp + vm->last_update = dma_fence_get_stub(); + vm->last_unlocked = dma_fence_get_stub(); + vm->last_tlb_flush = dma_fence_get_stub(); +- vm->generation = 0; ++ vm->generation = amdgpu_vm_generation(adev, NULL); + + mutex_init(&vm->eviction_lock); + vm->evicting = false; +@@ -2178,34 +2202,33 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, int32_t xcp + false, &root, xcp_id); + if (r) + goto error_free_delayed; +- root_bo = &root->bo; ++ ++ root_bo = amdgpu_bo_ref(&root->bo); + r = amdgpu_bo_reserve(root_bo, true); +- if (r) +- goto error_free_root; ++ if (r) { ++ amdgpu_bo_unref(&root->shadow); ++ amdgpu_bo_unref(&root_bo); ++ goto error_free_delayed; ++ } + ++ amdgpu_vm_bo_base_init(&vm->root, vm, root_bo); + r = dma_resv_reserve_fences(root_bo->tbo.base.resv, 1); + if (r) +- goto error_unreserve; +- +- amdgpu_vm_bo_base_init(&vm->root, vm, root_bo); ++ goto error_free_root; + + r = amdgpu_vm_pt_clear(adev, vm, root, false); + if (r) +- goto error_unreserve; ++ goto error_free_root; + + amdgpu_bo_unreserve(vm->root.bo); +- +- INIT_KFIFO(vm->faults); ++ amdgpu_bo_unref(&root_bo); + + return 0; + +-error_unreserve: +- amdgpu_bo_unreserve(vm->root.bo); +- + error_free_root: +- amdgpu_bo_unref(&root->shadow); ++ amdgpu_vm_pt_free_root(adev, vm); ++ amdgpu_bo_unreserve(vm->root.bo); + amdgpu_bo_unref(&root_bo); +- vm->root.bo = NULL; + + error_free_delayed: + dma_fence_put(vm->last_tlb_flush); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c +index 96d601e209b8bd..026a3db9472983 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c +@@ -642,13 +642,14 @@ static void amdgpu_vm_pt_free(struct amdgpu_vm_bo_base *entry) + + if (!entry->bo) + return; ++ ++ entry->bo->vm_bo = NULL; + shadow = amdgpu_bo_shadowed(entry->bo); + if (shadow) { + ttm_bo_set_bulk_move(&shadow->tbo, NULL); + amdgpu_bo_unref(&shadow); + } + ttm_bo_set_bulk_move(&entry->bo->tbo, NULL); +- entry->bo->vm_bo = NULL; + + spin_lock(&entry->vm->status_lock); + list_del(&entry->vm_status); +@@ -765,11 +766,15 @@ int amdgpu_vm_pde_update(struct amdgpu_vm_update_params *params, + struct amdgpu_vm_bo_base *entry) + { + struct amdgpu_vm_bo_base *parent = amdgpu_vm_pt_parent(entry); +- struct amdgpu_bo *bo = parent->bo, *pbo; ++ struct amdgpu_bo *bo, *pbo; + struct amdgpu_vm *vm = params->vm; + uint64_t pde, pt, flags; + unsigned int level; + ++ if (WARN_ON(!parent)) ++ return -EINVAL; ++ ++ bo = parent->bo; + for (level = 0, pbo = bo->parent; pbo; ++level) + pbo = pbo->parent; + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c +index 349416e176a127..1cf1498204678b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c +@@ -102,6 +102,11 @@ static int amdgpu_vm_sdma_prepare(struct amdgpu_vm_update_params *p, + if (!r) + r = amdgpu_sync_push_to_job(&sync, p->job); + amdgpu_sync_free(&sync); ++ ++ if (r) { ++ p->num_dw_left = 0; ++ amdgpu_job_free(p->job); ++ } + return r; + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h +index 9a1036aeec2a0b..9142238e7791a5 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h +@@ -179,6 +179,6 @@ amdgpu_get_next_xcp(struct amdgpu_xcp_mgr *xcp_mgr, int *from) + + #define for_each_xcp(xcp_mgr, xcp, i) \ + for (i = 0, xcp = amdgpu_get_next_xcp(xcp_mgr, &i); xcp; \ +- xcp = amdgpu_get_next_xcp(xcp_mgr, &i)) ++ ++i, xcp = amdgpu_get_next_xcp(xcp_mgr, &i)) + + #endif +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h +index 104a5ad8397da7..198687545407e9 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h +@@ -209,7 +209,7 @@ struct amd_sriov_msg_pf2vf_info { + uint32_t pcie_atomic_ops_support_flags; + /* reserved */ + uint32_t reserved[256 - AMD_SRIOV_MSG_PF2VF_INFO_FILLED_SIZE]; +-}; ++} __packed; + + struct amd_sriov_msg_vf2pf_info_header { + /* the total structure size in byte */ +@@ -267,7 +267,7 @@ struct amd_sriov_msg_vf2pf_info { + + /* reserved */ + uint32_t reserved[256 - AMD_SRIOV_MSG_VF2PF_INFO_FILLED_SIZE]; +-}; ++} __packed; + + /* mailbox message send from guest to host */ + enum amd_sriov_mailbox_request_message { +diff --git a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c +index d0fc62784e8217..6c6f9d9b5d8978 100644 +--- a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c ++++ b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c +@@ -61,6 +61,11 @@ void aqua_vanjaram_doorbell_index_init(struct amdgpu_device *adev) + adev->doorbell_index.max_assignment = AMDGPU_DOORBELL_LAYOUT1_MAX_ASSIGNMENT << 1; + } + ++static bool aqua_vanjaram_xcp_vcn_shared(struct amdgpu_device *adev) ++{ ++ return (adev->xcp_mgr->num_xcps > adev->vcn.num_vcn_inst); ++} ++ + static void aqua_vanjaram_set_xcp_id(struct amdgpu_device *adev, + uint32_t inst_idx, struct amdgpu_ring *ring) + { +@@ -86,7 +91,7 @@ static void aqua_vanjaram_set_xcp_id(struct amdgpu_device *adev, + case AMDGPU_RING_TYPE_VCN_ENC: + case AMDGPU_RING_TYPE_VCN_JPEG: + ip_blk = AMDGPU_XCP_VCN; +- if (adev->xcp_mgr->mode == AMDGPU_CPX_PARTITION_MODE) ++ if (aqua_vanjaram_xcp_vcn_shared(adev)) + inst_mask = 1 << (inst_idx * 2); + break; + default: +@@ -139,10 +144,12 @@ static int aqua_vanjaram_xcp_sched_list_update( + + aqua_vanjaram_xcp_gpu_sched_update(adev, ring, ring->xcp_id); + +- /* VCN is shared by two partitions under CPX MODE */ ++ /* VCN may be shared by two partitions under CPX MODE in certain ++ * configs. ++ */ + if ((ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC || +- ring->funcs->type == AMDGPU_RING_TYPE_VCN_JPEG) && +- adev->xcp_mgr->mode == AMDGPU_CPX_PARTITION_MODE) ++ ring->funcs->type == AMDGPU_RING_TYPE_VCN_JPEG) && ++ aqua_vanjaram_xcp_vcn_shared(adev)) + aqua_vanjaram_xcp_gpu_sched_update(adev, ring, ring->xcp_id + 1); + } + +@@ -493,6 +500,12 @@ static int aqua_vanjaram_switch_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr, + + if (mode == AMDGPU_AUTO_COMPUTE_PARTITION_MODE) { + mode = __aqua_vanjaram_get_auto_mode(xcp_mgr); ++ if (mode == AMDGPU_UNKNOWN_COMPUTE_PARTITION_MODE) { ++ dev_err(adev->dev, ++ "Invalid config, no compatible compute partition mode found, available memory partitions: %d", ++ adev->gmc.num_mem_partitions); ++ return -EINVAL; ++ } + } else if (!__aqua_vanjaram_is_valid_mode(xcp_mgr, mode)) { + dev_err(adev->dev, + "Invalid compute partition mode requested, requested: %s, available memory partitions: %d", +diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c +index 9f63ddb89b75c1..1195d37f19fc5c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/atom.c ++++ b/drivers/gpu/drm/amd/amdgpu/atom.c +@@ -313,7 +313,7 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, + DEBUG("IMM 0x%02X\n", val); + return val; + } +- return 0; ++ break; + case ATOM_ARG_PLL: + idx = U8(*ptr); + (*ptr)++; +diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c +index d95b2dc7806341..157e898dc3820d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c ++++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c +@@ -2065,26 +2065,29 @@ amdgpu_atombios_encoder_get_lcd_info(struct amdgpu_encoder *encoder) + fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; + if (fake_edid_record->ucFakeEDIDLength) { + struct edid *edid; +- int edid_size = +- max((int)EDID_LENGTH, (int)fake_edid_record->ucFakeEDIDLength); +- edid = kmalloc(edid_size, GFP_KERNEL); ++ int edid_size; ++ ++ if (fake_edid_record->ucFakeEDIDLength == 128) ++ edid_size = fake_edid_record->ucFakeEDIDLength; ++ else ++ edid_size = fake_edid_record->ucFakeEDIDLength * 128; ++ edid = kmemdup(&fake_edid_record->ucFakeEDIDString[0], ++ edid_size, GFP_KERNEL); + if (edid) { +- memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0], +- fake_edid_record->ucFakeEDIDLength); +- + if (drm_edid_is_valid(edid)) { + adev->mode_info.bios_hardcoded_edid = edid; + adev->mode_info.bios_hardcoded_edid_size = edid_size; +- } else ++ } else { + kfree(edid); ++ } + } ++ record += struct_size(fake_edid_record, ++ ucFakeEDIDString, ++ edid_size); ++ } else { ++ /* empty fake edid record must be 3 bytes long */ ++ record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1; + } +- record += fake_edid_record->ucFakeEDIDLength ? +- struct_size(fake_edid_record, +- ucFakeEDIDString, +- fake_edid_record->ucFakeEDIDLength) : +- /* empty fake edid record must be 3 bytes long */ +- sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1; + break; + case LCD_PANEL_RESOLUTION_RECORD_TYPE: + panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; +diff --git a/drivers/gpu/drm/amd/amdgpu/cik_ih.c b/drivers/gpu/drm/amd/amdgpu/cik_ih.c +index 6f7c031dd197a2..f24e34dc33d1de 100644 +--- a/drivers/gpu/drm/amd/amdgpu/cik_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/cik_ih.c +@@ -204,6 +204,12 @@ static u32 cik_ih_get_wptr(struct amdgpu_device *adev, + tmp = RREG32(mmIH_RB_CNTL); + tmp |= IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK; + WREG32(mmIH_RB_CNTL, tmp); ++ ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp &= ~IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK; ++ WREG32(mmIH_RB_CNTL, tmp); + } + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/cz_ih.c b/drivers/gpu/drm/amd/amdgpu/cz_ih.c +index b8c47e0cf37ad5..c19681492efa74 100644 +--- a/drivers/gpu/drm/amd/amdgpu/cz_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/cz_ih.c +@@ -216,6 +216,11 @@ static u32 cz_ih_get_wptr(struct amdgpu_device *adev, + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32(mmIH_RB_CNTL, tmp); + ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32(mmIH_RB_CNTL, tmp); + + out: + return (wptr & ih->ptr_mask); +diff --git a/drivers/gpu/drm/amd/amdgpu/df_v1_7.c b/drivers/gpu/drm/amd/amdgpu/df_v1_7.c +index 5dfab80ffff213..cd298556f7a608 100644 +--- a/drivers/gpu/drm/amd/amdgpu/df_v1_7.c ++++ b/drivers/gpu/drm/amd/amdgpu/df_v1_7.c +@@ -70,6 +70,8 @@ static u32 df_v1_7_get_hbm_channel_number(struct amdgpu_device *adev) + int fb_channel_number; + + fb_channel_number = adev->df.funcs->get_fb_channel_number(adev); ++ if (fb_channel_number >= ARRAY_SIZE(df_v1_7_channel_number)) ++ fb_channel_number = 0; + + return df_v1_7_channel_number[fb_channel_number]; + } +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +index 9032d7a24d7cd7..53c99bc6abb333 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +@@ -3989,16 +3989,13 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev) + + if (!amdgpu_sriov_vf(adev)) { + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", ucode_prefix); +- err = amdgpu_ucode_request(adev, &adev->gfx.rlc_fw, fw_name); +- /* don't check this. There are apparently firmwares in the wild with +- * incorrect size in the header +- */ +- if (err == -ENODEV) +- goto out; ++ err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev); + if (err) +- dev_dbg(adev->dev, +- "gfx10: amdgpu_ucode_request() failed \"%s\"\n", +- fw_name); ++ goto out; ++ ++ /* don't validate this firmware. There are apparently firmwares ++ * in the wild with incorrect size in the header ++ */ + rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data; + version_major = le16_to_cpu(rlc_hdr->header.header_version_major); + version_minor = le16_to_cpu(rlc_hdr->header.header_version_minor); +@@ -4023,8 +4020,6 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev) + err = 0; + adev->gfx.mec2_fw = NULL; + } +- amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2); +- amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2_JT); + + gfx_v10_0_check_fw_write_wait(adev); + out: +@@ -6457,11 +6452,11 @@ static int gfx_v10_0_gfx_init_queue(struct amdgpu_ring *ring) + nv_grbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); + if (adev->gfx.me.mqd_backup[mqd_idx]) +- memcpy(adev->gfx.me.mqd_backup[mqd_idx], mqd, sizeof(*mqd)); ++ memcpy_fromio(adev->gfx.me.mqd_backup[mqd_idx], mqd, sizeof(*mqd)); + } else { + /* restore mqd with the backup copy */ + if (adev->gfx.me.mqd_backup[mqd_idx]) +- memcpy(mqd, adev->gfx.me.mqd_backup[mqd_idx], sizeof(*mqd)); ++ memcpy_toio(mqd, adev->gfx.me.mqd_backup[mqd_idx], sizeof(*mqd)); + /* reset the ring */ + ring->wptr = 0; + *ring->wptr_cpu_addr = 0; +@@ -6575,7 +6570,7 @@ static int gfx_v10_0_compute_mqd_init(struct amdgpu_device *adev, void *m, + #ifdef __BIG_ENDIAN + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, ENDIAN_SWAP, 1); + #endif +- tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 0); ++ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 1); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH, 0); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, KMD_QUEUE, 1); +@@ -6735,7 +6730,7 @@ static int gfx_v10_0_kiq_init_queue(struct amdgpu_ring *ring) + if (amdgpu_in_reset(adev)) { /* for GPU_RESET case */ + /* reset MQD to a clean status */ + if (adev->gfx.kiq[0].mqd_backup) +- memcpy(mqd, adev->gfx.kiq[0].mqd_backup, sizeof(*mqd)); ++ memcpy_toio(mqd, adev->gfx.kiq[0].mqd_backup, sizeof(*mqd)); + + /* reset ring buffer */ + ring->wptr = 0; +@@ -6758,7 +6753,7 @@ static int gfx_v10_0_kiq_init_queue(struct amdgpu_ring *ring) + mutex_unlock(&adev->srbm_mutex); + + if (adev->gfx.kiq[0].mqd_backup) +- memcpy(adev->gfx.kiq[0].mqd_backup, mqd, sizeof(*mqd)); ++ memcpy_fromio(adev->gfx.kiq[0].mqd_backup, mqd, sizeof(*mqd)); + } + + return 0; +@@ -6779,11 +6774,11 @@ static int gfx_v10_0_kcq_init_queue(struct amdgpu_ring *ring) + mutex_unlock(&adev->srbm_mutex); + + if (adev->gfx.mec.mqd_backup[mqd_idx]) +- memcpy(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(*mqd)); ++ memcpy_fromio(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(*mqd)); + } else { + /* restore MQD to a clean status */ + if (adev->gfx.mec.mqd_backup[mqd_idx]) +- memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(*mqd)); ++ memcpy_toio(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(*mqd)); + /* reset ring buffer */ + ring->wptr = 0; + atomic64_set((atomic64_t *)ring->wptr_cpu_addr, 0); +@@ -7897,22 +7892,15 @@ static int gfx_v10_0_update_gfx_clock_gating(struct amdgpu_device *adev, + static void gfx_v10_0_update_spm_vmid_internal(struct amdgpu_device *adev, + unsigned int vmid) + { +- u32 reg, data; ++ u32 data; + + /* not for *_SOC15 */ +- reg = SOC15_REG_OFFSET(GC, 0, mmRLC_SPM_MC_CNTL); +- if (amdgpu_sriov_is_pp_one_vf(adev)) +- data = RREG32_NO_KIQ(reg); +- else +- data = RREG32_SOC15(GC, 0, mmRLC_SPM_MC_CNTL); ++ data = RREG32_SOC15_NO_KIQ(GC, 0, mmRLC_SPM_MC_CNTL); + + data &= ~RLC_SPM_MC_CNTL__RLC_SPM_VMID_MASK; + data |= (vmid & RLC_SPM_MC_CNTL__RLC_SPM_VMID_MASK) << RLC_SPM_MC_CNTL__RLC_SPM_VMID__SHIFT; + +- if (amdgpu_sriov_is_pp_one_vf(adev)) +- WREG32_SOC15_NO_KIQ(GC, 0, mmRLC_SPM_MC_CNTL, data); +- else +- WREG32_SOC15(GC, 0, mmRLC_SPM_MC_CNTL, data); ++ WREG32_SOC15_NO_KIQ(GC, 0, mmRLC_SPM_MC_CNTL, data); + } + + static void gfx_v10_0_update_spm_vmid(struct amdgpu_device *adev, unsigned int vmid) +@@ -8760,7 +8748,9 @@ static void gfx_v10_0_ring_soft_recovery(struct amdgpu_ring *ring, + value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01); + value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1); + value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid); ++ amdgpu_gfx_rlc_enter_safe_mode(adev, 0); + WREG32_SOC15(GC, 0, mmSQ_CMD, value); ++ amdgpu_gfx_rlc_exit_safe_mode(adev, 0); + } + + static void +@@ -9162,7 +9152,7 @@ static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_gfx = { + 7 + /* PIPELINE_SYNC */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + +- 2 + /* VM_FLUSH */ ++ 4 + /* VM_FLUSH */ + 8 + /* FENCE for VM_FLUSH */ + 20 + /* GDS switch */ + 4 + /* double SWITCH_BUFFER, +@@ -9253,7 +9243,6 @@ static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_kiq = { + 7 + /* gfx_v10_0_ring_emit_pipeline_sync */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + +- 2 + /* gfx_v10_0_ring_emit_vm_flush */ + 8 + 8 + 8, /* gfx_v10_0_ring_emit_fence_kiq x3 for user fence, vm fence */ + .emit_ib_size = 7, /* gfx_v10_0_ring_emit_ib_compute */ + .emit_ib = gfx_v10_0_ring_emit_ib_compute, +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +index 762d7a19f1be16..54ec9b32562c28 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +@@ -83,6 +83,10 @@ MODULE_FIRMWARE("amdgpu/gc_11_0_4_me.bin"); + MODULE_FIRMWARE("amdgpu/gc_11_0_4_mec.bin"); + MODULE_FIRMWARE("amdgpu/gc_11_0_4_rlc.bin"); + ++static const struct soc15_reg_golden golden_settings_gc_11_0[] = { ++ SOC15_REG_GOLDEN_VALUE(GC, 0, regTCP_CNTL, 0x20000000, 0x20000000) ++}; ++ + static const struct soc15_reg_golden golden_settings_gc_11_0_1[] = + { + SOC15_REG_GOLDEN_VALUE(GC, 0, regCGTT_GS_NGG_CLK_CTRL, 0x9fff8fff, 0x00000010), +@@ -275,6 +279,10 @@ static void gfx_v11_0_init_golden_registers(struct amdgpu_device *adev) + default: + break; + } ++ soc15_program_register_sequence(adev, ++ golden_settings_gc_11_0, ++ (const u32)ARRAY_SIZE(golden_settings_gc_11_0)); ++ + } + + static void gfx_v11_0_write_data_to_reg(struct amdgpu_ring *ring, int eng_sel, +@@ -390,7 +398,7 @@ static int gfx_v11_0_ring_test_ib(struct amdgpu_ring *ring, long timeout) + adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD); + cpu_ptr = &adev->wb.wb[index]; + +- r = amdgpu_ib_get(adev, NULL, 16, AMDGPU_IB_POOL_DIRECT, &ib); ++ r = amdgpu_ib_get(adev, NULL, 20, AMDGPU_IB_POOL_DIRECT, &ib); + if (r) { + DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r); + goto err1; +@@ -1608,7 +1616,7 @@ static void gfx_v11_0_setup_rb(struct amdgpu_device *adev) + active_rb_bitmap |= (0x3 << (i * rb_bitmap_width_per_sa)); + } + +- active_rb_bitmap |= global_active_rb_bitmap; ++ active_rb_bitmap &= global_active_rb_bitmap; + adev->gfx.config.backend_enable_mask = active_rb_bitmap; + adev->gfx.config.num_rbs = hweight32(active_rb_bitmap); + } +@@ -3684,11 +3692,11 @@ static int gfx_v11_0_gfx_init_queue(struct amdgpu_ring *ring) + soc21_grbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); + if (adev->gfx.me.mqd_backup[mqd_idx]) +- memcpy(adev->gfx.me.mqd_backup[mqd_idx], mqd, sizeof(*mqd)); ++ memcpy_fromio(adev->gfx.me.mqd_backup[mqd_idx], mqd, sizeof(*mqd)); + } else { + /* restore mqd with the backup copy */ + if (adev->gfx.me.mqd_backup[mqd_idx]) +- memcpy(mqd, adev->gfx.me.mqd_backup[mqd_idx], sizeof(*mqd)); ++ memcpy_toio(mqd, adev->gfx.me.mqd_backup[mqd_idx], sizeof(*mqd)); + /* reset the ring */ + ring->wptr = 0; + *ring->wptr_cpu_addr = 0; +@@ -3799,7 +3807,7 @@ static int gfx_v11_0_compute_mqd_init(struct amdgpu_device *adev, void *m, + (order_base_2(prop->queue_size / 4) - 1)); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, RPTR_BLOCK_SIZE, + (order_base_2(AMDGPU_GPU_PAGE_SIZE / 4) - 1)); +- tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 0); ++ tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 1); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH, 0); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, KMD_QUEUE, 1); +@@ -3977,7 +3985,7 @@ static int gfx_v11_0_kiq_init_queue(struct amdgpu_ring *ring) + if (amdgpu_in_reset(adev)) { /* for GPU_RESET case */ + /* reset MQD to a clean status */ + if (adev->gfx.kiq[0].mqd_backup) +- memcpy(mqd, adev->gfx.kiq[0].mqd_backup, sizeof(*mqd)); ++ memcpy_toio(mqd, adev->gfx.kiq[0].mqd_backup, sizeof(*mqd)); + + /* reset ring buffer */ + ring->wptr = 0; +@@ -4000,7 +4008,7 @@ static int gfx_v11_0_kiq_init_queue(struct amdgpu_ring *ring) + mutex_unlock(&adev->srbm_mutex); + + if (adev->gfx.kiq[0].mqd_backup) +- memcpy(adev->gfx.kiq[0].mqd_backup, mqd, sizeof(*mqd)); ++ memcpy_fromio(adev->gfx.kiq[0].mqd_backup, mqd, sizeof(*mqd)); + } + + return 0; +@@ -4021,11 +4029,11 @@ static int gfx_v11_0_kcq_init_queue(struct amdgpu_ring *ring) + mutex_unlock(&adev->srbm_mutex); + + if (adev->gfx.mec.mqd_backup[mqd_idx]) +- memcpy(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(*mqd)); ++ memcpy_fromio(adev->gfx.mec.mqd_backup[mqd_idx], mqd, sizeof(*mqd)); + } else { + /* restore MQD to a clean status */ + if (adev->gfx.mec.mqd_backup[mqd_idx]) +- memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(*mqd)); ++ memcpy_toio(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(*mqd)); + /* reset ring buffer */ + ring->wptr = 0; + atomic64_set((atomic64_t *)ring->wptr_cpu_addr, 0); +@@ -4261,11 +4269,11 @@ static int gfx_v11_0_hw_init(void *handle) + /* RLC autoload sequence 1: Program rlc ram */ + if (adev->gfx.imu.funcs->program_rlc_ram) + adev->gfx.imu.funcs->program_rlc_ram(adev); ++ /* rlc autoload firmware */ ++ r = gfx_v11_0_rlc_backdoor_autoload_enable(adev); ++ if (r) ++ return r; + } +- /* rlc autoload firmware */ +- r = gfx_v11_0_rlc_backdoor_autoload_enable(adev); +- if (r) +- return r; + } else { + if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) { + if (adev->gfx.imu.funcs && (amdgpu_dpm > 0)) { +@@ -4953,23 +4961,16 @@ static int gfx_v11_0_update_gfx_clock_gating(struct amdgpu_device *adev, + + static void gfx_v11_0_update_spm_vmid(struct amdgpu_device *adev, unsigned vmid) + { +- u32 reg, data; ++ u32 data; + + amdgpu_gfx_off_ctrl(adev, false); + +- reg = SOC15_REG_OFFSET(GC, 0, regRLC_SPM_MC_CNTL); +- if (amdgpu_sriov_is_pp_one_vf(adev)) +- data = RREG32_NO_KIQ(reg); +- else +- data = RREG32(reg); ++ data = RREG32_SOC15_NO_KIQ(GC, 0, regRLC_SPM_MC_CNTL); + + data &= ~RLC_SPM_MC_CNTL__RLC_SPM_VMID_MASK; + data |= (vmid & RLC_SPM_MC_CNTL__RLC_SPM_VMID_MASK) << RLC_SPM_MC_CNTL__RLC_SPM_VMID__SHIFT; + +- if (amdgpu_sriov_is_pp_one_vf(adev)) +- WREG32_SOC15_NO_KIQ(GC, 0, regRLC_SPM_MC_CNTL, data); +- else +- WREG32_SOC15(GC, 0, regRLC_SPM_MC_CNTL, data); ++ WREG32_SOC15_NO_KIQ(GC, 0, regRLC_SPM_MC_CNTL, data); + + amdgpu_gfx_off_ctrl(adev, true); + } +@@ -5700,7 +5701,9 @@ static void gfx_v11_0_ring_soft_recovery(struct amdgpu_ring *ring, + value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01); + value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1); + value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid); ++ amdgpu_gfx_rlc_enter_safe_mode(adev, 0); + WREG32_SOC15(GC, 0, regSQ_CMD, value); ++ amdgpu_gfx_rlc_exit_safe_mode(adev, 0); + } + + static void +@@ -6094,7 +6097,7 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_gfx = { + 7 + /* PIPELINE_SYNC */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + +- 2 + /* VM_FLUSH */ ++ 4 + /* VM_FLUSH */ + 8 + /* FENCE for VM_FLUSH */ + 20 + /* GDS switch */ + 5 + /* COND_EXEC */ +@@ -6179,7 +6182,6 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_kiq = { + 7 + /* gfx_v11_0_ring_emit_pipeline_sync */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + +- 2 + /* gfx_v11_0_ring_emit_vm_flush */ + 8 + 8 + 8, /* gfx_v11_0_ring_emit_fence_kiq x3 for user fence, vm fence */ + .emit_ib_size = 7, /* gfx_v11_0_ring_emit_ib_compute */ + .emit_ib = gfx_v11_0_ring_emit_ib_compute, +@@ -6345,6 +6347,9 @@ static int gfx_v11_0_get_cu_info(struct amdgpu_device *adev, + mutex_lock(&adev->grbm_idx_mutex); + for (i = 0; i < adev->gfx.config.max_shader_engines; i++) { + for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) { ++ bitmap = i * adev->gfx.config.max_sh_per_se + j; ++ if (!((gfx_v11_0_get_sa_active_bitmap(adev) >> bitmap) & 1)) ++ continue; + mask = 1; + counter = 0; + gfx_v11_0_select_se_sh(adev, i, j, 0xffffffff, 0); +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +index 885ebd703260f0..1943beb135c4c2 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +@@ -883,8 +883,8 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring, long timeout) + gpu_addr = adev->wb.gpu_addr + (index * 4); + adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD); + memset(&ib, 0, sizeof(ib)); +- r = amdgpu_ib_get(adev, NULL, 16, +- AMDGPU_IB_POOL_DIRECT, &ib); ++ ++ r = amdgpu_ib_get(adev, NULL, 20, AMDGPU_IB_POOL_DIRECT, &ib); + if (r) + goto err1; + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +index fd61574a737cb1..895060f6948f30 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +@@ -1039,8 +1039,8 @@ static int gfx_v9_0_ring_test_ib(struct amdgpu_ring *ring, long timeout) + gpu_addr = adev->wb.gpu_addr + (index * 4); + adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD); + memset(&ib, 0, sizeof(ib)); +- r = amdgpu_ib_get(adev, NULL, 16, +- AMDGPU_IB_POOL_DIRECT, &ib); ++ ++ r = amdgpu_ib_get(adev, NULL, 20, AMDGPU_IB_POOL_DIRECT, &ib); + if (r) + goto err1; + +@@ -1172,6 +1172,10 @@ static const struct amdgpu_gfxoff_quirk amdgpu_gfxoff_quirk_list[] = { + { 0x1002, 0x15dd, 0x1002, 0x15dd, 0xc6 }, + /* Apple MacBook Pro (15-inch, 2019) Radeon Pro Vega 20 4 GB */ + { 0x1002, 0x69af, 0x106b, 0x019a, 0xc0 }, ++ /* https://bbs.openkylin.top/t/topic/171497 */ ++ { 0x1002, 0x15d8, 0x19e5, 0x3e14, 0xc2 }, ++ /* HP 705G4 DM with R5 2400G */ ++ { 0x1002, 0x15dd, 0x103c, 0x8464, 0xd6 }, + { 0, 0, 0, 0, 0 }, + }; + +@@ -3033,6 +3037,14 @@ static int gfx_v9_0_cp_gfx_start(struct amdgpu_device *adev) + + gfx_v9_0_cp_gfx_enable(adev, true); + ++ /* Now only limit the quirk on the APU gfx9 series and already ++ * confirmed that the APU gfx10/gfx11 needn't such update. ++ */ ++ if (adev->flags & AMD_IS_APU && ++ adev->in_s3 && !adev->suspend_complete) { ++ DRM_INFO(" Will skip the CSB packet resubmit\n"); ++ return 0; ++ } + r = amdgpu_ring_alloc(ring, gfx_v9_0_get_csb_size(adev) + 4 + 3); + if (r) { + DRM_ERROR("amdgpu: cp failed to lock ring (%d).\n", r); +@@ -5697,7 +5709,9 @@ static void gfx_v9_0_ring_soft_recovery(struct amdgpu_ring *ring, unsigned vmid) + value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01); + value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1); + value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid); ++ amdgpu_gfx_rlc_enter_safe_mode(adev, 0); + WREG32_SOC15(GC, 0, mmSQ_CMD, value); ++ amdgpu_gfx_rlc_exit_safe_mode(adev, 0); + } + + static void gfx_v9_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev, +@@ -6980,7 +6994,6 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_compute = { + 7 + /* gfx_v9_0_ring_emit_pipeline_sync */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + +- 2 + /* gfx_v9_0_ring_emit_vm_flush */ + 8 + 8 + 8 + /* gfx_v9_0_ring_emit_fence x3 for user fence, vm fence */ + 7 + /* gfx_v9_0_emit_mem_sync */ + 5 + /* gfx_v9_0_emit_wave_limit for updating mmSPI_WCL_PIPE_PERCENT_GFX register */ +@@ -7018,7 +7031,6 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_kiq = { + 7 + /* gfx_v9_0_ring_emit_pipeline_sync */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + +- 2 + /* gfx_v9_0_ring_emit_vm_flush */ + 8 + 8 + 8, /* gfx_v9_0_ring_emit_fence_kiq x3 for user fence, vm fence */ + .emit_ib_size = 7, /* gfx_v9_0_ring_emit_ib_compute */ + .emit_fence = gfx_v9_0_ring_emit_fence_kiq, +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +index 18ce5fe45f6f86..caa04d897c2ded 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +@@ -296,8 +296,8 @@ static int gfx_v9_4_3_ring_test_ib(struct amdgpu_ring *ring, long timeout) + gpu_addr = adev->wb.gpu_addr + (index * 4); + adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD); + memset(&ib, 0, sizeof(ib)); +- r = amdgpu_ib_get(adev, NULL, 16, +- AMDGPU_IB_POOL_DIRECT, &ib); ++ ++ r = amdgpu_ib_get(adev, NULL, 20, AMDGPU_IB_POOL_DIRECT, &ib); + if (r) + goto err1; + +@@ -425,16 +425,16 @@ static int gfx_v9_4_3_init_cp_compute_microcode(struct amdgpu_device *adev, + + static int gfx_v9_4_3_init_microcode(struct amdgpu_device *adev) + { +- const char *chip_name; ++ char ucode_prefix[15]; + int r; + +- chip_name = "gc_9_4_3"; ++ amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix)); + +- r = gfx_v9_4_3_init_rlc_microcode(adev, chip_name); ++ r = gfx_v9_4_3_init_rlc_microcode(adev, ucode_prefix); + if (r) + return r; + +- r = gfx_v9_4_3_init_cp_compute_microcode(adev, chip_name); ++ r = gfx_v9_4_3_init_cp_compute_microcode(adev, ucode_prefix); + if (r) + return r; + +@@ -4290,9 +4290,10 @@ static u32 gfx_v9_4_3_get_cu_active_bitmap(struct amdgpu_device *adev, int xcc_i + static int gfx_v9_4_3_get_cu_info(struct amdgpu_device *adev, + struct amdgpu_cu_info *cu_info) + { +- int i, j, k, counter, xcc_id, active_cu_number = 0; +- u32 mask, bitmap, ao_bitmap, ao_cu_mask = 0; ++ int i, j, k, prev_counter, counter, xcc_id, active_cu_number = 0; ++ u32 mask, bitmap, ao_bitmap, ao_cu_mask = 0, tmp; + unsigned disable_masks[4 * 4]; ++ bool is_symmetric_cus; + + if (!adev || !cu_info) + return -EINVAL; +@@ -4310,6 +4311,7 @@ static int gfx_v9_4_3_get_cu_info(struct amdgpu_device *adev, + + mutex_lock(&adev->grbm_idx_mutex); + for (xcc_id = 0; xcc_id < NUM_XCC(adev->gfx.xcc_mask); xcc_id++) { ++ is_symmetric_cus = true; + for (i = 0; i < adev->gfx.config.max_shader_engines; i++) { + for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) { + mask = 1; +@@ -4337,6 +4339,15 @@ static int gfx_v9_4_3_get_cu_info(struct amdgpu_device *adev, + ao_cu_mask |= (ao_bitmap << (i * 16 + j * 8)); + cu_info->ao_cu_bitmap[i][j] = ao_bitmap; + } ++ if (i && is_symmetric_cus && prev_counter != counter) ++ is_symmetric_cus = false; ++ prev_counter = counter; ++ } ++ if (is_symmetric_cus) { ++ tmp = RREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_CPC_DEBUG); ++ tmp = REG_SET_FIELD(tmp, CP_CPC_DEBUG, CPC_HARVESTING_RELAUNCH_DISABLE, 1); ++ tmp = REG_SET_FIELD(tmp, CP_CPC_DEBUG, CPC_HARVESTING_DISPATCH_DISABLE, 1); ++ WREG32_SOC15(GC, GET_INST(GC, xcc_id), regCP_CPC_DEBUG, tmp); + } + gfx_v9_4_3_xcc_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, + xcc_id); +diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c +index cdc290a474a927..66c6bab75f8a58 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c +@@ -102,7 +102,9 @@ static void gfxhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev) + WREG32_SOC15_RLC(GC, 0, mmMC_VM_SYSTEM_APERTURE_LOW_ADDR, + min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18); + +- if (adev->apu_flags & AMD_APU_IS_RAVEN2) ++ if (adev->apu_flags & (AMD_APU_IS_RAVEN2 | ++ AMD_APU_IS_RENOIR | ++ AMD_APU_IS_GREEN_SARDINE)) + /* + * Raven2 has a HW issue that it is unable to use the + * vram which is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. +diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c +index 0834af7715497d..b50f24f7ea5c99 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c +@@ -139,7 +139,9 @@ gfxhub_v1_2_xcc_init_system_aperture_regs(struct amdgpu_device *adev, + WREG32_SOC15_RLC(GC, GET_INST(GC, i), regMC_VM_SYSTEM_APERTURE_LOW_ADDR, + min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18); + +- if (adev->apu_flags & AMD_APU_IS_RAVEN2) ++ if (adev->apu_flags & (AMD_APU_IS_RAVEN2 | ++ AMD_APU_IS_RENOIR | ++ AMD_APU_IS_GREEN_SARDINE)) + /* + * Raven2 has a HW issue that it is unable to use the + * vram which is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +index fa87a85e1017e7..62ecf4d89cb9cd 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +@@ -1141,6 +1141,10 @@ static int gmc_v10_0_hw_fini(void *handle) + + amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); + ++ if (adev->gmc.ecc_irq.funcs && ++ amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC)) ++ amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); ++ + return 0; + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +index e3b76fd28d158c..3d797a1adef3e5 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +@@ -974,6 +974,11 @@ static int gmc_v11_0_hw_fini(void *handle) + } + + amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); ++ ++ if (adev->gmc.ecc_irq.funcs && ++ amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC)) ++ amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); ++ + gmc_v11_0_gart_disable(adev); + + return 0; +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +index 5b837a65fad20c..dfee4aae80393a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +@@ -914,8 +914,8 @@ static int gmc_v6_0_hw_init(void *handle) + + if (amdgpu_emu_mode == 1) + return amdgpu_gmc_vram_checking(adev); +- else +- return r; ++ ++ return 0; + } + + static int gmc_v6_0_hw_fini(void *handle) +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +index 6a6929ac27482d..fd905889a4c63b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +@@ -1103,8 +1103,8 @@ static int gmc_v7_0_hw_init(void *handle) + + if (amdgpu_emu_mode == 1) + return amdgpu_gmc_vram_checking(adev); +- else +- return r; ++ ++ return 0; + } + + static int gmc_v7_0_hw_fini(void *handle) +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +index 5af23520251322..0bebcdbb265807 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +@@ -1224,8 +1224,8 @@ static int gmc_v8_0_hw_init(void *handle) + + if (amdgpu_emu_mode == 1) + return amdgpu_gmc_vram_checking(adev); +- else +- return r; ++ ++ return 0; + } + + static int gmc_v8_0_hw_fini(void *handle) +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +index f9a5a2c0573e41..6d2b9d260d92c5 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +@@ -1949,7 +1949,7 @@ gmc_v9_0_init_sw_mem_ranges(struct amdgpu_device *adev, + break; + } + +- size = adev->gmc.real_vram_size >> AMDGPU_GPU_PAGE_SHIFT; ++ size = (adev->gmc.real_vram_size + SZ_16M) >> AMDGPU_GPU_PAGE_SHIFT; + size /= adev->gmc.num_mem_partitions; + + for (i = 0; i < adev->gmc.num_mem_partitions; ++i) { +@@ -2220,8 +2220,6 @@ static int gmc_v9_0_sw_fini(void *handle) + + if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(9, 4, 3)) + amdgpu_gmc_sysfs_fini(adev); +- adev->gmc.num_mem_partitions = 0; +- kfree(adev->gmc.mem_partitions); + + amdgpu_gmc_ras_fini(adev); + amdgpu_gem_force_release(adev); +@@ -2235,6 +2233,9 @@ static int gmc_v9_0_sw_fini(void *handle) + amdgpu_bo_free_kernel(&adev->gmc.pdb0_bo, NULL, &adev->gmc.ptr_pdb0); + amdgpu_bo_fini(adev); + ++ adev->gmc.num_mem_partitions = 0; ++ kfree(adev->gmc.mem_partitions); ++ + return 0; + } + +@@ -2372,8 +2373,8 @@ static int gmc_v9_0_hw_init(void *handle) + + if (amdgpu_emu_mode == 1) + return amdgpu_gmc_vram_checking(adev); +- else +- return r; ++ ++ return 0; + } + + /** +@@ -2412,6 +2413,10 @@ static int gmc_v9_0_hw_fini(void *handle) + + amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); + ++ if (adev->gmc.ecc_irq.funcs && ++ amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC)) ++ amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); ++ + return 0; + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c +index aecad530b10a61..2c02ae69883d2b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c +@@ -215,6 +215,11 @@ static u32 iceland_ih_get_wptr(struct amdgpu_device *adev, + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32(mmIH_RB_CNTL, tmp); + ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32(mmIH_RB_CNTL, tmp); + + out: + return (wptr & ih->ptr_mask); +diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c b/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c +index ec0c8f8b465ab2..725b1a585088db 100644 +--- a/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c +@@ -135,6 +135,34 @@ static int ih_v6_0_toggle_ring_interrupts(struct amdgpu_device *adev, + + tmp = RREG32(ih_regs->ih_rb_cntl); + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_ENABLE, (enable ? 1 : 0)); ++ ++ if (enable) { ++ /* Unset the CLEAR_OVERFLOW bit to make sure the next step ++ * is switching the bit from 0 to 1 ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ if (amdgpu_sriov_vf(adev) && amdgpu_sriov_reg_indirect_ih(adev)) { ++ if (psp_reg_program(&adev->psp, ih_regs->psp_reg_id, tmp)) ++ return -ETIMEDOUT; ++ } else { ++ WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); ++ } ++ ++ /* Clear RB_OVERFLOW bit */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); ++ if (amdgpu_sriov_vf(adev) && amdgpu_sriov_reg_indirect_ih(adev)) { ++ if (psp_reg_program(&adev->psp, ih_regs->psp_reg_id, tmp)) ++ return -ETIMEDOUT; ++ } else { ++ WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); ++ } ++ ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ } ++ + /* enable_intr field is only valid in ring0 */ + if (ih == &adev->irq.ih) + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, ENABLE_INTR, (enable ? 1 : 0)); +@@ -418,6 +446,12 @@ static u32 ih_v6_0_get_wptr(struct amdgpu_device *adev, + tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl); + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); ++ ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + out: + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c b/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c +index 8fb05eae340ad2..b8da0fc29378c4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c +@@ -418,6 +418,13 @@ static u32 ih_v6_1_get_wptr(struct amdgpu_device *adev, + tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl); + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); ++ ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); ++ + out: + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c b/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c +index 4ab90c7852c3ed..ca123ff553477e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c +@@ -39,7 +39,7 @@ MODULE_FIRMWARE("amdgpu/gc_11_0_4_imu.bin"); + + static int imu_v11_0_init_microcode(struct amdgpu_device *adev) + { +- char fw_name[40]; ++ char fw_name[45]; + char ucode_prefix[30]; + int err; + const struct imu_firmware_header_v1_0 *imu_hdr; +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c +index 77595e9622da34..7ac0228fe532ee 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c +@@ -23,6 +23,7 @@ + + #include "amdgpu.h" + #include "amdgpu_jpeg.h" ++#include "amdgpu_cs.h" + #include "soc15.h" + #include "soc15d.h" + #include "vcn_v1_0.h" +@@ -34,6 +35,9 @@ + static void jpeg_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev); + static void jpeg_v1_0_set_irq_funcs(struct amdgpu_device *adev); + static void jpeg_v1_0_ring_begin_use(struct amdgpu_ring *ring); ++static int jpeg_v1_dec_ring_parse_cs(struct amdgpu_cs_parser *parser, ++ struct amdgpu_job *job, ++ struct amdgpu_ib *ib); + + static void jpeg_v1_0_decode_ring_patch_wreg(struct amdgpu_ring *ring, uint32_t *ptr, uint32_t reg_offset, uint32_t val) + { +@@ -300,7 +304,10 @@ static void jpeg_v1_0_decode_ring_emit_ib(struct amdgpu_ring *ring, + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_LMI_JRBC_IB_VMID), 0, 0, PACKETJ_TYPE0)); +- amdgpu_ring_write(ring, (vmid | (vmid << 4))); ++ if (ring->funcs->parse_cs) ++ amdgpu_ring_write(ring, 0); ++ else ++ amdgpu_ring_write(ring, (vmid | (vmid << 4))); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_LMI_JPEG_VMID), 0, 0, PACKETJ_TYPE0)); +@@ -554,6 +561,7 @@ static const struct amdgpu_ring_funcs jpeg_v1_0_decode_ring_vm_funcs = { + .get_rptr = jpeg_v1_0_decode_ring_get_rptr, + .get_wptr = jpeg_v1_0_decode_ring_get_wptr, + .set_wptr = jpeg_v1_0_decode_ring_set_wptr, ++ .parse_cs = jpeg_v1_dec_ring_parse_cs, + .emit_frame_size = + 6 + 6 + /* hdp invalidate / flush */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + +@@ -612,3 +620,69 @@ static void jpeg_v1_0_ring_begin_use(struct amdgpu_ring *ring) + + vcn_v1_0_set_pg_for_begin_use(ring, set_clocks); + } ++ ++/** ++ * jpeg_v1_dec_ring_parse_cs - command submission parser ++ * ++ * @parser: Command submission parser context ++ * @job: the job to parse ++ * @ib: the IB to parse ++ * ++ * Parse the command stream, return -EINVAL for invalid packet, ++ * 0 otherwise ++ */ ++static int jpeg_v1_dec_ring_parse_cs(struct amdgpu_cs_parser *parser, ++ struct amdgpu_job *job, ++ struct amdgpu_ib *ib) ++{ ++ u32 i, reg, res, cond, type; ++ int ret = 0; ++ struct amdgpu_device *adev = parser->adev; ++ ++ for (i = 0; i < ib->length_dw ; i += 2) { ++ reg = CP_PACKETJ_GET_REG(ib->ptr[i]); ++ res = CP_PACKETJ_GET_RES(ib->ptr[i]); ++ cond = CP_PACKETJ_GET_COND(ib->ptr[i]); ++ type = CP_PACKETJ_GET_TYPE(ib->ptr[i]); ++ ++ if (res || cond != PACKETJ_CONDITION_CHECK0) /* only allow 0 for now */ ++ return -EINVAL; ++ ++ if (reg >= JPEG_V1_REG_RANGE_START && reg <= JPEG_V1_REG_RANGE_END) ++ continue; ++ ++ switch (type) { ++ case PACKETJ_TYPE0: ++ if (reg != JPEG_V1_LMI_JPEG_WRITE_64BIT_BAR_HIGH && ++ reg != JPEG_V1_LMI_JPEG_WRITE_64BIT_BAR_LOW && ++ reg != JPEG_V1_LMI_JPEG_READ_64BIT_BAR_HIGH && ++ reg != JPEG_V1_LMI_JPEG_READ_64BIT_BAR_LOW && ++ reg != JPEG_V1_REG_CTX_INDEX && ++ reg != JPEG_V1_REG_CTX_DATA) { ++ ret = -EINVAL; ++ } ++ break; ++ case PACKETJ_TYPE1: ++ if (reg != JPEG_V1_REG_CTX_DATA) ++ ret = -EINVAL; ++ break; ++ case PACKETJ_TYPE3: ++ if (reg != JPEG_V1_REG_SOFT_RESET) ++ ret = -EINVAL; ++ break; ++ case PACKETJ_TYPE6: ++ if (ib->ptr[i] != CP_PACKETJ_NOP) ++ ret = -EINVAL; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ ++ if (ret) { ++ dev_err(adev->dev, "Invalid packet [0x%08x]!\n", ib->ptr[i]); ++ break; ++ } ++ } ++ ++ return ret; ++} +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h +index bbf33a6a397298..9654d22e03763c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h +@@ -29,4 +29,15 @@ int jpeg_v1_0_sw_init(void *handle); + void jpeg_v1_0_sw_fini(void *handle); + void jpeg_v1_0_start(struct amdgpu_device *adev, int mode); + ++#define JPEG_V1_REG_RANGE_START 0x8000 ++#define JPEG_V1_REG_RANGE_END 0x803f ++ ++#define JPEG_V1_LMI_JPEG_WRITE_64BIT_BAR_HIGH 0x8238 ++#define JPEG_V1_LMI_JPEG_WRITE_64BIT_BAR_LOW 0x8239 ++#define JPEG_V1_LMI_JPEG_READ_64BIT_BAR_HIGH 0x825a ++#define JPEG_V1_LMI_JPEG_READ_64BIT_BAR_LOW 0x825b ++#define JPEG_V1_REG_CTX_INDEX 0x8328 ++#define JPEG_V1_REG_CTX_DATA 0x8329 ++#define JPEG_V1_REG_SOFT_RESET 0x83a0 ++ + #endif /*__JPEG_V1_0_H__*/ +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +index 1c8116d75f63c4..fbe57499495ec5 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +@@ -543,11 +543,11 @@ void jpeg_v2_0_dec_ring_emit_ib(struct amdgpu_ring *ring, + + amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_IB_VMID_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); +- amdgpu_ring_write(ring, (vmid | (vmid << 4))); ++ amdgpu_ring_write(ring, (vmid | (vmid << 4) | (vmid << 8))); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JPEG_VMID_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); +- amdgpu_ring_write(ring, (vmid | (vmid << 4))); ++ amdgpu_ring_write(ring, (vmid | (vmid << 4) | (vmid << 8))); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +index 1de79d660285d7..78aaaee492e111 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +@@ -23,6 +23,7 @@ + + #include "amdgpu.h" + #include "amdgpu_jpeg.h" ++#include "amdgpu_cs.h" + #include "soc15.h" + #include "soc15d.h" + #include "jpeg_v4_0_3.h" +@@ -769,11 +770,15 @@ static void jpeg_v4_0_3_dec_ring_emit_ib(struct amdgpu_ring *ring, + + amdgpu_ring_write(ring, PACKETJ(regUVD_LMI_JRBC_IB_VMID_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); +- amdgpu_ring_write(ring, (vmid | (vmid << 4))); ++ ++ if (ring->funcs->parse_cs) ++ amdgpu_ring_write(ring, 0); ++ else ++ amdgpu_ring_write(ring, (vmid | (vmid << 4) | (vmid << 8))); + + amdgpu_ring_write(ring, PACKETJ(regUVD_LMI_JPEG_VMID_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); +- amdgpu_ring_write(ring, (vmid | (vmid << 4))); ++ amdgpu_ring_write(ring, (vmid | (vmid << 4) | (vmid << 8))); + + amdgpu_ring_write(ring, PACKETJ(regUVD_LMI_JRBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); +@@ -1052,6 +1057,7 @@ static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = { + .get_rptr = jpeg_v4_0_3_dec_ring_get_rptr, + .get_wptr = jpeg_v4_0_3_dec_ring_get_wptr, + .set_wptr = jpeg_v4_0_3_dec_ring_set_wptr, ++ .parse_cs = jpeg_v4_0_3_dec_ring_parse_cs, + .emit_frame_size = + SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 + +@@ -1216,3 +1222,56 @@ static void jpeg_v4_0_3_set_ras_funcs(struct amdgpu_device *adev) + { + adev->jpeg.ras = &jpeg_v4_0_3_ras; + } ++ ++/** ++ * jpeg_v4_0_3_dec_ring_parse_cs - command submission parser ++ * ++ * @parser: Command submission parser context ++ * @job: the job to parse ++ * @ib: the IB to parse ++ * ++ * Parse the command stream, return -EINVAL for invalid packet, ++ * 0 otherwise ++ */ ++int jpeg_v4_0_3_dec_ring_parse_cs(struct amdgpu_cs_parser *parser, ++ struct amdgpu_job *job, ++ struct amdgpu_ib *ib) ++{ ++ uint32_t i, reg, res, cond, type; ++ struct amdgpu_device *adev = parser->adev; ++ ++ for (i = 0; i < ib->length_dw ; i += 2) { ++ reg = CP_PACKETJ_GET_REG(ib->ptr[i]); ++ res = CP_PACKETJ_GET_RES(ib->ptr[i]); ++ cond = CP_PACKETJ_GET_COND(ib->ptr[i]); ++ type = CP_PACKETJ_GET_TYPE(ib->ptr[i]); ++ ++ if (res) /* only support 0 at the moment */ ++ return -EINVAL; ++ ++ switch (type) { ++ case PACKETJ_TYPE0: ++ if (cond != PACKETJ_CONDITION_CHECK0 || reg < JPEG_REG_RANGE_START || reg > JPEG_REG_RANGE_END) { ++ dev_err(adev->dev, "Invalid packet [0x%08x]!\n", ib->ptr[i]); ++ return -EINVAL; ++ } ++ break; ++ case PACKETJ_TYPE3: ++ if (cond != PACKETJ_CONDITION_CHECK3 || reg < JPEG_REG_RANGE_START || reg > JPEG_REG_RANGE_END) { ++ dev_err(adev->dev, "Invalid packet [0x%08x]!\n", ib->ptr[i]); ++ return -EINVAL; ++ } ++ break; ++ case PACKETJ_TYPE6: ++ if (ib->ptr[i] == CP_PACKETJ_NOP) ++ continue; ++ dev_err(adev->dev, "Invalid packet [0x%08x]!\n", ib->ptr[i]); ++ return -EINVAL; ++ default: ++ dev_err(adev->dev, "Unknown packet type %d !\n", type); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h +index 22483dc663518f..9598eda9d71564 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h +@@ -46,6 +46,12 @@ + + #define JRBC_DEC_EXTERNAL_REG_WRITE_ADDR 0x18000 + ++#define JPEG_REG_RANGE_START 0x4000 ++#define JPEG_REG_RANGE_END 0x41c2 ++ + extern const struct amdgpu_ip_block_version jpeg_v4_0_3_ip_block; + ++int jpeg_v4_0_3_dec_ring_parse_cs(struct amdgpu_cs_parser *parser, ++ struct amdgpu_job *job, ++ struct amdgpu_ib *ib); + #endif /* __JPEG_V4_0_3_H__ */ +diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c +index fb91b31056cae7..d25f87fb197148 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c +@@ -96,7 +96,9 @@ static void mmhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev) + WREG32_SOC15(MMHUB, 0, mmMC_VM_SYSTEM_APERTURE_LOW_ADDR, + min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18); + +- if (adev->apu_flags & AMD_APU_IS_RAVEN2) ++ if (adev->apu_flags & (AMD_APU_IS_RAVEN2 | ++ AMD_APU_IS_RENOIR | ++ AMD_APU_IS_GREEN_SARDINE)) + /* + * Raven2 has a HW issue that it is unable to use the vram which + * is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. So here is the +diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c +index 784c4e07747077..3d8e579d5c4e8a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c ++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c +@@ -130,6 +130,9 @@ static void mmhub_v1_8_init_system_aperture_regs(struct amdgpu_device *adev) + uint64_t value; + int i; + ++ if (amdgpu_sriov_vf(adev)) ++ return; ++ + inst_mask = adev->aid_mask; + for_each_inst(i, inst_mask) { + /* Program the AGP BAR */ +@@ -139,9 +142,6 @@ static void mmhub_v1_8_init_system_aperture_regs(struct amdgpu_device *adev) + WREG32_SOC15(MMHUB, i, regMC_VM_AGP_TOP, + adev->gmc.agp_end >> 24); + +- if (amdgpu_sriov_vf(adev)) +- return; +- + /* Program the system aperture low logical page number. */ + WREG32_SOC15(MMHUB, i, regMC_VM_SYSTEM_APERTURE_LOW_ADDR, + min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18); +diff --git a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c +index b6a8478dabf43c..737eff53f54f04 100644 +--- a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c +@@ -442,6 +442,12 @@ static u32 navi10_ih_get_wptr(struct amdgpu_device *adev, + tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl); + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); ++ ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + out: + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c b/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c +index 4038455d799845..ef368ca79a6686 100644 +--- a/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c +@@ -28,6 +28,7 @@ + #include "nbio/nbio_2_3_offset.h" + #include "nbio/nbio_2_3_sh_mask.h" + #include ++#include + #include + + #define smnPCIE_CONFIG_CNTL 0x11180044 +@@ -361,7 +362,7 @@ static void nbio_v2_3_enable_aspm(struct amdgpu_device *adev, + + data |= NAVI10_PCIE__LC_L0S_INACTIVITY_DEFAULT << PCIE_LC_CNTL__LC_L0S_INACTIVITY__SHIFT; + +- if (pci_is_thunderbolt_attached(adev->pdev)) ++ if (dev_is_removable(&adev->pdev->dev)) + data |= NAVI10_PCIE__LC_L1_INACTIVITY_TBT_DEFAULT << PCIE_LC_CNTL__LC_L1_INACTIVITY__SHIFT; + else + data |= NAVI10_PCIE__LC_L1_INACTIVITY_DEFAULT << PCIE_LC_CNTL__LC_L1_INACTIVITY__SHIFT; +@@ -480,7 +481,7 @@ static void nbio_v2_3_program_aspm(struct amdgpu_device *adev) + + def = data = RREG32_PCIE(smnPCIE_LC_CNTL); + data |= NAVI10_PCIE__LC_L0S_INACTIVITY_DEFAULT << PCIE_LC_CNTL__LC_L0S_INACTIVITY__SHIFT; +- if (pci_is_thunderbolt_attached(adev->pdev)) ++ if (dev_is_removable(&adev->pdev->dev)) + data |= NAVI10_PCIE__LC_L1_INACTIVITY_TBT_DEFAULT << PCIE_LC_CNTL__LC_L1_INACTIVITY__SHIFT; + else + data |= NAVI10_PCIE__LC_L1_INACTIVITY_DEFAULT << PCIE_LC_CNTL__LC_L1_INACTIVITY__SHIFT; +diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c +index 685abf57ffddc1..977b956bf930a7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c ++++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c +@@ -384,7 +384,7 @@ static void nbio_v7_4_handle_ras_controller_intr_no_bifring(struct amdgpu_device + else + WREG32_SOC15(NBIO, 0, mmBIF_DOORBELL_INT_CNTL, bif_doorbell_intr_cntl); + +- if (!ras->disable_ras_err_cnt_harvest) { ++ if (ras && !ras->disable_ras_err_cnt_harvest && obj) { + /* + * clear error status after ras_controller_intr + * according to hw team and count ue number +diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c +index f85eec05d21815..0a601336cf697f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c ++++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c +@@ -426,6 +426,12 @@ static void nbio_v7_9_init_registers(struct amdgpu_device *adev) + u32 inst_mask; + int i; + ++ if (amdgpu_sriov_vf(adev)) ++ adev->rmmio_remap.reg_offset = ++ SOC15_REG_OFFSET( ++ NBIO, 0, ++ regBIF_BX_DEV0_EPF0_VF0_HDP_MEM_COHERENCY_FLUSH_CNTL) ++ << 2; + WREG32_SOC15(NBIO, 0, regXCC_DOORBELL_FENCE, + 0xff & ~(adev->gfx.xcc_mask)); + +@@ -604,11 +610,6 @@ static void nbio_v7_9_handle_ras_controller_intr_no_bifring(struct amdgpu_device + + dev_info(adev->dev, "RAS controller interrupt triggered " + "by NBIF error\n"); +- +- /* ras_controller_int is dedicated for nbif ras error, +- * not the global interrupt for sync flood +- */ +- amdgpu_ras_reset_gpu(adev); + } + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c +index 469eed084976c7..fe1995ed13be7b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c +@@ -59,6 +59,9 @@ MODULE_FIRMWARE("amdgpu/psp_14_0_0_ta.bin"); + /* Read USB-PD from LFB */ + #define GFX_CMD_USB_PD_USE_LFB 0x480 + ++/* Retry times for vmbx ready wait */ ++#define PSP_VMBX_POLLING_LIMIT 3000 ++ + /* VBIOS gfl defines */ + #define MBOX_READY_MASK 0x80000000 + #define MBOX_STATUS_MASK 0x0000FFFF +@@ -138,7 +141,7 @@ static int psp_v13_0_wait_for_vmbx_ready(struct psp_context *psp) + struct amdgpu_device *adev = psp->adev; + int retry_loop, ret; + +- for (retry_loop = 0; retry_loop < 70; retry_loop++) { ++ for (retry_loop = 0; retry_loop < PSP_VMBX_POLLING_LIMIT; retry_loop++) { + /* Wait for bootloader to signify that is + ready having bit 31 of C2PMSG_33 set to 1 */ + ret = psp_wait_for( +@@ -158,14 +161,18 @@ static int psp_v13_0_wait_for_vmbx_ready(struct psp_context *psp) + static int psp_v13_0_wait_for_bootloader(struct psp_context *psp) + { + struct amdgpu_device *adev = psp->adev; +- int retry_loop, ret; ++ int retry_loop, retry_cnt, ret; + ++ retry_cnt = ++ (adev->ip_versions[MP0_HWIP][0] == IP_VERSION(13, 0, 6)) ? ++ PSP_VMBX_POLLING_LIMIT : ++ 10; + /* 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++) { ++ for (retry_loop = 0; retry_loop < retry_cnt; retry_loop++) { + ret = psp_wait_for( + psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_35), + 0x80000000, 0xffffffff, false); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +index cd37f45e01a119..0ba9a3d3312f5a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +@@ -2027,10 +2027,13 @@ static int sdma_v4_0_process_trap_irq(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) + { +- uint32_t instance; ++ int instance; + + DRM_DEBUG("IH: SDMA trap\n"); + instance = sdma_v4_0_irq_id_to_seq(entry->client_id); ++ if (instance < 0) ++ return instance; ++ + switch (entry->ring_id) { + case 0: + amdgpu_fence_process(&adev->sdma.instance[instance].ring); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +index f413898dda37db..4e8d5e6a65e410 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +@@ -365,7 +365,8 @@ static void sdma_v4_4_2_ring_emit_hdp_flush(struct amdgpu_ring *ring) + u32 ref_and_mask = 0; + const struct nbio_hdp_flush_reg *nbio_hf_reg = adev->nbio.hdp_flush_reg; + +- ref_and_mask = nbio_hf_reg->ref_and_mask_sdma0 << ring->me; ++ ref_and_mask = nbio_hf_reg->ref_and_mask_sdma0 ++ << (ring->me % adev->sdma.num_inst_per_aid); + + sdma_v4_4_2_wait_reg_mem(ring, 0, 1, + adev->nbio.funcs->get_hdp_flush_done_offset(adev), +@@ -1612,19 +1613,9 @@ static int sdma_v4_4_2_set_ecc_irq_state(struct amdgpu_device *adev, + u32 sdma_cntl; + + sdma_cntl = RREG32_SDMA(type, regSDMA_CNTL); +- switch (state) { +- case AMDGPU_IRQ_STATE_DISABLE: +- sdma_cntl = REG_SET_FIELD(sdma_cntl, SDMA_CNTL, +- DRAM_ECC_INT_ENABLE, 0); +- WREG32_SDMA(type, regSDMA_CNTL, sdma_cntl); +- break; +- /* sdma ecc interrupt is enabled by default +- * driver doesn't need to do anything to +- * enable the interrupt */ +- case AMDGPU_IRQ_STATE_ENABLE: +- default: +- break; +- } ++ sdma_cntl = REG_SET_FIELD(sdma_cntl, SDMA_CNTL, DRAM_ECC_INT_ENABLE, ++ state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0); ++ WREG32_SDMA(type, regSDMA_CNTL, sdma_cntl); + + return 0; + } +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +index 2b3ebebc4299c0..47d4840c6275c7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +@@ -188,6 +188,14 @@ static void sdma_v5_2_ring_set_wptr(struct amdgpu_ring *ring) + DRM_DEBUG("calling WDOORBELL64(0x%08x, 0x%016llx)\n", + ring->doorbell_index, ring->wptr << 2); + WDOORBELL64(ring->doorbell_index, ring->wptr << 2); ++ /* SDMA seems to miss doorbells sometimes when powergating kicks in. ++ * Updating the wptr directly will wake it. This is only safe because ++ * we disallow gfxoff in begin_use() and then allow it again in end_use(). ++ */ ++ WREG32(sdma_v5_2_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR), ++ lower_32_bits(ring->wptr << 2)); ++ WREG32(sdma_v5_2_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR_HI), ++ upper_32_bits(ring->wptr << 2)); + } else { + DRM_DEBUG("Not using doorbell -- " + "mmSDMA%i_GFX_RB_WPTR == 0x%08x " +@@ -292,17 +300,21 @@ static void sdma_v5_2_ring_emit_hdp_flush(struct amdgpu_ring *ring) + u32 ref_and_mask = 0; + const struct nbio_hdp_flush_reg *nbio_hf_reg = adev->nbio.hdp_flush_reg; + +- ref_and_mask = nbio_hf_reg->ref_and_mask_sdma0 << ring->me; +- +- amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_POLL_REGMEM) | +- SDMA_PKT_POLL_REGMEM_HEADER_HDP_FLUSH(1) | +- SDMA_PKT_POLL_REGMEM_HEADER_FUNC(3)); /* == */ +- amdgpu_ring_write(ring, (adev->nbio.funcs->get_hdp_flush_done_offset(adev)) << 2); +- amdgpu_ring_write(ring, (adev->nbio.funcs->get_hdp_flush_req_offset(adev)) << 2); +- amdgpu_ring_write(ring, ref_and_mask); /* reference */ +- amdgpu_ring_write(ring, ref_and_mask); /* mask */ +- amdgpu_ring_write(ring, SDMA_PKT_POLL_REGMEM_DW5_RETRY_COUNT(0xfff) | +- SDMA_PKT_POLL_REGMEM_DW5_INTERVAL(10)); /* retry count, poll interval */ ++ if (ring->me > 1) { ++ amdgpu_asic_flush_hdp(adev, ring); ++ } else { ++ ref_and_mask = nbio_hf_reg->ref_and_mask_sdma0 << ring->me; ++ ++ amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_POLL_REGMEM) | ++ SDMA_PKT_POLL_REGMEM_HEADER_HDP_FLUSH(1) | ++ SDMA_PKT_POLL_REGMEM_HEADER_FUNC(3)); /* == */ ++ amdgpu_ring_write(ring, (adev->nbio.funcs->get_hdp_flush_done_offset(adev)) << 2); ++ amdgpu_ring_write(ring, (adev->nbio.funcs->get_hdp_flush_req_offset(adev)) << 2); ++ amdgpu_ring_write(ring, ref_and_mask); /* reference */ ++ amdgpu_ring_write(ring, ref_and_mask); /* mask */ ++ amdgpu_ring_write(ring, SDMA_PKT_POLL_REGMEM_DW5_RETRY_COUNT(0xfff) | ++ SDMA_PKT_POLL_REGMEM_DW5_INTERVAL(10)); /* retry count, poll interval */ ++ } + } + + /** +@@ -1651,6 +1663,36 @@ static void sdma_v5_2_get_clockgating_state(void *handle, u64 *flags) + *flags |= AMD_CG_SUPPORT_SDMA_LS; + } + ++static void sdma_v5_2_ring_begin_use(struct amdgpu_ring *ring) ++{ ++ struct amdgpu_device *adev = ring->adev; ++ ++ /* SDMA 5.2.3 (RMB) FW doesn't seem to properly ++ * disallow GFXOFF in some cases leading to ++ * hangs in SDMA. Disallow GFXOFF while SDMA is active. ++ * We can probably just limit this to 5.2.3, ++ * but it shouldn't hurt for other parts since ++ * this GFXOFF will be disallowed anyway when SDMA is ++ * active, this just makes it explicit. ++ * sdma_v5_2_ring_set_wptr() takes advantage of this ++ * to update the wptr because sometimes SDMA seems to miss ++ * doorbells when entering PG. If you remove this, update ++ * sdma_v5_2_ring_set_wptr() as well! ++ */ ++ amdgpu_gfx_off_ctrl(adev, false); ++} ++ ++static void sdma_v5_2_ring_end_use(struct amdgpu_ring *ring) ++{ ++ struct amdgpu_device *adev = ring->adev; ++ ++ /* SDMA 5.2.3 (RMB) FW doesn't seem to properly ++ * disallow GFXOFF in some cases leading to ++ * hangs in SDMA. Allow GFXOFF when SDMA is complete. ++ */ ++ amdgpu_gfx_off_ctrl(adev, true); ++} ++ + const struct amd_ip_funcs sdma_v5_2_ip_funcs = { + .name = "sdma_v5_2", + .early_init = sdma_v5_2_early_init, +@@ -1698,6 +1740,8 @@ static const struct amdgpu_ring_funcs sdma_v5_2_ring_funcs = { + .test_ib = sdma_v5_2_ring_test_ib, + .insert_nop = sdma_v5_2_ring_insert_nop, + .pad_ib = sdma_v5_2_ring_pad_ib, ++ .begin_use = sdma_v5_2_ring_begin_use, ++ .end_use = sdma_v5_2_ring_end_use, + .emit_wreg = sdma_v5_2_ring_emit_wreg, + .emit_reg_wait = sdma_v5_2_ring_emit_reg_wait, + .emit_reg_write_reg_wait = sdma_v5_2_ring_emit_reg_write_reg_wait, +diff --git a/drivers/gpu/drm/amd/amdgpu/si_ih.c b/drivers/gpu/drm/amd/amdgpu/si_ih.c +index 9a24f17a57502e..cada9f300a7f51 100644 +--- a/drivers/gpu/drm/amd/amdgpu/si_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/si_ih.c +@@ -119,6 +119,12 @@ static u32 si_ih_get_wptr(struct amdgpu_device *adev, + tmp = RREG32(IH_RB_CNTL); + tmp |= IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK; + WREG32(IH_RB_CNTL, tmp); ++ ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp &= ~IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK; ++ WREG32(IH_RB_CNTL, tmp); + } + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c b/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c +index 8b8086d5c864bc..896c7e434d3bc8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c ++++ b/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c +@@ -93,7 +93,7 @@ static int sienna_cichlid_mode2_suspend_ip(struct amdgpu_device *adev) + adev->ip_blocks[i].status.hw = false; + } + +- return r; ++ return 0; + } + + static int +diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.c b/drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.c +index ae29620b1ea405..a7cef33a2a3da6 100644 +--- a/drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.c ++++ b/drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.c +@@ -92,7 +92,7 @@ static int smu_v13_0_10_mode2_suspend_ip(struct amdgpu_device *adev) + adev->ip_blocks[i].status.hw = false; + } + +- return r; ++ return 0; + } + + static int +diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c +index f5be40d7ba3679..a41ed67ea9feaf 100644 +--- a/drivers/gpu/drm/amd/amdgpu/soc15.c ++++ b/drivers/gpu/drm/amd/amdgpu/soc15.c +@@ -325,7 +325,8 @@ static u32 soc15_get_xclk(struct amdgpu_device *adev) + u32 reference_clock = adev->clock.spll.reference_freq; + + if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(12, 0, 0) || +- adev->ip_versions[MP1_HWIP][0] == IP_VERSION(12, 0, 1)) ++ adev->ip_versions[MP1_HWIP][0] == IP_VERSION(12, 0, 1) || ++ adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 6)) + return 10000; + if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(10, 0, 0) || + adev->ip_versions[MP1_HWIP][0] == IP_VERSION(10, 0, 1)) +@@ -573,11 +574,34 @@ soc15_asic_reset_method(struct amdgpu_device *adev) + return AMD_RESET_METHOD_MODE1; + } + ++static bool soc15_need_reset_on_resume(struct amdgpu_device *adev) ++{ ++ u32 sol_reg; ++ ++ sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81); ++ ++ /* Will reset for the following suspend abort cases. ++ * 1) Only reset limit on APU side, dGPU hasn't checked yet. ++ * 2) S3 suspend abort and TOS already launched. ++ */ ++ if (adev->flags & AMD_IS_APU && adev->in_s3 && ++ !adev->suspend_complete && ++ sol_reg) ++ return true; ++ ++ return false; ++} ++ + static int soc15_asic_reset(struct amdgpu_device *adev) + { + /* original raven doesn't have full asic reset */ +- if ((adev->apu_flags & AMD_APU_IS_RAVEN) || +- (adev->apu_flags & AMD_APU_IS_RAVEN2)) ++ /* On the latest Raven, the GPU reset can be performed ++ * successfully. So now, temporarily enable it for the ++ * S3 suspend abort case. ++ */ ++ if (((adev->apu_flags & AMD_APU_IS_RAVEN) || ++ (adev->apu_flags & AMD_APU_IS_RAVEN2)) && ++ !soc15_need_reset_on_resume(adev)) + return 0; + + switch (soc15_asic_reset_method(adev)) { +@@ -1159,6 +1183,11 @@ static int soc15_common_early_init(void *handle) + AMD_PG_SUPPORT_VCN_DPG | + AMD_PG_SUPPORT_JPEG; + adev->external_rev_id = adev->rev_id + 0x46; ++ /* GC 9.4.3 uses MMIO register region hole at a different offset */ ++ if (!amdgpu_sriov_vf(adev)) { ++ adev->rmmio_remap.reg_offset = 0x1A000; ++ adev->rmmio_remap.bus_addr = adev->rmmio_base + 0x1A000; ++ } + break; + default: + /* FIXME: not supported yet */ +@@ -1294,6 +1323,10 @@ static int soc15_common_resume(void *handle) + { + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + ++ if (soc15_need_reset_on_resume(adev)) { ++ dev_info(adev->dev, "S3 suspend abort case, let's reset ASIC.\n"); ++ soc15_asic_reset(adev); ++ } + return soc15_common_hw_init(adev); + } + +@@ -1416,9 +1449,11 @@ static void soc15_common_get_clockgating_state(void *handle, u64 *flags) + if (amdgpu_sriov_vf(adev)) + *flags = 0; + +- adev->nbio.funcs->get_clockgating_state(adev, flags); ++ if (adev->nbio.funcs && adev->nbio.funcs->get_clockgating_state) ++ adev->nbio.funcs->get_clockgating_state(adev, flags); + +- adev->hdp.funcs->get_clock_gating_state(adev, flags); ++ if (adev->hdp.funcs && adev->hdp.funcs->get_clock_gating_state) ++ adev->hdp.funcs->get_clock_gating_state(adev, flags); + + if (adev->ip_versions[MP0_HWIP][0] != IP_VERSION(13, 0, 2)) { + +@@ -1434,9 +1469,11 @@ static void soc15_common_get_clockgating_state(void *handle, u64 *flags) + } + + /* AMD_CG_SUPPORT_ROM_MGCG */ +- adev->smuio.funcs->get_clock_gating_state(adev, flags); ++ if (adev->smuio.funcs && adev->smuio.funcs->get_clock_gating_state) ++ adev->smuio.funcs->get_clock_gating_state(adev, flags); + +- adev->df.funcs->get_clockgating_state(adev, flags); ++ if (adev->df.funcs && adev->df.funcs->get_clockgating_state) ++ adev->df.funcs->get_clockgating_state(adev, flags); + } + + static int soc15_common_set_powergating_state(void *handle, +diff --git a/drivers/gpu/drm/amd/amdgpu/soc15d.h b/drivers/gpu/drm/amd/amdgpu/soc15d.h +index 2357ff39323f05..e74e1983da53aa 100644 +--- a/drivers/gpu/drm/amd/amdgpu/soc15d.h ++++ b/drivers/gpu/drm/amd/amdgpu/soc15d.h +@@ -76,6 +76,12 @@ + ((cond & 0xF) << 24) | \ + ((type & 0xF) << 28)) + ++#define CP_PACKETJ_NOP 0x60000000 ++#define CP_PACKETJ_GET_REG(x) ((x) & 0x3FFFF) ++#define CP_PACKETJ_GET_RES(x) (((x) >> 18) & 0x3F) ++#define CP_PACKETJ_GET_COND(x) (((x) >> 24) & 0xF) ++#define CP_PACKETJ_GET_TYPE(x) (((x) >> 28) & 0xF) ++ + /* Packet 3 types */ + #define PACKET3_NOP 0x10 + #define PACKET3_SET_BASE 0x11 +diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c +index 8b2ff2b281b0ad..4712ffc0a482c8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/soc21.c ++++ b/drivers/gpu/drm/amd/amdgpu/soc21.c +@@ -50,13 +50,13 @@ static const struct amd_ip_funcs soc21_common_ip_funcs; + /* SOC21 */ + static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array_vcn0[] = { + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2304, 0)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)}, + }; + + static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array_vcn1[] = { + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2304, 0)}, +- {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)}, ++ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 0)}, + }; + + static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_encode_vcn0 = { +@@ -449,10 +449,8 @@ static bool soc21_need_full_reset(struct amdgpu_device *adev) + { + switch (adev->ip_versions[GC_HWIP][0]) { + case IP_VERSION(11, 0, 0): +- return amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC); + case IP_VERSION(11, 0, 2): + case IP_VERSION(11, 0, 3): +- return false; + default: + return true; + } +@@ -804,10 +802,35 @@ static int soc21_common_suspend(void *handle) + return soc21_common_hw_fini(adev); + } + ++static bool soc21_need_reset_on_resume(struct amdgpu_device *adev) ++{ ++ u32 sol_reg1, sol_reg2; ++ ++ /* Will reset for the following suspend abort cases. ++ * 1) Only reset dGPU side. ++ * 2) S3 suspend got aborted and TOS is active. ++ */ ++ if (!(adev->flags & AMD_IS_APU) && adev->in_s3 && ++ !adev->suspend_complete) { ++ sol_reg1 = RREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_81); ++ msleep(100); ++ sol_reg2 = RREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_81); ++ ++ return (sol_reg1 != sol_reg2); ++ } ++ ++ return false; ++} ++ + static int soc21_common_resume(void *handle) + { + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + ++ if (soc21_need_reset_on_resume(adev)) { ++ dev_info(adev->dev, "S3 suspend aborted, resetting..."); ++ soc21_asic_reset(adev); ++ } ++ + return soc21_common_hw_init(adev); + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c +index 917707bba7f362..450b6e83150914 100644 +--- a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c +@@ -219,6 +219,12 @@ static u32 tonga_ih_get_wptr(struct amdgpu_device *adev, + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32(mmIH_RB_CNTL, tmp); + ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32(mmIH_RB_CNTL, tmp); ++ + out: + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c +index d364c6dd152c33..bf68e18e3824b8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c +@@ -373,6 +373,12 @@ static u32 vega10_ih_get_wptr(struct amdgpu_device *adev, + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); ++ + out: + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c +index dbc99536440f2f..131e7b769519c8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c +@@ -421,6 +421,12 @@ static u32 vega20_ih_get_wptr(struct amdgpu_device *adev, + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + ++ /* Unset the CLEAR_OVERFLOW bit immediately so new overflows ++ * can be detected. ++ */ ++ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); ++ WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); ++ + out: + return (wptr & ih->ptr_mask); + } +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +index c37f1fcd2165b5..19d46be6394295 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +@@ -417,7 +417,7 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p, + + err_create_queue: + if (wptr_bo) +- amdgpu_amdkfd_free_gtt_mem(dev->adev, wptr_bo); ++ amdgpu_amdkfd_free_gtt_mem(dev->adev, (void **)&wptr_bo); + err_wptr_map_gart: + err_bind_process: + err_pdd: +@@ -778,8 +778,8 @@ static int kfd_ioctl_get_process_apertures_new(struct file *filp, + * nodes, but not more than args->num_of_nodes as that is + * the amount of memory allocated by user + */ +- pa = kzalloc((sizeof(struct kfd_process_device_apertures) * +- args->num_of_nodes), GFP_KERNEL); ++ pa = kcalloc(args->num_of_nodes, sizeof(struct kfd_process_device_apertures), ++ GFP_KERNEL); + if (!pa) + return -ENOMEM; + +@@ -1138,7 +1138,7 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep, + goto err_unlock; + } + offset = dev->adev->rmmio_remap.bus_addr; +- if (!offset) { ++ if (!offset || (PAGE_SIZE > 4096)) { + err = -ENOMEM; + goto err_unlock; + } +@@ -1432,17 +1432,23 @@ static int kfd_ioctl_unmap_memory_from_gpu(struct file *filep, + goto sync_memory_failed; + } + } +- mutex_unlock(&p->mutex); + +- if (flush_tlb) { +- /* Flush TLBs after waiting for the page table updates to complete */ +- for (i = 0; i < args->n_devices; i++) { +- peer_pdd = kfd_process_device_data_by_id(p, devices_arr[i]); +- if (WARN_ON_ONCE(!peer_pdd)) +- continue; ++ /* Flush TLBs after waiting for the page table updates to complete */ ++ for (i = 0; i < args->n_devices; i++) { ++ peer_pdd = kfd_process_device_data_by_id(p, devices_arr[i]); ++ if (WARN_ON_ONCE(!peer_pdd)) ++ continue; ++ if (flush_tlb) + kfd_flush_tlb(peer_pdd, TLB_FLUSH_HEAVYWEIGHT); +- } ++ ++ /* Remove dma mapping after tlb flush to avoid IO_PAGE_FAULT */ ++ err = amdgpu_amdkfd_gpuvm_dmaunmap_mem(mem, peer_pdd->drm_priv); ++ if (err) ++ goto sync_memory_failed; + } ++ ++ mutex_unlock(&p->mutex); ++ + kfree(devices_arr); + + return 0; +@@ -1516,7 +1522,7 @@ static int kfd_ioctl_get_dmabuf_info(struct file *filep, + + /* Find a KFD GPU device that supports the get_dmabuf_info query */ + for (i = 0; kfd_topology_enum_kfd_devices(i, &dev) == 0; i++) +- if (dev) ++ if (dev && !kfd_devcgroup_check_permission(dev)) + break; + if (!dev) + return -EINVAL; +@@ -1538,7 +1544,7 @@ static int kfd_ioctl_get_dmabuf_info(struct file *filep, + if (xcp_id >= 0) + args->gpu_id = dmabuf_adev->kfd.dev->nodes[xcp_id]->id; + else +- args->gpu_id = dmabuf_adev->kfd.dev->nodes[0]->id; ++ args->gpu_id = dev->id; + args->flags = flags; + + /* Copy metadata buffer to user mode */ +@@ -2307,7 +2313,7 @@ static int criu_restore_memory_of_gpu(struct kfd_process_device *pdd, + return -EINVAL; + } + offset = pdd->dev->adev->rmmio_remap.bus_addr; +- if (!offset) { ++ if (!offset || (PAGE_SIZE > 4096)) { + pr_err("amdgpu_amdkfd_get_mmio_remap_phys_addr failed\n"); + return -ENOMEM; + } +@@ -3348,6 +3354,9 @@ static int kfd_mmio_mmap(struct kfd_node *dev, struct kfd_process *process, + if (vma->vm_end - vma->vm_start != PAGE_SIZE) + return -EINVAL; + ++ if (PAGE_SIZE > 4096) ++ return -EINVAL; ++ + address = dev->adev->rmmio_remap.bus_addr; + + vm_flags_set(vma, VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_NORESERVE | +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.h b/drivers/gpu/drm/amd/amdkfd/kfd_crat.h +index 74c2d7a0d62857..2f54ee08f26961 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.h ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.h +@@ -42,8 +42,6 @@ + #define CRAT_OEMTABLEID_LENGTH 8 + #define CRAT_RESERVED_LENGTH 6 + +-#define CRAT_OEMID_64BIT_MASK ((1ULL << (CRAT_OEMID_LENGTH * 8)) - 1) +- + /* Compute Unit flags */ + #define COMPUTE_UNIT_CPU (1 << 0) /* Create Virtual CRAT for CPU */ + #define COMPUTE_UNIT_GPU (1 << 1) /* Create Virtual CRAT for GPU */ +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c +index 9ec750666382fe..94aaf2fc556ca1 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c +@@ -103,7 +103,8 @@ void debug_event_write_work_handler(struct work_struct *work) + struct kfd_process, + debug_event_workarea); + +- kernel_write(process->dbg_ev_file, &write_data, 1, &pos); ++ if (process->debug_trap_enabled && process->dbg_ev_file) ++ kernel_write(process->dbg_ev_file, &write_data, 1, &pos); + } + + /* update process/device/queue exception status, write to descriptor +@@ -645,6 +646,7 @@ int kfd_dbg_trap_disable(struct kfd_process *target) + else if (target->runtime_info.runtime_state != DEBUG_RUNTIME_STATE_DISABLED) + target->runtime_info.runtime_state = DEBUG_RUNTIME_STATE_ENABLED; + ++ cancel_work_sync(&target->debug_event_workarea); + fput(target->dbg_ev_file); + target->dbg_ev_file = NULL; + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c +index 93ce181eb3baa0..9d0b0bf70ad1ea 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c +@@ -402,15 +402,8 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf) + f2g = &gfx_v11_kfd2kgd; + break; + case IP_VERSION(11, 0, 3): +- if ((adev->pdev->device == 0x7460 && +- adev->pdev->revision == 0x00) || +- (adev->pdev->device == 0x7461 && +- adev->pdev->revision == 0x00)) +- /* Note: Compiler version is 11.0.5 while HW version is 11.0.3 */ +- gfx_target_version = 110005; +- else +- /* Note: Compiler version is 11.0.1 while HW version is 11.0.3 */ +- gfx_target_version = 110001; ++ /* Note: Compiler version is 11.0.1 while HW version is 11.0.3 */ ++ gfx_target_version = 110001; + f2g = &gfx_v11_kfd2kgd; + break; + default: +@@ -845,7 +838,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, + kfd_doorbell_error: + kfd_gtt_sa_fini(kfd); + kfd_gtt_sa_init_error: +- amdgpu_amdkfd_free_gtt_mem(kfd->adev, kfd->gtt_mem); ++ amdgpu_amdkfd_free_gtt_mem(kfd->adev, &kfd->gtt_mem); + alloc_gtt_mem_failure: + dev_err(kfd_device, + "device %x:%x NOT added due to errors\n", +@@ -863,7 +856,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd) + kfd_doorbell_fini(kfd); + ida_destroy(&kfd->doorbell_ida); + kfd_gtt_sa_fini(kfd); +- amdgpu_amdkfd_free_gtt_mem(kfd->adev, kfd->gtt_mem); ++ amdgpu_amdkfd_free_gtt_mem(kfd->adev, &kfd->gtt_mem); + } + + kfree(kfd); +@@ -935,7 +928,6 @@ void kgd2kfd_suspend(struct kfd_dev *kfd, bool run_pm) + { + struct kfd_node *node; + int i; +- int count; + + if (!kfd->init_complete) + return; +@@ -943,12 +935,10 @@ void kgd2kfd_suspend(struct kfd_dev *kfd, bool run_pm) + /* for runtime suspend, skip locking kfd */ + if (!run_pm) { + mutex_lock(&kfd_processes_mutex); +- count = ++kfd_locked; +- mutex_unlock(&kfd_processes_mutex); +- + /* For first KFD device suspend all the KFD processes */ +- if (count == 1) ++ if (++kfd_locked == 1) + kfd_suspend_all_processes(); ++ mutex_unlock(&kfd_processes_mutex); + } + + for (i = 0; i < kfd->num_nodes; i++) { +@@ -959,7 +949,7 @@ void kgd2kfd_suspend(struct kfd_dev *kfd, bool run_pm) + + int kgd2kfd_resume(struct kfd_dev *kfd, bool run_pm) + { +- int ret, count, i; ++ int ret, i; + + if (!kfd->init_complete) + return 0; +@@ -973,12 +963,10 @@ int kgd2kfd_resume(struct kfd_dev *kfd, bool run_pm) + /* for runtime resume, skip unlocking kfd */ + if (!run_pm) { + mutex_lock(&kfd_processes_mutex); +- count = --kfd_locked; +- mutex_unlock(&kfd_processes_mutex); +- +- WARN_ONCE(count < 0, "KFD suspend / resume ref. error"); +- if (count == 0) ++ if (--kfd_locked == 0) + ret = kfd_resume_all_processes(); ++ WARN_ONCE(kfd_locked < 0, "KFD suspend / resume ref. error"); ++ mutex_unlock(&kfd_processes_mutex); + } + + return ret; +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +index 0d3d538b64ebc3..4d9a406925e189 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +@@ -407,7 +407,8 @@ static int allocate_doorbell(struct qcm_process_device *qpd, + + q->properties.doorbell_off = amdgpu_doorbell_index_on_bar(dev->adev, + qpd->proc_doorbells, +- q->doorbell_id); ++ q->doorbell_id, ++ dev->kfd->device_info.doorbell_size); + return 0; + } + +@@ -1979,6 +1980,7 @@ static int unmap_queues_cpsch(struct device_queue_manager *dqm, + pr_err("HIQ MQD's queue_doorbell_id0 is not 0, Queue preemption time out\n"); + while (halt_if_hws_hang) + schedule(); ++ kfd_hws_hang(dqm); + return -ETIME; + } + +@@ -2608,7 +2610,7 @@ static void deallocate_hiq_sdma_mqd(struct kfd_node *dev, + { + WARN(!mqd, "No hiq sdma mqd trunk to free"); + +- amdgpu_amdkfd_free_gtt_mem(dev->adev, mqd->gtt_mem); ++ amdgpu_amdkfd_free_gtt_mem(dev->adev, &mqd->gtt_mem); + } + + void device_queue_manager_uninit(struct device_queue_manager *dqm) +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c +index 7b38537c7c99bd..05c74887fd6fda 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c +@@ -161,7 +161,10 @@ void __iomem *kfd_get_kernel_doorbell(struct kfd_dev *kfd, + if (inx >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS) + return NULL; + +- *doorbell_off = amdgpu_doorbell_index_on_bar(kfd->adev, kfd->doorbells, inx); ++ *doorbell_off = amdgpu_doorbell_index_on_bar(kfd->adev, ++ kfd->doorbells, ++ inx, ++ kfd->device_info.doorbell_size); + inx *= 2; + + pr_debug("Get kernel queue doorbell\n" +@@ -240,7 +243,10 @@ phys_addr_t kfd_get_process_doorbells(struct kfd_process_device *pdd) + return 0; + } + +- first_db_index = amdgpu_doorbell_index_on_bar(adev, pdd->qpd.proc_doorbells, 0); ++ first_db_index = amdgpu_doorbell_index_on_bar(adev, ++ pdd->qpd.proc_doorbells, ++ 0, ++ pdd->dev->kfd->device_info.doorbell_size); + return adev->doorbell.base + first_db_index * sizeof(uint32_t); + } + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c +index 62b205dac63a05..6604a3f99c5ecf 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c +@@ -330,12 +330,6 @@ static void kfd_init_apertures_vi(struct kfd_process_device *pdd, uint8_t id) + pdd->gpuvm_limit = + pdd->dev->kfd->shared_resources.gpuvm_size - 1; + +- /* dGPUs: the reserved space for kernel +- * before SVM +- */ +- pdd->qpd.cwsr_base = SVM_CWSR_BASE; +- pdd->qpd.ib_base = SVM_IB_BASE; +- + pdd->scratch_base = MAKE_SCRATCH_APP_BASE_VI(); + pdd->scratch_limit = MAKE_SCRATCH_APP_LIMIT(pdd->scratch_base); + } +@@ -345,18 +339,18 @@ static void kfd_init_apertures_v9(struct kfd_process_device *pdd, uint8_t id) + pdd->lds_base = MAKE_LDS_APP_BASE_V9(); + pdd->lds_limit = MAKE_LDS_APP_LIMIT(pdd->lds_base); + +- pdd->gpuvm_base = PAGE_SIZE; ++ /* Raven needs SVM to support graphic handle, etc. Leave the small ++ * reserved space before SVM on Raven as well, even though we don't ++ * have to. ++ * Set gpuvm_base and gpuvm_limit to CANONICAL addresses so that they ++ * are used in Thunk to reserve SVM. ++ */ ++ pdd->gpuvm_base = SVM_USER_BASE; + pdd->gpuvm_limit = + pdd->dev->kfd->shared_resources.gpuvm_size - 1; + + pdd->scratch_base = MAKE_SCRATCH_APP_BASE_V9(); + pdd->scratch_limit = MAKE_SCRATCH_APP_LIMIT(pdd->scratch_base); +- +- /* +- * Place TBA/TMA on opposite side of VM hole to prevent +- * stray faults from triggering SVM on these pages. +- */ +- pdd->qpd.cwsr_base = pdd->dev->kfd->shared_resources.gpuvm_size; + } + + int kfd_init_apertures(struct kfd_process *process) +@@ -413,6 +407,12 @@ int kfd_init_apertures(struct kfd_process *process) + return -EINVAL; + } + } ++ ++ /* dGPUs: the reserved space for kernel ++ * before SVM ++ */ ++ pdd->qpd.cwsr_base = SVM_CWSR_BASE; ++ pdd->qpd.ib_base = SVM_IB_BASE; + } + + dev_dbg(kfd_device, "node id %u\n", id); +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c +index c7991e07b6be56..f85ca6cb90f56c 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c +@@ -268,7 +268,7 @@ static void event_interrupt_wq_v10(struct kfd_node *dev, + SQ_INTERRUPT_WORD_WAVE_CTXID1, ENCODING); + switch (encoding) { + case SQ_INTERRUPT_WORD_ENCODING_AUTO: +- pr_debug( ++ pr_debug_ratelimited( + "sq_intr: auto, se %d, ttrace %d, wlt %d, ttrac_buf0_full %d, ttrac_buf1_full %d, ttrace_utc_err %d\n", + REG_GET_FIELD(context_id1, SQ_INTERRUPT_WORD_AUTO_CTXID1, + SE_ID), +@@ -284,7 +284,7 @@ static void event_interrupt_wq_v10(struct kfd_node *dev, + THREAD_TRACE_UTC_ERROR)); + break; + case SQ_INTERRUPT_WORD_ENCODING_INST: +- pr_debug("sq_intr: inst, se %d, data 0x%x, sa %d, priv %d, wave_id %d, simd_id %d, wgp_id %d\n", ++ pr_debug_ratelimited("sq_intr: inst, se %d, data 0x%x, sa %d, priv %d, wave_id %d, simd_id %d, wgp_id %d\n", + REG_GET_FIELD(context_id1, SQ_INTERRUPT_WORD_WAVE_CTXID1, + SE_ID), + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID0, +@@ -310,7 +310,7 @@ static void event_interrupt_wq_v10(struct kfd_node *dev, + case SQ_INTERRUPT_WORD_ENCODING_ERROR: + sq_intr_err_type = REG_GET_FIELD(context_id0, KFD_CTXID0, + ERR_TYPE); +- pr_warn("sq_intr: error, se %d, data 0x%x, sa %d, priv %d, wave_id %d, simd_id %d, wgp_id %d, err_type %d\n", ++ pr_warn_ratelimited("sq_intr: error, se %d, data 0x%x, sa %d, priv %d, wave_id %d, simd_id %d, wgp_id %d, err_type %d\n", + REG_GET_FIELD(context_id1, SQ_INTERRUPT_WORD_WAVE_CTXID1, + SE_ID), + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID0, +@@ -336,7 +336,8 @@ static void event_interrupt_wq_v10(struct kfd_node *dev, + break; + } + kfd_signal_event_interrupt(pasid, context_id0 & 0x7fffff, 23); +- } else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE) { ++ } else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE && ++ KFD_DBG_EC_TYPE_IS_PACKET(KFD_DEBUG_CP_BAD_OP_ECODE(context_id0))) { + kfd_set_dbg_ev_from_interrupt(dev, pasid, + KFD_DEBUG_DOORBELL_ID(context_id0), + KFD_EC_MASK(KFD_DEBUG_CP_BAD_OP_ECODE(context_id0)), +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c +index f933bd231fb9ce..3ca9c160da7c23 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c +@@ -150,7 +150,7 @@ enum SQ_INTERRUPT_ERROR_TYPE { + + static void print_sq_intr_info_auto(uint32_t context_id0, uint32_t context_id1) + { +- pr_debug( ++ pr_debug_ratelimited( + "sq_intr: auto, ttrace %d, wlt %d, ttrace_buf_full %d, reg_tms %d, cmd_tms %d, host_cmd_ovf %d, host_reg_ovf %d, immed_ovf %d, ttrace_utc_err %d\n", + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, THREAD_TRACE), + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, WLT), +@@ -165,7 +165,7 @@ static void print_sq_intr_info_auto(uint32_t context_id0, uint32_t context_id1) + + static void print_sq_intr_info_inst(uint32_t context_id0, uint32_t context_id1) + { +- pr_debug( ++ pr_debug_ratelimited( + "sq_intr: inst, data 0x%08x, sh %d, priv %d, wave_id %d, simd_id %d, wgp_id %d\n", + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID0, DATA), + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID0, SH_ID), +@@ -177,7 +177,7 @@ static void print_sq_intr_info_inst(uint32_t context_id0, uint32_t context_id1) + + static void print_sq_intr_info_error(uint32_t context_id0, uint32_t context_id1) + { +- pr_warn( ++ pr_warn_ratelimited( + "sq_intr: error, detail 0x%08x, type %d, sh %d, priv %d, wave_id %d, simd_id %d, wgp_id %d\n", + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_ERROR_CTXID0, DETAIL), + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_ERROR_CTXID0, TYPE), +@@ -325,7 +325,8 @@ static void event_interrupt_wq_v11(struct kfd_node *dev, + /* CP */ + if (source_id == SOC15_INTSRC_CP_END_OF_PIPE) + kfd_signal_event_interrupt(pasid, context_id0, 32); +- else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE) ++ else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE && ++ KFD_DBG_EC_TYPE_IS_PACKET(KFD_CTXID0_CP_BAD_OP_ECODE(context_id0))) + kfd_set_dbg_ev_from_interrupt(dev, pasid, + KFD_CTXID0_DOORBELL_ID(context_id0), + KFD_EC_MASK(KFD_CTXID0_CP_BAD_OP_ECODE(context_id0)), +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c +index 830396b1c3b145..8a6729939ae55f 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c +@@ -333,7 +333,7 @@ static void event_interrupt_wq_v9(struct kfd_node *dev, + encoding = REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID, ENCODING); + switch (encoding) { + case SQ_INTERRUPT_WORD_ENCODING_AUTO: +- pr_debug( ++ pr_debug_ratelimited( + "sq_intr: auto, se %d, ttrace %d, wlt %d, ttrac_buf_full %d, reg_tms %d, cmd_tms %d, host_cmd_ovf %d, host_reg_ovf %d, immed_ovf %d, ttrace_utc_err %d\n", + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID, SE_ID), + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID, THREAD_TRACE), +@@ -347,7 +347,7 @@ static void event_interrupt_wq_v9(struct kfd_node *dev, + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID, THREAD_TRACE_UTC_ERROR)); + break; + case SQ_INTERRUPT_WORD_ENCODING_INST: +- pr_debug("sq_intr: inst, se %d, data 0x%x, sh %d, priv %d, wave_id %d, simd_id %d, cu_id %d, intr_data 0x%x\n", ++ pr_debug_ratelimited("sq_intr: inst, se %d, data 0x%x, sh %d, priv %d, wave_id %d, simd_id %d, cu_id %d, intr_data 0x%x\n", + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID, SE_ID), + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID, DATA), + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID, SH_ID), +@@ -366,7 +366,7 @@ static void event_interrupt_wq_v9(struct kfd_node *dev, + break; + case SQ_INTERRUPT_WORD_ENCODING_ERROR: + sq_intr_err = REG_GET_FIELD(sq_int_data, KFD_SQ_INT_DATA, ERR_TYPE); +- pr_warn("sq_intr: error, se %d, data 0x%x, sh %d, priv %d, wave_id %d, simd_id %d, cu_id %d, err_type %d\n", ++ pr_warn_ratelimited("sq_intr: error, se %d, data 0x%x, sh %d, priv %d, wave_id %d, simd_id %d, cu_id %d, err_type %d\n", + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID, SE_ID), + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID, DATA), + REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID, SH_ID), +@@ -385,7 +385,8 @@ static void event_interrupt_wq_v9(struct kfd_node *dev, + break; + } + kfd_signal_event_interrupt(pasid, sq_int_data, 24); +- } else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE) { ++ } else if (source_id == SOC15_INTSRC_CP_BAD_OPCODE && ++ KFD_DBG_EC_TYPE_IS_PACKET(KFD_DEBUG_CP_BAD_OP_ECODE(context_id0))) { + kfd_set_dbg_ev_from_interrupt(dev, pasid, + KFD_DEBUG_DOORBELL_ID(context_id0), + KFD_EC_MASK(KFD_DEBUG_CP_BAD_OP_ECODE(context_id0)), +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +index 7d82c7da223ab8..3263b5fa182d20 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +@@ -516,10 +516,19 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, + start = prange->start << PAGE_SHIFT; + end = (prange->last + 1) << PAGE_SHIFT; + ++ r = amdgpu_amdkfd_reserve_mem_limit(node->adev, ++ prange->npages * PAGE_SIZE, ++ KFD_IOC_ALLOC_MEM_FLAGS_VRAM, ++ node->xcp ? node->xcp->id : 0); ++ if (r) { ++ dev_dbg(node->adev->dev, "failed to reserve VRAM, r: %ld\n", r); ++ return -ENOSPC; ++ } ++ + r = svm_range_vram_node_new(node, prange, true); + if (r) { + dev_dbg(node->adev->dev, "fail %ld to alloc vram\n", r); +- return r; ++ goto out; + } + ttm_res_offset = prange->offset << PAGE_SHIFT; + +@@ -549,6 +558,11 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, + svm_range_vram_node_free(prange); + } + ++out: ++ amdgpu_amdkfd_unreserve_mem_limit(node->adev, ++ prange->npages * PAGE_SIZE, ++ KFD_IOC_ALLOC_MEM_FLAGS_VRAM, ++ node->xcp ? node->xcp->id : 0); + return r < 0 ? r : 0; + } + +@@ -1021,7 +1035,7 @@ int kgd2kfd_init_zone_device(struct amdgpu_device *adev) + } else { + res = devm_request_free_mem_region(adev->dev, &iomem_resource, size); + if (IS_ERR(res)) +- return -ENOMEM; ++ return PTR_ERR(res); + pgmap->range.start = res->start; + pgmap->range.end = res->end; + pgmap->type = MEMORY_DEVICE_PRIVATE; +@@ -1037,10 +1051,10 @@ int kgd2kfd_init_zone_device(struct amdgpu_device *adev) + r = devm_memremap_pages(adev->dev, pgmap); + if (IS_ERR(r)) { + pr_err("failed to register HMM device memory\n"); +- /* Disable SVM support capability */ +- pgmap->type = 0; + if (pgmap->type == MEMORY_DEVICE_PRIVATE) + devm_release_mem_region(adev->dev, res->start, resource_size(res)); ++ /* Disable SVM support capability */ ++ pgmap->type = 0; + return PTR_ERR(r); + } + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c +index 447829c22295c6..4c3f379803117e 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c +@@ -223,7 +223,7 @@ void kfd_free_mqd_cp(struct mqd_manager *mm, void *mqd, + struct kfd_mem_obj *mqd_mem_obj) + { + if (mqd_mem_obj->gtt_mem) { +- amdgpu_amdkfd_free_gtt_mem(mm->dev->adev, mqd_mem_obj->gtt_mem); ++ amdgpu_amdkfd_free_gtt_mem(mm->dev->adev, &mqd_mem_obj->gtt_mem); + kfree(mqd_mem_obj); + } else { + kfd_gtt_sa_free(mm->dev, mqd_mem_obj); +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +index 8b7fed91352696..22cbfa1bdaddb9 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +@@ -170,6 +170,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, + m->cp_hqd_pq_control = 5 << CP_HQD_PQ_CONTROL__RPTR_BLOCK_SIZE__SHIFT; + m->cp_hqd_pq_control |= + ffs(q->queue_size / sizeof(unsigned int)) - 1 - 1; ++ m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__UNORD_DISPATCH_MASK; + pr_debug("cp_hqd_pq_control 0x%x\n", m->cp_hqd_pq_control); + + m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8); +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +index 15277f1d5cf0a9..d722cbd317834a 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +@@ -224,6 +224,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, + m->cp_hqd_pq_control = 5 << CP_HQD_PQ_CONTROL__RPTR_BLOCK_SIZE__SHIFT; + m->cp_hqd_pq_control |= + ffs(q->queue_size / sizeof(unsigned int)) - 1 - 1; ++ m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__UNORD_DISPATCH_MASK; + pr_debug("cp_hqd_pq_control 0x%x\n", m->cp_hqd_pq_control); + + m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8); +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +index 42d881809dc70e..1ac66c5337df47 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +@@ -686,7 +686,7 @@ static void update_mqd_v9_4_3(struct mqd_manager *mm, void *mqd, + m = get_mqd(mqd + size * xcc); + update_mqd(mm, m, q, minfo); + +- update_cu_mask(mm, mqd, minfo, xcc); ++ update_cu_mask(mm, m, minfo, xcc); + + if (q->format == KFD_QUEUE_FORMAT_AQL) { + switch (xcc) { +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +index fa24e1852493dc..67204c3dfbb8f6 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +@@ -971,7 +971,7 @@ struct kfd_process { + struct work_struct debug_event_workarea; + + /* Tracks debug per-vmid request for debug flags */ +- bool dbg_flags; ++ u32 dbg_flags; + + atomic_t poison; + /* Queues are in paused stated because we are in the process of doing a CRIU checkpoint */ +@@ -1128,7 +1128,7 @@ static inline struct kfd_node *kfd_node_by_irq_ids(struct amdgpu_device *adev, + struct kfd_dev *dev = adev->kfd.dev; + uint32_t i; + +- if (adev->ip_versions[GC_HWIP][0] != IP_VERSION(9, 4, 3)) ++ if (KFD_GC_VERSION(dev) != IP_VERSION(9, 4, 3)) + return dev->nodes[0]; + + for (i = 0; i < dev->num_nodes; i++) +@@ -1466,7 +1466,7 @@ void kfd_flush_tlb(struct kfd_process_device *pdd, enum TLB_FLUSH_TYPE type); + + static inline bool kfd_flush_tlb_after_unmap(struct kfd_dev *dev) + { +- return KFD_GC_VERSION(dev) > IP_VERSION(9, 4, 2) || ++ return KFD_GC_VERSION(dev) >= IP_VERSION(9, 4, 2) || + (KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 1) && dev->sdma_fw_version >= 18) || + KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 0); + } +@@ -1482,10 +1482,15 @@ void kfd_dec_compute_active(struct kfd_node *dev); + + /* Cgroup Support */ + /* Check with device cgroup if @kfd device is accessible */ +-static inline int kfd_devcgroup_check_permission(struct kfd_node *kfd) ++static inline int kfd_devcgroup_check_permission(struct kfd_node *node) + { + #if defined(CONFIG_CGROUP_DEVICE) || defined(CONFIG_CGROUP_BPF) +- struct drm_device *ddev = adev_to_drm(kfd->adev); ++ struct drm_device *ddev; ++ ++ if (node->xcp) ++ ddev = node->xcp->ddev; ++ else ++ ddev = adev_to_drm(node->adev); + + return devcgroup_check_permission(DEVCG_DEV_CHAR, DRM_MAJOR, + ddev->render->index, +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +index fbf053001af978..43f520b3796700 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +@@ -818,9 +818,9 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) + mutex_lock(&kfd_processes_mutex); + + if (kfd_is_locked()) { +- mutex_unlock(&kfd_processes_mutex); + pr_debug("KFD is locked! Cannot create process"); +- return ERR_PTR(-EINVAL); ++ process = ERR_PTR(-EINVAL); ++ goto out; + } + + /* A prior open of /dev/kfd could have already created the process. */ +@@ -828,6 +828,14 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) + if (process) { + pr_debug("Process already found\n"); + } else { ++ /* If the process just called exec(3), it is possible that the ++ * cleanup of the kfd_process (following the release of the mm ++ * of the old process image) is still in the cleanup work queue. ++ * Make sure to drain any job before trying to recreate any ++ * resource for this process. ++ */ ++ flush_workqueue(kfd_process_wq); ++ + process = create_process(thread); + if (IS_ERR(process)) + goto out; +@@ -1039,7 +1047,7 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) + + if (pdd->dev->kfd->shared_resources.enable_mes) + amdgpu_amdkfd_free_gtt_mem(pdd->dev->adev, +- pdd->proc_ctx_bo); ++ &pdd->proc_ctx_bo); + /* + * before destroying pdd, make sure to report availability + * for auto suspend +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +index adb5e4bdc0b204..0583af4e84fa3f 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +@@ -28,6 +28,7 @@ + #include "kfd_priv.h" + #include "kfd_kernel_queue.h" + #include "amdgpu_amdkfd.h" ++#include "amdgpu_reset.h" + + static inline struct process_queue_node *get_queue_by_qid( + struct process_queue_manager *pqm, unsigned int qid) +@@ -87,6 +88,12 @@ void kfd_process_dequeue_from_device(struct kfd_process_device *pdd) + return; + + dev->dqm->ops.process_termination(dev->dqm, &pdd->qpd); ++ if (dev->kfd->shared_resources.enable_mes && ++ down_read_trylock(&dev->adev->reset_domain->sem)) { ++ amdgpu_mes_flush_shader_debugger(dev->adev, ++ pdd->proc_ctx_gpu_addr); ++ up_read(&dev->adev->reset_domain->sem); ++ } + pdd->already_dequeued = true; + } + +@@ -169,16 +176,43 @@ int pqm_init(struct process_queue_manager *pqm, struct kfd_process *p) + return 0; + } + ++static void pqm_clean_queue_resource(struct process_queue_manager *pqm, ++ struct process_queue_node *pqn) ++{ ++ struct kfd_node *dev; ++ struct kfd_process_device *pdd; ++ ++ dev = pqn->q->device; ++ ++ pdd = kfd_get_process_device_data(dev, pqm->process); ++ if (!pdd) { ++ pr_err("Process device data doesn't exist\n"); ++ return; ++ } ++ ++ if (pqn->q->gws) { ++ if (KFD_GC_VERSION(pqn->q->device) != IP_VERSION(9, 4, 3) && ++ !dev->kfd->shared_resources.enable_mes) ++ amdgpu_amdkfd_remove_gws_from_process( ++ pqm->process->kgd_process_info, pqn->q->gws); ++ pdd->qpd.num_gws = 0; ++ } ++ ++ if (dev->kfd->shared_resources.enable_mes) { ++ amdgpu_amdkfd_free_gtt_mem(dev->adev, &pqn->q->gang_ctx_bo); ++ if (pqn->q->wptr_bo) ++ amdgpu_amdkfd_free_gtt_mem(dev->adev, (void **)&pqn->q->wptr_bo); ++ } ++} ++ + void pqm_uninit(struct process_queue_manager *pqm) + { + struct process_queue_node *pqn, *next; + + list_for_each_entry_safe(pqn, next, &pqm->queues, process_queue_list) { +- if (pqn->q && pqn->q->gws && +- KFD_GC_VERSION(pqn->q->device) != IP_VERSION(9, 4, 3) && +- !pqn->q->device->kfd->shared_resources.enable_mes) +- amdgpu_amdkfd_remove_gws_from_process(pqm->process->kgd_process_info, +- pqn->q->gws); ++ if (pqn->q) ++ pqm_clean_queue_resource(pqm, pqn); ++ + kfd_procfs_del_queue(pqn->q); + uninit_queue(pqn->q); + list_del(&pqn->process_queue_list); +@@ -377,7 +411,8 @@ int pqm_create_queue(struct process_queue_manager *pqm, + */ + uint32_t first_db_index = amdgpu_doorbell_index_on_bar(pdd->dev->adev, + pdd->qpd.proc_doorbells, +- 0); ++ 0, ++ pdd->dev->kfd->device_info.doorbell_size); + + *p_doorbell_offset_in_process = (q->properties.doorbell_off + - first_db_index) * sizeof(uint32_t); +@@ -460,22 +495,7 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid) + goto err_destroy_queue; + } + +- if (pqn->q->gws) { +- if (KFD_GC_VERSION(pqn->q->device) != IP_VERSION(9, 4, 3) && +- !dev->kfd->shared_resources.enable_mes) +- amdgpu_amdkfd_remove_gws_from_process( +- pqm->process->kgd_process_info, +- pqn->q->gws); +- pdd->qpd.num_gws = 0; +- } +- +- if (dev->kfd->shared_resources.enable_mes) { +- amdgpu_amdkfd_free_gtt_mem(dev->adev, +- pqn->q->gang_ctx_bo); +- if (pqn->q->wptr_bo) +- amdgpu_amdkfd_free_gtt_mem(dev->adev, pqn->q->wptr_bo); +- +- } ++ pqm_clean_queue_resource(pqm, pqn); + uninit_queue(pqn->q); + } + +@@ -962,6 +982,7 @@ int kfd_criu_restore_queue(struct kfd_process *p, + pr_debug("Queue id %d was restored successfully\n", queue_id); + + kfree(q_data); ++ kfree(q_extra_data); + + return ret; + } +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +index bb16b795d1bc2a..ce76d455499841 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +@@ -391,14 +391,9 @@ static void svm_range_bo_release(struct kref *kref) + spin_lock(&svm_bo->list_lock); + } + spin_unlock(&svm_bo->list_lock); +- if (!dma_fence_is_signaled(&svm_bo->eviction_fence->base)) { +- /* We're not in the eviction worker. +- * Signal the fence and synchronize with any +- * pending eviction work. +- */ ++ if (!dma_fence_is_signaled(&svm_bo->eviction_fence->base)) ++ /* We're not in the eviction worker. Signal the fence. */ + dma_fence_signal(&svm_bo->eviction_fence->base); +- cancel_work_sync(&svm_bo->eviction_work); +- } + dma_fence_put(&svm_bo->eviction_fence->base); + amdgpu_bo_unref(&svm_bo->bo); + kfree(svm_bo); +@@ -495,11 +490,11 @@ svm_range_validate_svm_bo(struct kfd_node *node, struct svm_range *prange) + + /* We need a new svm_bo. Spin-loop to wait for concurrent + * svm_range_bo_release to finish removing this range from +- * its range list. After this, it is safe to reuse the +- * svm_bo pointer and svm_bo_list head. ++ * its range list and set prange->svm_bo to null. After this, ++ * it is safe to reuse the svm_bo pointer and svm_bo_list head. + */ +- while (!list_empty_careful(&prange->svm_bo_list)) +- ; ++ while (!list_empty_careful(&prange->svm_bo_list) || prange->svm_bo) ++ cond_resched(); + + return false; + } +@@ -628,8 +623,15 @@ svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange, + + void svm_range_vram_node_free(struct svm_range *prange) + { +- svm_range_bo_unref(prange->svm_bo); +- prange->ttm_res = NULL; ++ /* serialize prange->svm_bo unref */ ++ mutex_lock(&prange->lock); ++ /* prange->svm_bo has not been unref */ ++ if (prange->ttm_res) { ++ prange->ttm_res = NULL; ++ mutex_unlock(&prange->lock); ++ svm_range_bo_unref(prange->svm_bo); ++ } else ++ mutex_unlock(&prange->lock); + } + + struct kfd_node * +@@ -760,7 +762,7 @@ svm_range_apply_attrs(struct kfd_process *p, struct svm_range *prange, + prange->flags &= ~attrs[i].value; + break; + case KFD_IOCTL_SVM_ATTR_GRANULARITY: +- prange->granularity = attrs[i].value; ++ prange->granularity = min_t(uint32_t, attrs[i].value, 0x3F); + break; + default: + WARN_ONCE(1, "svm_range_check_attrs wasn't called?"); +@@ -820,7 +822,7 @@ svm_range_is_same_attrs(struct kfd_process *p, struct svm_range *prange, + } + } + +- return !prange->is_error_flag; ++ return true; + } + + /** +@@ -1625,18 +1627,24 @@ static int svm_range_validate_and_map(struct mm_struct *mm, + if (test_bit(gpuidx, prange->bitmap_access)) + bitmap_set(ctx->bitmap, gpuidx, 1); + } ++ ++ /* ++ * If prange is already mapped or with always mapped flag, ++ * update mapping on GPUs with ACCESS attribute ++ */ ++ if (bitmap_empty(ctx->bitmap, MAX_GPU_INSTANCE)) { ++ if (prange->mapped_to_gpu || ++ prange->flags & KFD_IOCTL_SVM_FLAG_GPU_ALWAYS_MAPPED) ++ bitmap_copy(ctx->bitmap, prange->bitmap_access, MAX_GPU_INSTANCE); ++ } + } else { + bitmap_or(ctx->bitmap, prange->bitmap_access, + prange->bitmap_aip, MAX_GPU_INSTANCE); + } + + if (bitmap_empty(ctx->bitmap, MAX_GPU_INSTANCE)) { +- bitmap_copy(ctx->bitmap, prange->bitmap_access, MAX_GPU_INSTANCE); +- if (!prange->mapped_to_gpu || +- bitmap_empty(ctx->bitmap, MAX_GPU_INSTANCE)) { +- r = 0; +- goto free_ctx; +- } ++ r = 0; ++ goto free_ctx; + } + + if (prange->actual_loc && !prange->ttm_res) { +@@ -1662,73 +1670,66 @@ static int svm_range_validate_and_map(struct mm_struct *mm, + + start = prange->start << PAGE_SHIFT; + end = (prange->last + 1) << PAGE_SHIFT; +- for (addr = start; addr < end && !r; ) { ++ for (addr = start; !r && addr < end; ) { + struct hmm_range *hmm_range; + struct vm_area_struct *vma; +- unsigned long next; ++ unsigned long next = 0; + unsigned long offset; + unsigned long npages; + bool readonly; + + vma = vma_lookup(mm, addr); +- if (!vma) { ++ if (vma) { ++ readonly = !(vma->vm_flags & VM_WRITE); ++ ++ next = min(vma->vm_end, end); ++ npages = (next - addr) >> PAGE_SHIFT; ++ WRITE_ONCE(p->svms.faulting_task, current); ++ r = amdgpu_hmm_range_get_pages(&prange->notifier, addr, npages, ++ readonly, owner, NULL, ++ &hmm_range); ++ WRITE_ONCE(p->svms.faulting_task, NULL); ++ if (r) { ++ pr_debug("failed %d to get svm range pages\n", r); ++ if (r == -EBUSY) ++ r = -EAGAIN; ++ } ++ } else { + r = -EFAULT; +- goto unreserve_out; +- } +- readonly = !(vma->vm_flags & VM_WRITE); +- +- next = min(vma->vm_end, end); +- npages = (next - addr) >> PAGE_SHIFT; +- WRITE_ONCE(p->svms.faulting_task, current); +- r = amdgpu_hmm_range_get_pages(&prange->notifier, addr, npages, +- readonly, owner, NULL, +- &hmm_range); +- WRITE_ONCE(p->svms.faulting_task, NULL); +- if (r) { +- pr_debug("failed %d to get svm range pages\n", r); +- if (r == -EBUSY) +- r = -EAGAIN; +- goto unreserve_out; + } + +- offset = (addr - start) >> PAGE_SHIFT; +- r = svm_range_dma_map(prange, ctx->bitmap, offset, npages, +- hmm_range->hmm_pfns); +- if (r) { +- pr_debug("failed %d to dma map range\n", r); +- goto unreserve_out; ++ if (!r) { ++ offset = (addr - start) >> PAGE_SHIFT; ++ r = svm_range_dma_map(prange, ctx->bitmap, offset, npages, ++ hmm_range->hmm_pfns); ++ if (r) ++ pr_debug("failed %d to dma map range\n", r); + } + + svm_range_lock(prange); +- if (amdgpu_hmm_range_get_pages_done(hmm_range)) { ++ if (!r && amdgpu_hmm_range_get_pages_done(hmm_range)) { + pr_debug("hmm update the range, need validate again\n"); + r = -EAGAIN; +- goto unlock_out; + } +- if (!list_empty(&prange->child_list)) { ++ ++ if (!r && !list_empty(&prange->child_list)) { + pr_debug("range split by unmap in parallel, validate again\n"); + r = -EAGAIN; +- goto unlock_out; + } + +- r = svm_range_map_to_gpus(prange, offset, npages, readonly, +- ctx->bitmap, wait, flush_tlb); ++ if (!r) ++ r = svm_range_map_to_gpus(prange, offset, npages, readonly, ++ ctx->bitmap, wait, flush_tlb); ++ ++ if (!r && next == end) ++ prange->mapped_to_gpu = true; + +-unlock_out: + svm_range_unlock(prange); + + addr = next; + } + +- if (addr == end) { +- prange->validated_once = true; +- prange->mapped_to_gpu = true; +- } +- +-unreserve_out: + svm_range_unreserve_bos(ctx); +- +- prange->is_error_flag = !!r; + if (!r) + prange->validate_timestamp = ktime_get_boottime(); + +@@ -2097,7 +2098,8 @@ svm_range_add(struct kfd_process *p, uint64_t start, uint64_t size, + next = interval_tree_iter_next(node, start, last); + next_start = min(node->last, last) + 1; + +- if (svm_range_is_same_attrs(p, prange, nattr, attrs)) { ++ if (svm_range_is_same_attrs(p, prange, nattr, attrs) && ++ prange->mapped_to_gpu) { + /* nothing to do */ + } else if (node->start < start || node->last > last) { + /* node intersects the update range and its attributes +@@ -2341,8 +2343,10 @@ static void svm_range_deferred_list_work(struct work_struct *work) + mutex_unlock(&svms->lock); + mmap_write_unlock(mm); + +- /* Pairs with mmget in svm_range_add_list_work */ +- mmput(mm); ++ /* Pairs with mmget in svm_range_add_list_work. If dropping the ++ * last mm refcount, schedule release work to avoid circular locking ++ */ ++ mmput_async(mm); + + spin_lock(&svms->deferred_list_lock); + } +@@ -2653,6 +2657,7 @@ svm_range_get_range_boundaries(struct kfd_process *p, int64_t addr, + { + struct vm_area_struct *vma; + struct interval_tree_node *node; ++ struct rb_node *rb_node; + unsigned long start_limit, end_limit; + + vma = vma_lookup(p->mm, addr << PAGE_SHIFT); +@@ -2672,16 +2677,15 @@ svm_range_get_range_boundaries(struct kfd_process *p, int64_t addr, + if (node) { + end_limit = min(end_limit, node->start); + /* Last range that ends before the fault address */ +- node = container_of(rb_prev(&node->rb), +- struct interval_tree_node, rb); ++ rb_node = rb_prev(&node->rb); + } else { + /* Last range must end before addr because + * there was no range after addr + */ +- node = container_of(rb_last(&p->svms.objects.rb_root), +- struct interval_tree_node, rb); ++ rb_node = rb_last(&p->svms.objects.rb_root); + } +- if (node) { ++ if (rb_node) { ++ node = container_of(rb_node, struct interval_tree_node, rb); + if (node->last >= addr) { + WARN(1, "Overlap with prev node and page fault addr\n"); + return -EFAULT; +@@ -3412,18 +3416,19 @@ svm_range_trigger_migration(struct mm_struct *mm, struct svm_range *prange, + r = svm_migrate_to_vram(prange, best_loc, mm, KFD_MIGRATE_TRIGGER_PREFETCH); + *migrated = !r; + +- return r; ++ return 0; + } + + int svm_range_schedule_evict_svm_bo(struct amdgpu_amdkfd_fence *fence) + { +- if (!fence) +- return -EINVAL; +- +- if (dma_fence_is_signaled(&fence->base)) +- return 0; +- +- if (fence->svm_bo) { ++ /* Dereferencing fence->svm_bo is safe here because the fence hasn't ++ * signaled yet and we're under the protection of the fence->lock. ++ * After the fence is signaled in svm_range_bo_release, we cannot get ++ * here any more. ++ * ++ * Reference is dropped in svm_range_evict_svm_bo_worker. ++ */ ++ if (svm_bo_ref_unless_zero(fence->svm_bo)) { + WRITE_ONCE(fence->svm_bo->evicting, 1); + schedule_work(&fence->svm_bo->eviction_work); + } +@@ -3438,8 +3443,6 @@ static void svm_range_evict_svm_bo_worker(struct work_struct *work) + int r = 0; + + svm_bo = container_of(work, struct svm_range_bo, eviction_work); +- if (!svm_bo_ref_unless_zero(svm_bo)) +- return; /* svm_bo was freed while eviction was pending */ + + if (mmget_not_zero(svm_bo->eviction_fence->mm)) { + mm = svm_bo->eviction_fence->mm; +@@ -3507,7 +3510,7 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm, + struct svm_range *next; + bool update_mapping = false; + bool flush_tlb; +- int r = 0; ++ int r, ret = 0; + + pr_debug("pasid 0x%x svms 0x%p [0x%llx 0x%llx] pages 0x%llx\n", + p->pasid, &p->svms, start, start + size - 1, size); +@@ -3595,7 +3598,7 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm, + out_unlock_range: + mutex_unlock(&prange->migrate_mutex); + if (r) +- break; ++ ret = r; + } + + dynamic_svm_range_dump(svms); +@@ -3608,7 +3611,7 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm, + pr_debug("pasid 0x%x svms 0x%p [0x%llx 0x%llx] done, r=%d\n", p->pasid, + &p->svms, start, start + size - 1, r); + +- return r; ++ return ret ? ret : r; + } + + static int +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +index 9e668eeefb32df..25f71190573865 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +@@ -132,9 +132,7 @@ struct svm_range { + struct list_head child_list; + DECLARE_BITMAP(bitmap_access, MAX_GPU_INSTANCE); + DECLARE_BITMAP(bitmap_aip, MAX_GPU_INSTANCE); +- bool validated_once; + bool mapped_to_gpu; +- bool is_error_flag; + }; + + static inline void svm_range_lock(struct svm_range *prange) +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +index c8c75ff7cea80d..8362a71ab70752 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +@@ -958,8 +958,7 @@ static void kfd_update_system_properties(void) + dev = list_last_entry(&topology_device_list, + struct kfd_topology_device, list); + if (dev) { +- sys_props.platform_id = +- (*((uint64_t *)dev->oem_id)) & CRAT_OEMID_64BIT_MASK; ++ sys_props.platform_id = dev->oem_id64; + sys_props.platform_oem = *((uint64_t *)dev->oem_table_id); + sys_props.platform_rev = dev->oem_revision; + } +@@ -1342,10 +1341,11 @@ static int kfd_create_indirect_link_prop(struct kfd_topology_device *kdev, int g + num_cpu++; + } + ++ if (list_empty(&kdev->io_link_props)) ++ return -ENODATA; ++ + gpu_link = list_first_entry(&kdev->io_link_props, +- struct kfd_iolink_properties, list); +- if (!gpu_link) +- return -ENOMEM; ++ struct kfd_iolink_properties, list); + + for (i = 0; i < num_cpu; i++) { + /* CPU <--> GPU */ +@@ -1423,15 +1423,17 @@ static int kfd_add_peer_prop(struct kfd_topology_device *kdev, + peer->gpu->adev)) + return ret; + ++ if (list_empty(&kdev->io_link_props)) ++ return -ENODATA; ++ + iolink1 = list_first_entry(&kdev->io_link_props, +- struct kfd_iolink_properties, list); +- if (!iolink1) +- return -ENOMEM; ++ struct kfd_iolink_properties, list); ++ ++ if (list_empty(&peer->io_link_props)) ++ return -ENODATA; + + iolink2 = list_first_entry(&peer->io_link_props, +- struct kfd_iolink_properties, list); +- if (!iolink2) +- return -ENOMEM; ++ struct kfd_iolink_properties, list); + + props = kfd_alloc_struct(props); + if (!props) +@@ -1449,17 +1451,19 @@ static int kfd_add_peer_prop(struct kfd_topology_device *kdev, + /* CPU->CPU link*/ + cpu_dev = kfd_topology_device_by_proximity_domain(iolink1->node_to); + if (cpu_dev) { +- list_for_each_entry(iolink3, &cpu_dev->io_link_props, list) +- if (iolink3->node_to == iolink2->node_to) +- break; +- +- props->weight += iolink3->weight; +- props->min_latency += iolink3->min_latency; +- props->max_latency += iolink3->max_latency; +- props->min_bandwidth = min(props->min_bandwidth, +- iolink3->min_bandwidth); +- props->max_bandwidth = min(props->max_bandwidth, +- iolink3->max_bandwidth); ++ list_for_each_entry(iolink3, &cpu_dev->io_link_props, list) { ++ if (iolink3->node_to != iolink2->node_to) ++ continue; ++ ++ props->weight += iolink3->weight; ++ props->min_latency += iolink3->min_latency; ++ props->max_latency += iolink3->max_latency; ++ props->min_bandwidth = min(props->min_bandwidth, ++ iolink3->min_bandwidth); ++ props->max_bandwidth = min(props->max_bandwidth, ++ iolink3->max_bandwidth); ++ break; ++ } + } else { + WARN(1, "CPU node not found"); + } +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h +index 27386ce9a021da..2d1c9d771bef2d 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h +@@ -154,7 +154,10 @@ struct kfd_topology_device { + struct attribute attr_gpuid; + struct attribute attr_name; + struct attribute attr_props; +- uint8_t oem_id[CRAT_OEMID_LENGTH]; ++ union { ++ uint8_t oem_id[CRAT_OEMID_LENGTH]; ++ uint64_t oem_id64; ++ }; + uint8_t oem_table_id[CRAT_OEMTABLEID_LENGTH]; + uint32_t oem_revision; + }; +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 868946dd7ef126..a3f17c572bf06e 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -65,7 +65,6 @@ + #include "amdgpu_dm_debugfs.h" + #endif + #include "amdgpu_dm_psr.h" +-#include "amdgpu_dm_replay.h" + + #include "ivsrcid/ivsrcid_vislands30.h" + +@@ -265,7 +264,7 @@ static u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc) + static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc, + u32 *vbl, u32 *position) + { +- u32 v_blank_start, v_blank_end, h_position, v_position; ++ u32 v_blank_start = 0, v_blank_end = 0, h_position = 0, v_position = 0; + struct amdgpu_crtc *acrtc = NULL; + + if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc)) +@@ -715,6 +714,12 @@ static void dmub_hpd_callback(struct amdgpu_device *adev, + return; + } + ++ /* Skip DMUB HPD IRQ in suspend/resume. We will probe them later. */ ++ if (notify->type == DMUB_NOTIFICATION_HPD && adev->in_suspend) { ++ DRM_INFO("Skip DMUB HPD IRQ callback in suspend/resume\n"); ++ return; ++ } ++ + link_index = notify->link_index; + link = adev->dm.dc->links[link_index]; + dev = adev->dm.ddev; +@@ -802,7 +807,7 @@ static void dm_handle_hpd_work(struct work_struct *work) + */ + static void dm_dmub_outbox1_low_irq(void *interrupt_params) + { +- struct dmub_notification notify; ++ struct dmub_notification notify = {0}; + struct common_irq_params *irq_params = interrupt_params; + struct amdgpu_device *adev = irq_params->adev; + struct amdgpu_display_manager *dm = &adev->dm; +@@ -1248,7 +1253,9 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_ + /* AGP aperture is disabled */ + if (agp_bot == agp_top) { + logical_addr_low = adev->gmc.fb_start >> 18; +- if (adev->apu_flags & AMD_APU_IS_RAVEN2) ++ if (adev->apu_flags & (AMD_APU_IS_RAVEN2 | ++ AMD_APU_IS_RENOIR | ++ AMD_APU_IS_GREEN_SARDINE)) + /* + * Raven2 has a HW issue that it is unable to use the vram which + * is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. So here is the +@@ -1260,7 +1267,9 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_ + logical_addr_high = adev->gmc.fb_end >> 18; + } else { + logical_addr_low = min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18; +- if (adev->apu_flags & AMD_APU_IS_RAVEN2) ++ if (adev->apu_flags & (AMD_APU_IS_RAVEN2 | ++ AMD_APU_IS_RENOIR | ++ AMD_APU_IS_GREEN_SARDINE)) + /* + * Raven2 has a HW issue that it is unable to use the vram which + * is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. So here is the +@@ -1692,8 +1701,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) + DRM_INFO("Display Core v%s initialized on %s\n", DC_VER, + dce_version_to_string(adev->dm.dc->ctx->dce_version)); + } else { +- DRM_INFO("Display Core v%s failed to initialize on %s\n", DC_VER, +- dce_version_to_string(adev->dm.dc->ctx->dce_version)); ++ DRM_INFO("Display Core failed to initialize with v%s!\n", DC_VER); + goto error; + } + +@@ -1814,21 +1822,12 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) + DRM_ERROR("amdgpu: fail to register dmub aux callback"); + goto error; + } +- if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD, dmub_hpd_callback, true)) { +- DRM_ERROR("amdgpu: fail to register dmub hpd callback"); +- goto error; +- } +- if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD_IRQ, dmub_hpd_callback, true)) { +- DRM_ERROR("amdgpu: fail to register dmub hpd callback"); +- goto error; +- } +- } +- +- /* Enable outbox notification only after IRQ handlers are registered and DMUB is alive. +- * It is expected that DMUB will resend any pending notifications at this point, for +- * example HPD from DPIA. +- */ +- if (dc_is_dmub_outbox_supported(adev->dm.dc)) { ++ /* Enable outbox notification only after IRQ handlers are registered and DMUB is alive. ++ * It is expected that DMUB will resend any pending notifications at this point. Note ++ * that hpd and hpd_irq handler registration are deferred to register_hpd_handlers() to ++ * align legacy interface initialization sequence. Connection status will be proactivly ++ * detected once in the amdgpu_dm_initialize_drm_device. ++ */ + dc_enable_dmub_outbox(adev->dm.dc); + + /* DPIA trace goes to dmesg logs only if outbox is enabled */ +@@ -1909,17 +1908,15 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev) + adev->dm.hdcp_workqueue = NULL; + } + +- if (adev->dm.dc) ++ if (adev->dm.dc) { + dc_deinit_callbacks(adev->dm.dc); +- +- if (adev->dm.dc) + dc_dmub_srv_destroy(&adev->dm.dc->ctx->dmub_srv); +- +- if (dc_enable_dmub_notifications(adev->dm.dc)) { +- kfree(adev->dm.dmub_notify); +- adev->dm.dmub_notify = NULL; +- destroy_workqueue(adev->dm.delayed_hpd_wq); +- adev->dm.delayed_hpd_wq = NULL; ++ if (dc_enable_dmub_notifications(adev->dm.dc)) { ++ kfree(adev->dm.dmub_notify); ++ adev->dm.dmub_notify = NULL; ++ destroy_workqueue(adev->dm.delayed_hpd_wq); ++ adev->dm.delayed_hpd_wq = NULL; ++ } + } + + if (adev->dm.dmub_bo) +@@ -2085,7 +2082,7 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) + struct dmub_srv_create_params create_params; + struct dmub_srv_region_params region_params; + struct dmub_srv_region_info region_info; +- struct dmub_srv_fb_params fb_params; ++ struct dmub_srv_memory_params memory_params; + struct dmub_srv_fb_info *fb_info; + struct dmub_srv *dmub_srv; + const struct dmcub_firmware_header_v1_0 *hdr; +@@ -2185,6 +2182,7 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) + adev->dm.dmub_fw->data + + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + + PSP_HEADER_BYTES; ++ region_params.is_mailbox_in_inbox = false; + + status = dmub_srv_calc_region_info(dmub_srv, ®ion_params, + ®ion_info); +@@ -2208,10 +2206,10 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) + return r; + + /* Rebase the regions on the framebuffer address. */ +- memset(&fb_params, 0, sizeof(fb_params)); +- fb_params.cpu_addr = adev->dm.dmub_bo_cpu_addr; +- fb_params.gpu_addr = adev->dm.dmub_bo_gpu_addr; +- fb_params.region_info = ®ion_info; ++ memset(&memory_params, 0, sizeof(memory_params)); ++ memory_params.cpu_fb_addr = adev->dm.dmub_bo_cpu_addr; ++ memory_params.gpu_fb_addr = adev->dm.dmub_bo_gpu_addr; ++ memory_params.region_info = ®ion_info; + + adev->dm.dmub_fb_info = + kzalloc(sizeof(*adev->dm.dmub_fb_info), GFP_KERNEL); +@@ -2223,7 +2221,7 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) + return -ENOMEM; + } + +- status = dmub_srv_calc_fb_info(dmub_srv, &fb_params, fb_info); ++ status = dmub_srv_calc_mem_info(dmub_srv, &memory_params, fb_info); + if (status != DMUB_STATUS_OK) { + DRM_ERROR("Error calculating DMUB FB info: %d\n", status); + return -EINVAL; +@@ -2253,6 +2251,7 @@ static int dm_sw_fini(void *handle) + + if (adev->dm.dmub_srv) { + dmub_srv_destroy(adev->dm.dmub_srv); ++ kfree(adev->dm.dmub_srv); + adev->dm.dmub_srv = NULL; + } + +@@ -2635,7 +2634,8 @@ static int dm_suspend(void *handle) + + dm->cached_dc_state = dc_copy_state(dm->dc->current_state); + +- dm_gpureset_toggle_interrupts(adev, dm->cached_dc_state, false); ++ if (dm->cached_dc_state) ++ dm_gpureset_toggle_interrupts(adev, dm->cached_dc_state, false); + + amdgpu_dm_commit_zero_streams(dm->dc); + +@@ -2963,6 +2963,7 @@ static int dm_resume(void *handle) + dc_stream_release(dm_new_crtc_state->stream); + dm_new_crtc_state->stream = NULL; + } ++ dm_new_crtc_state->base.color_mgmt_changed = true; + } + + for_each_new_plane_in_state(dm->cached_state, plane, new_plane_state, i) { +@@ -2981,6 +2982,10 @@ static int dm_resume(void *handle) + /* Do mst topology probing after resuming cached state*/ + drm_connector_list_iter_begin(ddev, &iter); + drm_for_each_connector_iter(connector, &iter) { ++ ++ if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) ++ continue; ++ + aconnector = to_amdgpu_dm_connector(connector); + if (aconnector->dc_link->type != dc_connection_mst_branch || + aconnector->mst_root) +@@ -3481,6 +3486,14 @@ static void register_hpd_handlers(struct amdgpu_device *adev) + int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT; + int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT; + ++ if (dc_is_dmub_outbox_supported(adev->dm.dc)) { ++ if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD, dmub_hpd_callback, true)) ++ DRM_ERROR("amdgpu: fail to register dmub hpd callback"); ++ ++ if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD_IRQ, dmub_hpd_callback, true)) ++ DRM_ERROR("amdgpu: fail to register dmub hpd callback"); ++ } ++ + list_for_each_entry(connector, + &dev->mode_config.connector_list, head) { + +@@ -3506,10 +3519,6 @@ static void register_hpd_handlers(struct amdgpu_device *adev) + handle_hpd_rx_irq, + (void *) aconnector); + } +- +- if (adev->dm.hpd_rx_offload_wq) +- adev->dm.hpd_rx_offload_wq[connector->index].aconnector = +- aconnector; + } + } + +@@ -4034,6 +4043,7 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) + + #define AMDGPU_DM_DEFAULT_MIN_BACKLIGHT 12 + #define AMDGPU_DM_DEFAULT_MAX_BACKLIGHT 255 ++#define AMDGPU_DM_MIN_SPREAD ((AMDGPU_DM_DEFAULT_MAX_BACKLIGHT - AMDGPU_DM_DEFAULT_MIN_BACKLIGHT) / 2) + #define AUX_BL_DEFAULT_TRANSITION_TIME_MS 50 + + static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm, +@@ -4048,6 +4058,21 @@ static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm, + return; + + amdgpu_acpi_get_backlight_caps(&caps); ++ ++ /* validate the firmware value is sane */ ++ if (caps.caps_valid) { ++ int spread = caps.max_input_signal - caps.min_input_signal; ++ ++ if (caps.max_input_signal > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT || ++ caps.min_input_signal < 0 || ++ spread > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT || ++ spread < AMDGPU_DM_MIN_SPREAD) { ++ DRM_DEBUG_KMS("DM: Invalid backlight caps: min=%d, max=%d\n", ++ caps.min_input_signal, caps.max_input_signal); ++ caps.caps_valid = false; ++ } ++ } ++ + if (caps.caps_valid) { + dm->backlight_caps[bl_idx].caps_valid = true; + if (caps.aux_support) +@@ -4338,7 +4363,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) + enum dc_connection_type new_connection_type = dc_connection_none; + const struct dc_plane_cap *plane; + bool psr_feature_enabled = false; +- bool replay_feature_enabled = false; + int max_overlay = dm->dc->caps.max_slave_planes; + + dm->display_indexes_num = dm->dc->caps.max_streams; +@@ -4355,7 +4379,10 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) + + /* There is one primary plane per CRTC */ + primary_planes = dm->dc->caps.max_streams; +- ASSERT(primary_planes <= AMDGPU_MAX_PLANES); ++ if (primary_planes > AMDGPU_MAX_PLANES) { ++ DRM_ERROR("DM: Plane nums out of 6 planes\n"); ++ return -EINVAL; ++ } + + /* + * Initialize primary planes, implicit planes for legacy IOCTLS. +@@ -4448,20 +4475,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) + } + } + +- if (!(amdgpu_dc_debug_mask & DC_DISABLE_REPLAY)) { +- switch (adev->ip_versions[DCE_HWIP][0]) { +- case IP_VERSION(3, 1, 4): +- case IP_VERSION(3, 1, 5): +- case IP_VERSION(3, 1, 6): +- case IP_VERSION(3, 2, 0): +- case IP_VERSION(3, 2, 1): +- replay_feature_enabled = true; +- break; +- default: +- replay_feature_enabled = amdgpu_dc_feature_mask & DC_REPLAY_MASK; +- break; +- } +- } + /* loops over all connectors on the board */ + for (i = 0; i < link_cnt; i++) { + struct dc_link *link = NULL; +@@ -4493,6 +4506,10 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) + + link = dc_get_link_at_index(dm->dc, i); + ++ if (dm->hpd_rx_offload_wq) ++ dm->hpd_rx_offload_wq[aconnector->base.index].aconnector = ++ aconnector; ++ + if (!dc_link_detect_connection_type(link, &new_connection_type)) + DRM_ERROR("KMS: Failed to detect connector\n"); + +@@ -4510,12 +4527,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) + amdgpu_dm_update_connector_after_detect(aconnector); + setup_backlight_device(dm, aconnector); + +- /* +- * Disable psr if replay can be enabled +- */ +- if (replay_feature_enabled && amdgpu_dm_setup_replay(link, aconnector)) +- psr_feature_enabled = false; +- + if (psr_feature_enabled) + amdgpu_dm_set_psr_caps(link); + +@@ -5170,6 +5181,9 @@ static void fill_dc_dirty_rects(struct drm_plane *plane, + if (plane->type == DRM_PLANE_TYPE_CURSOR) + return; + ++ if (new_plane_state->rotation != DRM_MODE_ROTATE_0) ++ goto ffu; ++ + num_clips = drm_plane_get_damage_clips_count(new_plane_state); + clips = drm_plane_get_damage_clips(new_plane_state); + +@@ -5773,6 +5787,9 @@ get_highest_refresh_rate_mode(struct amdgpu_dm_connector *aconnector, + &aconnector->base.probed_modes : + &aconnector->base.modes; + ++ if (aconnector->base.connector_type == DRM_MODE_CONNECTOR_WRITEBACK) ++ return NULL; ++ + if (aconnector->freesync_vid_base.clock != 0) + return &aconnector->freesync_vid_base; + +@@ -6087,7 +6104,9 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + if (recalculate_timing) { + freesync_mode = get_highest_refresh_rate_mode(aconnector, false); + drm_mode_copy(&saved_mode, &mode); ++ saved_mode.picture_aspect_ratio = mode.picture_aspect_ratio; + drm_mode_copy(&mode, freesync_mode); ++ mode.picture_aspect_ratio = saved_mode.picture_aspect_ratio; + } else { + decide_crtc_timing_for_drm_display_mode( + &mode, preferred_mode, scale); +@@ -6137,19 +6156,25 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) + mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket); + +- if (stream->link->psr_settings.psr_feature_enabled || stream->link->replay_settings.replay_feature_enabled) { ++ if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT || ++ stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST || ++ stream->signal == SIGNAL_TYPE_EDP) { ++ const struct dc_edid_caps *edid_caps; ++ unsigned int disable_colorimetry = 0; ++ ++ if (aconnector->dc_sink) { ++ edid_caps = &aconnector->dc_sink->edid_caps; ++ disable_colorimetry = edid_caps->panel_patch.disable_colorimetry; ++ } ++ + // + // should decide stream support vsc sdp colorimetry capability + // before building vsc info packet + // +- stream->use_vsc_sdp_for_colorimetry = false; +- if (aconnector->dc_sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { +- stream->use_vsc_sdp_for_colorimetry = +- aconnector->dc_sink->is_vsc_sdp_colorimetry_supported; +- } else { +- if (stream->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED) +- stream->use_vsc_sdp_for_colorimetry = true; +- } ++ stream->use_vsc_sdp_for_colorimetry = stream->link->dpcd_caps.dpcd_rev.raw >= 0x14 && ++ stream->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED && ++ !disable_colorimetry; ++ + if (stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) + tf = TRANSFER_FUNC_GAMMA_22; + mod_build_vsc_infopacket(stream, &stream->vsc_infopacket, stream->output_color_space, tf); +@@ -6236,7 +6261,7 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector, + dm_new_state->underscan_enable = val; + ret = 0; + } else if (property == adev->mode_info.abm_level_property) { +- dm_new_state->abm_level = val; ++ dm_new_state->abm_level = val ?: ABM_LEVEL_IMMEDIATE_DISABLE; + ret = 0; + } + +@@ -6281,7 +6306,8 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector, + *val = dm_state->underscan_enable; + ret = 0; + } else if (property == adev->mode_info.abm_level_property) { +- *val = dm_state->abm_level; ++ *val = (dm_state->abm_level != ABM_LEVEL_IMMEDIATE_DISABLE) ? ++ dm_state->abm_level : 0; + ret = 0; + } + +@@ -6354,7 +6380,8 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector) + state->pbn = 0; + + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) +- state->abm_level = amdgpu_dm_abm_level; ++ state->abm_level = amdgpu_dm_abm_level ?: ++ ABM_LEVEL_IMMEDIATE_DISABLE; + + __drm_atomic_helper_connector_reset(connector, &state->base); + } +@@ -6491,7 +6518,8 @@ static void create_eml_sink(struct amdgpu_dm_connector *aconnector) + aconnector->dc_sink = aconnector->dc_link->local_sink ? + aconnector->dc_link->local_sink : + aconnector->dc_em_sink; +- dc_sink_retain(aconnector->dc_sink); ++ if (aconnector->dc_sink) ++ dc_sink_retain(aconnector->dc_sink); + } + } + +@@ -6863,8 +6891,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, + if (IS_ERR(mst_state)) + return PTR_ERR(mst_state); + +- if (!mst_state->pbn_div) +- mst_state->pbn_div = dm_mst_get_pbn_divider(aconnector->mst_root->dc_link); ++ mst_state->pbn_div = dm_mst_get_pbn_divider(aconnector->mst_root->dc_link); + + if (!state->duplicated) { + int max_bpc = conn_state->max_requested_bpc; +@@ -6876,7 +6903,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, + max_bpc); + bpp = convert_dc_color_depth_into_bpc(color_depth) * 3; + clock = adjusted_mode->clock; +- dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp, false); ++ dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp << 4); + } + + dm_new_connector_state->vcpi_slots = +@@ -6904,7 +6931,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state, + struct amdgpu_dm_connector *aconnector; + struct dm_connector_state *dm_conn_state; + int i, j, ret; +- int vcpi, pbn_div, pbn, slot_num = 0; ++ int vcpi, pbn_div, pbn = 0, slot_num = 0; + + for_each_new_connector_in_state(state, connector, new_con_state, i) { + +@@ -6941,7 +6968,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state, + } + } + +- if (j == dc_state->stream_count) ++ if (j == dc_state->stream_count || pbn_div == 0) + continue; + + slot_num = DIV_ROUND_UP(pbn, pbn_div); +@@ -7305,7 +7332,8 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) + drm_add_modes_noedid(connector, 1920, 1080); + } else { + amdgpu_dm_connector_ddc_get_modes(connector, edid); +- amdgpu_dm_connector_add_common_modes(encoder, connector); ++ if (encoder) ++ amdgpu_dm_connector_add_common_modes(encoder, connector); + amdgpu_dm_connector_add_freesync_modes(connector, edid); + } + amdgpu_dm_fbc_init(connector); +@@ -7431,6 +7459,9 @@ static int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap, + int i; + int result = -EIO; + ++ if (!ddc_service->ddc_pin || !ddc_service->ddc_pin->hw_info.hw_supported) ++ return result; ++ + cmd.payloads = kcalloc(num, sizeof(struct i2c_payload), GFP_KERNEL); + + if (!cmd.payloads) +@@ -8286,15 +8317,13 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, + bundle->stream_update.vrr_infopacket = + &acrtc_state->stream->vrr_infopacket; + } +- } else if (cursor_update && acrtc_state->active_planes > 0 && +- acrtc_attach->base.state->event) { +- drm_crtc_vblank_get(pcrtc); +- ++ } else if (cursor_update && acrtc_state->active_planes > 0) { + spin_lock_irqsave(&pcrtc->dev->event_lock, flags); +- +- acrtc_attach->event = acrtc_attach->base.state->event; +- acrtc_attach->base.state->event = NULL; +- ++ if (acrtc_attach->base.state->event) { ++ drm_crtc_vblank_get(pcrtc); ++ acrtc_attach->event = acrtc_attach->base.state->event; ++ acrtc_attach->base.state->event = NULL; ++ } + spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags); + } + +@@ -8459,6 +8488,9 @@ static void amdgpu_dm_commit_audio(struct drm_device *dev, + continue; + + notify: ++ if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) ++ continue; ++ + aconnector = to_amdgpu_dm_connector(connector); + + mutex_lock(&adev->dm.audio_lock); +@@ -9539,14 +9571,14 @@ static bool should_reset_plane(struct drm_atomic_state *state, + struct drm_plane *other; + struct drm_plane_state *old_other_state, *new_other_state; + struct drm_crtc_state *new_crtc_state; ++ struct amdgpu_device *adev = drm_to_adev(plane->dev); + int i; + + /* +- * TODO: Remove this hack once the checks below are sufficient +- * enough to determine when we need to reset all the planes on +- * the stream. ++ * TODO: Remove this hack for all asics once it proves that the ++ * fast updates works fine on DCN3.2+. + */ +- if (state->allow_modeset) ++ if (adev->ip_versions[DCE_HWIP][0] < IP_VERSION(3, 2, 0) && state->allow_modeset) + return true; + + /* Exit early if we know that we're adding or removing the plane. */ +@@ -9892,16 +9924,27 @@ static void dm_get_oriented_plane_size(struct drm_plane_state *plane_state, + } + } + ++static void ++dm_get_plane_scale(struct drm_plane_state *plane_state, ++ int *out_plane_scale_w, int *out_plane_scale_h) ++{ ++ int plane_src_w, plane_src_h; ++ ++ dm_get_oriented_plane_size(plane_state, &plane_src_w, &plane_src_h); ++ *out_plane_scale_w = plane_state->crtc_w * 1000 / plane_src_w; ++ *out_plane_scale_h = plane_state->crtc_h * 1000 / plane_src_h; ++} ++ + static int dm_check_crtc_cursor(struct drm_atomic_state *state, + struct drm_crtc *crtc, + struct drm_crtc_state *new_crtc_state) + { +- struct drm_plane *cursor = crtc->cursor, *underlying; ++ struct drm_plane *cursor = crtc->cursor, *plane, *underlying; ++ struct drm_plane_state *old_plane_state, *new_plane_state; + struct drm_plane_state *new_cursor_state, *new_underlying_state; + int i; + int cursor_scale_w, cursor_scale_h, underlying_scale_w, underlying_scale_h; +- int cursor_src_w, cursor_src_h; +- int underlying_src_w, underlying_src_h; ++ bool any_relevant_change = false; + + /* On DCE and DCN there is no dedicated hardware cursor plane. We get a + * cursor per pipe but it's going to inherit the scaling and +@@ -9909,13 +9952,50 @@ static int dm_check_crtc_cursor(struct drm_atomic_state *state, + * blending properties match the underlying planes'. + */ + +- new_cursor_state = drm_atomic_get_new_plane_state(state, cursor); +- if (!new_cursor_state || !new_cursor_state->fb) ++ /* If no plane was enabled or changed scaling, no need to check again */ ++ for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { ++ int new_scale_w, new_scale_h, old_scale_w, old_scale_h; ++ ++ if (!new_plane_state || !new_plane_state->fb || new_plane_state->crtc != crtc) ++ continue; ++ ++ if (!old_plane_state || !old_plane_state->fb || old_plane_state->crtc != crtc) { ++ any_relevant_change = true; ++ break; ++ } ++ ++ if (new_plane_state->fb == old_plane_state->fb && ++ new_plane_state->crtc_w == old_plane_state->crtc_w && ++ new_plane_state->crtc_h == old_plane_state->crtc_h) ++ continue; ++ ++ dm_get_plane_scale(new_plane_state, &new_scale_w, &new_scale_h); ++ dm_get_plane_scale(old_plane_state, &old_scale_w, &old_scale_h); ++ ++ if (new_scale_w != old_scale_w || new_scale_h != old_scale_h) { ++ any_relevant_change = true; ++ break; ++ } ++ } ++ ++ if (!any_relevant_change) + return 0; + +- dm_get_oriented_plane_size(new_cursor_state, &cursor_src_w, &cursor_src_h); +- cursor_scale_w = new_cursor_state->crtc_w * 1000 / cursor_src_w; +- cursor_scale_h = new_cursor_state->crtc_h * 1000 / cursor_src_h; ++ new_cursor_state = drm_atomic_get_plane_state(state, cursor); ++ if (IS_ERR(new_cursor_state)) ++ return PTR_ERR(new_cursor_state); ++ ++ if (!new_cursor_state->fb) ++ return 0; ++ ++ dm_get_plane_scale(new_cursor_state, &cursor_scale_w, &cursor_scale_h); ++ ++ /* Need to check all enabled planes, even if this commit doesn't change ++ * their state ++ */ ++ i = drm_atomic_add_affected_planes(state, crtc); ++ if (i) ++ return i; + + for_each_new_plane_in_state_reverse(state, underlying, new_underlying_state, i) { + /* Narrow down to non-cursor planes on the same CRTC as the cursor */ +@@ -9926,10 +10006,8 @@ static int dm_check_crtc_cursor(struct drm_atomic_state *state, + if (!new_underlying_state->fb) + continue; + +- dm_get_oriented_plane_size(new_underlying_state, +- &underlying_src_w, &underlying_src_h); +- underlying_scale_w = new_underlying_state->crtc_w * 1000 / underlying_src_w; +- underlying_scale_h = new_underlying_state->crtc_h * 1000 / underlying_src_h; ++ dm_get_plane_scale(new_underlying_state, ++ &underlying_scale_w, &underlying_scale_h); + + if (cursor_scale_w != underlying_scale_w || + cursor_scale_h != underlying_scale_h) { +@@ -10021,7 +10099,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, + struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state; + struct drm_dp_mst_topology_mgr *mgr; + struct drm_dp_mst_topology_state *mst_state; +- struct dsc_mst_fairness_vars vars[MAX_PIPES]; ++ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {0}; + + trace_amdgpu_dm_atomic_check_begin(state); + +@@ -10321,11 +10399,13 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, + goto fail; + } + +- ret = compute_mst_dsc_configs_for_state(state, dm_state->context, vars); +- if (ret) { +- DRM_DEBUG_DRIVER("compute_mst_dsc_configs_for_state() failed\n"); +- ret = -EINVAL; +- goto fail; ++ if (dc_resource_is_dsc_encoding_supported(dc)) { ++ ret = compute_mst_dsc_configs_for_state(state, dm_state->context, vars); ++ if (ret) { ++ DRM_DEBUG_DRIVER("compute_mst_dsc_configs_for_state() failed\n"); ++ ret = -EINVAL; ++ goto fail; ++ } + } + + ret = dm_update_mst_vcpi_slots_for_dsc(state, dm_state->context, vars); +@@ -10585,6 +10665,49 @@ static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector, + return ret; + } + ++static void parse_edid_displayid_vrr(struct drm_connector *connector, ++ struct edid *edid) ++{ ++ u8 *edid_ext = NULL; ++ int i; ++ int j = 0; ++ u16 min_vfreq; ++ u16 max_vfreq; ++ ++ if (edid == NULL || edid->extensions == 0) ++ return; ++ ++ /* Find DisplayID extension */ ++ for (i = 0; i < edid->extensions; i++) { ++ edid_ext = (void *)(edid + (i + 1)); ++ if (edid_ext[0] == DISPLAYID_EXT) ++ break; ++ } ++ ++ if (edid_ext == NULL) ++ return; ++ ++ while (j < EDID_LENGTH) { ++ /* Get dynamic video timing range from DisplayID if available */ ++ if (EDID_LENGTH - j > 13 && edid_ext[j] == 0x25 && ++ (edid_ext[j+1] & 0xFE) == 0 && (edid_ext[j+2] == 9)) { ++ min_vfreq = edid_ext[j+9]; ++ if (edid_ext[j+1] & 7) ++ max_vfreq = edid_ext[j+10] + ((edid_ext[j+11] & 3) << 8); ++ else ++ max_vfreq = edid_ext[j+10]; ++ ++ if (max_vfreq && min_vfreq) { ++ connector->display_info.monitor_range.max_vfreq = max_vfreq; ++ connector->display_info.monitor_range.min_vfreq = min_vfreq; ++ ++ return; ++ } ++ } ++ j++; ++ } ++} ++ + static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector, + struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info) + { +@@ -10707,18 +10830,31 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, + if (!adev->dm.freesync_module) + goto update; + +- if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT +- || sink->sink_signal == SIGNAL_TYPE_EDP) { ++ /* Some eDP panels only have the refresh rate range info in DisplayID */ ++ if ((connector->display_info.monitor_range.min_vfreq == 0 || ++ connector->display_info.monitor_range.max_vfreq == 0)) ++ parse_edid_displayid_vrr(connector, edid); ++ ++ if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT || ++ sink->sink_signal == SIGNAL_TYPE_EDP)) { + bool edid_check_required = false; + +- if (edid) { +- edid_check_required = is_dp_capable_without_timing_msa( +- adev->dm.dc, +- amdgpu_dm_connector); ++ if (is_dp_capable_without_timing_msa(adev->dm.dc, ++ amdgpu_dm_connector)) { ++ if (edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ) { ++ amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq; ++ amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq; ++ if (amdgpu_dm_connector->max_vfreq - ++ amdgpu_dm_connector->min_vfreq > 10) ++ freesync_capable = true; ++ } else { ++ edid_check_required = edid->version > 1 || ++ (edid->version == 1 && ++ edid->revision > 1); ++ } + } + +- if (edid_check_required == true && (edid->version > 1 || +- (edid->version == 1 && edid->revision > 1))) { ++ if (edid_check_required) { + for (i = 0; i < 4; i++) { + + timing = &edid->detailed_timings[i]; +@@ -10738,14 +10874,23 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, + if (range->flags != 1) + continue; + +- amdgpu_dm_connector->min_vfreq = range->min_vfreq; +- amdgpu_dm_connector->max_vfreq = range->max_vfreq; +- amdgpu_dm_connector->pixel_clock_mhz = +- range->pixel_clock_mhz * 10; +- + connector->display_info.monitor_range.min_vfreq = range->min_vfreq; + connector->display_info.monitor_range.max_vfreq = range->max_vfreq; + ++ if (edid->revision >= 4) { ++ if (data->pad2 & DRM_EDID_RANGE_OFFSET_MIN_VFREQ) ++ connector->display_info.monitor_range.min_vfreq += 255; ++ if (data->pad2 & DRM_EDID_RANGE_OFFSET_MAX_VFREQ) ++ connector->display_info.monitor_range.max_vfreq += 255; ++ } ++ ++ amdgpu_dm_connector->min_vfreq = ++ connector->display_info.monitor_range.min_vfreq; ++ amdgpu_dm_connector->max_vfreq = ++ connector->display_info.monitor_range.max_vfreq; ++ amdgpu_dm_connector->pixel_clock_mhz = ++ range->pixel_clock_mhz * 10; ++ + break; + } + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index 9e4cc5eeda767e..88606b805330d7 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -49,7 +49,7 @@ + + #define AMDGPU_DM_MAX_NUM_EDP 2 + +-#define AMDGPU_DMUB_NOTIFICATION_MAX 5 ++#define AMDGPU_DMUB_NOTIFICATION_MAX 6 + + #define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID 0x00001A + #define AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE 0x40 +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 97b7a0b8a1c26c..30d4c6fd95f531 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 +@@ -29,7 +29,6 @@ + #include "dc.h" + #include "amdgpu.h" + #include "amdgpu_dm_psr.h" +-#include "amdgpu_dm_replay.h" + #include "amdgpu_dm_crtc.h" + #include "amdgpu_dm_plane.h" + #include "amdgpu_dm_trace.h" +@@ -124,12 +123,7 @@ static void vblank_control_worker(struct work_struct *work) + * fill_dc_dirty_rects(). + */ + if (vblank_work->stream && vblank_work->stream->link) { +- /* +- * Prioritize replay, instead of psr +- */ +- if (vblank_work->stream->link->replay_settings.replay_feature_enabled) +- amdgpu_dm_replay_enable(vblank_work->stream, false); +- else if (vblank_work->enable) { ++ if (vblank_work->enable) { + if (vblank_work->stream->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1 && + vblank_work->stream->link->psr_settings.psr_allow_active) + amdgpu_dm_psr_disable(vblank_work->stream); +@@ -138,7 +132,6 @@ static void vblank_control_worker(struct work_struct *work) + #ifdef CONFIG_DRM_AMD_SECURE_DISPLAY + !amdgpu_dm_crc_window_is_activated(&vblank_work->acrtc->base) && + #endif +- vblank_work->stream->link->panel_config.psr.disallow_replay && + vblank_work->acrtc->dm_irq_params.allow_psr_entry) { + amdgpu_dm_psr_enable(vblank_work->stream); + } +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +index 7c21e21bcc51a0..c8609595f324b4 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +@@ -1219,7 +1219,7 @@ static ssize_t dp_sdp_message_debugfs_write(struct file *f, const char __user *b + size_t size, loff_t *pos) + { + int r; +- uint8_t data[36]; ++ uint8_t data[36] = {0}; + struct amdgpu_dm_connector *connector = file_inode(f)->i_private; + struct dm_crtc_state *acrtc_state; + uint32_t write_size = 36; +@@ -1453,7 +1453,7 @@ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf, + const uint32_t rd_buf_size = 10; + struct pipe_ctx *pipe_ctx; + ssize_t result = 0; +- int i, r, str_len = 30; ++ int i, r, str_len = 10; + + rd_buf = kcalloc(rd_buf_size, sizeof(char), GFP_KERNEL); + +@@ -1465,7 +1465,9 @@ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf, + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && +- pipe_ctx->stream->link == aconnector->dc_link) ++ pipe_ctx->stream->link == aconnector->dc_link && ++ pipe_ctx->stream->sink && ++ pipe_ctx->stream->sink == aconnector->dc_sink) + break; + } + +@@ -1566,7 +1568,9 @@ static ssize_t dp_dsc_clock_en_write(struct file *f, const char __user *buf, + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && +- pipe_ctx->stream->link == aconnector->dc_link) ++ pipe_ctx->stream->link == aconnector->dc_link && ++ pipe_ctx->stream->sink && ++ pipe_ctx->stream->sink == aconnector->dc_sink) + break; + } + +@@ -1651,7 +1655,9 @@ static ssize_t dp_dsc_slice_width_read(struct file *f, char __user *buf, + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && +- pipe_ctx->stream->link == aconnector->dc_link) ++ pipe_ctx->stream->link == aconnector->dc_link && ++ pipe_ctx->stream->sink && ++ pipe_ctx->stream->sink == aconnector->dc_sink) + break; + } + +@@ -1750,7 +1756,9 @@ static ssize_t dp_dsc_slice_width_write(struct file *f, const char __user *buf, + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && +- pipe_ctx->stream->link == aconnector->dc_link) ++ pipe_ctx->stream->link == aconnector->dc_link && ++ pipe_ctx->stream->sink && ++ pipe_ctx->stream->sink == aconnector->dc_sink) + break; + } + +@@ -1835,7 +1843,9 @@ static ssize_t dp_dsc_slice_height_read(struct file *f, char __user *buf, + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && +- pipe_ctx->stream->link == aconnector->dc_link) ++ pipe_ctx->stream->link == aconnector->dc_link && ++ pipe_ctx->stream->sink && ++ pipe_ctx->stream->sink == aconnector->dc_sink) + break; + } + +@@ -1934,7 +1944,9 @@ static ssize_t dp_dsc_slice_height_write(struct file *f, const char __user *buf, + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && +- pipe_ctx->stream->link == aconnector->dc_link) ++ pipe_ctx->stream->link == aconnector->dc_link && ++ pipe_ctx->stream->sink && ++ pipe_ctx->stream->sink == aconnector->dc_sink) + break; + } + +@@ -2015,7 +2027,9 @@ static ssize_t dp_dsc_bits_per_pixel_read(struct file *f, char __user *buf, + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && +- pipe_ctx->stream->link == aconnector->dc_link) ++ pipe_ctx->stream->link == aconnector->dc_link && ++ pipe_ctx->stream->sink && ++ pipe_ctx->stream->sink == aconnector->dc_sink) + break; + } + +@@ -2111,7 +2125,9 @@ static ssize_t dp_dsc_bits_per_pixel_write(struct file *f, const char __user *bu + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && +- pipe_ctx->stream->link == aconnector->dc_link) ++ pipe_ctx->stream->link == aconnector->dc_link && ++ pipe_ctx->stream->sink && ++ pipe_ctx->stream->sink == aconnector->dc_sink) + break; + } + +@@ -2190,7 +2206,9 @@ static ssize_t dp_dsc_pic_width_read(struct file *f, char __user *buf, + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && +- pipe_ctx->stream->link == aconnector->dc_link) ++ pipe_ctx->stream->link == aconnector->dc_link && ++ pipe_ctx->stream->sink && ++ pipe_ctx->stream->sink == aconnector->dc_sink) + break; + } + +@@ -2246,7 +2264,9 @@ static ssize_t dp_dsc_pic_height_read(struct file *f, char __user *buf, + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && +- pipe_ctx->stream->link == aconnector->dc_link) ++ pipe_ctx->stream->link == aconnector->dc_link && ++ pipe_ctx->stream->sink && ++ pipe_ctx->stream->sink == aconnector->dc_sink) + break; + } + +@@ -2317,7 +2337,9 @@ static ssize_t dp_dsc_chunk_size_read(struct file *f, char __user *buf, + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && +- pipe_ctx->stream->link == aconnector->dc_link) ++ pipe_ctx->stream->link == aconnector->dc_link && ++ pipe_ctx->stream->sink && ++ pipe_ctx->stream->sink == aconnector->dc_sink) + break; + } + +@@ -2388,7 +2410,9 @@ static ssize_t dp_dsc_slice_bpg_offset_read(struct file *f, char __user *buf, + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && +- pipe_ctx->stream->link == aconnector->dc_link) ++ pipe_ctx->stream->link == aconnector->dc_link && ++ pipe_ctx->stream->sink && ++ pipe_ctx->stream->sink == aconnector->dc_sink) + break; + } + +@@ -2905,7 +2929,7 @@ static int psr_read_residency(void *data, u64 *val) + { + struct amdgpu_dm_connector *connector = data; + struct dc_link *link = connector->dc_link; +- u32 residency; ++ u32 residency = 0; + + link->dc->link_srv->edp_get_psr_residency(link, &residency); + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +index 4b230933b28ebf..227a148b0f82a5 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +@@ -63,6 +63,18 @@ static void apply_edid_quirks(struct edid *edid, struct dc_edid_caps *edid_caps) + DRM_DEBUG_DRIVER("Disabling FAMS on monitor with panel id %X\n", panel_id); + edid_caps->panel_patch.disable_fams = true; + break; ++ /* Workaround for some monitors that do not clear DPCD 0x317 if FreeSync is unsupported */ ++ case drm_edid_encode_panel_id('A', 'U', 'O', 0xA7AB): ++ case drm_edid_encode_panel_id('A', 'U', 'O', 0xE69B): ++ case drm_edid_encode_panel_id('B', 'O', 'E', 0x092A): ++ case drm_edid_encode_panel_id('L', 'G', 'D', 0x06D1): ++ DRM_DEBUG_DRIVER("Clearing DPCD 0x317 on monitor with panel id %X\n", panel_id); ++ edid_caps->panel_patch.remove_sink_ext_caps = true; ++ break; ++ case drm_edid_encode_panel_id('S', 'D', 'C', 0x4154): ++ DRM_DEBUG_DRIVER("Disabling VSC on monitor with panel id %X\n", panel_id); ++ edid_caps->panel_patch.disable_colorimetry = true; ++ break; + default: + return; + } +@@ -113,6 +125,8 @@ enum dc_edid_status dm_helpers_parse_edid_caps( + + edid_caps->edid_hdmi = connector->display_info.is_hdmi; + ++ apply_edid_quirks(edid_buf, edid_caps); ++ + sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads); + if (sad_count <= 0) + return result; +@@ -139,8 +153,6 @@ enum dc_edid_status dm_helpers_parse_edid_caps( + else + edid_caps->speaker_flags = DEFAULT_SPEAKER_LOCATION; + +- apply_edid_quirks(edid_buf, edid_caps); +- + kfree(sads); + kfree(sadb); + +@@ -950,6 +962,11 @@ int dm_helper_dmub_aux_transfer_sync( + struct aux_payload *payload, + enum aux_return_code_type *operation_result) + { ++ if (!link->hpd_status) { ++ *operation_result = AUX_RET_ERROR_HPD_DISCON; ++ return -1; ++ } ++ + return amdgpu_dm_process_dmub_aux_transfer_sync(ctx, link->link_index, payload, + operation_result); + } +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +index 57230661132bd9..d390e3d62e56e3 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +@@ -246,7 +246,7 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto + aconnector->dsc_aux = &aconnector->mst_root->dm_dp_aux.aux; + + /* synaptics cascaded MST hub case */ +- if (!aconnector->dsc_aux && is_synaptics_cascaded_panamera(aconnector->dc_link, port)) ++ if (is_synaptics_cascaded_panamera(aconnector->dc_link, port)) + aconnector->dsc_aux = port->mgr->aux; + + if (!aconnector->dsc_aux) +@@ -606,6 +606,9 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, + &connector->base, + dev->mode_config.tile_property, + 0); ++ connector->colorspace_property = master->base.colorspace_property; ++ if (connector->colorspace_property) ++ drm_connector_attach_colorspace_property(connector); + + drm_connector_set_path_property(connector, pathprop); + +@@ -1112,7 +1115,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, + params[count].num_slices_v = aconnector->dsc_settings.dsc_num_slices_v; + params[count].bpp_overwrite = aconnector->dsc_settings.dsc_bits_per_pixel; + params[count].compression_possible = stream->sink->dsc_caps.dsc_dec_caps.is_dsc_supported; +- dc_dsc_get_policy_for_timing(params[count].timing, 0, &dsc_policy); ++ dc_dsc_get_policy_for_timing(params[count].timing, 0, &dsc_policy, dc_link_get_highest_encoding_format(stream->link)); + if (!dc_dsc_compute_bandwidth_range( + stream->sink->ctx->dc->res_pool->dscs[0], + stream->sink->ctx->dc->debug.dsc_min_slice_height_override, +@@ -1263,6 +1266,9 @@ static bool is_dsc_need_re_compute( + } + } + ++ if (new_stream_on_link_num == 0) ++ return false; ++ + /* check current_state if there stream on link but it is not in + * new request state + */ +@@ -1577,7 +1583,7 @@ static bool is_dsc_common_config_possible(struct dc_stream_state *stream, + { + struct dc_dsc_policy dsc_policy = {0}; + +- dc_dsc_get_policy_for_timing(&stream->timing, 0, &dsc_policy); ++ dc_dsc_get_policy_for_timing(&stream->timing, 0, &dsc_policy, dc_link_get_highest_encoding_format(stream->link)); + dc_dsc_compute_bandwidth_range(stream->sink->ctx->dc->res_pool->dscs[0], + stream->sink->ctx->dc->debug.dsc_min_slice_height_override, + dsc_policy.min_target_bpp * 16, +@@ -1598,31 +1604,31 @@ enum dc_status dm_dp_mst_is_port_support_mode( + unsigned int upper_link_bw_in_kbps = 0, down_link_bw_in_kbps = 0; + unsigned int max_compressed_bw_in_kbps = 0; + struct dc_dsc_bw_range bw_range = {0}; +- struct drm_dp_mst_topology_mgr *mst_mgr; ++ uint16_t full_pbn = aconnector->mst_output_port->full_pbn; + + /* +- * check if the mode could be supported if DSC pass-through is supported +- * AND check if there enough bandwidth available to support the mode +- * with DSC enabled. ++ * Consider the case with the depth of the mst topology tree is equal or less than 2 ++ * A. When dsc bitstream can be transmitted along the entire path ++ * 1. dsc is possible between source and branch/leaf device (common dsc params is possible), AND ++ * 2. dsc passthrough supported at MST branch, or ++ * 3. dsc decoding supported at leaf MST device ++ * Use maximum dsc compression as bw constraint ++ * B. When dsc bitstream cannot be transmitted along the entire path ++ * Use native bw as bw constraint + */ + if (is_dsc_common_config_possible(stream, &bw_range) && +- aconnector->mst_output_port->passthrough_aux) { +- mst_mgr = aconnector->mst_output_port->mgr; +- mutex_lock(&mst_mgr->lock); +- ++ (aconnector->mst_output_port->passthrough_aux || ++ aconnector->dsc_aux == &aconnector->mst_output_port->aux)) { + cur_link_settings = stream->link->verified_link_cap; + + upper_link_bw_in_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, +- &cur_link_settings +- ); +- down_link_bw_in_kbps = kbps_from_pbn(aconnector->mst_output_port->full_pbn); ++ &cur_link_settings); ++ down_link_bw_in_kbps = kbps_from_pbn(full_pbn); + + /* pick the bottleneck */ + end_to_end_bw_in_kbps = min(upper_link_bw_in_kbps, + down_link_bw_in_kbps); + +- mutex_unlock(&mst_mgr->lock); +- + /* + * use the maximum dsc compression bandwidth as the required + * bandwidth for the mode +@@ -1636,9 +1642,8 @@ enum dc_status dm_dp_mst_is_port_support_mode( + } else { + /* check if mode could be supported within full_pbn */ + bpp = convert_dc_color_depth_into_bpc(stream->timing.display_color_depth) * 3; +- pbn = drm_dp_calc_pbn_mode(stream->timing.pix_clk_100hz / 10, bpp, false); +- +- if (pbn > aconnector->mst_output_port->full_pbn) ++ pbn = drm_dp_calc_pbn_mode(stream->timing.pix_clk_100hz / 10, bpp << 4); ++ if (pbn > full_pbn) + return DC_FAIL_BANDWIDTH_VALIDATE; + } + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +index cc74dd69acf2ba..d1329f20b7bd4b 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + #include + + #include "amdgpu.h" +@@ -848,10 +849,14 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, + } + + afb = to_amdgpu_framebuffer(new_state->fb); +- obj = new_state->fb->obj[0]; ++ obj = drm_gem_fb_get_obj(new_state->fb, 0); ++ if (!obj) { ++ DRM_ERROR("Failed to get obj from framebuffer\n"); ++ return -EINVAL; ++ } ++ + rbo = gem_to_amdgpu_bo(obj); + adev = amdgpu_ttm_adev(rbo->tbo.bdev); +- + r = amdgpu_bo_reserve(rbo, true); + if (r) { + dev_err(adev->dev, "fail to reserve bo (%d)\n", r); +@@ -1276,7 +1281,8 @@ void amdgpu_dm_plane_handle_cursor_update(struct drm_plane *plane, + adev->dm.dc->caps.color.dpp.gamma_corr) + attributes.attribute_flags.bits.ENABLE_CURSOR_DEGAMMA = 1; + +- attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0]; ++ if (afb) ++ attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0]; + + if (crtc_state->stream) { + mutex_lock(&adev->dm.dc_lock); +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +index 6b319044758151..684b005f564c47 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +@@ -667,6 +667,9 @@ static enum bp_result get_ss_info_v3_1( + ss_table_header_include = ((ATOM_ASIC_INTERNAL_SS_INFO_V3 *) bios_get_image(&bp->base, + DATA_TABLES(ASIC_InternalSS_Info), + struct_size(ss_table_header_include, asSpreadSpectrum, 1))); ++ if (!ss_table_header_include) ++ return BP_RESULT_UNSUPPORTED; ++ + table_size = + (le16_to_cpu(ss_table_header_include->sHeader.usStructureSize) + - sizeof(ATOM_COMMON_TABLE_HEADER)) +@@ -1036,6 +1039,8 @@ static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1( + &bp->base, + DATA_TABLES(ASIC_InternalSS_Info), + struct_size(header, asSpreadSpectrum, 1))); ++ if (!header) ++ return result; + + memset(info, 0, sizeof(struct spread_spectrum_info)); + +@@ -1109,6 +1114,8 @@ static enum bp_result get_ss_info_from_ss_info_table( + get_atom_data_table_revision(header, &revision); + + tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO, DATA_TABLES(SS_Info)); ++ if (!tbl) ++ return result; + + if (1 != revision.major || 2 > revision.minor) + return result; +@@ -1636,6 +1643,8 @@ static uint32_t get_ss_entry_number_from_ss_info_tbl( + + tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO, + DATA_TABLES(SS_Info)); ++ if (!tbl) ++ return number; + + if (1 != revision.major || 2 > revision.minor) + return number; +@@ -1718,6 +1727,8 @@ static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1( + &bp->base, + DATA_TABLES(ASIC_InternalSS_Info), + struct_size(header_include, asSpreadSpectrum, 1))); ++ if (!header_include) ++ return 0; + + size = (le16_to_cpu(header_include->sHeader.usStructureSize) + - sizeof(ATOM_COMMON_TABLE_HEADER)) +@@ -1756,6 +1767,9 @@ static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1( + header_include = ((ATOM_ASIC_INTERNAL_SS_INFO_V3 *) bios_get_image(&bp->base, + DATA_TABLES(ASIC_InternalSS_Info), + struct_size(header_include, asSpreadSpectrum, 1))); ++ if (!header_include) ++ return number; ++ + size = (le16_to_cpu(header_include->sHeader.usStructureSize) - + sizeof(ATOM_COMMON_TABLE_HEADER)) / + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3); +@@ -2552,8 +2566,8 @@ static enum bp_result construct_integrated_info( + + /* Sort voltage table from low to high*/ + if (result == BP_RESULT_OK) { +- uint32_t i; +- uint32_t j; ++ int32_t i; ++ int32_t j; + + for (i = 1; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) { + for (j = i; j > 0; --j) { +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +index 484d62bcf2c2e2..384ddb28e6f6d6 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +@@ -1015,13 +1015,20 @@ static enum bp_result get_ss_info_v4_5( + DC_LOG_BIOS("AS_SIGNAL_TYPE_HDMI ss_percentage: %d\n", ss_info->spread_spectrum_percentage); + break; + case AS_SIGNAL_TYPE_DISPLAY_PORT: +- ss_info->spread_spectrum_percentage = ++ if (bp->base.integrated_info) { ++ DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", bp->base.integrated_info->gpuclk_ss_percentage); ++ ss_info->spread_spectrum_percentage = ++ bp->base.integrated_info->gpuclk_ss_percentage; ++ ss_info->type.CENTER_MODE = ++ bp->base.integrated_info->gpuclk_ss_type; ++ } else { ++ ss_info->spread_spectrum_percentage = + disp_cntl_tbl->dp_ss_percentage; +- ss_info->spread_spectrum_range = ++ ss_info->spread_spectrum_range = + disp_cntl_tbl->dp_ss_rate_10hz * 10; +- if (disp_cntl_tbl->dp_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) +- ss_info->type.CENTER_MODE = true; +- ++ if (disp_cntl_tbl->dp_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) ++ ss_info->type.CENTER_MODE = true; ++ } + DC_LOG_BIOS("AS_SIGNAL_TYPE_DISPLAY_PORT ss_percentage: %d\n", ss_info->spread_spectrum_percentage); + break; + case AS_SIGNAL_TYPE_GPU_PLL: +@@ -1692,7 +1699,7 @@ static enum bp_result bios_parser_enable_disp_power_gating( + static enum bp_result bios_parser_enable_lvtma_control( + struct dc_bios *dcb, + uint8_t uc_pwr_on, +- uint8_t panel_instance, ++ uint8_t pwrseq_instance, + uint8_t bypass_panel_control_wait) + { + struct bios_parser *bp = BP_FROM_DCB(dcb); +@@ -1700,7 +1707,7 @@ static enum bp_result bios_parser_enable_lvtma_control( + if (!bp->cmd_tbl.enable_lvtma_control) + return BP_RESULT_FAILURE; + +- return bp->cmd_tbl.enable_lvtma_control(bp, uc_pwr_on, panel_instance, bypass_panel_control_wait); ++ return bp->cmd_tbl.enable_lvtma_control(bp, uc_pwr_on, pwrseq_instance, bypass_panel_control_wait); + } + + static bool bios_parser_is_accelerated_mode( +@@ -1853,19 +1860,21 @@ static enum bp_result get_firmware_info_v3_2( + /* Vega12 */ + smu_info_v3_2 = GET_IMAGE(struct atom_smu_info_v3_2, + DATA_TABLES(smu_info)); +- DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info_v3_2->gpuclk_ss_percentage); + if (!smu_info_v3_2) + return BP_RESULT_BADBIOSTABLE; + ++ DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info_v3_2->gpuclk_ss_percentage); ++ + info->default_engine_clk = smu_info_v3_2->bootup_dcefclk_10khz * 10; + } else if (revision.minor == 3) { + /* Vega20 */ + smu_info_v3_3 = GET_IMAGE(struct atom_smu_info_v3_3, + DATA_TABLES(smu_info)); +- DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info_v3_3->gpuclk_ss_percentage); + if (!smu_info_v3_3) + return BP_RESULT_BADBIOSTABLE; + ++ DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", smu_info_v3_3->gpuclk_ss_percentage); ++ + info->default_engine_clk = smu_info_v3_3->bootup_dcefclk_10khz * 10; + } + +@@ -2428,10 +2437,11 @@ static enum bp_result get_integrated_info_v11( + info_v11 = GET_IMAGE(struct atom_integrated_system_info_v1_11, + DATA_TABLES(integratedsysteminfo)); + +- DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v11->gpuclk_ss_percentage); + if (info_v11 == NULL) + return BP_RESULT_BADBIOSTABLE; + ++ DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v11->gpuclk_ss_percentage); ++ + info->gpu_cap_info = + le32_to_cpu(info_v11->gpucapinfo); + /* +@@ -2643,11 +2653,12 @@ static enum bp_result get_integrated_info_v2_1( + + info_v2_1 = GET_IMAGE(struct atom_integrated_system_info_v2_1, + DATA_TABLES(integratedsysteminfo)); +- DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v2_1->gpuclk_ss_percentage); + + if (info_v2_1 == NULL) + return BP_RESULT_BADBIOSTABLE; + ++ DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v2_1->gpuclk_ss_percentage); ++ + info->gpu_cap_info = + le32_to_cpu(info_v2_1->gpucapinfo); + /* +@@ -2805,11 +2816,11 @@ static enum bp_result get_integrated_info_v2_2( + info_v2_2 = GET_IMAGE(struct atom_integrated_system_info_v2_2, + DATA_TABLES(integratedsysteminfo)); + +- DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v2_2->gpuclk_ss_percentage); +- + if (info_v2_2 == NULL) + return BP_RESULT_BADBIOSTABLE; + ++ DC_LOG_BIOS("gpuclk_ss_percentage (unit of 0.001 percent): %d\n", info_v2_2->gpuclk_ss_percentage); ++ + info->gpu_cap_info = + le32_to_cpu(info_v2_2->gpucapinfo); + /* +@@ -2826,6 +2837,8 @@ static enum bp_result get_integrated_info_v2_2( + info->ma_channel_number = info_v2_2->umachannelnumber; + info->dp_ss_control = + le16_to_cpu(info_v2_2->reserved1); ++ info->gpuclk_ss_percentage = info_v2_2->gpuclk_ss_percentage; ++ info->gpuclk_ss_type = info_v2_2->gpuclk_ss_type; + + for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) { + info->ext_disp_conn_info.gu_id[i] = +@@ -2922,8 +2935,11 @@ static enum bp_result construct_integrated_info( + struct atom_common_table_header *header; + struct atom_data_revision revision; + +- uint32_t i; +- uint32_t j; ++ int32_t i; ++ int32_t j; ++ ++ if (!info) ++ return result; + + if (info && DATA_TABLES(integratedsysteminfo)) { + header = GET_IMAGE(struct atom_common_table_header, +@@ -2948,6 +2964,7 @@ static enum bp_result construct_integrated_info( + result = get_integrated_info_v2_1(bp, info); + break; + case 2: ++ case 3: + result = get_integrated_info_v2_2(bp, info); + break; + default: +diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +index 90a02d7bd3da3f..ab0adabf9dd4c6 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +@@ -976,7 +976,7 @@ static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp, uint8_t id) + static enum bp_result enable_lvtma_control( + struct bios_parser *bp, + uint8_t uc_pwr_on, +- uint8_t panel_instance, ++ uint8_t pwrseq_instance, + uint8_t bypass_panel_control_wait); + + static void init_enable_lvtma_control(struct bios_parser *bp) +@@ -989,7 +989,7 @@ static void init_enable_lvtma_control(struct bios_parser *bp) + static void enable_lvtma_control_dmcub( + struct dc_dmub_srv *dmcub, + uint8_t uc_pwr_on, +- uint8_t panel_instance, ++ uint8_t pwrseq_instance, + uint8_t bypass_panel_control_wait) + { + +@@ -1002,8 +1002,8 @@ static void enable_lvtma_control_dmcub( + DMUB_CMD__VBIOS_LVTMA_CONTROL; + cmd.lvtma_control.data.uc_pwr_action = + uc_pwr_on; +- cmd.lvtma_control.data.panel_inst = +- panel_instance; ++ cmd.lvtma_control.data.pwrseq_inst = ++ pwrseq_instance; + cmd.lvtma_control.data.bypass_panel_control_wait = + bypass_panel_control_wait; + dm_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); +@@ -1012,7 +1012,7 @@ static void enable_lvtma_control_dmcub( + static enum bp_result enable_lvtma_control( + struct bios_parser *bp, + uint8_t uc_pwr_on, +- uint8_t panel_instance, ++ uint8_t pwrseq_instance, + uint8_t bypass_panel_control_wait) + { + enum bp_result result = BP_RESULT_FAILURE; +@@ -1021,7 +1021,7 @@ static enum bp_result enable_lvtma_control( + bp->base.ctx->dc->debug.dmub_command_table) { + enable_lvtma_control_dmcub(bp->base.ctx->dmub_srv, + uc_pwr_on, +- panel_instance, ++ pwrseq_instance, + bypass_panel_control_wait); + return BP_RESULT_OK; + } +diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h +index b6d09bf6cf72b6..41c8c014397f29 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h ++++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h +@@ -96,7 +96,7 @@ struct cmd_tbl { + struct bios_parser *bp, uint8_t id); + enum bp_result (*enable_lvtma_control)(struct bios_parser *bp, + uint8_t uc_pwr_on, +- uint8_t panel_instance, ++ uint8_t pwrseq_instance, + uint8_t bypass_panel_control_wait); + }; + +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c +index 0c6a4ab72b1d29..97cdc24cef9a5c 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c +@@ -484,7 +484,8 @@ static void build_watermark_ranges(struct clk_bw_params *bw_params, struct pp_sm + ranges->reader_wm_sets[num_valid_sets].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + + /* Modify previous watermark range to cover up to max */ +- ranges->reader_wm_sets[num_valid_sets - 1].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; ++ if (num_valid_sets > 0) ++ ranges->reader_wm_sets[num_valid_sets - 1].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + } + num_valid_sets++; + } +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c +index 7326b756584610..2618504e260e47 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c +@@ -131,30 +131,27 @@ static int dcn314_get_active_display_cnt_wa( + return display_count; + } + +-static void dcn314_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable) ++static void dcn314_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, ++ bool safe_to_lower, bool disable) + { + struct dc *dc = clk_mgr_base->ctx->dc; + int i; + + for (i = 0; i < dc->res_pool->pipe_count; ++i) { +- struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; ++ struct pipe_ctx *pipe = safe_to_lower ++ ? &context->res_ctx.pipe_ctx[i] ++ : &dc->current_state->res_ctx.pipe_ctx[i]; + + if (pipe->top_pipe || pipe->prev_odm_pipe) + continue; + if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))) { +- struct stream_encoder *stream_enc = pipe->stream_res.stream_enc; +- + if (disable) { +- if (stream_enc && stream_enc->funcs->disable_fifo) +- pipe->stream_res.stream_enc->funcs->disable_fifo(stream_enc); ++ if (pipe->stream_res.tg && pipe->stream_res.tg->funcs->immediate_disable_crtc) ++ pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); + +- pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); + reset_sync_context_for_pipe(dc, context, i); + } else { + pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg); +- +- if (stream_enc && stream_enc->funcs->enable_fifo) +- pipe->stream_res.stream_enc->funcs->enable_fifo(stream_enc); + } + } + } +@@ -252,11 +249,11 @@ void dcn314_update_clocks(struct clk_mgr *clk_mgr_base, + } + + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { +- dcn314_disable_otg_wa(clk_mgr_base, context, true); ++ dcn314_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true); + + clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; + dcn314_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); +- dcn314_disable_otg_wa(clk_mgr_base, context, false); ++ dcn314_disable_otg_wa(clk_mgr_base, context, safe_to_lower, false); + + update_dispclk = true; + } +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c +index b2c4f97afc8b4c..d4d3f58a613f7a 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c +@@ -145,6 +145,10 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, + */ + clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; + if (safe_to_lower) { ++ if (clk_mgr_base->clks.dtbclk_en && !new_clocks->dtbclk_en) { ++ dcn315_smu_set_dtbclk(clk_mgr, false); ++ clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en; ++ } + /* check that we're not already in lower */ + if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) { + display_count = dcn315_get_active_display_cnt_wa(dc, context); +@@ -160,6 +164,10 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, + } + } + } else { ++ if (!clk_mgr_base->clks.dtbclk_en && new_clocks->dtbclk_en) { ++ dcn315_smu_set_dtbclk(clk_mgr, true); ++ clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en; ++ } + /* check that we're not already in D0 */ + if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) { + union display_idle_optimization_u idle_info = { 0 }; +@@ -334,7 +342,7 @@ static struct wm_table lpddr5_wm_table = { + { + .wm_inst = WM_A, + .wm_type = WM_TYPE_PSTATE_CHG, +- .pstate_latency_us = 11.65333, ++ .pstate_latency_us = 129.0, + .sr_exit_time_us = 11.5, + .sr_enter_plus_exit_time_us = 14.5, + .valid = true, +@@ -342,7 +350,7 @@ static struct wm_table lpddr5_wm_table = { + { + .wm_inst = WM_B, + .wm_type = WM_TYPE_PSTATE_CHG, +- .pstate_latency_us = 11.65333, ++ .pstate_latency_us = 129.0, + .sr_exit_time_us = 11.5, + .sr_enter_plus_exit_time_us = 14.5, + .valid = true, +@@ -350,7 +358,7 @@ static struct wm_table lpddr5_wm_table = { + { + .wm_inst = WM_C, + .wm_type = WM_TYPE_PSTATE_CHG, +- .pstate_latency_us = 11.65333, ++ .pstate_latency_us = 129.0, + .sr_exit_time_us = 11.5, + .sr_enter_plus_exit_time_us = 14.5, + .valid = true, +@@ -358,7 +366,7 @@ static struct wm_table lpddr5_wm_table = { + { + .wm_inst = WM_D, + .wm_type = WM_TYPE_PSTATE_CHG, +- .pstate_latency_us = 11.65333, ++ .pstate_latency_us = 129.0, + .sr_exit_time_us = 11.5, + .sr_enter_plus_exit_time_us = 14.5, + .valid = true, +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c +index 09151cc56ce4f2..a13ead3d21e310 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c +@@ -99,20 +99,25 @@ static int dcn316_get_active_display_cnt_wa( + return display_count; + } + +-static void dcn316_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable) ++static void dcn316_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, ++ bool safe_to_lower, bool disable) + { + struct dc *dc = clk_mgr_base->ctx->dc; + int i; + + for (i = 0; i < dc->res_pool->pipe_count; ++i) { +- struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; ++ struct pipe_ctx *pipe = safe_to_lower ++ ? &context->res_ctx.pipe_ctx[i] ++ : &dc->current_state->res_ctx.pipe_ctx[i]; + + if (pipe->top_pipe || pipe->prev_odm_pipe) + continue; +- if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL || +- dc_is_virtual_signal(pipe->stream->signal))) { ++ if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal) || ++ !pipe->stream->link_enc)) { + if (disable) { +- pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); ++ if (pipe->stream_res.tg && pipe->stream_res.tg->funcs->immediate_disable_crtc) ++ pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); ++ + reset_sync_context_for_pipe(dc, context, i); + } else + pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg); +@@ -207,11 +212,11 @@ static void dcn316_update_clocks(struct clk_mgr *clk_mgr_base, + } + + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { +- dcn316_disable_otg_wa(clk_mgr_base, context, true); ++ dcn316_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true); + + clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; + dcn316_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); +- dcn316_disable_otg_wa(clk_mgr_base, context, false); ++ dcn316_disable_otg_wa(clk_mgr_base, context, safe_to_lower, false); + + update_dispclk = true; + } +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +index e9345f6554dbcb..2428a4763b85f6 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +@@ -547,8 +547,12 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base, + * since we calculate mode support based on softmax being the max UCLK + * frequency. + */ +- dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, +- dc->clk_mgr->bw_params->dc_mode_softmax_memclk); ++ if (dc->debug.disable_dc_mode_overwrite) { ++ dcn30_smu_set_hard_max_by_freq(clk_mgr, PPCLK_UCLK, dc->clk_mgr->bw_params->max_memclk_mhz); ++ dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, dc->clk_mgr->bw_params->max_memclk_mhz); ++ } else ++ dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, ++ dc->clk_mgr->bw_params->dc_mode_softmax_memclk); + } else { + dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, dc->clk_mgr->bw_params->max_memclk_mhz); + } +@@ -581,8 +585,13 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base, + /* set UCLK to requested value if P-State switching is supported, or to re-enable P-State switching */ + if (clk_mgr_base->clks.p_state_change_support && + (update_uclk || !clk_mgr_base->clks.prev_p_state_change_support) && +- !dc->work_arounds.clock_update_disable_mask.uclk) ++ !dc->work_arounds.clock_update_disable_mask.uclk) { ++ if (dc->clk_mgr->dc_mode_softmax_enabled && dc->debug.disable_dc_mode_overwrite) ++ dcn30_smu_set_hard_max_by_freq(clk_mgr, PPCLK_UCLK, ++ max((int)dc->clk_mgr->bw_params->dc_mode_softmax_memclk, khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz))); ++ + dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz)); ++ } + + if (clk_mgr_base->clks.num_ways != new_clocks->num_ways && + clk_mgr_base->clks.num_ways > new_clocks->num_ways) { +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index d08e60dff46deb..c2efe18ceacd07 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -990,7 +990,8 @@ static bool dc_construct(struct dc *dc, + /* set i2c speed if not done by the respective dcnxxx__resource.c */ + if (dc->caps.i2c_speed_in_khz_hdcp == 0) + dc->caps.i2c_speed_in_khz_hdcp = dc->caps.i2c_speed_in_khz; +- ++ if (dc->caps.max_optimizable_video_width == 0) ++ dc->caps.max_optimizable_video_width = 5120; + dc->clk_mgr = dc_clk_mgr_create(dc->ctx, dc->res_pool->pp_smu, dc->res_pool->dccg); + if (!dc->clk_mgr) + goto fail; +@@ -1069,53 +1070,6 @@ static void apply_ctx_interdependent_lock(struct dc *dc, + } + } + +-static void phantom_pipe_blank( +- struct dc *dc, +- struct timing_generator *tg, +- int width, +- int height) +-{ +- struct dce_hwseq *hws = dc->hwseq; +- enum dc_color_space color_space; +- struct tg_color black_color = {0}; +- struct output_pixel_processor *opp = NULL; +- uint32_t num_opps, opp_id_src0, opp_id_src1; +- uint32_t otg_active_width, otg_active_height; +- uint32_t i; +- +- /* program opp dpg blank color */ +- color_space = COLOR_SPACE_SRGB; +- color_space_to_black_color(dc, color_space, &black_color); +- +- otg_active_width = width; +- otg_active_height = height; +- +- /* get the OPTC source */ +- tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); +- ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp); +- +- for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { +- if (dc->res_pool->opps[i] != NULL && dc->res_pool->opps[i]->inst == opp_id_src0) { +- opp = dc->res_pool->opps[i]; +- break; +- } +- } +- +- if (opp && opp->funcs->opp_set_disp_pattern_generator) +- opp->funcs->opp_set_disp_pattern_generator( +- opp, +- CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, +- CONTROLLER_DP_COLOR_SPACE_UDEFINED, +- COLOR_DEPTH_UNDEFINED, +- &black_color, +- otg_active_width, +- otg_active_height, +- 0); +- +- if (tg->funcs->is_tg_enabled(tg)) +- hws->funcs.wait_for_blank_complete(opp); +-} +- + static void dc_update_viusal_confirm_color(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) + { + if (dc->ctx->dce_version >= DCN_VERSION_1_0) { +@@ -1206,7 +1160,8 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context) + + main_pipe_width = old_stream->mall_stream_config.paired_stream->dst.width; + main_pipe_height = old_stream->mall_stream_config.paired_stream->dst.height; +- phantom_pipe_blank(dc, tg, main_pipe_width, main_pipe_height); ++ if (dc->hwss.blank_phantom) ++ dc->hwss.blank_phantom(dc, tg, main_pipe_width, main_pipe_height); + tg->funcs->enable_crtc(tg); + } + } +@@ -1343,6 +1298,7 @@ struct dc *dc_create(const struct dc_init_data *init_params) + return NULL; + + if (init_params->dce_environment == DCE_ENV_VIRTUAL_HW) { ++ dc->caps.linear_pitch_alignment = 64; + if (!dc_construct_ctx(dc, init_params)) + goto destruct_dc; + } else { +@@ -1735,7 +1691,7 @@ bool dc_validate_boot_timing(const struct dc *dc, + if (crtc_timing->pix_clk_100hz != pix_clk_100hz) + return false; + +- if (!se->funcs->dp_get_pixel_format) ++ if (!se || !se->funcs->dp_get_pixel_format) + return false; + + if (!se->funcs->dp_get_pixel_format( +@@ -1755,6 +1711,9 @@ bool dc_validate_boot_timing(const struct dc *dc, + return false; + } + ++ if (link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) ++ return false; ++ + if (dc->link_srv->edp_is_ilr_optimization_required(link, crtc_timing)) { + DC_LOG_EVENT_LINK_TRAINING("Seamless boot disabled to optimize eDP link rate\n"); + return false; +@@ -1888,7 +1847,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c + if (dc->hwss.subvp_pipe_control_lock) + dc->hwss.subvp_pipe_control_lock(dc, context, true, true, NULL, subvp_prev_use); + +- if (dc->debug.enable_double_buffered_dsc_pg_support) ++ if (dc->hwss.update_dsc_pg) + dc->hwss.update_dsc_pg(dc, context, false); + + disable_dangling_plane(dc, context); +@@ -1993,9 +1952,13 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c + wait_for_no_pipes_pending(dc, context); + /* pplib is notified if disp_num changed */ + dc->hwss.optimize_bandwidth(dc, context); ++ /* Need to do otg sync again as otg could be out of sync due to otg ++ * workaround applied during clock update ++ */ ++ dc_trigger_sync(dc, context); + } + +- if (dc->debug.enable_double_buffered_dsc_pg_support) ++ if (dc->hwss.update_dsc_pg) + dc->hwss.update_dsc_pg(dc, context, true); + + if (dc->ctx->dce_version >= DCE_VERSION_MAX) +@@ -2242,7 +2205,7 @@ void dc_post_update_surfaces_to_stream(struct dc *dc) + + dc->hwss.optimize_bandwidth(dc, context); + +- if (dc->debug.enable_double_buffered_dsc_pg_support) ++ if (dc->hwss.update_dsc_pg) + dc->hwss.update_dsc_pg(dc, context, true); + } + +@@ -2488,6 +2451,7 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa + } + + static enum surface_update_type get_scaling_info_update_type( ++ const struct dc *dc, + const struct dc_surface_update *u) + { + union surface_update_flags *update_flags = &u->surface->update_flags; +@@ -2520,6 +2484,12 @@ static enum surface_update_type get_scaling_info_update_type( + update_flags->bits.clock_change = 1; + } + ++ if (u->scaling_info->src_rect.width > dc->caps.max_optimizable_video_width && ++ (u->scaling_info->clip_rect.width > u->surface->clip_rect.width || ++ u->scaling_info->clip_rect.height > u->surface->clip_rect.height)) ++ /* Changing clip size of a large surface may result in MPC slice count change */ ++ update_flags->bits.bandwidth_change = 1; ++ + if (u->scaling_info->src_rect.x != u->surface->src_rect.x + || u->scaling_info->src_rect.y != u->surface->src_rect.y + || u->scaling_info->clip_rect.x != u->surface->clip_rect.x +@@ -2557,7 +2527,7 @@ static enum surface_update_type det_surface_update(const struct dc *dc, + type = get_plane_info_update_type(u); + elevate_update_type(&overall_type, type); + +- type = get_scaling_info_update_type(u); ++ type = get_scaling_info_update_type(dc, u); + elevate_update_type(&overall_type, type); + + if (u->flip_addr) { +@@ -3571,7 +3541,7 @@ static void commit_planes_for_stream(struct dc *dc, + if (get_seamless_boot_stream_count(context) == 0) + dc->hwss.prepare_bandwidth(dc, context); + +- if (dc->debug.enable_double_buffered_dsc_pg_support) ++ if (dc->hwss.update_dsc_pg) + dc->hwss.update_dsc_pg(dc, context, false); + + context_clock_trace(dc, context); +@@ -3827,7 +3797,8 @@ static void commit_planes_for_stream(struct dc *dc, + } + + if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed) +- if (top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) { ++ if (top_pipe_to_program && ++ top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) { + top_pipe_to_program->stream_res.tg->funcs->wait_for_state( + top_pipe_to_program->stream_res.tg, + CRTC_STATE_VACTIVE); +@@ -4374,6 +4345,14 @@ bool dc_update_planes_and_stream(struct dc *dc, + update_type, + context); + } else { ++ if (!stream_update && ++ dc->hwss.is_pipe_topology_transition_seamless && ++ !dc->hwss.is_pipe_topology_transition_seamless( ++ dc, dc->current_state, context)) { ++ ++ DC_LOG_ERROR("performing non-seamless pipe topology transition with surface only update!\n"); ++ BREAK_TO_DEBUGGER(); ++ } + commit_planes_for_stream( + dc, + srf_updates, +@@ -4737,7 +4716,8 @@ void dc_allow_idle_optimizations(struct dc *dc, bool allow) + if (allow == dc->idle_optimizations_allowed) + return; + +- if (dc->hwss.apply_idle_power_optimizations && dc->hwss.apply_idle_power_optimizations(dc, allow)) ++ if (dc->hwss.apply_idle_power_optimizations && dc->clk_mgr != NULL && ++ dc->hwss.apply_idle_power_optimizations(dc, allow)) + dc->idle_optimizations_allowed = allow; + } + +@@ -4895,18 +4875,28 @@ void dc_mclk_switch_using_fw_based_vblank_stretch_shut_down(struct dc *dc) + */ + bool dc_is_dmub_outbox_supported(struct dc *dc) + { +- /* DCN31 B0 USB4 DPIA needs dmub notifications for interrupts */ +- if (dc->ctx->asic_id.chip_family == FAMILY_YELLOW_CARP && +- dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0 && +- !dc->debug.dpia_debug.bits.disable_dpia) +- return true; ++ switch (dc->ctx->asic_id.chip_family) { + +- if (dc->ctx->asic_id.chip_family == AMDGPU_FAMILY_GC_11_0_1 && +- !dc->debug.dpia_debug.bits.disable_dpia) +- return true; ++ case FAMILY_YELLOW_CARP: ++ /* DCN31 B0 USB4 DPIA needs dmub notifications for interrupts */ ++ if (dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0 && ++ !dc->debug.dpia_debug.bits.disable_dpia) ++ return true; ++ break; ++ ++ case AMDGPU_FAMILY_GC_11_0_1: ++ case AMDGPU_FAMILY_GC_11_5_0: ++ if (!dc->debug.dpia_debug.bits.disable_dpia) ++ return true; ++ break; ++ ++ default: ++ break; ++ } + + /* dmub aux needs dmub notifications to be enabled */ + return dc->debug.enable_dmub_aux_for_legacy_ddc; ++ + } + + /** +@@ -5284,3 +5274,24 @@ void dc_query_current_properties(struct dc *dc, struct dc_current_properties *pr + properties->cursor_size_limit = subvp_in_use ? 64 : dc->caps.max_cursor_size; + } + ++/** ++ ***************************************************************************** ++ * dc_set_edp_power() - DM controls eDP power to be ON/OFF ++ * ++ * Called when DM wants to power on/off eDP. ++ * Only work on links with flag skip_implict_edp_power_control is set. ++ * ++ ***************************************************************************** ++ */ ++void dc_set_edp_power(const struct dc *dc, struct dc_link *edp_link, ++ bool powerOn) ++{ ++ if (edp_link->connector_signal != SIGNAL_TYPE_EDP) ++ return; ++ ++ if (edp_link->skip_implict_edp_power_control == false) ++ return; ++ ++ edp_link->dc->link_srv->edp_set_panel_power(edp_link, powerOn); ++} ++ +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c +index ed94187c2afa2d..f365773d571485 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c +@@ -497,7 +497,7 @@ void dc_link_enable_hpd_filter(struct dc_link *link, bool enable) + link->dc->link_srv->enable_hpd_filter(link, enable); + } + +-bool dc_link_validate(struct dc *dc, const struct dc_stream_state *streams, const unsigned int count) ++bool dc_link_dp_dpia_validate(struct dc *dc, const struct dc_stream_state *streams, const unsigned int count) + { + return dc->link_srv->validate_dpia_bandwidth(streams, count); + } +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +index f7b51aca602006..99fcd39bb15e0d 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -996,7 +996,7 @@ static void adjust_recout_for_visual_confirm(struct rect *recout, + struct dc *dc = pipe_ctx->stream->ctx->dc; + int dpp_offset, base_offset; + +- if (dc->debug.visual_confirm == VISUAL_CONFIRM_DISABLE) ++ if (dc->debug.visual_confirm == VISUAL_CONFIRM_DISABLE || !pipe_ctx->plane_res.dpp) + return; + + dpp_offset = pipe_ctx->stream->timing.v_addressable / VISUAL_CONFIRM_DPP_OFFSET_DENO; +@@ -2154,6 +2154,8 @@ static bool are_stream_backends_same( + bool dc_is_stream_unchanged( + struct dc_stream_state *old_stream, struct dc_stream_state *stream) + { ++ if (!old_stream || !stream) ++ return false; + + if (!are_stream_backends_same(old_stream, stream)) + return false; +@@ -2385,6 +2387,9 @@ static struct audio *find_first_free_audio( + { + int i, available_audio_count; + ++ if (id == ENGINE_ID_UNKNOWN) ++ return NULL; ++ + available_audio_count = pool->audio_count; + + for (i = 0; i < available_audio_count; i++) { +@@ -2874,8 +2879,10 @@ static bool planes_changed_for_existing_stream(struct dc_state *context, + } + } + +- if (!stream_status) ++ if (!stream_status) { + ASSERT(0); ++ return false; ++ } + + for (i = 0; i < set_count; i++) + if (set[i].stream == stream) +@@ -3924,6 +3931,9 @@ void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream, + + enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream) + { ++ if (dc == NULL || stream == NULL) ++ return DC_ERROR_UNEXPECTED; ++ + struct dc_link *link = stream->link; + struct timing_generator *tg = dc->res_pool->timing_generators[0]; + enum dc_status res = DC_OK; +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +index 01fe2d2fd24172..ebe571fcefe32e 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +@@ -582,7 +582,7 @@ uint32_t dc_stream_get_vblank_counter(const struct dc_stream_state *stream) + for (i = 0; i < MAX_PIPES; i++) { + struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg; + +- if (res_ctx->pipe_ctx[i].stream != stream) ++ if (res_ctx->pipe_ctx[i].stream != stream || !tg) + continue; + + return tg->funcs->get_frame_count(tg); +@@ -641,7 +641,7 @@ bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream, + for (i = 0; i < MAX_PIPES; i++) { + struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg; + +- if (res_ctx->pipe_ctx[i].stream != stream) ++ if (res_ctx->pipe_ctx[i].stream != stream || !tg) + continue; + + tg->funcs->get_scanoutpos(tg, +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c +index a80e45300783c0..f4f3ca7aad60e2 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c +@@ -154,7 +154,8 @@ const struct dc_plane_status *dc_plane_get_status( + if (pipe_ctx->plane_state != plane_state) + continue; + +- pipe_ctx->plane_state->status.is_flip_pending = false; ++ if (pipe_ctx->plane_state) ++ pipe_ctx->plane_state->status.is_flip_pending = false; + + break; + } +diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h +index 31e3183497a7f5..5f2eac868b7472 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc.h ++++ b/drivers/gpu/drm/amd/display/dc/dc.h +@@ -231,6 +231,11 @@ struct dc_caps { + uint32_t dmdata_alloc_size; + unsigned int max_cursor_size; + unsigned int max_video_width; ++ /* ++ * max video plane width that can be safely assumed to be always ++ * supported by single DPP pipe. ++ */ ++ unsigned int max_optimizable_video_width; + unsigned int min_horizontal_blanking_period; + int linear_pitch_alignment; + bool dcc_const_color; +@@ -1533,7 +1538,6 @@ struct dc_link { + enum edp_revision edp_revision; + union dpcd_sink_ext_caps dpcd_sink_ext_caps; + +- struct backlight_settings backlight_settings; + struct psr_settings psr_settings; + + struct replay_settings replay_settings; +@@ -1573,6 +1577,7 @@ struct dc_link { + struct phy_state phy_state; + // BW ALLOCATON USB4 ONLY + struct dc_dpia_bw_alloc dpia_bw_alloc_config; ++ bool skip_implict_edp_power_control; + }; + + /* Return an enumerated dc_link. +@@ -1592,6 +1597,9 @@ void dc_get_edp_links(const struct dc *dc, + struct dc_link **edp_links, + int *edp_num); + ++void dc_set_edp_power(const struct dc *dc, struct dc_link *edp_link, ++ bool powerOn); ++ + /* The function initiates detection handshake over the given link. It first + * determines if there are display connections over the link. If so it initiates + * detection protocols supported by the connected receiver device. The function +@@ -2108,11 +2116,11 @@ int dc_link_dp_dpia_handle_usb4_bandwidth_allocation_for_link( + * + * @dc: pointer to dc struct + * @stream: pointer to all possible streams +- * @num_streams: number of valid DPIA streams ++ * @count: number of valid DPIA streams + * + * return: TRUE if bw used by DPIAs doesn't exceed available BW else return FALSE + */ +-bool dc_link_validate(struct dc *dc, const struct dc_stream_state *streams, ++bool dc_link_dp_dpia_validate(struct dc *dc, const struct dc_stream_state *streams, + const unsigned int count); + + /* Sink Interfaces - A sink corresponds to a display output device */ +diff --git a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h +index be9aa1a71847d7..26940d94d8fb40 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h +@@ -140,7 +140,7 @@ struct dc_vbios_funcs { + enum bp_result (*enable_lvtma_control)( + struct dc_bios *bios, + uint8_t uc_pwr_on, +- uint8_t panel_instance, ++ uint8_t pwrseq_instance, + uint8_t bypass_panel_control_wait); + + enum bp_result (*get_soc_bb_info)( +diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +index cfaa39c5dd16bd..83719f5bea4956 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +@@ -1433,6 +1433,12 @@ struct dp_trace { + #ifndef DP_TUNNELING_STATUS + #define DP_TUNNELING_STATUS 0xE0025 /* 1.4a */ + #endif ++#ifndef DP_TUNNELING_MAX_LINK_RATE ++#define DP_TUNNELING_MAX_LINK_RATE 0xE0028 /* 1.4a */ ++#endif ++#ifndef DP_TUNNELING_MAX_LANE_COUNT ++#define DP_TUNNELING_MAX_LANE_COUNT 0xE0029 /* 1.4a */ ++#endif + #ifndef DPTX_BW_ALLOCATION_MODE_CONTROL + #define DPTX_BW_ALLOCATION_MODE_CONTROL 0xE0030 /* 1.4a */ + #endif +diff --git a/drivers/gpu/drm/amd/display/dc/dc_dsc.h b/drivers/gpu/drm/amd/display/dc/dc_dsc.h +index fe3078b8789ef1..01c07545ef6b47 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_dsc.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_dsc.h +@@ -100,7 +100,8 @@ uint32_t dc_dsc_stream_bandwidth_overhead_in_kbps( + */ + void dc_dsc_get_policy_for_timing(const struct dc_crtc_timing *timing, + uint32_t max_target_bpp_limit_override_x16, +- struct dc_dsc_policy *policy); ++ struct dc_dsc_policy *policy, ++ const enum dc_link_encoding_format link_encoding); + + void dc_dsc_policy_set_max_target_bpp_limit(uint32_t limit); + +diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +index 100d62162b717e..00de342e5290b7 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +@@ -244,7 +244,7 @@ enum pixel_format { + #define DC_MAX_DIRTY_RECTS 3 + struct dc_flip_addrs { + struct dc_plane_address address; +- unsigned int flip_timestamp_in_us; ++ unsigned long long flip_timestamp_in_us; + bool flip_immediate; + /* TODO: add flip duration for FreeSync */ + bool triplebuffer_flips; +@@ -465,6 +465,7 @@ struct dc_cursor_mi_param { + struct fixed31_32 v_scale_ratio; + enum dc_rotation_angle rotation; + bool mirror; ++ struct dc_stream_state *stream; + }; + + /* IPP related types */ +diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h +index 3697ea1d14c1bf..d5b3e3a32cc6d4 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h +@@ -302,7 +302,6 @@ struct dc_stream_state { + bool vblank_synchronized; + bool fpo_in_use; + struct mall_stream_config mall_stream_config; +- bool skip_edp_power_down; + }; + + #define ABM_LEVEL_IMMEDIATE_DISABLE 255 +diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h +index 445ad79001ce2d..6eaa02a80344bc 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_types.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_types.h +@@ -189,6 +189,8 @@ struct dc_panel_patch { + unsigned int disable_fams; + unsigned int skip_avmute; + unsigned int mst_start_top_delay; ++ unsigned int remove_sink_ext_caps; ++ unsigned int disable_colorimetry; + }; + + struct dc_edid_caps { +@@ -1002,10 +1004,6 @@ struct link_mst_stream_allocation_table { + struct link_mst_stream_allocation stream_allocations[MAX_CONTROLLER_NUM]; + }; + +-struct backlight_settings { +- uint32_t backlight_millinits; +-}; +- + /* PSR feature flags */ + struct psr_settings { + bool psr_feature_enabled; // PSR is supported by sink +@@ -1113,21 +1111,25 @@ struct dc_panel_config { + } ilr; + }; + ++#define MAX_SINKS_PER_LINK 4 ++ + /* + * USB4 DPIA BW ALLOCATION STRUCTS + */ + struct dc_dpia_bw_alloc { +- int sink_verified_bw; // The Verified BW that sink can allocated and use that has been verified already +- int sink_allocated_bw; // The Actual Allocated BW that sink currently allocated +- int sink_max_bw; // The Max BW that sink can require/support ++ int remote_sink_req_bw[MAX_SINKS_PER_LINK]; // BW requested by remote sinks ++ int link_verified_bw; // The Verified BW that link can allocated and use that has been verified already ++ int link_max_bw; // The Max BW that link can require/support ++ int allocated_bw; // The Actual Allocated BW for this DPIA + int estimated_bw; // The estimated available BW for this DPIA + int bw_granularity; // BW Granularity ++ int dp_overhead; // DP overhead in dp tunneling + bool bw_alloc_enabled; // The BW Alloc Mode Support is turned ON for all 3: DP-Tx & Dpia & CM + bool response_ready; // Response ready from the CM side ++ uint8_t nrd_max_lane_count; // Non-reduced max lane count ++ uint8_t nrd_max_link_rate; // Non-reduced max link rate + }; + +-#define MAX_SINKS_PER_LINK 4 +- + enum dc_hpd_enable_select { + HPD_EN_FOR_ALL_EDP = 0, + HPD_EN_FOR_PRIMARY_EDP_ONLY, +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c +index b87bfecb7755ae..a8e79104b684ea 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c +@@ -586,7 +586,8 @@ static void dcn10_dmcu_set_psr_enable(struct dmcu *dmcu, bool enable, bool wait) + if (state == PSR_STATE0) + break; + } +- fsleep(500); ++ /* must *not* be fsleep - this can be called from high irq levels */ ++ udelay(500); + } + + /* assert if max retry hit */ +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c +index d3e6544022b787..930fd929e93a4f 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c +@@ -145,7 +145,11 @@ static bool dmub_abm_save_restore_ex( + return ret; + } + +-static bool dmub_abm_set_pipe_ex(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst) ++static bool dmub_abm_set_pipe_ex(struct abm *abm, ++ uint32_t otg_inst, ++ uint32_t option, ++ uint32_t panel_inst, ++ uint32_t pwrseq_inst) + { + bool ret = false; + unsigned int feature_support; +@@ -153,7 +157,7 @@ static bool dmub_abm_set_pipe_ex(struct abm *abm, uint32_t otg_inst, uint32_t op + feature_support = abm_feature_support(abm, panel_inst); + + if (feature_support == ABM_LCD_SUPPORT) +- ret = dmub_abm_set_pipe(abm, otg_inst, option, panel_inst); ++ ret = dmub_abm_set_pipe(abm, otg_inst, option, panel_inst, pwrseq_inst); + + return ret; + } +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c +index 592a8f7a1c6d00..42c802afc4681b 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c +@@ -254,7 +254,11 @@ bool dmub_abm_save_restore( + return true; + } + +-bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst) ++bool dmub_abm_set_pipe(struct abm *abm, ++ uint32_t otg_inst, ++ uint32_t option, ++ uint32_t panel_inst, ++ uint32_t pwrseq_inst) + { + union dmub_rb_cmd cmd; + struct dc_context *dc = abm->ctx; +@@ -264,6 +268,7 @@ bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint + cmd.abm_set_pipe.header.type = DMUB_CMD__ABM; + cmd.abm_set_pipe.header.sub_type = DMUB_CMD__ABM_SET_PIPE; + cmd.abm_set_pipe.abm_set_pipe_data.otg_inst = otg_inst; ++ cmd.abm_set_pipe.abm_set_pipe_data.pwrseq_inst = pwrseq_inst; + cmd.abm_set_pipe.abm_set_pipe_data.set_pipe_option = option; + cmd.abm_set_pipe.abm_set_pipe_data.panel_inst = panel_inst; + cmd.abm_set_pipe.abm_set_pipe_data.ramping_boundary = ramping_boundary; +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h +index 853564d7f4714c..07ea6c8d414f3b 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h ++++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h +@@ -44,7 +44,7 @@ bool dmub_abm_save_restore( + struct dc_context *dc, + unsigned int panel_inst, + struct abm_save_restore *pData); +-bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst); ++bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst, uint32_t pwrseq_inst); + bool dmub_abm_set_backlight_level(struct abm *abm, + unsigned int backlight_pwm_u16_16, + unsigned int frame_ramp, +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c +index 0f24b6fbd22013..4704c9c85ee6f5 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c +@@ -216,7 +216,8 @@ static void dmub_psr_enable(struct dmub_psr *dmub, bool enable, bool wait, uint8 + break; + } + +- fsleep(500); ++ /* must *not* be fsleep - this can be called from high irq levels */ ++ udelay(500); + } + + /* assert if max retry hit */ +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c +index 28149e53c2a68f..eeb5b8247c9652 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c +@@ -102,7 +102,8 @@ static void dmub_replay_enable(struct dmub_replay *dmub, bool enable, bool wait, + break; + } + +- fsleep(500); ++ /* must *not* be fsleep - this can be called from high irq levels */ ++ udelay(500); + } + + /* assert if max retry hit */ +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 2a6157555fd1e4..7b5c1498941dd6 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 +@@ -788,7 +788,7 @@ void dce110_edp_power_control( + struct dc_context *ctx = link->ctx; + struct bp_transmitter_control cntl = { 0 }; + enum bp_result bp_result; +- uint8_t panel_instance; ++ uint8_t pwrseq_instance; + + + if (dal_graphics_object_id_get_connector_id(link->link_enc->connector) +@@ -871,7 +871,7 @@ void dce110_edp_power_control( + cntl.coherent = false; + cntl.lanes_number = LANE_COUNT_FOUR; + cntl.hpd_sel = link->link_enc->hpd_source; +- panel_instance = link->panel_cntl->inst; ++ pwrseq_instance = link->panel_cntl->pwrseq_inst; + + if (ctx->dc->ctx->dmub_srv && + ctx->dc->debug.dmub_command_table) { +@@ -879,11 +879,11 @@ void dce110_edp_power_control( + if (cntl.action == TRANSMITTER_CONTROL_POWER_ON) { + bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, + LVTMA_CONTROL_POWER_ON, +- panel_instance, link->link_powered_externally); ++ pwrseq_instance, link->link_powered_externally); + } else { + bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, + LVTMA_CONTROL_POWER_OFF, +- panel_instance, link->link_powered_externally); ++ pwrseq_instance, link->link_powered_externally); + } + } + +@@ -954,7 +954,7 @@ void dce110_edp_backlight_control( + { + struct dc_context *ctx = link->ctx; + struct bp_transmitter_control cntl = { 0 }; +- uint8_t panel_instance; ++ uint8_t pwrseq_instance; + unsigned int pre_T11_delay = OLED_PRE_T11_DELAY; + unsigned int post_T7_delay = OLED_POST_T7_DELAY; + +@@ -1007,7 +1007,7 @@ void dce110_edp_backlight_control( + */ + /* dc_service_sleep_in_milliseconds(50); */ + /*edp 1.2*/ +- panel_instance = link->panel_cntl->inst; ++ pwrseq_instance = link->panel_cntl->pwrseq_inst; + + if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) { + if (!link->dc->config.edp_no_power_sequencing) +@@ -1032,11 +1032,11 @@ void dce110_edp_backlight_control( + if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) + ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, + LVTMA_CONTROL_LCD_BLON, +- panel_instance, link->link_powered_externally); ++ pwrseq_instance, link->link_powered_externally); + else + ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, + LVTMA_CONTROL_LCD_BLOFF, +- panel_instance, link->link_powered_externally); ++ pwrseq_instance, link->link_powered_externally); + } + + link_transmitter_control(ctx->dc_bios, &cntl); +@@ -1179,9 +1179,10 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx) + dto_params.timing = &pipe_ctx->stream->timing; + dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; + if (dccg) { +- dccg->funcs->set_dtbclk_dto(dccg, &dto_params); + dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst); + dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst, dp_hpo_inst); ++ if (dccg && dccg->funcs->set_dtbclk_dto) ++ dccg->funcs->set_dtbclk_dto(dccg, &dto_params); + } + } else if (dccg && dccg->funcs->disable_symclk_se) { + dccg->funcs->disable_symclk_se(dccg, stream_enc->stream_enc_inst, +@@ -1226,7 +1227,7 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx) + struct dce_hwseq *hws = link->dc->hwseq; + + if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { +- if (!stream->skip_edp_power_down) ++ if (!link->skip_implict_edp_power_control) + hws->funcs.edp_backlight_control(link, false); + link->dc->hwss.set_abm_immediate_disable(pipe_ctx); + } +@@ -2124,7 +2125,8 @@ static void dce110_reset_hw_ctx_wrap( + BREAK_TO_DEBUGGER(); + } + pipe_ctx_old->stream_res.tg->funcs->disable_crtc(pipe_ctx_old->stream_res.tg); +- pipe_ctx_old->stream->link->phy_state.symclk_ref_cnts.otg = 0; ++ if (dc_is_hdmi_tmds_signal(pipe_ctx_old->stream->signal)) ++ pipe_ctx_old->stream->link->phy_state.symclk_ref_cnts.otg = 0; + pipe_ctx_old->plane_res.mi->funcs->free_mem_input( + pipe_ctx_old->plane_res.mi, dc->current_state->stream_count); + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +index 3538973bd0c6cb..684e30f9cf8985 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +@@ -382,6 +382,11 @@ bool cm_helper_translate_curve_to_hw_format(struct dc_context *ctx, + i += increment) { + if (j == hw_points - 1) + break; ++ if (i >= TRANSFER_FUNC_POINTS) { ++ DC_LOG_ERROR("Index out of bounds: i=%d, TRANSFER_FUNC_POINTS=%d\n", ++ i, TRANSFER_FUNC_POINTS); ++ return false; ++ } + rgb_resulted[j].red = output_tf->tf_pts.red[i]; + rgb_resulted[j].green = output_tf->tf_pts.green[i]; + rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; +@@ -566,6 +571,8 @@ bool cm_helper_translate_curve_to_degamma_hw_format( + i += increment) { + if (j == hw_points - 1) + break; ++ if (i >= TRANSFER_FUNC_POINTS) ++ return false; + rgb_resulted[j].red = output_tf->tf_pts.red[i]; + rgb_resulted[j].green = output_tf->tf_pts.green[i]; + rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +index 9834b75f1837ba..ff38a85c4fa22d 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +@@ -111,7 +111,8 @@ void dcn10_lock_all_pipes(struct dc *dc, + if (pipe_ctx->top_pipe || + !pipe_ctx->stream || + (!pipe_ctx->plane_state && !old_pipe_ctx->plane_state) || +- !tg->funcs->is_tg_enabled(tg)) ++ !tg->funcs->is_tg_enabled(tg) || ++ pipe_ctx->stream->mall_stream_config.type == SUBVP_PHANTOM) + continue; + + if (lock) +@@ -1053,7 +1054,8 @@ static void dcn10_reset_back_end_for_pipe( + if (pipe_ctx->stream_res.tg->funcs->set_drr) + pipe_ctx->stream_res.tg->funcs->set_drr( + pipe_ctx->stream_res.tg, NULL); +- pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; ++ if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) ++ pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) +@@ -1830,6 +1832,9 @@ bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + { + struct dpp *dpp = pipe_ctx->plane_res.dpp; + ++ if (!stream) ++ return false; ++ + if (dpp == NULL) + return false; + +@@ -1852,8 +1857,8 @@ bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + } else + dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_BYPASS); + +- if (stream != NULL && stream->ctx != NULL && +- stream->out_transfer_func != NULL) { ++ if (stream->ctx && ++ stream->out_transfer_func) { + log_tf(stream->ctx, + stream->out_transfer_func, + dpp->regamma_params.hw_points_num); +@@ -3406,7 +3411,8 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) + .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, + .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert, + .rotation = pipe_ctx->plane_state->rotation, +- .mirror = pipe_ctx->plane_state->horizontal_mirror ++ .mirror = pipe_ctx->plane_state->horizontal_mirror, ++ .stream = pipe_ctx->stream, + }; + bool pipe_split_on = false; + bool odm_combine_on = (pipe_ctx->next_odm_pipe != NULL) || +@@ -3515,7 +3521,7 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) + (int)hubp->curs_attr.width || pos_cpy.x + <= (int)hubp->curs_attr.width + + pipe_ctx->plane_state->src_rect.x) { +- pos_cpy.x = temp_x + viewport_width; ++ pos_cpy.x = 2 * viewport_width - temp_x; + } + } + } else { +@@ -3608,7 +3614,7 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) + (int)hubp->curs_attr.width || pos_cpy.x + <= (int)hubp->curs_attr.width + + pipe_ctx->plane_state->src_rect.x) { +- pos_cpy.x = 2 * viewport_width - temp_x; ++ pos_cpy.x = temp_x + viewport_width; + } + } + } else { +diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb_scl.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb_scl.c +index 994fb732a7cb76..a0d437f0ce2baf 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb_scl.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb_scl.c +@@ -690,6 +690,9 @@ static void wbscl_set_scaler_filter( + int pair; + uint16_t odd_coef, even_coef; + ++ if (!filter) ++ return; ++ + for (phase = 0; phase < (NUM_PHASES / 2 + 1); phase++) { + for (pair = 0; pair < tap_pairs; pair++) { + even_coef = filter[phase * taps + 2 * pair]; +diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c +index 4566bc7abf17e6..aa252dc2632671 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c +@@ -1075,8 +1075,16 @@ void hubp2_cursor_set_position( + if (src_y_offset < 0) + src_y_offset = 0; + /* Save necessary cursor info x, y position. w, h is saved in attribute func. */ +- hubp->cur_rect.x = src_x_offset + param->viewport.x; +- hubp->cur_rect.y = src_y_offset + param->viewport.y; ++ if (param->stream->link->psr_settings.psr_version >= DC_PSR_VERSION_SU_1 && ++ param->rotation != ROTATION_ANGLE_0) { ++ hubp->cur_rect.x = 0; ++ hubp->cur_rect.y = 0; ++ hubp->cur_rect.w = param->stream->timing.h_addressable; ++ hubp->cur_rect.h = param->stream->timing.v_addressable; ++ } else { ++ hubp->cur_rect.x = src_x_offset + param->viewport.x; ++ hubp->cur_rect.y = src_y_offset + param->viewport.y; ++ } + } + + void hubp2_clk_cntl(struct hubp *hubp, bool enable) +diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +index aeadc587433fd5..12af2859002f72 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +@@ -1792,6 +1792,8 @@ void dcn20_program_front_end_for_ctx( + int i; + struct dce_hwseq *hws = dc->hwseq; + DC_LOGGER_INIT(dc->ctx->logger); ++ unsigned int prev_hubp_count = 0; ++ unsigned int hubp_count = 0; + + /* Carry over GSL groups in case the context is changing. */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { +@@ -1815,6 +1817,20 @@ void dcn20_program_front_end_for_ctx( + } + } + ++ for (i = 0; i < dc->res_pool->pipe_count; i++) { ++ if (dc->current_state->res_ctx.pipe_ctx[i].plane_state) ++ prev_hubp_count++; ++ if (context->res_ctx.pipe_ctx[i].plane_state) ++ hubp_count++; ++ } ++ ++ if (prev_hubp_count == 0 && hubp_count > 0) { ++ if (dc->res_pool->hubbub->funcs->force_pstate_change_control) ++ dc->res_pool->hubbub->funcs->force_pstate_change_control( ++ dc->res_pool->hubbub, true, false); ++ udelay(500); ++ } ++ + /* Set pipe update flags and lock pipes */ + for (i = 0; i < dc->res_pool->pipe_count; i++) + dcn20_detect_pipe_changes(&dc->current_state->res_ctx.pipe_ctx[i], +@@ -1830,8 +1846,16 @@ void dcn20_program_front_end_for_ctx( + dc->current_state->res_ctx.pipe_ctx[i].stream->mall_stream_config.type == SUBVP_PHANTOM) { + struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg; + +- if (tg->funcs->enable_crtc) ++ if (tg->funcs->enable_crtc) { ++ if (dc->hwss.blank_phantom) { ++ int main_pipe_width, main_pipe_height; ++ ++ main_pipe_width = dc->current_state->res_ctx.pipe_ctx[i].stream->mall_stream_config.paired_stream->dst.width; ++ main_pipe_height = dc->current_state->res_ctx.pipe_ctx[i].stream->mall_stream_config.paired_stream->dst.height; ++ dc->hwss.blank_phantom(dc, tg, main_pipe_width, main_pipe_height); ++ } + tg->funcs->enable_crtc(tg); ++ } + } + } + /* OTG blank before disabling all front ends */ +@@ -1954,6 +1978,10 @@ void dcn20_post_unlock_program_front_end( + } + } + ++ if (dc->res_pool->hubbub->funcs->force_pstate_change_control) ++ dc->res_pool->hubbub->funcs->force_pstate_change_control( ++ dc->res_pool->hubbub, false, false); ++ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + +@@ -2505,7 +2533,8 @@ static void dcn20_reset_back_end_for_pipe( + * the case where the same symclk is shared across multiple otg + * instances + */ +- link->phy_state.symclk_ref_cnts.otg = 0; ++ if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) ++ link->phy_state.symclk_ref_cnts.otg = 0; + if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) { + link_hwss->disable_link_output(link, + &pipe_ctx->link_res, pipe_ctx->stream->signal); +@@ -2699,18 +2728,17 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) + } + + if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { +- dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; +- dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, dp_hpo_inst); +- +- phyd32clk = get_phyd32clk_src(link); +- dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk); +- + dto_params.otg_inst = tg->inst; + dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10; + dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx); + dto_params.timing = &pipe_ctx->stream->timing; + dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr); + dccg->funcs->set_dtbclk_dto(dccg, &dto_params); ++ dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; ++ dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, dp_hpo_inst); ++ ++ phyd32clk = get_phyd32clk_src(link); ++ dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk); + } else { + } + if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) { +diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c +index 43463d08f21ba9..1b08749b084b1d 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c +@@ -137,7 +137,8 @@ void dcn21_PLAT_58856_wa(struct dc_state *context, struct pipe_ctx *pipe_ctx) + pipe_ctx->stream->dpms_off = true; + } + +-static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst) ++static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, ++ uint32_t option, uint32_t panel_inst, uint32_t pwrseq_inst) + { + union dmub_rb_cmd cmd; + struct dc_context *dc = abm->ctx; +@@ -147,6 +148,7 @@ static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t optio + cmd.abm_set_pipe.header.type = DMUB_CMD__ABM; + cmd.abm_set_pipe.header.sub_type = DMUB_CMD__ABM_SET_PIPE; + cmd.abm_set_pipe.abm_set_pipe_data.otg_inst = otg_inst; ++ cmd.abm_set_pipe.abm_set_pipe_data.pwrseq_inst = pwrseq_inst; + cmd.abm_set_pipe.abm_set_pipe_data.set_pipe_option = option; + cmd.abm_set_pipe.abm_set_pipe_data.panel_inst = panel_inst; + cmd.abm_set_pipe.abm_set_pipe_data.ramping_boundary = ramping_boundary; +@@ -179,7 +181,6 @@ void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) + struct abm *abm = pipe_ctx->stream_res.abm; + uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; + struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; +- + struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu; + + if (dmcu) { +@@ -190,9 +191,13 @@ void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) + if (abm && panel_cntl) { + if (abm->funcs && abm->funcs->set_pipe_ex) { + abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_IMMEDIATELY_DISABLE, +- panel_cntl->inst); ++ panel_cntl->inst, panel_cntl->pwrseq_inst); + } else { +- dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_IMMEDIATELY_DISABLE, panel_cntl->inst); ++ dmub_abm_set_pipe(abm, ++ otg_inst, ++ SET_ABM_PIPE_IMMEDIATELY_DISABLE, ++ panel_cntl->inst, ++ panel_cntl->pwrseq_inst); + } + panel_cntl->funcs->store_backlight_level(panel_cntl); + } +@@ -201,21 +206,32 @@ void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) + void dcn21_set_pipe(struct pipe_ctx *pipe_ctx) + { + struct abm *abm = pipe_ctx->stream_res.abm; +- uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; ++ struct timing_generator *tg = pipe_ctx->stream_res.tg; + struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; + struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu; ++ uint32_t otg_inst; ++ ++ if (!abm && !tg && !panel_cntl) ++ return; ++ ++ otg_inst = tg->inst; + + if (dmcu) { + dce110_set_pipe(pipe_ctx); + return; + } + +- if (abm && panel_cntl) { +- if (abm->funcs && abm->funcs->set_pipe_ex) { +- abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); +- } else { +- dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); +- } ++ if (abm->funcs && abm->funcs->set_pipe_ex) { ++ abm->funcs->set_pipe_ex(abm, ++ otg_inst, ++ SET_ABM_PIPE_NORMAL, ++ panel_cntl->inst, ++ panel_cntl->pwrseq_inst); ++ } else { ++ dmub_abm_set_pipe(abm, otg_inst, ++ SET_ABM_PIPE_NORMAL, ++ panel_cntl->inst, ++ panel_cntl->pwrseq_inst); + } + } + +@@ -225,26 +241,35 @@ bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx, + { + struct dc_context *dc = pipe_ctx->stream->ctx; + struct abm *abm = pipe_ctx->stream_res.abm; ++ struct timing_generator *tg = pipe_ctx->stream_res.tg; + struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; ++ uint32_t otg_inst; ++ ++ if (!abm && !tg && !panel_cntl) ++ return false; ++ ++ otg_inst = tg->inst; + + if (dc->dc->res_pool->dmcu) { + dce110_set_backlight_level(pipe_ctx, backlight_pwm_u16_16, frame_ramp); + return true; + } + +- if (abm != NULL) { +- uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; +- +- if (abm && panel_cntl) { +- if (abm->funcs && abm->funcs->set_pipe_ex) { +- abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); +- } else { +- dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); +- } +- } ++ if (abm->funcs && abm->funcs->set_pipe_ex) { ++ abm->funcs->set_pipe_ex(abm, ++ otg_inst, ++ SET_ABM_PIPE_NORMAL, ++ panel_cntl->inst, ++ panel_cntl->pwrseq_inst); ++ } else { ++ dmub_abm_set_pipe(abm, ++ otg_inst, ++ SET_ABM_PIPE_NORMAL, ++ panel_cntl->inst, ++ panel_cntl->pwrseq_inst); + } + +- if (abm && abm->funcs && abm->funcs->set_backlight_level_pwm) ++ if (abm->funcs && abm->funcs->set_backlight_level_pwm) + abm->funcs->set_backlight_level_pwm(abm, backlight_pwm_u16_16, + frame_ramp, 0, panel_cntl->inst); + else +diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c +index e0df9b0065f9c0..62c02adae7e76e 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c +@@ -178,6 +178,8 @@ bool cm3_helper_translate_curve_to_hw_format( + i += increment) { + if (j == hw_points - 1) + break; ++ if (i >= TRANSFER_FUNC_POINTS) ++ return false; + rgb_resulted[j].red = output_tf->tf_pts.red[i]; + rgb_resulted[j].green = output_tf->tf_pts.green[i]; + rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; +@@ -355,6 +357,8 @@ bool cm3_helper_translate_curve_to_degamma_hw_format( + i += increment) { + if (j == hw_points - 1) + break; ++ if (i >= TRANSFER_FUNC_POINTS) ++ return false; + rgb_resulted[j].red = output_tf->tf_pts.red[i]; + rgb_resulted[j].green = output_tf->tf_pts.green[i]; + rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; +diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +index 255713ec29bb0f..d59af329d0009e 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +@@ -214,7 +214,11 @@ bool dcn30_set_output_transfer_func(struct dc *dc, + } + } + +- mpc->funcs->set_output_gamma(mpc, mpcc_id, params); ++ if (mpc->funcs->set_output_gamma) ++ mpc->funcs->set_output_gamma(mpc, mpcc_id, params); ++ else ++ DC_LOG_ERROR("%s: set_output_gamma function pointer is NULL.\n", __func__); ++ + return ret; + } + +@@ -619,10 +623,20 @@ void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) + if (pipe_ctx == NULL) + return; + +- if (dc_is_hdmi_signal(pipe_ctx->stream->signal) && pipe_ctx->stream_res.stream_enc != NULL) ++ if (dc_is_hdmi_signal(pipe_ctx->stream->signal) && pipe_ctx->stream_res.stream_enc != NULL) { + pipe_ctx->stream_res.stream_enc->funcs->set_avmute( + pipe_ctx->stream_res.stream_enc, + enable); ++ ++ /* Wait for two frame to make sure AV mute is sent out */ ++ if (enable) { ++ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); ++ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK); ++ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); ++ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK); ++ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); ++ } ++ } + } + + void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx) +diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +index 79d6697d13b678..9485fda890cd71 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +@@ -996,7 +996,7 @@ static struct stream_encoder *dcn301_stream_encoder_create(enum engine_id eng_id + vpg = dcn301_vpg_create(ctx, vpg_inst); + afmt = dcn301_afmt_create(ctx, afmt_inst); + +- if (!enc1 || !vpg || !afmt) { ++ if (!enc1 || !vpg || !afmt || eng_id >= ARRAY_SIZE(stream_enc_regs)) { + kfree(enc1); + kfree(vpg); + kfree(afmt); +diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c +index 5b7ad38f85e08f..65e45a0b4ff343 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c +@@ -395,6 +395,12 @@ void dcn31_hpo_dp_link_enc_set_throttled_vcp_size( + x), + 25)); + ++ // If y rounds up to integer, carry it over to x. ++ if (y >> 25) { ++ x += 1; ++ y = 0; ++ } ++ + switch (stream_encoder_inst) { + case 0: + REG_SET_2(DP_DPHY_SYM32_VC_RATE_CNTL0, 0, +diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +index 2a7f47642a4479..22da2007601ee9 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +@@ -523,7 +523,8 @@ static void dcn31_reset_back_end_for_pipe( + if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass) + pipe_ctx->stream_res.tg->funcs->set_odm_bypass( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); +- pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; ++ if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) ++ pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; + + if (pipe_ctx->stream_res.tg->funcs->set_drr) + pipe_ctx->stream_res.tg->funcs->set_drr( +diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c +index 217acd4e292a30..d849b1eaa4a5c3 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c +@@ -50,7 +50,7 @@ static bool dcn31_query_backlight_info(struct panel_cntl *panel_cntl, union dmub + cmd->panel_cntl.header.type = DMUB_CMD__PANEL_CNTL; + cmd->panel_cntl.header.sub_type = DMUB_CMD__PANEL_CNTL_QUERY_BACKLIGHT_INFO; + cmd->panel_cntl.header.payload_bytes = sizeof(cmd->panel_cntl.data); +- cmd->panel_cntl.data.inst = dcn31_panel_cntl->base.inst; ++ cmd->panel_cntl.data.pwrseq_inst = dcn31_panel_cntl->base.pwrseq_inst; + + return dm_execute_dmub_cmd(dc_dmub_srv->ctx, cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY); + } +@@ -78,7 +78,7 @@ static uint32_t dcn31_panel_cntl_hw_init(struct panel_cntl *panel_cntl) + cmd.panel_cntl.header.type = DMUB_CMD__PANEL_CNTL; + cmd.panel_cntl.header.sub_type = DMUB_CMD__PANEL_CNTL_HW_INIT; + cmd.panel_cntl.header.payload_bytes = sizeof(cmd.panel_cntl.data); +- cmd.panel_cntl.data.inst = dcn31_panel_cntl->base.inst; ++ cmd.panel_cntl.data.pwrseq_inst = dcn31_panel_cntl->base.pwrseq_inst; + cmd.panel_cntl.data.bl_pwm_cntl = panel_cntl->stored_backlight_registers.BL_PWM_CNTL; + cmd.panel_cntl.data.bl_pwm_period_cntl = panel_cntl->stored_backlight_registers.BL_PWM_PERIOD_CNTL; + cmd.panel_cntl.data.bl_pwm_ref_div1 = +@@ -157,4 +157,5 @@ void dcn31_panel_cntl_construct( + dcn31_panel_cntl->base.funcs = &dcn31_link_panel_cntl_funcs; + dcn31_panel_cntl->base.ctx = init_data->ctx; + dcn31_panel_cntl->base.inst = init_data->inst; ++ dcn31_panel_cntl->base.pwrseq_inst = init_data->pwrseq_inst; + } +diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c +index 4d2820ffe4682f..33a8626bda7359 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c +@@ -476,7 +476,8 @@ void dcn314_disable_link_output(struct dc_link *link, + struct dmcu *dmcu = dc->res_pool->dmcu; + + if (signal == SIGNAL_TYPE_EDP && +- link->dc->hwss.edp_backlight_control) ++ link->dc->hwss.edp_backlight_control && ++ !link->skip_implict_edp_power_control) + link->dc->hwss.edp_backlight_control(link, false); + else if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->lock_phy(dmcu); +diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +index 004beed9bd444c..3e65e683db0acf 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +@@ -869,7 +869,7 @@ static const struct dc_plane_cap plane_cap = { + static const struct dc_debug_options debug_defaults_drv = { + .disable_z10 = false, + .enable_z9_disable_interface = true, +- .minimum_z8_residency_time = 2000, ++ .minimum_z8_residency_time = 2100, + .psr_skip_crtc_disable = true, + .replay_skip_crtc_disabled = true, + .disable_dmcu = true, +diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +index 680e7fa8d18abc..650e1598bddcb1 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +@@ -77,6 +77,9 @@ void dcn32_dsc_pg_control( + if (hws->ctx->dc->debug.disable_dsc_power_gate) + return; + ++ if (!hws->ctx->dc->debug.enable_double_buffered_dsc_pg_support) ++ return; ++ + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); +@@ -214,7 +217,7 @@ static bool dcn32_check_no_memory_request_for_cab(struct dc *dc) + static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *ctx) + { + int i; +- uint8_t num_ways = 0; ++ uint32_t num_ways = 0; + uint32_t mall_ss_size_bytes = 0; + + mall_ss_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_size_bytes; +@@ -244,7 +247,8 @@ static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *c + bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable) + { + union dmub_rb_cmd cmd; +- uint8_t ways, i; ++ uint8_t i; ++ uint32_t ways; + int j; + bool mall_ss_unsupported = false; + struct dc_plane_state *plane = NULL; +@@ -304,7 +308,7 @@ bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable) + cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS; + cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_FIT_IN_CAB; + cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header); +- cmd.cab.cab_alloc_ways = ways; ++ cmd.cab.cab_alloc_ways = (uint8_t)ways; + + dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); + +@@ -482,8 +486,7 @@ bool dcn32_set_mcm_luts( + if (plane_state->blend_tf->type == TF_TYPE_HWPWL) + lut_params = &plane_state->blend_tf->pwl; + else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) { +- cm_helper_translate_curve_to_hw_format(plane_state->ctx, +- plane_state->blend_tf, ++ cm3_helper_translate_curve_to_hw_format(plane_state->blend_tf, + &dpp_base->regamma_params, false); + lut_params = &dpp_base->regamma_params; + } +@@ -497,8 +500,7 @@ bool dcn32_set_mcm_luts( + else if (plane_state->in_shaper_func->type == TF_TYPE_DISTRIBUTED_POINTS) { + // TODO: dpp_base replace + ASSERT(false); +- cm_helper_translate_curve_to_hw_format(plane_state->ctx, +- plane_state->in_shaper_func, ++ cm3_helper_translate_curve_to_hw_format(plane_state->in_shaper_func, + &dpp_base->shaper_params, true); + lut_params = &dpp_base->shaper_params; + } +@@ -1573,3 +1575,101 @@ void dcn32_init_blank( + if (opp) + hws->funcs.wait_for_blank_complete(opp); + } ++ ++void dcn32_blank_phantom(struct dc *dc, ++ struct timing_generator *tg, ++ int width, ++ int height) ++{ ++ struct dce_hwseq *hws = dc->hwseq; ++ enum dc_color_space color_space; ++ struct tg_color black_color = {0}; ++ struct output_pixel_processor *opp = NULL; ++ uint32_t num_opps, opp_id_src0, opp_id_src1; ++ uint32_t otg_active_width, otg_active_height; ++ uint32_t i; ++ ++ /* program opp dpg blank color */ ++ color_space = COLOR_SPACE_SRGB; ++ color_space_to_black_color(dc, color_space, &black_color); ++ ++ otg_active_width = width; ++ otg_active_height = height; ++ ++ /* get the OPTC source */ ++ tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); ++ ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp); ++ ++ for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { ++ if (dc->res_pool->opps[i] != NULL && dc->res_pool->opps[i]->inst == opp_id_src0) { ++ opp = dc->res_pool->opps[i]; ++ break; ++ } ++ } ++ ++ if (opp && opp->funcs->opp_set_disp_pattern_generator) ++ opp->funcs->opp_set_disp_pattern_generator( ++ opp, ++ CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, ++ CONTROLLER_DP_COLOR_SPACE_UDEFINED, ++ COLOR_DEPTH_UNDEFINED, ++ &black_color, ++ otg_active_width, ++ otg_active_height, ++ 0); ++ ++ if (tg->funcs->is_tg_enabled(tg)) ++ hws->funcs.wait_for_blank_complete(opp); ++} ++ ++bool dcn32_is_pipe_topology_transition_seamless(struct dc *dc, ++ const struct dc_state *cur_ctx, ++ const struct dc_state *new_ctx) ++{ ++ int i; ++ const struct pipe_ctx *cur_pipe, *new_pipe; ++ bool is_seamless = true; ++ ++ for (i = 0; i < dc->res_pool->pipe_count; i++) { ++ cur_pipe = &cur_ctx->res_ctx.pipe_ctx[i]; ++ new_pipe = &new_ctx->res_ctx.pipe_ctx[i]; ++ ++ if (resource_is_pipe_type(cur_pipe, FREE_PIPE) || ++ resource_is_pipe_type(new_pipe, FREE_PIPE)) ++ /* adding or removing free pipes is always seamless */ ++ continue; ++ else if (resource_is_pipe_type(cur_pipe, OTG_MASTER)) { ++ if (resource_is_pipe_type(new_pipe, OTG_MASTER)) ++ if (cur_pipe->stream->stream_id == new_pipe->stream->stream_id) ++ /* OTG master with the same stream is seamless */ ++ continue; ++ } else if (resource_is_pipe_type(cur_pipe, OPP_HEAD)) { ++ if (resource_is_pipe_type(new_pipe, OPP_HEAD)) { ++ if (cur_pipe->stream_res.tg == new_pipe->stream_res.tg) ++ /* ++ * OPP heads sharing the same timing ++ * generator is seamless ++ */ ++ continue; ++ } ++ } else if (resource_is_pipe_type(cur_pipe, DPP_PIPE)) { ++ if (resource_is_pipe_type(new_pipe, DPP_PIPE)) { ++ if (cur_pipe->stream_res.opp == new_pipe->stream_res.opp) ++ /* ++ * DPP pipes sharing the same OPP head is ++ * seamless ++ */ ++ continue; ++ } ++ } ++ ++ /* ++ * This pipe's transition doesn't fall under any seamless ++ * conditions ++ */ ++ is_seamless = false; ++ break; ++ } ++ ++ return is_seamless; ++} +diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h +index 2d2628f31bed7d..9992e40acd217b 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h ++++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h +@@ -115,4 +115,13 @@ void dcn32_init_blank( + struct dc *dc, + struct timing_generator *tg); + ++void dcn32_blank_phantom(struct dc *dc, ++ struct timing_generator *tg, ++ int width, ++ int height); ++ ++bool dcn32_is_pipe_topology_transition_seamless(struct dc *dc, ++ const struct dc_state *cur_ctx, ++ const struct dc_state *new_ctx); ++ + #endif /* __DC_HWSS_DCN32_H__ */ +diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c +index c7417147dff19b..1edadff39a5eff 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c +@@ -115,6 +115,8 @@ static const struct hw_sequencer_funcs dcn32_funcs = { + .update_phantom_vp_position = dcn32_update_phantom_vp_position, + .update_dsc_pg = dcn32_update_dsc_pg, + .apply_update_flags_for_phantom = dcn32_apply_update_flags_for_phantom, ++ .blank_phantom = dcn32_blank_phantom, ++ .is_pipe_topology_transition_seamless = dcn32_is_pipe_topology_transition_seamless, + }; + + static const struct hwseq_private_funcs dcn32_private_funcs = { +diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.c +index 8abb94f60078fc..058dee76054ea7 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.c +@@ -142,6 +142,16 @@ static bool optc32_disable_crtc(struct timing_generator *optc) + { + struct optc *optc1 = DCN10TG_FROM_TG(optc); + ++ REG_UPDATE_5(OPTC_DATA_SOURCE_SELECT, ++ OPTC_SEG0_SRC_SEL, 0xf, ++ OPTC_SEG1_SRC_SEL, 0xf, ++ OPTC_SEG2_SRC_SEL, 0xf, ++ OPTC_SEG3_SRC_SEL, 0xf, ++ OPTC_NUM_OF_INPUT_SEGMENT, 0); ++ ++ REG_UPDATE(OPTC_MEMORY_CONFIG, ++ OPTC_MEM_SEL, 0); ++ + /* disable otg request until end of the first line + * in the vertical blank region + */ +@@ -174,6 +184,13 @@ static void optc32_disable_phantom_otg(struct timing_generator *optc) + { + struct optc *optc1 = DCN10TG_FROM_TG(optc); + ++ REG_UPDATE_5(OPTC_DATA_SOURCE_SELECT, ++ OPTC_SEG0_SRC_SEL, 0xf, ++ OPTC_SEG1_SRC_SEL, 0xf, ++ OPTC_SEG2_SRC_SEL, 0xf, ++ OPTC_SEG3_SRC_SEL, 0xf, ++ OPTC_NUM_OF_INPUT_SEGMENT, 0); ++ + REG_UPDATE(OTG_CONTROL, OTG_MASTER_EN, 0); + } + +@@ -219,9 +236,6 @@ static void optc32_setup_manual_trigger(struct timing_generator *optc) + OTG_V_TOTAL_MAX_SEL, 1, + OTG_FORCE_LOCK_ON_EVENT, 0, + OTG_SET_V_TOTAL_MIN_MASK, (1 << 1)); /* TRIGA */ +- +- // Setup manual flow control for EOF via TRIG_A +- optc->funcs->setup_manual_trigger(optc); + } + } + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c +index 8d73cceb485bf4..aa4c64eec7b3d6 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c +@@ -1756,6 +1756,9 @@ static bool dcn321_resource_construct( + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + ++ /* Use pipe context based otg sync logic */ ++ dc->config.use_pipe_ctx_sync_logic = true; ++ + dc->config.dc_mode_clk_limit_support = true; + /* read VBIOS LTTPR caps */ + { +diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile +index 77cf5545c94cc8..0ba9a7997d561c 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/Makefile ++++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile +@@ -61,18 +61,22 @@ endif + endif + + ifneq ($(CONFIG_FRAME_WARN),0) ++ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)),y) ++frame_warn_flag := -Wframe-larger-than=3072 ++else + frame_warn_flag := -Wframe-larger-than=2048 + endif ++endif + + CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags) + CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_ccflags) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn10/dcn10_fpu.o := $(dml_ccflags) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/dcn20_fpu.o := $(dml_ccflags) +-CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20.o := $(dml_ccflags) ++CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20.o := $(dml_ccflags) $(frame_warn_flag) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_rq_dlg_calc_20.o := $(dml_ccflags) +-CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20v2.o := $(dml_ccflags) ++CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20v2.o := $(dml_ccflags) $(frame_warn_flag) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_rq_dlg_calc_20v2.o := $(dml_ccflags) +-CFLAGS_$(AMDDALPATH)/dc/dml/dcn21/display_mode_vba_21.o := $(dml_ccflags) ++CFLAGS_$(AMDDALPATH)/dc/dml/dcn21/display_mode_vba_21.o := $(dml_ccflags) $(frame_warn_flag) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn21/display_rq_dlg_calc_21.o := $(dml_ccflags) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_ccflags) $(frame_warn_flag) + CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_ccflags) +diff --git a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c +index 50b0434354f8f5..c08169de3660c5 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c +@@ -1453,10 +1453,9 @@ void dcn_bw_update_from_pplib_fclks( + ASSERT(fclks->num_levels); + + vmin0p65_idx = 0; +- vmid0p72_idx = fclks->num_levels - +- (fclks->num_levels > 2 ? 3 : (fclks->num_levels > 1 ? 2 : 1)); +- vnom0p8_idx = fclks->num_levels - (fclks->num_levels > 1 ? 2 : 1); +- vmax0p9_idx = fclks->num_levels - 1; ++ vmid0p72_idx = fclks->num_levels > 2 ? fclks->num_levels - 3 : 0; ++ vnom0p8_idx = fclks->num_levels > 1 ? fclks->num_levels - 2 : 0; ++ vmax0p9_idx = fclks->num_levels > 0 ? fclks->num_levels - 1 : 0; + + dc->dcn_soc->fabric_and_dram_bandwidth_vmin0p65 = + 32 * (fclks->data[vmin0p65_idx].clocks_in_khz / 1000.0) / 1000.0; +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dc_features.h b/drivers/gpu/drm/amd/display/dc/dml/dc_features.h +index 2cbdd75429ffd6..6e669a2c5b2d44 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dc_features.h ++++ b/drivers/gpu/drm/amd/display/dc/dml/dc_features.h +@@ -36,7 +36,7 @@ + * Define the maximum amount of states supported by the ASIC. Every ASIC has a + * specific number of states; this macro defines the maximum number of states. + */ +-#define DC__VOLTAGE_STATES 20 ++#define DC__VOLTAGE_STATES 40 + #define DC__NUM_DPP__4 1 + #define DC__NUM_DPP__0_PRESENT 1 + #define DC__NUM_DPP__1_PRESENT 1 +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +index 5805fb02af14e3..8a5a038fd85578 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +@@ -438,7 +438,115 @@ struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv14_soc = { + .use_urgent_burst_bw = 0 + }; + +-struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv12_soc = { 0 }; ++struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv12_soc = { ++ .clock_limits = { ++ { ++ .state = 0, ++ .dcfclk_mhz = 560.0, ++ .fabricclk_mhz = 560.0, ++ .dispclk_mhz = 513.0, ++ .dppclk_mhz = 513.0, ++ .phyclk_mhz = 540.0, ++ .socclk_mhz = 560.0, ++ .dscclk_mhz = 171.0, ++ .dram_speed_mts = 1069.0, ++ }, ++ { ++ .state = 1, ++ .dcfclk_mhz = 694.0, ++ .fabricclk_mhz = 694.0, ++ .dispclk_mhz = 642.0, ++ .dppclk_mhz = 642.0, ++ .phyclk_mhz = 600.0, ++ .socclk_mhz = 694.0, ++ .dscclk_mhz = 214.0, ++ .dram_speed_mts = 1324.0, ++ }, ++ { ++ .state = 2, ++ .dcfclk_mhz = 875.0, ++ .fabricclk_mhz = 875.0, ++ .dispclk_mhz = 734.0, ++ .dppclk_mhz = 734.0, ++ .phyclk_mhz = 810.0, ++ .socclk_mhz = 875.0, ++ .dscclk_mhz = 245.0, ++ .dram_speed_mts = 1670.0, ++ }, ++ { ++ .state = 3, ++ .dcfclk_mhz = 1000.0, ++ .fabricclk_mhz = 1000.0, ++ .dispclk_mhz = 1100.0, ++ .dppclk_mhz = 1100.0, ++ .phyclk_mhz = 810.0, ++ .socclk_mhz = 1000.0, ++ .dscclk_mhz = 367.0, ++ .dram_speed_mts = 2000.0, ++ }, ++ { ++ .state = 4, ++ .dcfclk_mhz = 1200.0, ++ .fabricclk_mhz = 1200.0, ++ .dispclk_mhz = 1284.0, ++ .dppclk_mhz = 1284.0, ++ .phyclk_mhz = 810.0, ++ .socclk_mhz = 1200.0, ++ .dscclk_mhz = 428.0, ++ .dram_speed_mts = 2000.0, ++ }, ++ { ++ .state = 5, ++ .dcfclk_mhz = 1200.0, ++ .fabricclk_mhz = 1200.0, ++ .dispclk_mhz = 1284.0, ++ .dppclk_mhz = 1284.0, ++ .phyclk_mhz = 810.0, ++ .socclk_mhz = 1200.0, ++ .dscclk_mhz = 428.0, ++ .dram_speed_mts = 2000.0, ++ }, ++ }, ++ ++ .num_states = 5, ++ .sr_exit_time_us = 1.9, ++ .sr_enter_plus_exit_time_us = 4.4, ++ .urgent_latency_us = 3.0, ++ .urgent_latency_pixel_data_only_us = 4.0, ++ .urgent_latency_pixel_mixed_with_vm_data_us = 4.0, ++ .urgent_latency_vm_data_only_us = 4.0, ++ .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096, ++ .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096, ++ .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096, ++ .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 40.0, ++ .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 40.0, ++ .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0, ++ .max_avg_sdp_bw_use_normal_percent = 40.0, ++ .max_avg_dram_bw_use_normal_percent = 40.0, ++ .writeback_latency_us = 12.0, ++ .ideal_dram_bw_after_urgent_percent = 40.0, ++ .max_request_size_bytes = 256, ++ .dram_channel_width_bytes = 16, ++ .fabric_datapath_to_dcn_data_return_bytes = 64, ++ .dcn_downspread_percent = 0.5, ++ .downspread_percent = 0.5, ++ .dram_page_open_time_ns = 50.0, ++ .dram_rw_turnaround_time_ns = 17.5, ++ .dram_return_buffer_per_channel_bytes = 8192, ++ .round_trip_ping_latency_dcfclk_cycles = 131, ++ .urgent_out_of_order_return_per_channel_bytes = 4096, ++ .channel_interleave_bytes = 256, ++ .num_banks = 8, ++ .num_chans = 16, ++ .vmm_page_size_bytes = 4096, ++ .dram_clock_change_latency_us = 45.0, ++ .writeback_dram_clock_change_latency_us = 23.0, ++ .return_bus_width_bytes = 64, ++ .dispclk_dppclk_vco_speed_mhz = 3850, ++ .xfc_bus_transport_time_us = 20, ++ .xfc_xbuf_latency_tolerance_us = 50, ++ .use_urgent_burst_bw = 0, ++}; + + struct _vcs_dpi_ip_params_st dcn2_1_ip = { + .odm_capable = 1, +@@ -948,10 +1056,8 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc + { + int plane_count; + int i; +- unsigned int min_dst_y_next_start_us; + + plane_count = 0; +- min_dst_y_next_start_us = 0; + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (context->res_ctx.pipe_ctx[i].plane_state) + plane_count++; +@@ -973,26 +1079,15 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc + else if (context->stream_count == 1 && context->streams[0]->signal == SIGNAL_TYPE_EDP) { + struct dc_link *link = context->streams[0]->sink->link; + struct dc_stream_status *stream_status = &context->stream_status[0]; +- struct dc_stream_state *current_stream = context->streams[0]; + int minmum_z8_residency = dc->debug.minimum_z8_residency_time > 0 ? dc->debug.minimum_z8_residency_time : 1000; + bool allow_z8 = context->bw_ctx.dml.vba.StutterPeriod > (double)minmum_z8_residency; + bool is_pwrseq0 = link->link_index == 0; +- bool isFreesyncVideo; +- +- isFreesyncVideo = current_stream->adjust.v_total_min == current_stream->adjust.v_total_max; +- isFreesyncVideo = isFreesyncVideo && current_stream->timing.v_total < current_stream->adjust.v_total_min; +- for (i = 0; i < dc->res_pool->pipe_count; i++) { +- if (context->res_ctx.pipe_ctx[i].stream == current_stream && isFreesyncVideo) { +- min_dst_y_next_start_us = context->res_ctx.pipe_ctx[i].dlg_regs.min_dst_y_next_start_us; +- break; +- } +- } + + /* Don't support multi-plane configurations */ + if (stream_status->plane_count > 1) + return DCN_ZSTATE_SUPPORT_DISALLOW; + +- if (is_pwrseq0 && (context->bw_ctx.dml.vba.StutterPeriod > 5000.0 || min_dst_y_next_start_us > 5000)) ++ if (is_pwrseq0 && context->bw_ctx.dml.vba.StutterPeriod > 5000.0) + return DCN_ZSTATE_SUPPORT_ALLOW; + else if (is_pwrseq0 && link->psr_settings.psr_version == DC_PSR_VERSION_1 && !link->panel_config.psr.disable_psr) + return allow_z8 ? DCN_ZSTATE_SUPPORT_ALLOW_Z8_Z10_ONLY : DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY; +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c +index 0fc9f3e3ffaefd..f603486af6e306 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c +@@ -78,7 +78,7 @@ static void calculate_ttu_cursor(struct display_mode_lib *mode_lib, + + static unsigned int get_bytes_per_element(enum source_format_class source_format, bool is_chroma) + { +- unsigned int ret_val = 0; ++ unsigned int ret_val = 1; + + if (source_format == dm_444_16) { + if (!is_chroma) +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c +index 618f4b682ab1b1..9f28e4d3c664c7 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c +@@ -53,7 +53,7 @@ static void calculate_ttu_cursor( + + static unsigned int get_bytes_per_element(enum source_format_class source_format, bool is_chroma) + { +- unsigned int ret_val = 0; ++ unsigned int ret_val = 1; + + if (source_format == dm_444_16) { + if (!is_chroma) +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn302/dcn302_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn302/dcn302_fpu.c +index e2bcd205aa936f..8da97a96b1ceb9 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn302/dcn302_fpu.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn302/dcn302_fpu.c +@@ -304,6 +304,16 @@ void dcn302_fpu_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_p + dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16; + } + ++ /* bw_params->clk_table.entries[MAX_NUM_DPM_LVL]. ++ * MAX_NUM_DPM_LVL is 8. ++ * dcn3_02_soc.clock_limits[DC__VOLTAGE_STATES]. ++ * DC__VOLTAGE_STATES is 40. ++ */ ++ if (num_states > MAX_NUM_DPM_LVL) { ++ ASSERT(0); ++ return; ++ } ++ + dcn3_02_soc.num_states = num_states; + for (i = 0; i < dcn3_02_soc.num_states; i++) { + dcn3_02_soc.clock_limits[i].state = i; +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.c +index 3eb3a021ab7d72..c283780ad0621a 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.c +@@ -299,6 +299,16 @@ void dcn303_fpu_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_p + dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16; + } + ++ /* bw_params->clk_table.entries[MAX_NUM_DPM_LVL]. ++ * MAX_NUM_DPM_LVL is 8. ++ * dcn3_02_soc.clock_limits[DC__VOLTAGE_STATES]. ++ * DC__VOLTAGE_STATES is 40. ++ */ ++ if (num_states > MAX_NUM_DPM_LVL) { ++ ASSERT(0); ++ return; ++ } ++ + dcn3_03_soc.num_states = num_states; + for (i = 0; i < dcn3_03_soc.num_states; i++) { + dcn3_03_soc.clock_limits[i].state = i; +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c +index deb6d162a2d5c0..7307b7b8d8ad75 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c +@@ -291,6 +291,7 @@ static struct _vcs_dpi_soc_bounding_box_st dcn3_15_soc = { + .do_urgent_latency_adjustment = false, + .urgent_latency_adjustment_fabric_clock_component_us = 0, + .urgent_latency_adjustment_fabric_clock_reference_mhz = 0, ++ .dispclk_dppclk_vco_speed_mhz = 2400.0, + .num_chans = 4, + .dummy_pstate_latency_us = 10.0 + }; +@@ -438,6 +439,7 @@ static struct _vcs_dpi_soc_bounding_box_st dcn3_16_soc = { + .do_urgent_latency_adjustment = false, + .urgent_latency_adjustment_fabric_clock_component_us = 0, + .urgent_latency_adjustment_fabric_clock_reference_mhz = 0, ++ .dispclk_dppclk_vco_speed_mhz = 2500.0, + }; + + void dcn31_zero_pipe_dcc_fraction(display_e2e_pipe_params_st *pipes, +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +index 711d4085b33b8f..3d82cbef12740c 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +@@ -1964,6 +1964,7 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, + int i, pipe_idx, vlevel_temp = 0; + double dcfclk = dcn3_2_soc.clock_limits[0].dcfclk_mhz; + double dcfclk_from_validation = context->bw_ctx.dml.vba.DCFCLKState[vlevel][context->bw_ctx.dml.vba.maxMpcComb]; ++ double dram_speed_from_validation = context->bw_ctx.dml.vba.DRAMSpeed; + double dcfclk_from_fw_based_mclk_switching = dcfclk_from_validation; + bool pstate_en = context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] != + dm_dram_clock_change_unsupported; +@@ -2151,7 +2152,7 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, + } + + if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].valid) { +- min_dram_speed_mts = context->bw_ctx.dml.vba.DRAMSpeed; ++ min_dram_speed_mts = dram_speed_from_validation; + min_dram_speed_mts_margin = 160; + + context->bw_ctx.dml.soc.dram_clock_change_latency_us = +@@ -2884,6 +2885,16 @@ void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_pa + dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16; + } + ++ /* bw_params->clk_table.entries[MAX_NUM_DPM_LVL]. ++ * MAX_NUM_DPM_LVL is 8. ++ * dcn3_02_soc.clock_limits[DC__VOLTAGE_STATES]. ++ * DC__VOLTAGE_STATES is 40. ++ */ ++ if (num_states > MAX_NUM_DPM_LVL) { ++ ASSERT(0); ++ return; ++ } ++ + dcn3_2_soc.num_states = num_states; + for (i = 0; i < dcn3_2_soc.num_states; i++) { + dcn3_2_soc.clock_limits[i].state = i; +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c +index cbdfb762c10c58..0782a34689a00f 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c +@@ -813,6 +813,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman + (v->DRAMSpeedPerState[mode_lib->vba.VoltageLevel] <= MEM_STROBE_FREQ_MHZ || + v->DCFCLKPerState[mode_lib->vba.VoltageLevel] <= DCFCLK_FREQ_EXTRA_PREFETCH_REQ_MHZ) ? + mode_lib->vba.ip.min_prefetch_in_strobe_us : 0, ++ mode_lib->vba.PrefetchModePerState[mode_lib->vba.VoltageLevel][mode_lib->vba.maxMpcComb] > 0 || mode_lib->vba.DRAMClockChangeRequirementFinal == false, ++ + /* Output */ + &v->DSTXAfterScaler[k], + &v->DSTYAfterScaler[k], +@@ -3317,6 +3319,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l + v->SwathHeightCThisState[k], v->TWait, + (v->DRAMSpeedPerState[i] <= MEM_STROBE_FREQ_MHZ || v->DCFCLKState[i][j] <= DCFCLK_FREQ_EXTRA_PREFETCH_REQ_MHZ) ? + mode_lib->vba.ip.min_prefetch_in_strobe_us : 0, ++ mode_lib->vba.PrefetchModePerState[i][j] > 0 || mode_lib->vba.DRAMClockChangeRequirementFinal == false, + + /* Output */ + &v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.DSTXAfterScaler[k], +@@ -3361,6 +3364,9 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l + &mode_lib->vba.UrgentBurstFactorLumaPre[k], + &mode_lib->vba.UrgentBurstFactorChromaPre[k], + &mode_lib->vba.NotUrgentLatencyHidingPre[k]); ++ ++ v->cursor_bw_pre[k] = mode_lib->vba.NumberOfCursors[k] * mode_lib->vba.CursorWidth[k][0] * mode_lib->vba.CursorBPP[k][0] / ++ 8.0 / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) * v->VRatioPreY[i][j][k]; + } + + { +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c +index ecea008f19d3aa..208b89d13d3f6d 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c +@@ -3423,6 +3423,7 @@ bool dml32_CalculatePrefetchSchedule( + unsigned int SwathHeightC, + double TWait, + double TPreReq, ++ bool ExtendPrefetchIfPossible, + /* Output */ + double *DSTXAfterScaler, + double *DSTYAfterScaler, +@@ -3892,12 +3893,32 @@ bool dml32_CalculatePrefetchSchedule( + /* Clamp to oto for bandwidth calculation */ + LinesForPrefetchBandwidth = dst_y_prefetch_oto; + } else { +- *DestinationLinesForPrefetch = dst_y_prefetch_equ; +- TimeForFetchingMetaPTE = Tvm_equ; +- TimeForFetchingRowInVBlank = Tr0_equ; +- *PrefetchBandwidth = prefetch_bw_equ; +- /* Clamp to equ for bandwidth calculation */ +- LinesForPrefetchBandwidth = dst_y_prefetch_equ; ++ /* For mode programming we want to extend the prefetch as much as possible ++ * (up to oto, or as long as we can for equ) if we're not already applying ++ * the 60us prefetch requirement. This is to avoid intermittent underflow ++ * issues during prefetch. ++ * ++ * The prefetch extension is applied under the following scenarios: ++ * 1. We're in prefetch mode > 0 (i.e. we don't support MCLK switch in blank) ++ * 2. We're using subvp or drr methods of p-state switch, in which case we ++ * we don't care if prefetch takes up more of the blanking time ++ * ++ * Mode programming typically chooses the smallest prefetch time possible ++ * (i.e. highest bandwidth during prefetch) presumably to create margin between ++ * p-states / c-states that happen in vblank and prefetch. Therefore we only ++ * apply this prefetch extension when p-state in vblank is not required (UCLK ++ * p-states take up the most vblank time). ++ */ ++ if (ExtendPrefetchIfPossible && TPreReq == 0 && VStartup < MaxVStartup) { ++ MyError = true; ++ } else { ++ *DestinationLinesForPrefetch = dst_y_prefetch_equ; ++ TimeForFetchingMetaPTE = Tvm_equ; ++ TimeForFetchingRowInVBlank = Tr0_equ; ++ *PrefetchBandwidth = prefetch_bw_equ; ++ /* Clamp to equ for bandwidth calculation */ ++ LinesForPrefetchBandwidth = dst_y_prefetch_equ; ++ } + } + + *DestinationLinesToRequestVMInVBlank = dml_ceil(4.0 * TimeForFetchingMetaPTE / LineTime, 1.0) / 4.0; +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h +index 592d174df6c629..5d34735df83db1 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h +@@ -747,6 +747,7 @@ bool dml32_CalculatePrefetchSchedule( + unsigned int SwathHeightC, + double TWait, + double TPreReq, ++ bool ExtendPrefetchIfPossible, + /* Output */ + double *DSTXAfterScaler, + double *DSTYAfterScaler, +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c +index b26fcf86014c70..ae2196c36f218b 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c +@@ -789,6 +789,16 @@ void dcn321_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_p + dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16; + } + ++ /* bw_params->clk_table.entries[MAX_NUM_DPM_LVL]. ++ * MAX_NUM_DPM_LVL is 8. ++ * dcn3_02_soc.clock_limits[DC__VOLTAGE_STATES]. ++ * DC__VOLTAGE_STATES is 40. ++ */ ++ if (num_states > MAX_NUM_DPM_LVL) { ++ ASSERT(0); ++ return; ++ } ++ + dcn3_21_soc.num_states = num_states; + for (i = 0; i < dcn3_21_soc.num_states; i++) { + dcn3_21_soc.clock_limits[i].state = i; +diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c +index 9a3ded31119529..85453bbb4f9b13 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c +@@ -1099,8 +1099,13 @@ void ModeSupportAndSystemConfiguration(struct display_mode_lib *mode_lib) + + // Total Available Pipes Support Check + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { +- total_pipes += mode_lib->vba.DPPPerPlane[k]; + pipe_idx = get_pipe_idx(mode_lib, k); ++ if (pipe_idx == -1) { ++ ASSERT(0); ++ continue; // skip inactive planes ++ } ++ total_pipes += mode_lib->vba.DPPPerPlane[k]; ++ + if (mode_lib->vba.cache_pipes[pipe_idx].clks_cfg.dppclk_mhz > 0.0) + mode_lib->vba.DPPCLK[k] = mode_lib->vba.cache_pipes[pipe_idx].clks_cfg.dppclk_mhz; + else +diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c +index 3966845c769453..9edc9b0e3f082d 100644 +--- a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c ++++ b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c +@@ -861,7 +861,7 @@ static bool setup_dsc_config( + + memset(dsc_cfg, 0, sizeof(struct dc_dsc_config)); + +- dc_dsc_get_policy_for_timing(timing, options->max_target_bpp_limit_override_x16, &policy); ++ dc_dsc_get_policy_for_timing(timing, options->max_target_bpp_limit_override_x16, &policy, link_encoding); + pic_width = timing->h_addressable + timing->h_border_left + timing->h_border_right; + pic_height = timing->v_addressable + timing->v_border_top + timing->v_border_bottom; + +@@ -1033,7 +1033,12 @@ static bool setup_dsc_config( + if (!is_dsc_possible) + goto done; + +- dsc_cfg->num_slices_v = pic_height/slice_height; ++ if (slice_height > 0) { ++ dsc_cfg->num_slices_v = pic_height / slice_height; ++ } else { ++ is_dsc_possible = false; ++ goto done; ++ } + + if (target_bandwidth_kbps > 0) { + is_dsc_possible = decide_dsc_target_bpp_x16( +@@ -1129,7 +1134,8 @@ uint32_t dc_dsc_stream_bandwidth_overhead_in_kbps( + + void dc_dsc_get_policy_for_timing(const struct dc_crtc_timing *timing, + uint32_t max_target_bpp_limit_override_x16, +- struct dc_dsc_policy *policy) ++ struct dc_dsc_policy *policy, ++ const enum dc_link_encoding_format link_encoding) + { + uint32_t bpc = 0; + +diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c +index 3ede6e02c3a786..f2037d78f71abd 100644 +--- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c ++++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c +@@ -56,7 +56,7 @@ struct gpio_service *dal_gpio_service_create( + struct dc_context *ctx) + { + struct gpio_service *service; +- uint32_t index_of_id; ++ int32_t index_of_id; + + service = kzalloc(sizeof(struct gpio_service), GFP_KERNEL); + +@@ -112,7 +112,7 @@ struct gpio_service *dal_gpio_service_create( + return service; + + failure_2: +- while (index_of_id) { ++ while (index_of_id > 0) { + --index_of_id; + kfree(service->busyness[index_of_id]); + } +@@ -239,6 +239,9 @@ static bool is_pin_busy( + enum gpio_id id, + uint32_t en) + { ++ if (id == GPIO_ID_UNKNOWN) ++ return false; ++ + return service->busyness[id][en]; + } + +@@ -247,6 +250,9 @@ static void set_pin_busy( + enum gpio_id id, + uint32_t en) + { ++ if (id == GPIO_ID_UNKNOWN) ++ return; ++ + service->busyness[id][en] = true; + } + +@@ -255,6 +261,9 @@ static void set_pin_free( + enum gpio_id id, + uint32_t en) + { ++ if (id == GPIO_ID_UNKNOWN) ++ return; ++ + service->busyness[id][en] = false; + } + +@@ -263,7 +272,7 @@ enum gpio_result dal_gpio_service_lock( + enum gpio_id id, + uint32_t en) + { +- if (!service->busyness[id]) { ++ if (id != GPIO_ID_UNKNOWN && !service->busyness[id]) { + ASSERT_CRITICAL(false); + return GPIO_RESULT_OPEN_FAILED; + } +@@ -277,7 +286,7 @@ enum gpio_result dal_gpio_service_unlock( + enum gpio_id id, + uint32_t en) + { +- if (!service->busyness[id]) { ++ if (id != GPIO_ID_UNKNOWN && !service->busyness[id]) { + ASSERT_CRITICAL(false); + return GPIO_RESULT_OPEN_FAILED; + } +diff --git a/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c b/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c +index 25ffc052d53be9..df2cb5279ce51d 100644 +--- a/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c ++++ b/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c +@@ -130,13 +130,21 @@ static bool hdmi_14_process_transaction( + const uint8_t hdcp_i2c_addr_link_primary = 0x3a; /* 0x74 >> 1*/ + const uint8_t hdcp_i2c_addr_link_secondary = 0x3b; /* 0x76 >> 1*/ + struct i2c_command i2c_command; +- uint8_t offset = hdcp_i2c_offsets[message_info->msg_id]; ++ uint8_t offset; + struct i2c_payload i2c_payloads[] = { +- { true, 0, 1, &offset }, ++ { true, 0, 1, 0 }, + /* actual hdcp payload, will be filled later, zeroed for now*/ + { 0 } + }; + ++ if (message_info->msg_id == HDCP_MESSAGE_ID_INVALID) { ++ DC_LOG_ERROR("%s: Invalid message_info msg_id - %d\n", __func__, message_info->msg_id); ++ return false; ++ } ++ ++ offset = hdcp_i2c_offsets[message_info->msg_id]; ++ i2c_payloads[0].data = &offset; ++ + switch (message_info->link) { + case HDCP_LINK_SECONDARY: + i2c_payloads[0].address = hdcp_i2c_addr_link_secondary; +@@ -310,6 +318,11 @@ static bool dp_11_process_transaction( + struct dc_link *link, + struct hdcp_protection_message *message_info) + { ++ if (message_info->msg_id == HDCP_MESSAGE_ID_INVALID) { ++ DC_LOG_ERROR("%s: Invalid message_info msg_id - %d\n", __func__, message_info->msg_id); ++ return false; ++ } ++ + return dpcd_access_helper( + link, + message_info->length, +diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h b/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h +index 33db15d69f2337..9f521cf0fc5a2b 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h +@@ -64,7 +64,8 @@ struct abm_funcs { + bool (*set_pipe_ex)(struct abm *abm, + unsigned int otg_inst, + unsigned int option, +- unsigned int panel_inst); ++ unsigned int panel_inst, ++ unsigned int pwrseq_inst); + }; + + #endif +diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h b/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h +index 24af9d80b9373a..248adc1705e357 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h +@@ -56,12 +56,14 @@ struct panel_cntl_funcs { + struct panel_cntl_init_data { + struct dc_context *ctx; + uint32_t inst; ++ uint32_t pwrseq_inst; + }; + + struct panel_cntl { + const struct panel_cntl_funcs *funcs; + struct dc_context *ctx; + uint32_t inst; ++ uint32_t pwrseq_inst; + /* registers setting needs to be saved and restored at InitBacklight */ + struct panel_cntl_backlight_registers stored_backlight_registers; + }; +diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +index 02ff99f7bec2ba..66e680902c95c7 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +@@ -388,6 +388,11 @@ struct hw_sequencer_funcs { + void (*z10_restore)(const struct dc *dc); + void (*z10_save_init)(struct dc *dc); + ++ void (*blank_phantom)(struct dc *dc, ++ struct timing_generator *tg, ++ int width, ++ int height); ++ + void (*update_visual_confirm_color)(struct dc *dc, + struct pipe_ctx *pipe_ctx, + int mpcc_id); +@@ -396,6 +401,9 @@ struct hw_sequencer_funcs { + struct dc_state *context, + struct pipe_ctx *phantom_pipe); + void (*apply_update_flags_for_phantom)(struct pipe_ctx *phantom_pipe); ++ bool (*is_pipe_topology_transition_seamless)(struct dc *dc, ++ const struct dc_state *cur_ctx, ++ const struct dc_state *new_ctx); + + void (*commit_subvp_config)(struct dc *dc, struct dc_state *context); + void (*enable_phantom_streams)(struct dc *dc, struct dc_state *context); +diff --git a/drivers/gpu/drm/amd/display/dc/inc/link.h b/drivers/gpu/drm/amd/display/dc/inc/link.h +index e3e8c76c17cfac..d7685368140ab5 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/link.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/link.h +@@ -295,6 +295,7 @@ struct link_service { + bool (*edp_receiver_ready_T9)(struct dc_link *link); + bool (*edp_receiver_ready_T7)(struct dc_link *link); + bool (*edp_power_alpm_dpcd_enable)(struct dc_link *link, bool enable); ++ void (*edp_set_panel_power)(struct dc_link *link, bool powerOn); + + + /*************************** DP CTS ************************************/ +diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c +index 44649db5f3e32f..5646b7788f02e4 100644 +--- a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c ++++ b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c +@@ -211,8 +211,12 @@ bool dce110_vblank_set(struct irq_service *irq_service, + info->ext_id); + uint8_t pipe_offset = dal_irq_src - IRQ_TYPE_VBLANK; + +- struct timing_generator *tg = +- dc->current_state->res_ctx.pipe_ctx[pipe_offset].stream_res.tg; ++ struct timing_generator *tg; ++ ++ if (pipe_offset >= MAX_PIPES) ++ return false; ++ ++ tg = dc->current_state->res_ctx.pipe_ctx[pipe_offset].stream_res.tg; + + if (enable) { + if (!tg || !tg->funcs->arm_vert_intr(tg, 2)) { +diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c +index e1257404357b11..cec68c5dba1322 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c ++++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c +@@ -28,6 +28,8 @@ + #include "dccg.h" + #include "clk_mgr.h" + ++#define DC_LOGGER link->ctx->logger ++ + void set_hpo_dp_throttled_vcp_size(struct pipe_ctx *pipe_ctx, + struct fixed31_32 throttled_vcp_size) + { +@@ -108,6 +110,11 @@ void enable_hpo_dp_link_output(struct dc_link *link, + enum clock_source_id clock_source, + const struct dc_link_settings *link_settings) + { ++ if (!link_res->hpo_dp_link_enc) { ++ DC_LOG_ERROR("%s: invalid hpo_dp_link_enc\n", __func__); ++ return; ++ } ++ + if (link->dc->res_pool->dccg->funcs->set_symclk32_le_root_clock_gating) + link->dc->res_pool->dccg->funcs->set_symclk32_le_root_clock_gating( + link->dc->res_pool->dccg, +@@ -124,6 +131,11 @@ void disable_hpo_dp_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal) + { ++ if (!link_res->hpo_dp_link_enc) { ++ DC_LOG_ERROR("%s: invalid hpo_dp_link_enc\n", __func__); ++ return; ++ } ++ + link_res->hpo_dp_link_enc->funcs->link_disable(link_res->hpo_dp_link_enc); + link_res->hpo_dp_link_enc->funcs->disable_link_phy( + link_res->hpo_dp_link_enc, signal); +diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.c +index b621b97711b617..a7f5b0f6272ce0 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.c ++++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.c +@@ -162,7 +162,12 @@ static void set_hpo_fixed_vs_pe_retimer_dp_link_test_pattern(struct dc_link *lin + link_res->hpo_dp_link_enc->funcs->set_link_test_pattern( + link_res->hpo_dp_link_enc, tp_params); + } ++ + link->dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN); ++ ++ // Give retimer extra time to lock before updating DP_TRAINING_PATTERN_SET to TPS1 ++ if (tp_params->dp_phy_pattern == DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE) ++ msleep(30); + } + + static void set_hpo_fixed_vs_pe_retimer_dp_lane_settings(struct dc_link *link, +diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c +index c9b6676eaf53b9..c7a9e286a5d4d3 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c ++++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c +@@ -876,7 +876,7 @@ static bool detect_link_and_local_sink(struct dc_link *link, + (link->dpcd_sink_ext_caps.bits.oled == 1)) { + dpcd_set_source_specific_data(link); + msleep(post_oui_delay); +- set_cached_brightness_aux(link); ++ set_default_brightness_aux(link); + } + + return true; +@@ -1085,6 +1085,9 @@ static bool detect_link_and_local_sink(struct dc_link *link, + if (sink->edid_caps.panel_patch.skip_scdc_overwrite) + link->ctx->dc->debug.hdmi20_disable = true; + ++ if (sink->edid_caps.panel_patch.remove_sink_ext_caps) ++ link->dpcd_sink_ext_caps.raw = 0; ++ + if (dc_is_hdmi_signal(link->connector_signal)) + read_scdc_caps(link->ddc, link->local_sink); + +@@ -1163,6 +1166,12 @@ static bool detect_link_and_local_sink(struct dc_link *link, + dm_helpers_init_panel_settings(dc_ctx, &link->panel_config, sink); + // Override dc_panel_config if system has specific settings + dm_helpers_override_panel_settings(dc_ctx, &link->panel_config); ++ ++ //sink only can use supported link rate table, we are foreced to enable it ++ if (link->reported_link_cap.link_rate == LINK_RATE_UNKNOWN) ++ link->panel_config.ilr.optimize_edp_link_rate = true; ++ if (edp_is_ilr_optimization_enabled(link)) ++ link->reported_link_cap.link_rate = get_max_link_rate_from_ilr_table(link); + } + + } else { +diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +index 79aef205598b7f..4901e27f678bcf 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c ++++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +@@ -873,11 +873,15 @@ bool link_set_dsc_pps_packet(struct pipe_ctx *pipe_ctx, bool enable, bool immedi + { + struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; + struct dc_stream_state *stream = pipe_ctx->stream; +- DC_LOGGER_INIT(dsc->ctx->logger); + +- if (!pipe_ctx->stream->timing.flags.DSC || !dsc) ++ if (!pipe_ctx->stream->timing.flags.DSC) ++ return false; ++ ++ if (!dsc) + return false; + ++ DC_LOGGER_INIT(dsc->ctx->logger); ++ + if (enable) { + struct dsc_config dsc_cfg; + uint8_t dsc_packed_pps[128]; +@@ -1055,18 +1059,21 @@ static struct fixed31_32 get_pbn_from_bw_in_kbps(uint64_t kbps) + uint32_t denominator = 1; + + /* +- * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 ++ * The 1.006 factor (margin 5300ppm + 300ppm ~ 0.6% as per spec) is not ++ * required when determining PBN/time slot utilization on the link between ++ * us and the branch, since that overhead is already accounted for in ++ * the get_pbn_per_slot function. ++ * + * The unit of 54/64Mbytes/sec is an arbitrary unit chosen based on + * common multiplier to render an integer PBN for all link rate/lane + * counts combinations + * calculate +- * peak_kbps *= (1006/1000) + * peak_kbps *= (64/54) +- * peak_kbps *= 8 convert to bytes ++ * peak_kbps /= (8 * 1000) convert to bytes + */ + +- numerator = 64 * PEAK_FACTOR_X1000; +- denominator = 54 * 8 * 1000 * 1000; ++ numerator = 64; ++ denominator = 54 * 8 * 1000; + kbps *= numerator; + peak_kbps = dc_fixpt_from_fraction(kbps, denominator); + +@@ -1930,7 +1937,7 @@ static void disable_link_dp(struct dc_link *link, + dp_disable_link_phy(link, link_res, signal); + + if (link->connector_signal == SIGNAL_TYPE_EDP) { +- if (!link->dc->config.edp_no_power_sequencing) ++ if (!link->skip_implict_edp_power_control) + link->dc->hwss.edp_power_control(link, false); + } + +@@ -2064,17 +2071,11 @@ static enum dc_status enable_link_dp(struct dc_state *state, + } + } + +- /* +- * If the link is DP-over-USB4 do the following: +- * - Train with fallback when enabling DPIA link. Conventional links are ++ /* Train with fallback when enabling DPIA link. Conventional links are + * trained with fallback during sink detection. +- * - Allocate only what the stream needs for bw in Gbps. Inform the CM +- * in case stream needs more or less bw from what has been allocated +- * earlier at plug time. + */ +- if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { ++ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) + do_fallback = true; +- } + + /* + * Temporary w/a to get DP2.0 link rates to work with SST. +@@ -2140,8 +2141,7 @@ static enum dc_status enable_link_dp(struct dc_state *state, + if (link->dpcd_sink_ext_caps.bits.oled == 1 || + link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1 || + link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1) { +- set_cached_brightness_aux(link); +- ++ set_default_brightness_aux(link); + if (link->dpcd_sink_ext_caps.bits.oled == 1) + msleep(bl_oled_enable_delay); + edp_backlight_enable_aux(link, true); +@@ -2219,7 +2219,7 @@ static enum dc_status enable_link( + * link settings. Need to call disable first before enabling at + * new link settings. + */ +- if (link->link_status.link_active && !stream->skip_edp_power_down) ++ if (link->link_status.link_active) + disable_link(link, &pipe_ctx->link_res, pipe_ctx->stream->signal); + + switch (pipe_ctx->stream->signal) { +@@ -2257,6 +2257,32 @@ static enum dc_status enable_link( + return status; + } + ++static bool allocate_usb4_bandwidth_for_stream(struct dc_stream_state *stream, int bw) ++{ ++ return true; ++} ++ ++static bool allocate_usb4_bandwidth(struct dc_stream_state *stream) ++{ ++ bool ret; ++ ++ int bw = dc_bandwidth_in_kbps_from_timing(&stream->timing, ++ dc_link_get_highest_encoding_format(stream->sink->link)); ++ ++ ret = allocate_usb4_bandwidth_for_stream(stream, bw); ++ ++ return ret; ++} ++ ++static bool deallocate_usb4_bandwidth(struct dc_stream_state *stream) ++{ ++ bool ret; ++ ++ ret = allocate_usb4_bandwidth_for_stream(stream, 0); ++ ++ return ret; ++} ++ + void link_set_dpms_off(struct pipe_ctx *pipe_ctx) + { + struct dc *dc = pipe_ctx->stream->ctx->dc; +@@ -2293,6 +2319,9 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx) + update_psp_stream_config(pipe_ctx, true); + dc->hwss.blank_stream(pipe_ctx); + ++ if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) ++ deallocate_usb4_bandwidth(pipe_ctx->stream); ++ + if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) + deallocate_mst_payload(pipe_ctx); + else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT && +@@ -2338,9 +2367,7 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx) + dc->hwss.disable_stream(pipe_ctx); + } else { + dc->hwss.disable_stream(pipe_ctx); +- if (!pipe_ctx->stream->skip_edp_power_down) { +- disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal); +- } ++ disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal); + } + + if (pipe_ctx->stream->timing.flags.DSC) { +@@ -2516,6 +2543,9 @@ void link_set_dpms_on( + } + } + ++ if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) ++ allocate_usb4_bandwidth(pipe_ctx->stream); ++ + if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) + allocate_mst_payload(pipe_ctx); + else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT && +diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c +index 0895742a310241..eb7c9f226af5cb 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c ++++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c +@@ -223,6 +223,7 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s + link_srv->edp_receiver_ready_T9 = edp_receiver_ready_T9; + link_srv->edp_receiver_ready_T7 = edp_receiver_ready_T7; + link_srv->edp_power_alpm_dpcd_enable = edp_power_alpm_dpcd_enable; ++ link_srv->edp_set_panel_power = edp_set_panel_power; + } + + /* link dp cts implements dp compliance test automation protocols and manual +@@ -366,6 +367,27 @@ static enum transmitter translate_encoder_to_transmitter( + } + } + ++static uint8_t translate_dig_inst_to_pwrseq_inst(struct dc_link *link) ++{ ++ uint8_t pwrseq_inst = 0xF; ++ ++ switch (link->eng_id) { ++ case ENGINE_ID_DIGA: ++ pwrseq_inst = 0; ++ break; ++ case ENGINE_ID_DIGB: ++ pwrseq_inst = 1; ++ break; ++ default: ++ DC_LOG_WARNING("Unsupported pwrseq engine id: %d!\n", link->eng_id); ++ ASSERT(false); ++ break; ++ } ++ ++ return pwrseq_inst; ++} ++ ++ + static void link_destruct(struct dc_link *link) + { + int i; +@@ -381,7 +403,7 @@ static void link_destruct(struct dc_link *link) + if (link->panel_cntl) + link->panel_cntl->funcs->destroy(&link->panel_cntl); + +- if (link->link_enc) { ++ if (link->link_enc && !link->is_dig_mapping_flexible) { + /* Update link encoder resource tracking variables. These are used for + * the dynamic assignment of link encoders to streams. Virtual links + * are not assigned encoder resources on creation. +@@ -593,24 +615,6 @@ static bool construct_phy(struct dc_link *link, + link->ddc_hw_inst = + dal_ddc_get_line(get_ddc_pin(link->ddc)); + +- +- if (link->dc->res_pool->funcs->panel_cntl_create && +- (link->link_id.id == CONNECTOR_ID_EDP || +- link->link_id.id == CONNECTOR_ID_LVDS)) { +- panel_cntl_init_data.ctx = dc_ctx; +- panel_cntl_init_data.inst = +- panel_cntl_init_data.ctx->dc_edp_id_count; +- link->panel_cntl = +- link->dc->res_pool->funcs->panel_cntl_create( +- &panel_cntl_init_data); +- panel_cntl_init_data.ctx->dc_edp_id_count++; +- +- if (link->panel_cntl == NULL) { +- DC_ERROR("Failed to create link panel_cntl!\n"); +- goto panel_cntl_create_fail; +- } +- } +- + enc_init_data.ctx = dc_ctx; + bp_funcs->get_src_obj(dc_ctx->dc_bios, link->link_id, 0, + &enc_init_data.encoder); +@@ -625,14 +629,14 @@ static bool construct_phy(struct dc_link *link, + link->link_enc = + link->dc->res_pool->funcs->link_enc_create(dc_ctx, &enc_init_data); + +- DC_LOG_DC("BIOS object table - DP_IS_USB_C: %d", link->link_enc->features.flags.bits.DP_IS_USB_C); +- DC_LOG_DC("BIOS object table - IS_DP2_CAPABLE: %d", link->link_enc->features.flags.bits.IS_DP2_CAPABLE); +- + if (!link->link_enc) { + DC_ERROR("Failed to create link encoder!\n"); + goto link_enc_create_fail; + } + ++ DC_LOG_DC("BIOS object table - DP_IS_USB_C: %d", link->link_enc->features.flags.bits.DP_IS_USB_C); ++ DC_LOG_DC("BIOS object table - IS_DP2_CAPABLE: %d", link->link_enc->features.flags.bits.IS_DP2_CAPABLE); ++ + /* Update link encoder tracking variables. These are used for the dynamic + * assignment of link encoders to streams. + */ +@@ -641,6 +645,23 @@ static bool construct_phy(struct dc_link *link, + link->dc->res_pool->dig_link_enc_count++; + + link->link_enc_hw_inst = link->link_enc->transmitter; ++ ++ if (link->dc->res_pool->funcs->panel_cntl_create && ++ (link->link_id.id == CONNECTOR_ID_EDP || ++ link->link_id.id == CONNECTOR_ID_LVDS)) { ++ panel_cntl_init_data.ctx = dc_ctx; ++ panel_cntl_init_data.inst = panel_cntl_init_data.ctx->dc_edp_id_count; ++ panel_cntl_init_data.pwrseq_inst = translate_dig_inst_to_pwrseq_inst(link); ++ link->panel_cntl = ++ link->dc->res_pool->funcs->panel_cntl_create( ++ &panel_cntl_init_data); ++ panel_cntl_init_data.ctx->dc_edp_id_count++; ++ ++ if (link->panel_cntl == NULL) { ++ DC_ERROR("Failed to create link panel_cntl!\n"); ++ goto panel_cntl_create_fail; ++ } ++ } + for (i = 0; i < 4; i++) { + if (bp_funcs->get_device_tag(dc_ctx->dc_bios, + link->link_id, i, +diff --git a/drivers/gpu/drm/amd/display/dc/link/link_validation.c b/drivers/gpu/drm/amd/display/dc/link/link_validation.c +index b45fda96eaf649..5b0bc7f6a188cc 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/link_validation.c ++++ b/drivers/gpu/drm/amd/display/dc/link/link_validation.c +@@ -346,23 +346,61 @@ enum dc_status link_validate_mode_timing( + return DC_OK; + } + ++/* ++ * This function calculates the bandwidth required for the stream timing ++ * and aggregates the stream bandwidth for the respective dpia link ++ * ++ * @stream: pointer to the dc_stream_state struct instance ++ * @num_streams: number of streams to be validated ++ * ++ * return: true if validation is succeeded ++ */ + bool link_validate_dpia_bandwidth(const struct dc_stream_state *stream, const unsigned int num_streams) + { +- bool ret = true; +- int bw_needed[MAX_DPIA_NUM]; +- struct dc_link *link[MAX_DPIA_NUM]; ++ int bw_needed[MAX_DPIA_NUM] = {0}; ++ struct dc_link *dpia_link[MAX_DPIA_NUM] = {0}; ++ int num_dpias = 0; ++ ++ for (unsigned int i = 0; i < num_streams; ++i) { ++ if (stream[i].signal == SIGNAL_TYPE_DISPLAY_PORT) { ++ /* new dpia sst stream, check whether it exceeds max dpia */ ++ if (num_dpias >= MAX_DPIA_NUM) ++ return false; + +- if (!num_streams || num_streams > MAX_DPIA_NUM) +- return ret; ++ dpia_link[num_dpias] = stream[i].link; ++ bw_needed[num_dpias] = dc_bandwidth_in_kbps_from_timing(&stream[i].timing, ++ dc_link_get_highest_encoding_format(dpia_link[num_dpias])); ++ num_dpias++; ++ } else if (stream[i].signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { ++ uint8_t j = 0; ++ /* check whether its a known dpia link */ ++ for (; j < num_dpias; ++j) { ++ if (dpia_link[j] == stream[i].link) ++ break; ++ } ++ ++ if (j == num_dpias) { ++ /* new dpia mst stream, check whether it exceeds max dpia */ ++ if (num_dpias >= MAX_DPIA_NUM) ++ return false; ++ else { ++ dpia_link[j] = stream[i].link; ++ num_dpias++; ++ } ++ } ++ ++ bw_needed[j] += dc_bandwidth_in_kbps_from_timing(&stream[i].timing, ++ dc_link_get_highest_encoding_format(dpia_link[j])); ++ } ++ } + +- for (uint8_t i = 0; i < num_streams; ++i) { ++ /* Include dp overheads */ ++ for (uint8_t i = 0; i < num_dpias; ++i) { ++ int dp_overhead = 0; + +- link[i] = stream[i].link; +- bw_needed[i] = dc_bandwidth_in_kbps_from_timing(&stream[i].timing, +- dc_link_get_highest_encoding_format(link[i])); ++ dp_overhead = link_dp_dpia_get_dp_overhead_in_dp_tunneling(dpia_link[i]); ++ bw_needed[i] += dp_overhead; + } + +- ret = dpia_validate_usb4_bw(link, bw_needed, num_streams); +- +- return ret; ++ return dpia_validate_usb4_bw(dpia_link, bw_needed, num_dpias); + } +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +index 237e0ff955f3cc..3d589072fe307e 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +@@ -528,7 +528,7 @@ static bool decide_fallback_link_setting_max_bw_policy( + struct dc_link_settings *cur, + enum link_training_result training_result) + { +- uint8_t cur_idx = 0, next_idx; ++ uint32_t cur_idx = 0, next_idx; + bool found = false; + + if (training_result == LINK_TRAINING_ABORT) +@@ -707,8 +707,7 @@ bool edp_decide_link_settings(struct dc_link *link, + * edp_supported_link_rates_count is only valid for eDP v1.4 or higher. + * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h" + */ +- if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 || +- link->dpcd_caps.edp_supported_link_rates_count == 0) { ++ if (!edp_is_ilr_optimization_enabled(link)) { + *link_setting = link->verified_link_cap; + return true; + } +@@ -772,8 +771,7 @@ bool decide_edp_link_settings_with_dsc(struct dc_link *link, + * edp_supported_link_rates_count is only valid for eDP v1.4 or higher. + * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h" + */ +- if ((link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 || +- link->dpcd_caps.edp_supported_link_rates_count == 0)) { ++ if (!edp_is_ilr_optimization_enabled(link)) { + /* for DSC enabled case, we search for minimum lane count */ + memset(&initial_link_setting, 0, sizeof(initial_link_setting)); + initial_link_setting.lane_count = LANE_COUNT_ONE; +@@ -910,21 +908,17 @@ bool link_decide_link_settings(struct dc_stream_state *stream, + + memset(link_setting, 0, sizeof(*link_setting)); + +- /* if preferred is specified through AMDDP, use it, if it's enough +- * to drive the mode +- */ +- if (link->preferred_link_setting.lane_count != +- LANE_COUNT_UNKNOWN && +- link->preferred_link_setting.link_rate != +- LINK_RATE_UNKNOWN) { ++ if (dc_is_dp_signal(stream->signal) && ++ link->preferred_link_setting.lane_count != LANE_COUNT_UNKNOWN && ++ link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN) { ++ /* if preferred is specified through AMDDP, use it, if it's enough ++ * to drive the mode ++ */ + *link_setting = link->preferred_link_setting; +- return true; +- } +- +- /* MST doesn't perform link training for now +- * TODO: add MST specific link training routine +- */ +- if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { ++ } else if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { ++ /* MST doesn't perform link training for now ++ * TODO: add MST specific link training routine ++ */ + decide_mst_link_settings(link, link_setting); + } else if (link->connector_signal == SIGNAL_TYPE_EDP) { + /* enable edp link optimization for DSC eDP case */ +@@ -1586,9 +1580,17 @@ static bool retrieve_link_cap(struct dc_link *link) + return false; + } + +- if (dp_is_lttpr_present(link)) ++ if (dp_is_lttpr_present(link)) { + configure_lttpr_mode_transparent(link); + ++ // Echo TOTAL_LTTPR_CNT back downstream ++ core_link_write_dpcd( ++ link, ++ DP_TOTAL_LTTPR_CNT, ++ &link->dpcd_caps.lttpr_caps.phy_repeater_cnt, ++ sizeof(link->dpcd_caps.lttpr_caps.phy_repeater_cnt)); ++ } ++ + /* Read DP tunneling information. */ + status = dpcd_get_tunneling_device_data(link); + +@@ -1938,9 +1940,7 @@ void detect_edp_sink_caps(struct dc_link *link) + * edp_supported_link_rates_count is only valid for eDP v1.4 or higher. + * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h" + */ +- if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 && +- (link->panel_config.ilr.optimize_edp_link_rate || +- link->reported_link_cap.link_rate == LINK_RATE_UNKNOWN)) { ++ if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13) { + // Read DPCD 00010h - 0001Fh 16 bytes at one shot + core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES, + supported_link_rates, sizeof(supported_link_rates)); +@@ -1958,12 +1958,10 @@ void detect_edp_sink_caps(struct dc_link *link) + link_rate = linkRateInKHzToLinkRateMultiplier(link_rate_in_khz); + link->dpcd_caps.edp_supported_link_rates[link->dpcd_caps.edp_supported_link_rates_count] = link_rate; + link->dpcd_caps.edp_supported_link_rates_count++; +- +- if (link->reported_link_cap.link_rate < link_rate) +- link->reported_link_cap.link_rate = link_rate; + } + } + } ++ + core_link_read_dpcd(link, DP_EDP_BACKLIGHT_ADJUSTMENT_CAP, + &backlight_adj_cap, sizeof(backlight_adj_cap)); + +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c +index 7581023daa4789..5a965c26bf2095 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c +@@ -50,15 +50,28 @@ static bool get_bw_alloc_proceed_flag(struct dc_link *tmp) + && tmp->hpd_status + && tmp->dpia_bw_alloc_config.bw_alloc_enabled); + } ++ + static void reset_bw_alloc_struct(struct dc_link *link) + { + link->dpia_bw_alloc_config.bw_alloc_enabled = false; +- link->dpia_bw_alloc_config.sink_verified_bw = 0; +- link->dpia_bw_alloc_config.sink_max_bw = 0; ++ link->dpia_bw_alloc_config.link_verified_bw = 0; ++ link->dpia_bw_alloc_config.link_max_bw = 0; ++ link->dpia_bw_alloc_config.allocated_bw = 0; + link->dpia_bw_alloc_config.estimated_bw = 0; + link->dpia_bw_alloc_config.bw_granularity = 0; ++ link->dpia_bw_alloc_config.dp_overhead = 0; + link->dpia_bw_alloc_config.response_ready = false; ++ link->dpia_bw_alloc_config.nrd_max_lane_count = 0; ++ link->dpia_bw_alloc_config.nrd_max_link_rate = 0; ++ for (int i = 0; i < MAX_SINKS_PER_LINK; i++) ++ link->dpia_bw_alloc_config.remote_sink_req_bw[i] = 0; ++ DC_LOG_DEBUG("reset usb4 bw alloc of link(%d)\n", link->link_index); + } ++ ++#define BW_GRANULARITY_0 4 // 0.25 Gbps ++#define BW_GRANULARITY_1 2 // 0.5 Gbps ++#define BW_GRANULARITY_2 1 // 1 Gbps ++ + static uint8_t get_bw_granularity(struct dc_link *link) + { + uint8_t bw_granularity = 0; +@@ -71,16 +84,20 @@ static uint8_t get_bw_granularity(struct dc_link *link) + + switch (bw_granularity & 0x3) { + case 0: +- bw_granularity = 4; ++ bw_granularity = BW_GRANULARITY_0; + break; + case 1: ++ bw_granularity = BW_GRANULARITY_1; ++ break; ++ case 2: + default: +- bw_granularity = 2; ++ bw_granularity = BW_GRANULARITY_2; + break; + } + + return bw_granularity; + } ++ + static int get_estimated_bw(struct dc_link *link) + { + uint8_t bw_estimated_bw = 0; +@@ -93,31 +110,33 @@ static int get_estimated_bw(struct dc_link *link) + + return bw_estimated_bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); + } +-static bool allocate_usb4_bw(int *stream_allocated_bw, int bw_needed, struct dc_link *link) ++ ++static int get_non_reduced_max_link_rate(struct dc_link *link) + { +- if (bw_needed > 0) +- *stream_allocated_bw += bw_needed; ++ uint8_t nrd_max_link_rate = 0; + +- return true; ++ core_link_read_dpcd( ++ link, ++ DP_TUNNELING_MAX_LINK_RATE, ++ &nrd_max_link_rate, ++ sizeof(uint8_t)); ++ ++ return nrd_max_link_rate; + } +-static bool deallocate_usb4_bw(int *stream_allocated_bw, int bw_to_dealloc, struct dc_link *link) +-{ +- bool ret = false; + +- if (*stream_allocated_bw > 0) { +- *stream_allocated_bw -= bw_to_dealloc; +- ret = true; +- } else { +- //Do nothing for now +- ret = true; +- } ++static int get_non_reduced_max_lane_count(struct dc_link *link) ++{ ++ uint8_t nrd_max_lane_count = 0; + +- // Unplug so reset values +- if (!link->hpd_status) +- reset_bw_alloc_struct(link); ++ core_link_read_dpcd( ++ link, ++ DP_TUNNELING_MAX_LANE_COUNT, ++ &nrd_max_lane_count, ++ sizeof(uint8_t)); + +- return ret; ++ return nrd_max_lane_count; + } ++ + /* + * Read all New BW alloc configuration ex: estimated_bw, allocated_bw, + * granuality, Driver_ID, CM_Group, & populate the BW allocation structs +@@ -125,10 +144,22 @@ static bool deallocate_usb4_bw(int *stream_allocated_bw, int bw_to_dealloc, stru + */ + static void init_usb4_bw_struct(struct dc_link *link) + { +- // Init the known values ++ reset_bw_alloc_struct(link); ++ ++ /* init the known values */ + link->dpia_bw_alloc_config.bw_granularity = get_bw_granularity(link); + link->dpia_bw_alloc_config.estimated_bw = get_estimated_bw(link); ++ link->dpia_bw_alloc_config.nrd_max_link_rate = get_non_reduced_max_link_rate(link); ++ link->dpia_bw_alloc_config.nrd_max_lane_count = get_non_reduced_max_lane_count(link); ++ ++ DC_LOG_DEBUG("%s: bw_granularity(%d), estimated_bw(%d)\n", ++ __func__, link->dpia_bw_alloc_config.bw_granularity, ++ link->dpia_bw_alloc_config.estimated_bw); ++ DC_LOG_DEBUG("%s: nrd_max_link_rate(%d), nrd_max_lane_count(%d)\n", ++ __func__, link->dpia_bw_alloc_config.nrd_max_link_rate, ++ link->dpia_bw_alloc_config.nrd_max_lane_count); + } ++ + static uint8_t get_lowest_dpia_index(struct dc_link *link) + { + const struct dc *dc_struct = link->dc; +@@ -141,51 +172,66 @@ static uint8_t get_lowest_dpia_index(struct dc_link *link) + dc_struct->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA) + continue; + +- if (idx > dc_struct->links[i]->link_index) ++ if (idx > dc_struct->links[i]->link_index) { + idx = dc_struct->links[i]->link_index; ++ break; ++ } + } + + return idx; + } ++ + /* +- * Get the Max Available BW or Max Estimated BW for each Host Router ++ * Get the maximum dp tunnel banwidth of host router + * +- * @link: pointer to the dc_link struct instance +- * @type: ESTIMATD BW or MAX AVAILABLE BW ++ * @dc: pointer to the dc struct instance ++ * @hr_index: host router index + * +- * return: response_ready flag from dc_link struct ++ * return: host router maximum dp tunnel bandwidth + */ +-static int get_host_router_total_bw(struct dc_link *link, uint8_t type) ++static int get_host_router_total_dp_tunnel_bw(const struct dc *dc, uint8_t hr_index) + { +- const struct dc *dc_struct = link->dc; +- uint8_t lowest_dpia_index = get_lowest_dpia_index(link); +- uint8_t idx = (link->link_index - lowest_dpia_index) / 2, idx_temp = 0; +- struct dc_link *link_temp; ++ uint8_t lowest_dpia_index = get_lowest_dpia_index(dc->links[0]); ++ uint8_t hr_index_temp = 0; ++ struct dc_link *link_dpia_primary, *link_dpia_secondary; + int total_bw = 0; +- int i; + +- for (i = 0; i < MAX_PIPES * 2; ++i) { +- +- if (!dc_struct->links[i] || dc_struct->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA) +- continue; ++ for (uint8_t i = 0; i < (MAX_PIPES * 2) - 1; ++i) { + +- link_temp = dc_struct->links[i]; +- if (!link_temp || !link_temp->hpd_status) ++ if (!dc->links[i] || dc->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA) + continue; + +- idx_temp = (link_temp->link_index - lowest_dpia_index) / 2; +- +- if (idx_temp == idx) { +- +- if (type == HOST_ROUTER_BW_ESTIMATED) +- total_bw += link_temp->dpia_bw_alloc_config.estimated_bw; +- else if (type == HOST_ROUTER_BW_ALLOCATED) +- total_bw += link_temp->dpia_bw_alloc_config.sink_allocated_bw; ++ hr_index_temp = (dc->links[i]->link_index - lowest_dpia_index) / 2; ++ ++ if (hr_index_temp == hr_index) { ++ link_dpia_primary = dc->links[i]; ++ link_dpia_secondary = dc->links[i + 1]; ++ ++ /** ++ * If BW allocation enabled on both DPIAs, then ++ * HR BW = Estimated(dpia_primary) + Allocated(dpia_secondary) ++ * otherwise HR BW = Estimated(bw alloc enabled dpia) ++ */ ++ if ((link_dpia_primary->hpd_status && ++ link_dpia_primary->dpia_bw_alloc_config.bw_alloc_enabled) && ++ (link_dpia_secondary->hpd_status && ++ link_dpia_secondary->dpia_bw_alloc_config.bw_alloc_enabled)) { ++ total_bw += link_dpia_primary->dpia_bw_alloc_config.estimated_bw + ++ link_dpia_secondary->dpia_bw_alloc_config.allocated_bw; ++ } else if (link_dpia_primary->hpd_status && ++ link_dpia_primary->dpia_bw_alloc_config.bw_alloc_enabled) { ++ total_bw = link_dpia_primary->dpia_bw_alloc_config.estimated_bw; ++ } else if (link_dpia_secondary->hpd_status && ++ link_dpia_secondary->dpia_bw_alloc_config.bw_alloc_enabled) { ++ total_bw += link_dpia_secondary->dpia_bw_alloc_config.estimated_bw; ++ } ++ break; + } + } + + return total_bw; + } ++ + /* + * Cleanup function for when the dpia is unplugged to reset struct + * and perform any required clean up +@@ -194,42 +240,49 @@ static int get_host_router_total_bw(struct dc_link *link, uint8_t type) + * + * return: none + */ +-static bool dpia_bw_alloc_unplug(struct dc_link *link) ++static void dpia_bw_alloc_unplug(struct dc_link *link) + { +- if (!link) +- return true; +- +- return deallocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw, +- link->dpia_bw_alloc_config.sink_allocated_bw, link); ++ if (link) { ++ DC_LOG_DEBUG("%s: resetting bw alloc config for link(%d)\n", ++ __func__, link->link_index); ++ reset_bw_alloc_struct(link); ++ } + } ++ + static void set_usb4_req_bw_req(struct dc_link *link, int req_bw) + { + uint8_t requested_bw; + uint32_t temp; + +- // 1. Add check for this corner case #1 +- if (req_bw > link->dpia_bw_alloc_config.estimated_bw) ++ /* Error check whether request bw greater than allocated */ ++ if (req_bw > link->dpia_bw_alloc_config.estimated_bw) { ++ DC_LOG_ERROR("%s: Request bw greater than estimated bw for link(%d)\n", ++ __func__, link->link_index); + req_bw = link->dpia_bw_alloc_config.estimated_bw; ++ } + + temp = req_bw * link->dpia_bw_alloc_config.bw_granularity; + requested_bw = temp / Kbps_TO_Gbps; + +- // Always make sure to add more to account for floating points ++ /* Always make sure to add more to account for floating points */ + if (temp % Kbps_TO_Gbps) + ++requested_bw; + +- // 2. Add check for this corner case #2 ++ /* Error check whether requested and allocated are equal */ + req_bw = requested_bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); +- if (req_bw == link->dpia_bw_alloc_config.sink_allocated_bw) +- return; ++ if (req_bw && (req_bw == link->dpia_bw_alloc_config.allocated_bw)) { ++ DC_LOG_ERROR("%s: Request bw equals to allocated bw for link(%d)\n", ++ __func__, link->link_index); ++ } + +- if (core_link_write_dpcd( ++ link->dpia_bw_alloc_config.response_ready = false; // Reset flag ++ core_link_write_dpcd( + link, + REQUESTED_BW, + &requested_bw, +- sizeof(uint8_t)) == DC_OK) +- link->dpia_bw_alloc_config.response_ready = false; // Reset flag ++ sizeof(uint8_t)); + } ++ + /* + * Return the response_ready flag from dc_link struct + * +@@ -241,6 +294,7 @@ static bool get_cm_response_ready_flag(struct dc_link *link) + { + return link->dpia_bw_alloc_config.response_ready; + } ++ + // ------------------------------------------------------------------ + // PUBLIC FUNCTIONS + // ------------------------------------------------------------------ +@@ -277,27 +331,35 @@ bool link_dp_dpia_set_dptx_usb4_bw_alloc_support(struct dc_link *link) + DPTX_BW_ALLOCATION_MODE_CONTROL, + &response, + sizeof(uint8_t)) != DC_OK) { +- DC_LOG_DEBUG("%s: **** FAILURE Enabling DPtx BW Allocation Mode Support ***\n", +- __func__); ++ DC_LOG_DEBUG("%s: FAILURE Enabling DPtx BW Allocation Mode Support for link(%d)\n", ++ __func__, link->link_index); + } else { + // SUCCESS Enabled DPtx BW Allocation Mode Support +- link->dpia_bw_alloc_config.bw_alloc_enabled = true; +- DC_LOG_DEBUG("%s: **** SUCCESS Enabling DPtx BW Allocation Mode Support ***\n", +- __func__); ++ DC_LOG_DEBUG("%s: SUCCESS Enabling DPtx BW Allocation Mode Support for link(%d)\n", ++ __func__, link->link_index); + + ret = true; + init_usb4_bw_struct(link); ++ link->dpia_bw_alloc_config.bw_alloc_enabled = true; ++ ++ /* ++ * During DP tunnel creation, CM preallocates BW and reduces estimated BW of other ++ * DPIA. CM release preallocation only when allocation is complete. Do zero alloc ++ * to make the CM to release preallocation and update estimated BW correctly for ++ * all DPIAs per host router ++ */ ++ link_dp_dpia_allocate_usb4_bandwidth_for_stream(link, 0); + } + } + + out: + return ret; + } ++ + void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t result) + { + int bw_needed = 0; + int estimated = 0; +- int host_router_total_estimated_bw = 0; + + if (!get_bw_alloc_proceed_flag((link))) + return; +@@ -306,14 +368,22 @@ void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t res + + case DPIA_BW_REQ_FAILED: + +- DC_LOG_DEBUG("%s: *** *** BW REQ FAILURE for DP-TX Request *** ***\n", __func__); ++ /* ++ * Ideally, we shouldn't run into this case as we always validate available ++ * bandwidth and request within that limit ++ */ ++ estimated = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); ++ ++ DC_LOG_ERROR("%s: BW REQ FAILURE for DP-TX Request for link(%d)\n", ++ __func__, link->link_index); ++ DC_LOG_ERROR("%s: current estimated_bw(%d), new estimated_bw(%d)\n", ++ __func__, link->dpia_bw_alloc_config.estimated_bw, estimated); + +- // Update the new Estimated BW value updated by CM +- link->dpia_bw_alloc_config.estimated_bw = +- bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); ++ /* Update the new Estimated BW value updated by CM */ ++ link->dpia_bw_alloc_config.estimated_bw = estimated; + ++ /* Allocate the previously requested bandwidth */ + set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.estimated_bw); +- link->dpia_bw_alloc_config.response_ready = false; + + /* + * If FAIL then it is either: +@@ -326,68 +396,34 @@ void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t res + + case DPIA_BW_REQ_SUCCESS: + +- DC_LOG_DEBUG("%s: *** BW REQ SUCCESS for DP-TX Request ***\n", __func__); +- +- // 1. SUCCESS 1st time before any Pruning is done +- // 2. SUCCESS after prev. FAIL before any Pruning is done +- // 3. SUCCESS after Pruning is done but before enabling link +- + bw_needed = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); + +- // 1. +- if (!link->dpia_bw_alloc_config.sink_allocated_bw) { +- +- allocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw, bw_needed, link); +- link->dpia_bw_alloc_config.sink_verified_bw = +- link->dpia_bw_alloc_config.sink_allocated_bw; +- +- // SUCCESS from first attempt +- if (link->dpia_bw_alloc_config.sink_allocated_bw > +- link->dpia_bw_alloc_config.sink_max_bw) +- link->dpia_bw_alloc_config.sink_verified_bw = +- link->dpia_bw_alloc_config.sink_max_bw; +- } +- // 3. +- else if (link->dpia_bw_alloc_config.sink_allocated_bw) { +- +- // Find out how much do we need to de-alloc +- if (link->dpia_bw_alloc_config.sink_allocated_bw > bw_needed) +- deallocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw, +- link->dpia_bw_alloc_config.sink_allocated_bw - bw_needed, link); +- else +- allocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw, +- bw_needed - link->dpia_bw_alloc_config.sink_allocated_bw, link); +- } ++ DC_LOG_DEBUG("%s: BW REQ SUCCESS for DP-TX Request for link(%d)\n", ++ __func__, link->link_index); ++ DC_LOG_DEBUG("%s: current allocated_bw(%d), new allocated_bw(%d)\n", ++ __func__, link->dpia_bw_alloc_config.allocated_bw, bw_needed); + +- // 4. If this is the 2nd sink then any unused bw will be reallocated to master DPIA +- // => check if estimated_bw changed ++ link->dpia_bw_alloc_config.allocated_bw = bw_needed; + + link->dpia_bw_alloc_config.response_ready = true; + break; + + case DPIA_EST_BW_CHANGED: + +- DC_LOG_DEBUG("%s: *** ESTIMATED BW CHANGED for DP-TX Request ***\n", __func__); +- + estimated = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); +- host_router_total_estimated_bw = get_host_router_total_bw(link, HOST_ROUTER_BW_ESTIMATED); + +- // 1. If due to unplug of other sink +- if (estimated == host_router_total_estimated_bw) { +- // First update the estimated & max_bw fields +- if (link->dpia_bw_alloc_config.estimated_bw < estimated) +- link->dpia_bw_alloc_config.estimated_bw = estimated; +- } +- // 2. If due to realloc bw btw 2 dpia due to plug OR realloc unused Bw +- else { +- // We lost estimated bw usually due to plug event of other dpia +- link->dpia_bw_alloc_config.estimated_bw = estimated; +- } ++ DC_LOG_DEBUG("%s: ESTIMATED BW CHANGED for link(%d)\n", ++ __func__, link->link_index); ++ DC_LOG_DEBUG("%s: current estimated_bw(%d), new estimated_bw(%d)\n", ++ __func__, link->dpia_bw_alloc_config.estimated_bw, estimated); ++ ++ link->dpia_bw_alloc_config.estimated_bw = estimated; + break; + + case DPIA_BW_ALLOC_CAPS_CHANGED: + +- DC_LOG_DEBUG("%s: *** BW ALLOC CAPABILITY CHANGED for DP-TX Request ***\n", __func__); ++ DC_LOG_ERROR("%s: BW ALLOC CAPABILITY CHANGED to Disabled for link(%d)\n", ++ __func__, link->link_index); + link->dpia_bw_alloc_config.bw_alloc_enabled = false; + break; + } +@@ -405,21 +441,21 @@ int dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int pea + if (link->hpd_status && peak_bw > 0) { + + // If DP over USB4 then we need to check BW allocation +- link->dpia_bw_alloc_config.sink_max_bw = peak_bw; +- set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.sink_max_bw); ++ link->dpia_bw_alloc_config.link_max_bw = peak_bw; ++ set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.link_max_bw); + + do { +- if (!(timeout > 0)) ++ if (timeout > 0) + timeout--; + else + break; +- fsleep(10 * 1000); ++ msleep(10); + } while (!get_cm_response_ready_flag(link)); + + if (!timeout) + ret = 0;// ERROR TIMEOUT waiting for response for allocating bw +- else if (link->dpia_bw_alloc_config.sink_allocated_bw > 0) +- ret = get_host_router_total_bw(link, HOST_ROUTER_BW_ALLOCATED); ++ else if (link->dpia_bw_alloc_config.allocated_bw > 0) ++ ret = link->dpia_bw_alloc_config.allocated_bw; + } + //2. Cold Unplug + else if (!link->hpd_status) +@@ -428,65 +464,102 @@ int dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int pea + out: + return ret; + } +-int link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw) ++bool link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw) + { +- int ret = 0; ++ bool ret = false; + uint8_t timeout = 10; + ++ DC_LOG_DEBUG("%s: ENTER: link(%d), hpd_status(%d), current allocated_bw(%d), req_bw(%d)\n", ++ __func__, link->link_index, link->hpd_status, ++ link->dpia_bw_alloc_config.allocated_bw, req_bw); ++ + if (!get_bw_alloc_proceed_flag(link)) + goto out; + +- /* +- * Sometimes stream uses same timing parameters as the already +- * allocated max sink bw so no need to re-alloc +- */ +- if (req_bw != link->dpia_bw_alloc_config.sink_allocated_bw) { +- set_usb4_req_bw_req(link, req_bw); +- do { +- if (!(timeout > 0)) +- timeout--; +- else +- break; +- udelay(10 * 1000); +- } while (!get_cm_response_ready_flag(link)); ++ set_usb4_req_bw_req(link, req_bw); ++ do { ++ if (timeout > 0) ++ timeout--; ++ else ++ break; ++ msleep(10); ++ } while (!get_cm_response_ready_flag(link)); + +- if (!timeout) +- ret = 0;// ERROR TIMEOUT waiting for response for allocating bw +- else if (link->dpia_bw_alloc_config.sink_allocated_bw > 0) +- ret = get_host_router_total_bw(link, HOST_ROUTER_BW_ALLOCATED); +- } ++ if (timeout) ++ ret = true; + + out: ++ DC_LOG_DEBUG("%s: EXIT: timeout(%d), ret(%d)\n", __func__, timeout, ret); + return ret; + } ++ + bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed_per_dpia, const unsigned int num_dpias) + { + bool ret = true; +- int bw_needed_per_hr[MAX_HR_NUM] = { 0, 0 }; +- uint8_t lowest_dpia_index = 0, dpia_index = 0; +- uint8_t i; ++ int bw_needed_per_hr[MAX_HR_NUM] = { 0, 0 }, host_router_total_dp_bw = 0; ++ uint8_t lowest_dpia_index, i, hr_index; + + if (!num_dpias || num_dpias > MAX_DPIA_NUM) + return ret; + +- //Get total Host Router BW & Validate against each Host Router max BW ++ lowest_dpia_index = get_lowest_dpia_index(link[0]); ++ ++ /* get total Host Router BW with granularity for the given modes */ + for (i = 0; i < num_dpias; ++i) { ++ int granularity_Gbps = 0; ++ int bw_granularity = 0; + + if (!link[i]->dpia_bw_alloc_config.bw_alloc_enabled) + continue; + +- lowest_dpia_index = get_lowest_dpia_index(link[i]); + if (link[i]->link_index < lowest_dpia_index) + continue; + +- dpia_index = (link[i]->link_index - lowest_dpia_index) / 2; +- bw_needed_per_hr[dpia_index] += bw_needed_per_dpia[i]; +- if (bw_needed_per_hr[dpia_index] > get_host_router_total_bw(link[i], HOST_ROUTER_BW_ALLOCATED)) { ++ granularity_Gbps = (Kbps_TO_Gbps / link[i]->dpia_bw_alloc_config.bw_granularity); ++ bw_granularity = (bw_needed_per_dpia[i] / granularity_Gbps) * granularity_Gbps + ++ ((bw_needed_per_dpia[i] % granularity_Gbps) ? granularity_Gbps : 0); + +- ret = false; +- break; ++ hr_index = (link[i]->link_index - lowest_dpia_index) / 2; ++ bw_needed_per_hr[hr_index] += bw_granularity; ++ } ++ ++ /* validate against each Host Router max BW */ ++ for (hr_index = 0; hr_index < MAX_HR_NUM; ++hr_index) { ++ if (bw_needed_per_hr[hr_index]) { ++ host_router_total_dp_bw = get_host_router_total_dp_tunnel_bw(link[0]->dc, hr_index); ++ if (bw_needed_per_hr[hr_index] > host_router_total_dp_bw) { ++ ret = false; ++ break; ++ } + } + } + + return ret; + } ++ ++int link_dp_dpia_get_dp_overhead_in_dp_tunneling(struct dc_link *link) ++{ ++ int dp_overhead = 0, link_mst_overhead = 0; ++ ++ if (!get_bw_alloc_proceed_flag((link))) ++ return dp_overhead; ++ ++ /* if its mst link, add MTPH overhead */ ++ if ((link->type == dc_connection_mst_branch) && ++ !link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) { ++ /* For 8b/10b encoding: MTP is 64 time slots long, slot 0 is used for MTPH ++ * MST overhead is 1/64 of link bandwidth (excluding any overhead) ++ */ ++ const struct dc_link_settings *link_cap = ++ dc_link_get_link_cap(link); ++ uint32_t link_bw_in_kbps = (uint32_t)link_cap->link_rate * ++ (uint32_t)link_cap->lane_count * ++ LINK_RATE_REF_FREQ_IN_KHZ * 8; ++ link_mst_overhead = (link_bw_in_kbps / 64) + ((link_bw_in_kbps % 64) ? 1 : 0); ++ } ++ ++ /* add all the overheads */ ++ dp_overhead = link_mst_overhead; ++ ++ return dp_overhead; ++} +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h +index 7292690383ae1f..3b6d8494f9d5da 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h +@@ -59,9 +59,9 @@ bool link_dp_dpia_set_dptx_usb4_bw_alloc_support(struct dc_link *link); + * @link: pointer to the dc_link struct instance + * @req_bw: Bw requested by the stream + * +- * return: allocated bw else return 0 ++ * return: true if allocated successfully + */ +-int link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw); ++bool link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw); + + /* + * Handle the USB4 BW Allocation related functionality here: +@@ -99,4 +99,13 @@ void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t res + */ + bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed, const unsigned int num_dpias); + ++/* ++ * Obtain all the DP overheads in dp tunneling for the dpia link ++ * ++ * @link: pointer to the dc_link struct instance ++ * ++ * return: DP overheads in DP tunneling ++ */ ++int link_dp_dpia_get_dp_overhead_in_dp_tunneling(struct dc_link *link); ++ + #endif /* DC_INC_LINK_DP_DPIA_BW_H_ */ +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c +index b7abba55bc2fdf..9bde0c8bf914a6 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c +@@ -73,7 +73,8 @@ void dp_disable_link_phy(struct dc_link *link, + { + struct dc *dc = link->ctx->dc; + +- if (!link->wa_flags.dp_keep_receiver_powered) ++ if (!link->wa_flags.dp_keep_receiver_powered && ++ !link->skip_implict_edp_power_control) + dpcd_write_rx_power_ctrl(link, false); + + dc->hwss.disable_link_output(link, link_res, signal); +@@ -142,32 +143,25 @@ enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource + + link_enc = link_enc_cfg_get_link_enc(link); + ASSERT(link_enc); ++ if (link_enc->funcs->fec_set_ready == NULL) ++ return DC_NOT_SUPPORTED; + +- if (!dp_should_enable_fec(link)) +- return status; +- +- if (link_enc->funcs->fec_set_ready && +- link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) { +- if (ready) { +- fec_config = 1; +- status = core_link_write_dpcd(link, +- DP_FEC_CONFIGURATION, +- &fec_config, +- sizeof(fec_config)); +- if (status == DC_OK) { +- link_enc->funcs->fec_set_ready(link_enc, true); +- link->fec_state = dc_link_fec_ready; +- } else { +- link_enc->funcs->fec_set_ready(link_enc, false); +- link->fec_state = dc_link_fec_not_ready; +- dm_error("dpcd write failed to set fec_ready"); +- } +- } else if (link->fec_state == dc_link_fec_ready) { ++ if (ready && dp_should_enable_fec(link)) { ++ fec_config = 1; ++ ++ status = core_link_write_dpcd(link, DP_FEC_CONFIGURATION, ++ &fec_config, sizeof(fec_config)); ++ ++ if (status == DC_OK) { ++ link_enc->funcs->fec_set_ready(link_enc, true); ++ link->fec_state = dc_link_fec_ready; ++ } ++ } else { ++ if (link->fec_state == dc_link_fec_ready) { + fec_config = 0; +- status = core_link_write_dpcd(link, +- DP_FEC_CONFIGURATION, +- &fec_config, +- sizeof(fec_config)); ++ core_link_write_dpcd(link, DP_FEC_CONFIGURATION, ++ &fec_config, sizeof(fec_config)); ++ + link_enc->funcs->fec_set_ready(link_enc, false); + link->fec_state = dc_link_fec_not_ready; + } +@@ -182,14 +176,12 @@ void dp_set_fec_enable(struct dc_link *link, bool enable) + + link_enc = link_enc_cfg_get_link_enc(link); + ASSERT(link_enc); +- +- if (!dp_should_enable_fec(link)) ++ if (link_enc->funcs->fec_set_enable == NULL) + return; + +- if (link_enc->funcs->fec_set_enable && +- link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) { +- if (link->fec_state == dc_link_fec_ready && enable) { +- /* Accord to DP spec, FEC enable sequence can first ++ if (enable && dp_should_enable_fec(link)) { ++ if (link->fec_state == dc_link_fec_ready) { ++ /* According to DP spec, FEC enable sequence can first + * be transmitted anytime after 1000 LL codes have + * been transmitted on the link after link training + * completion. Using 1 lane RBR should have the maximum +@@ -199,7 +191,9 @@ void dp_set_fec_enable(struct dc_link *link, bool enable) + udelay(7); + link_enc->funcs->fec_set_enable(link_enc, true); + link->fec_state = dc_link_fec_enabled; +- } else if (link->fec_state == dc_link_fec_enabled && !enable) { ++ } ++ } else { ++ if (link->fec_state == dc_link_fec_enabled) { + link_enc->funcs->fec_set_enable(link_enc, false); + link->fec_state = dc_link_fec_ready; + } +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c +index 90339c2dfd8487..9d1adfc09fb2aa 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c +@@ -517,6 +517,7 @@ enum link_training_result dp_check_link_loss_status( + { + enum link_training_result status = LINK_TRAINING_SUCCESS; + union lane_status lane_status; ++ union lane_align_status_updated dpcd_lane_status_updated; + uint8_t dpcd_buf[6] = {0}; + uint32_t lane; + +@@ -532,10 +533,12 @@ enum link_training_result dp_check_link_loss_status( + * check lanes status + */ + lane_status.raw = dp_get_nibble_at_index(&dpcd_buf[2], lane); ++ dpcd_lane_status_updated.raw = dpcd_buf[4]; + + if (!lane_status.bits.CHANNEL_EQ_DONE_0 || + !lane_status.bits.CR_DONE_0 || +- !lane_status.bits.SYMBOL_LOCKED_0) { ++ !lane_status.bits.SYMBOL_LOCKED_0 || ++ !dp_is_interlane_aligned(dpcd_lane_status_updated)) { + /* if one of the channel equalization, clock + * recovery or symbol lock is dropped + * consider it as (link has been +@@ -807,7 +810,7 @@ void dp_decide_lane_settings( + const struct link_training_settings *lt_settings, + const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], + struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], +- union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]) ++ union dpcd_training_lane *dpcd_lane_settings) + { + uint32_t lane; + +@@ -911,10 +914,10 @@ static enum dc_status configure_lttpr_mode_non_transparent( + /* Driver does not need to train the first hop. Skip DPCD read and clear + * AUX_RD_INTERVAL for DPTX-to-DPIA hop. + */ +- if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) ++ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && repeater_cnt > 0 && repeater_cnt < MAX_REPEATER_CNT) + link->dpcd_caps.lttpr_caps.aux_rd_interval[--repeater_cnt] = 0; + +- for (repeater_id = repeater_cnt; repeater_id > 0; repeater_id--) { ++ for (repeater_id = repeater_cnt; repeater_id > 0 && repeater_id < MAX_REPEATER_CNT; repeater_id--) { + aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 + + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (repeater_id - 1)); + core_link_read_dpcd( +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.h +index 7d027bac82551d..851bd17317a0c4 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.h ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.h +@@ -111,7 +111,7 @@ void dp_decide_lane_settings( + const struct link_training_settings *lt_settings, + const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX], + struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX], +- union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]); ++ union dpcd_training_lane *dpcd_lane_settings); + + enum dc_dp_training_pattern decide_cr_training_pattern( + const struct dc_link_settings *link_settings); +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c +index fd8f6f19814617..68096d12f52fd6 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c +@@ -115,7 +115,7 @@ static enum link_training_result perform_fixed_vs_pe_nontransparent_training_seq + lt_settings->cr_pattern_time = 16000; + + /* Fixed VS/PE specific: Toggle link rate */ +- apply_toggle_rate_wa = (link->vendor_specific_lttpr_link_rate_wa == target_rate); ++ apply_toggle_rate_wa = ((link->vendor_specific_lttpr_link_rate_wa == target_rate) || (link->vendor_specific_lttpr_link_rate_wa == 0)); + target_rate = get_dpcd_link_rate(<_settings->link_settings); + toggle_rate = (target_rate == 0x6) ? 0xA : 0x6; + +@@ -271,7 +271,7 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy( + /* Vendor specific: Toggle link rate */ + toggle_rate = (rate == 0x6) ? 0xA : 0x6; + +- if (link->vendor_specific_lttpr_link_rate_wa == rate) { ++ if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) { + core_link_write_dpcd( + link, + DP_LINK_BW_SET, +@@ -617,7 +617,7 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence( + /* Vendor specific: Toggle link rate */ + toggle_rate = (rate == 0x6) ? 0xA : 0x6; + +- if (link->vendor_specific_lttpr_link_rate_wa == rate) { ++ if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) { + core_link_write_dpcd( + link, + DP_LINK_BW_SET, +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c +index 5c9a30211c109f..fc50931c2aecbb 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c +@@ -205,7 +205,7 @@ enum dc_status core_link_read_dpcd( + uint32_t extended_size; + /* size of the remaining partitioned address space */ + uint32_t size_left_to_read; +- enum dc_status status; ++ enum dc_status status = DC_ERROR_UNEXPECTED; + /* size of the next partition to be read from */ + uint32_t partition_size; + uint32_t data_index = 0; +@@ -234,7 +234,7 @@ enum dc_status core_link_write_dpcd( + { + uint32_t partition_size; + uint32_t data_index = 0; +- enum dc_status status; ++ enum dc_status status = DC_ERROR_UNEXPECTED; + + while (size) { + partition_size = dpcd_get_next_partition_size(address, size); +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +index 98e715aa6d8e34..13104d000b9e09 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +@@ -33,6 +33,7 @@ + #include "link_dp_capability.h" + #include "dm_helpers.h" + #include "dal_asic_id.h" ++#include "link_dp_phy.h" + #include "dce/dmub_psr.h" + #include "dc/dc_dmub_srv.h" + #include "dce/dmub_replay.h" +@@ -167,7 +168,6 @@ bool edp_set_backlight_level_nits(struct dc_link *link, + *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits; + *(uint16_t *)&dpcd_backlight_set.backlight_transition_time_ms = (uint16_t)transition_time_in_ms; + +- link->backlight_settings.backlight_millinits = backlight_millinits; + + if (!link->dpcd_caps.panel_luminance_control) { + if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL, +@@ -280,9 +280,9 @@ bool set_default_brightness_aux(struct dc_link *link) + if (link && link->dpcd_sink_ext_caps.bits.oled == 1) { + if (!read_default_bl_aux(link, &default_backlight)) + default_backlight = 150000; +- // if < 5 nits or > 5000, it might be wrong readback +- if (default_backlight < 5000 || default_backlight > 5000000) +- default_backlight = 150000; // ++ // if < 1 nits or > 5000, it might be wrong readback ++ if (default_backlight < 1000 || default_backlight > 5000000) ++ default_backlight = 150000; + + return edp_set_backlight_level_nits(link, true, + default_backlight, 0); +@@ -290,14 +290,23 @@ bool set_default_brightness_aux(struct dc_link *link) + return false; + } + +-bool set_cached_brightness_aux(struct dc_link *link) ++bool edp_is_ilr_optimization_enabled(struct dc_link *link) + { +- if (link->backlight_settings.backlight_millinits) +- return edp_set_backlight_level_nits(link, true, +- link->backlight_settings.backlight_millinits, 0); +- else +- return set_default_brightness_aux(link); +- return false; ++ if (link->dpcd_caps.edp_supported_link_rates_count == 0 || !link->panel_config.ilr.optimize_edp_link_rate) ++ return false; ++ return true; ++} ++ ++enum dc_link_rate get_max_link_rate_from_ilr_table(struct dc_link *link) ++{ ++ enum dc_link_rate link_rate = link->reported_link_cap.link_rate; ++ ++ for (int i = 0; i < link->dpcd_caps.edp_supported_link_rates_count; i++) { ++ if (link_rate < link->dpcd_caps.edp_supported_link_rates[i]) ++ link_rate = link->dpcd_caps.edp_supported_link_rates[i]; ++ } ++ ++ return link_rate; + } + + bool edp_is_ilr_optimization_required(struct dc_link *link, +@@ -311,8 +320,7 @@ bool edp_is_ilr_optimization_required(struct dc_link *link, + + ASSERT(link || crtc_timing); // invalid input + +- if (link->dpcd_caps.edp_supported_link_rates_count == 0 || +- !link->panel_config.ilr.optimize_edp_link_rate) ++ if (!edp_is_ilr_optimization_enabled(link)) + return false; + + +@@ -362,6 +370,34 @@ void edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd) + link->dc->hwss.edp_backlight_control(link, true); + } + ++void edp_set_panel_power(struct dc_link *link, bool powerOn) ++{ ++ if (powerOn) { ++ // 1. panel VDD on ++ if (!link->dc->config.edp_no_power_sequencing) ++ link->dc->hwss.edp_power_control(link, true); ++ link->dc->hwss.edp_wait_for_hpd_ready(link, true); ++ ++ // 2. panel BL on ++ if (link->dc->hwss.edp_backlight_control) ++ link->dc->hwss.edp_backlight_control(link, true); ++ ++ // 3. Rx power on ++ dpcd_write_rx_power_ctrl(link, true); ++ } else { ++ // 3. Rx power off ++ dpcd_write_rx_power_ctrl(link, false); ++ ++ // 2. panel BL off ++ if (link->dc->hwss.edp_backlight_control) ++ link->dc->hwss.edp_backlight_control(link, false); ++ ++ // 1. panel VDD off ++ if (!link->dc->config.edp_no_power_sequencing) ++ link->dc->hwss.edp_power_control(link, false); ++ } ++} ++ + bool edp_wait_for_t12(struct dc_link *link) + { + if (link->connector_signal == SIGNAL_TYPE_EDP && link->dc->hwss.edp_wait_for_T12) { +@@ -846,7 +882,8 @@ bool edp_set_replay_allow_active(struct dc_link *link, const bool *allow_active, + + /* Set power optimization flag */ + if (power_opts && link->replay_settings.replay_power_opt_active != *power_opts) { +- if (link->replay_settings.replay_feature_enabled && replay->funcs->replay_set_power_opt) { ++ if (replay != NULL && link->replay_settings.replay_feature_enabled && ++ replay->funcs->replay_set_power_opt) { + replay->funcs->replay_set_power_opt(replay, *power_opts, panel_inst); + link->replay_settings.replay_power_opt_active = *power_opts; + } +@@ -884,8 +921,8 @@ bool edp_get_replay_state(const struct dc_link *link, uint64_t *state) + bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream) + { + /* To-do: Setup Replay */ +- struct dc *dc = link->ctx->dc; +- struct dmub_replay *replay = dc->res_pool->replay; ++ struct dc *dc; ++ struct dmub_replay *replay; + int i; + unsigned int panel_inst; + struct replay_context replay_context = { 0 }; +@@ -901,6 +938,10 @@ bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream + if (!link) + return false; + ++ dc = link->ctx->dc; ++ ++ replay = dc->res_pool->replay; ++ + if (!replay) + return false; + +@@ -929,8 +970,7 @@ bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream + + replay_context.line_time_in_ns = lineTimeInNs; + +- if (replay) +- link->replay_settings.replay_feature_enabled = ++ link->replay_settings.replay_feature_enabled = + replay->funcs->replay_copy_settings(replay, link, &replay_context, panel_inst); + if (link->replay_settings.replay_feature_enabled) { + +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h +index 0a5bbda8c739c4..a034288ad75d4a 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h +@@ -30,7 +30,6 @@ + enum dp_panel_mode dp_get_panel_mode(struct dc_link *link); + void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode); + bool set_default_brightness_aux(struct dc_link *link); +-bool set_cached_brightness_aux(struct dc_link *link); + void edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd); + int edp_get_backlight_level(const struct dc_link *link); + bool edp_get_backlight_level_nits(struct dc_link *link, +@@ -64,9 +63,12 @@ bool edp_get_replay_state(const struct dc_link *link, uint64_t *state); + bool edp_wait_for_t12(struct dc_link *link); + bool edp_is_ilr_optimization_required(struct dc_link *link, + struct dc_crtc_timing *crtc_timing); ++bool edp_is_ilr_optimization_enabled(struct dc_link *link); ++enum dc_link_rate get_max_link_rate_from_ilr_table(struct dc_link *link); + bool edp_backlight_enable_aux(struct dc_link *link, bool enable); + void edp_add_delay_for_T9(struct dc_link *link); + bool edp_receiver_ready_T9(struct dc_link *link); + bool edp_receiver_ready_T7(struct dc_link *link); + bool edp_power_alpm_dpcd_enable(struct dc_link *link, bool enable); ++void edp_set_panel_power(struct dc_link *link, bool powerOn); + #endif /* __DC_LINK_EDP_POWER_CONTROL_H__ */ +diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h +index 2d995c87fbb986..d3c4a9a577eeab 100644 +--- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h ++++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h +@@ -186,6 +186,7 @@ struct dmub_srv_region_params { + uint32_t vbios_size; + const uint8_t *fw_inst_const; + const uint8_t *fw_bss_data; ++ bool is_mailbox_in_inbox; + }; + + /** +@@ -205,20 +206,25 @@ struct dmub_srv_region_params { + */ + struct dmub_srv_region_info { + uint32_t fb_size; ++ uint32_t inbox_size; + uint8_t num_regions; + struct dmub_region regions[DMUB_WINDOW_TOTAL]; + }; + + /** +- * struct dmub_srv_fb_params - parameters used for driver fb setup ++ * struct dmub_srv_memory_params - parameters used for driver fb setup + * @region_info: region info calculated by dmub service +- * @cpu_addr: base cpu address for the framebuffer +- * @gpu_addr: base gpu virtual address for the framebuffer ++ * @cpu_fb_addr: base cpu address for the framebuffer ++ * @cpu_inbox_addr: base cpu address for the gart ++ * @gpu_fb_addr: base gpu virtual address for the framebuffer ++ * @gpu_inbox_addr: base gpu virtual address for the gart + */ +-struct dmub_srv_fb_params { ++struct dmub_srv_memory_params { + const struct dmub_srv_region_info *region_info; +- void *cpu_addr; +- uint64_t gpu_addr; ++ void *cpu_fb_addr; ++ void *cpu_inbox_addr; ++ uint64_t gpu_fb_addr; ++ uint64_t gpu_inbox_addr; + }; + + /** +@@ -546,8 +552,8 @@ dmub_srv_calc_region_info(struct dmub_srv *dmub, + * DMUB_STATUS_OK - success + * DMUB_STATUS_INVALID - unspecified error + */ +-enum dmub_status dmub_srv_calc_fb_info(struct dmub_srv *dmub, +- const struct dmub_srv_fb_params *params, ++enum dmub_status dmub_srv_calc_mem_info(struct dmub_srv *dmub, ++ const struct dmub_srv_memory_params *params, + struct dmub_srv_fb_info *out); + + /** +diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +index 7afa78b918b58f..d58cb7f63a4b12 100644 +--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h ++++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +@@ -3301,6 +3301,16 @@ struct dmub_cmd_abm_set_pipe_data { + * TODO: Remove. + */ + uint8_t ramping_boundary; ++ ++ /** ++ * PwrSeq HW Instance. ++ */ ++ uint8_t pwrseq_inst; ++ ++ /** ++ * Explicit padding to 4 byte boundary. ++ */ ++ uint8_t pad[3]; + }; + + /** +@@ -3715,7 +3725,7 @@ enum dmub_cmd_panel_cntl_type { + * struct dmub_cmd_panel_cntl_data - Panel control data. + */ + struct dmub_cmd_panel_cntl_data { +- uint32_t inst; /**< panel instance */ ++ uint32_t pwrseq_inst; /**< pwrseq instance */ + uint32_t current_backlight; /* in/out */ + uint32_t bl_pwm_cntl; /* in/out */ + uint32_t bl_pwm_period_cntl; /* in/out */ +@@ -3742,7 +3752,7 @@ struct dmub_cmd_lvtma_control_data { + uint8_t uc_pwr_action; /**< LVTMA_ACTION */ + uint8_t bypass_panel_control_wait; + uint8_t reserved_0[2]; /**< For future use */ +- uint8_t panel_inst; /**< LVTMA control instance */ ++ uint8_t pwrseq_inst; /**< LVTMA control instance */ + uint8_t reserved_1[3]; /**< For future use */ + }; + +diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +index 93624ffe4eb824..6c45e216c709c2 100644 +--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c ++++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +@@ -386,7 +386,7 @@ dmub_srv_calc_region_info(struct dmub_srv *dmub, + uint32_t fw_state_size = DMUB_FW_STATE_SIZE; + uint32_t trace_buffer_size = DMUB_TRACE_BUFFER_SIZE; + uint32_t scratch_mem_size = DMUB_SCRATCH_MEM_SIZE; +- ++ uint32_t previous_top = 0; + if (!dmub->sw_init) + return DMUB_STATUS_INVALID; + +@@ -411,8 +411,15 @@ dmub_srv_calc_region_info(struct dmub_srv *dmub, + bios->base = dmub_align(stack->top, 256); + bios->top = bios->base + params->vbios_size; + +- mail->base = dmub_align(bios->top, 256); +- mail->top = mail->base + DMUB_MAILBOX_SIZE; ++ if (params->is_mailbox_in_inbox) { ++ mail->base = 0; ++ mail->top = mail->base + DMUB_MAILBOX_SIZE; ++ previous_top = bios->top; ++ } else { ++ mail->base = dmub_align(bios->top, 256); ++ mail->top = mail->base + DMUB_MAILBOX_SIZE; ++ previous_top = mail->top; ++ } + + fw_info = dmub_get_fw_meta_info(params); + +@@ -431,7 +438,7 @@ dmub_srv_calc_region_info(struct dmub_srv *dmub, + dmub->fw_version = fw_info->fw_version; + } + +- trace_buff->base = dmub_align(mail->top, 256); ++ trace_buff->base = dmub_align(previous_top, 256); + trace_buff->top = trace_buff->base + dmub_align(trace_buffer_size, 64); + + fw_state->base = dmub_align(trace_buff->top, 256); +@@ -442,11 +449,14 @@ dmub_srv_calc_region_info(struct dmub_srv *dmub, + + out->fb_size = dmub_align(scratch_mem->top, 4096); + ++ if (params->is_mailbox_in_inbox) ++ out->inbox_size = dmub_align(mail->top, 4096); ++ + return DMUB_STATUS_OK; + } + +-enum dmub_status dmub_srv_calc_fb_info(struct dmub_srv *dmub, +- const struct dmub_srv_fb_params *params, ++enum dmub_status dmub_srv_calc_mem_info(struct dmub_srv *dmub, ++ const struct dmub_srv_memory_params *params, + struct dmub_srv_fb_info *out) + { + uint8_t *cpu_base; +@@ -461,8 +471,8 @@ enum dmub_status dmub_srv_calc_fb_info(struct dmub_srv *dmub, + if (params->region_info->num_regions != DMUB_NUM_WINDOWS) + return DMUB_STATUS_INVALID; + +- cpu_base = (uint8_t *)params->cpu_addr; +- gpu_base = params->gpu_addr; ++ cpu_base = (uint8_t *)params->cpu_fb_addr; ++ gpu_base = params->gpu_fb_addr; + + for (i = 0; i < DMUB_NUM_WINDOWS; ++i) { + const struct dmub_region *reg = +@@ -470,6 +480,12 @@ enum dmub_status dmub_srv_calc_fb_info(struct dmub_srv *dmub, + + out->fb[i].cpu_addr = cpu_base + reg->base; + out->fb[i].gpu_addr = gpu_base + reg->base; ++ ++ if (i == DMUB_WINDOW_4_MAILBOX && params->cpu_inbox_addr != 0) { ++ out->fb[i].cpu_addr = (uint8_t *)params->cpu_inbox_addr + reg->base; ++ out->fb[i].gpu_addr = params->gpu_inbox_addr + reg->base; ++ } ++ + out->fb[i].size = reg->top - reg->base; + } + +@@ -658,9 +674,16 @@ enum dmub_status dmub_srv_sync_inbox1(struct dmub_srv *dmub) + return DMUB_STATUS_INVALID; + + if (dmub->hw_funcs.get_inbox1_rptr && dmub->hw_funcs.get_inbox1_wptr) { +- dmub->inbox1_rb.rptr = dmub->hw_funcs.get_inbox1_rptr(dmub); +- dmub->inbox1_rb.wrpt = dmub->hw_funcs.get_inbox1_wptr(dmub); +- dmub->inbox1_last_wptr = dmub->inbox1_rb.wrpt; ++ uint32_t rptr = dmub->hw_funcs.get_inbox1_rptr(dmub); ++ uint32_t wptr = dmub->hw_funcs.get_inbox1_wptr(dmub); ++ ++ if (rptr > dmub->inbox1_rb.capacity || wptr > dmub->inbox1_rb.capacity) { ++ return DMUB_STATUS_HW_FAILURE; ++ } else { ++ dmub->inbox1_rb.rptr = rptr; ++ dmub->inbox1_rb.wrpt = wptr; ++ dmub->inbox1_last_wptr = dmub->inbox1_rb.wrpt; ++ } + } + + return DMUB_STATUS_OK; +@@ -694,6 +717,11 @@ enum dmub_status dmub_srv_cmd_queue(struct dmub_srv *dmub, + if (!dmub->hw_init) + return DMUB_STATUS_INVALID; + ++ if (dmub->inbox1_rb.rptr > dmub->inbox1_rb.capacity || ++ dmub->inbox1_rb.wrpt > dmub->inbox1_rb.capacity) { ++ return DMUB_STATUS_HW_FAILURE; ++ } ++ + if (dmub_rb_push_front(&dmub->inbox1_rb, cmd)) + return DMUB_STATUS_OK; + +@@ -969,6 +997,7 @@ enum dmub_status dmub_srv_wait_for_inbox0_ack(struct dmub_srv *dmub, uint32_t ti + ack = dmub->hw_funcs.read_inbox0_ack_register(dmub); + if (ack) + return DMUB_STATUS_OK; ++ udelay(1); + } + return DMUB_STATUS_TIMEOUT; + } +diff --git a/drivers/gpu/drm/amd/display/include/dpcd_defs.h b/drivers/gpu/drm/amd/display/include/dpcd_defs.h +index 914f28e9f22426..aee5170f5fb231 100644 +--- a/drivers/gpu/drm/amd/display/include/dpcd_defs.h ++++ b/drivers/gpu/drm/amd/display/include/dpcd_defs.h +@@ -177,4 +177,9 @@ enum dpcd_psr_sink_states { + #define DP_SINK_PR_PIXEL_DEVIATION_PER_LINE 0x379 + #define DP_SINK_PR_MAX_NUMBER_OF_DEVIATION_LINE 0x37A + ++/* Remove once drm_dp_helper.h is updated upstream */ ++#ifndef DP_TOTAL_LTTPR_CNT ++#define DP_TOTAL_LTTPR_CNT 0xF000A /* 2.1 */ ++#endif ++ + #endif /* __DAL_DPCD_DEFS_H__ */ +diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +index bc96d021136080..813463ffe15c52 100644 +--- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h ++++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +@@ -417,6 +417,8 @@ struct integrated_info { + /* V2.1 */ + struct edp_info edp1_info; + struct edp_info edp2_info; ++ uint32_t gpuclk_ss_percentage; ++ uint32_t gpuclk_ss_type; + }; + + /* +diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +index ef3a674090211c..803586f4267af8 100644 +--- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c ++++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +@@ -133,7 +133,7 @@ unsigned int mod_freesync_calc_v_total_from_refresh( + + v_total = div64_u64(div64_u64(((unsigned long long)( + frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)), +- stream->timing.h_total), 1000000); ++ stream->timing.h_total) + 500000, 1000000); + + /* v_total cannot be less than nominal */ + if (v_total < stream->timing.v_total) { +diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c +index 1ddb4f5eac8e53..cee5e9e64ae711 100644 +--- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c ++++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c +@@ -432,18 +432,18 @@ static enum mod_hdcp_status authenticated_dp(struct mod_hdcp *hdcp, + goto out; + } + +- if (status == MOD_HDCP_STATUS_SUCCESS) +- mod_hdcp_execute_and_set(mod_hdcp_read_bstatus, +- &input->bstatus_read, &status, +- hdcp, "bstatus_read"); +- if (status == MOD_HDCP_STATUS_SUCCESS) +- mod_hdcp_execute_and_set(check_link_integrity_dp, +- &input->link_integrity_check, &status, +- hdcp, "link_integrity_check"); +- if (status == MOD_HDCP_STATUS_SUCCESS) +- mod_hdcp_execute_and_set(check_no_reauthentication_request_dp, +- &input->reauth_request_check, &status, +- hdcp, "reauth_request_check"); ++ mod_hdcp_execute_and_set(mod_hdcp_read_bstatus, ++ &input->bstatus_read, &status, ++ hdcp, "bstatus_read"); ++ ++ mod_hdcp_execute_and_set(check_link_integrity_dp, ++ &input->link_integrity_check, &status, ++ hdcp, "link_integrity_check"); ++ ++ mod_hdcp_execute_and_set(check_no_reauthentication_request_dp, ++ &input->reauth_request_check, &status, ++ hdcp, "reauth_request_check"); ++ + out: + return status; + } +diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c +index f7b5583ee609a5..1b2df97226a3f2 100644 +--- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c ++++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c +@@ -156,7 +156,16 @@ static enum mod_hdcp_status read(struct mod_hdcp *hdcp, + uint32_t cur_size = 0; + uint32_t data_offset = 0; + ++ if (msg_id == MOD_HDCP_MESSAGE_ID_INVALID || ++ msg_id >= MOD_HDCP_MESSAGE_ID_MAX) ++ return MOD_HDCP_STATUS_DDC_FAILURE; ++ + if (is_dp_hdcp(hdcp)) { ++ int num_dpcd_addrs = sizeof(hdcp_dpcd_addrs) / ++ sizeof(hdcp_dpcd_addrs[0]); ++ if (msg_id >= num_dpcd_addrs) ++ return MOD_HDCP_STATUS_DDC_FAILURE; ++ + while (buf_len > 0) { + cur_size = MIN(buf_len, HDCP_MAX_AUX_TRANSACTION_SIZE); + success = hdcp->config.ddc.funcs.read_dpcd(hdcp->config.ddc.handle, +@@ -171,6 +180,11 @@ static enum mod_hdcp_status read(struct mod_hdcp *hdcp, + data_offset += cur_size; + } + } else { ++ int num_i2c_offsets = sizeof(hdcp_i2c_offsets) / ++ sizeof(hdcp_i2c_offsets[0]); ++ if (msg_id >= num_i2c_offsets) ++ return MOD_HDCP_STATUS_DDC_FAILURE; ++ + success = hdcp->config.ddc.funcs.read_i2c( + hdcp->config.ddc.handle, + HDCP_I2C_ADDR, +@@ -215,7 +229,16 @@ static enum mod_hdcp_status write(struct mod_hdcp *hdcp, + uint32_t cur_size = 0; + uint32_t data_offset = 0; + ++ if (msg_id == MOD_HDCP_MESSAGE_ID_INVALID || ++ msg_id >= MOD_HDCP_MESSAGE_ID_MAX) ++ return MOD_HDCP_STATUS_DDC_FAILURE; ++ + if (is_dp_hdcp(hdcp)) { ++ int num_dpcd_addrs = sizeof(hdcp_dpcd_addrs) / ++ sizeof(hdcp_dpcd_addrs[0]); ++ if (msg_id >= num_dpcd_addrs) ++ return MOD_HDCP_STATUS_DDC_FAILURE; ++ + while (buf_len > 0) { + cur_size = MIN(buf_len, HDCP_MAX_AUX_TRANSACTION_SIZE); + success = hdcp->config.ddc.funcs.write_dpcd( +@@ -231,6 +254,11 @@ static enum mod_hdcp_status write(struct mod_hdcp *hdcp, + data_offset += cur_size; + } + } else { ++ int num_i2c_offsets = sizeof(hdcp_i2c_offsets) / ++ sizeof(hdcp_i2c_offsets[0]); ++ if (msg_id >= num_i2c_offsets) ++ return MOD_HDCP_STATUS_DDC_FAILURE; ++ + hdcp->buf[0] = hdcp_i2c_offsets[msg_id]; + memmove(&hdcp->buf[1], buf, buf_len); + success = hdcp->config.ddc.funcs.write_i2c( +diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c +index ee67a35c2a8edd..ff930a71e496a9 100644 +--- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c ++++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c +@@ -513,6 +513,9 @@ enum mod_hdcp_status mod_hdcp_hdcp2_create_session(struct mod_hdcp *hdcp) + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.context.mem_context.shared_buf; + memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); + ++ if (!display) ++ return MOD_HDCP_STATUS_DISPLAY_NOT_FOUND; ++ + hdcp_cmd->in_msg.hdcp2_create_session_v2.display_handle = display->index; + + if (hdcp->connection.link.adjust.hdcp2.force_type == MOD_HDCP_FORCE_TYPE_0) +diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_stats.h b/drivers/gpu/drm/amd/display/modules/inc/mod_stats.h +index 4220fd8fdd60ca..54cd86060f4d67 100644 +--- a/drivers/gpu/drm/amd/display/modules/inc/mod_stats.h ++++ b/drivers/gpu/drm/amd/display/modules/inc/mod_stats.h +@@ -57,10 +57,10 @@ void mod_stats_update_event(struct mod_stats *mod_stats, + unsigned int length); + + void mod_stats_update_flip(struct mod_stats *mod_stats, +- unsigned long timestamp_in_ns); ++ unsigned long long timestamp_in_ns); + + void mod_stats_update_vupdate(struct mod_stats *mod_stats, +- unsigned long timestamp_in_ns); ++ unsigned long long timestamp_in_ns); + + void mod_stats_update_freesync(struct mod_stats *mod_stats, + unsigned int v_total_min, +diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +index 73a2b37fbbd759..2b3d5183818aca 100644 +--- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c ++++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +@@ -839,6 +839,8 @@ bool is_psr_su_specific_panel(struct dc_link *link) + ((dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x08) || + (dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x07))) + isPSRSUSupported = false; ++ else if (dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x03) ++ isPSRSUSupported = false; + else if (dpcd_caps->psr_info.force_psrsu_cap == 0x1) + isPSRSUSupported = true; + } +diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h +index 67d7b7ee8a2a02..a9880fc5319550 100644 +--- a/drivers/gpu/drm/amd/include/amd_shared.h ++++ b/drivers/gpu/drm/amd/include/amd_shared.h +@@ -240,7 +240,6 @@ enum DC_FEATURE_MASK { + DC_DISABLE_LTTPR_DP2_0 = (1 << 6), //0x40, disabled by default + DC_PSR_ALLOW_SMU_OPT = (1 << 7), //0x80, disabled by default + DC_PSR_ALLOW_MULTI_DISP_OPT = (1 << 8), //0x100, disabled by default +- DC_REPLAY_MASK = (1 << 9), //0x200, disabled by default for dcn < 3.1.4 + }; + + enum DC_DEBUG_MASK { +@@ -251,7 +250,6 @@ enum DC_DEBUG_MASK { + DC_DISABLE_PSR = 0x10, + DC_FORCE_SUBVP_MCLK_SWITCH = 0x20, + DC_DISABLE_MPO = 0x40, +- DC_DISABLE_REPLAY = 0x50, + DC_ENABLE_DPIA_TRACE = 0x80, + }; + +@@ -297,6 +295,7 @@ struct amd_ip_funcs { + int (*hw_init)(void *handle); + int (*hw_fini)(void *handle); + void (*late_fini)(void *handle); ++ int (*prepare_suspend)(void *handle); + int (*suspend)(void *handle); + int (*resume)(void *handle); + bool (*is_idle)(void *handle); +diff --git a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_0_offset.h +index c92c4b83253f81..4bff1ef8a9a640 100644 +--- a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_0_offset.h ++++ b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_0_offset.h +@@ -6369,6 +6369,8 @@ + #define regTCP_INVALIDATE_BASE_IDX 1 + #define regTCP_STATUS 0x19a1 + #define regTCP_STATUS_BASE_IDX 1 ++#define regTCP_CNTL 0x19a2 ++#define regTCP_CNTL_BASE_IDX 1 + #define regTCP_CNTL2 0x19a3 + #define regTCP_CNTL2_BASE_IDX 1 + #define regTCP_DEBUG_INDEX 0x19a5 +diff --git a/drivers/gpu/drm/amd/include/atomfirmware.h b/drivers/gpu/drm/amd/include/atomfirmware.h +index fa7d6ced786f19..ccc79bdd4f5adf 100644 +--- a/drivers/gpu/drm/amd/include/atomfirmware.h ++++ b/drivers/gpu/drm/amd/include/atomfirmware.h +@@ -702,7 +702,7 @@ struct atom_gpio_pin_lut_v2_1 + { + struct atom_common_table_header table_header; + /*the real number of this included in the structure is calcualted by using the (whole structure size - the header size)/size of atom_gpio_pin_lut */ +- struct atom_gpio_pin_assignment gpio_pin[8]; ++ struct atom_gpio_pin_assignment gpio_pin[]; + }; + + +@@ -1006,7 +1006,7 @@ struct display_object_info_table_v1_4 + uint16_t supporteddevices; + uint8_t number_of_path; + uint8_t reserved; +- struct atom_display_object_path_v2 display_path[8]; //the real number of this included in the structure is calculated by using the (whole structure size - the header size- number_of_path)/size of atom_display_object_path ++ struct atom_display_object_path_v2 display_path[]; //the real number of this included in the structure is calculated by using the (whole structure size - the header size- number_of_path)/size of atom_display_object_path + }; + + struct display_object_info_table_v1_5 { +@@ -1016,7 +1016,7 @@ struct display_object_info_table_v1_5 { + uint8_t reserved; + // the real number of this included in the structure is calculated by using the + // (whole structure size - the header size- number_of_path)/size of atom_display_object_path +- struct atom_display_object_path_v3 display_path[8]; ++ struct atom_display_object_path_v3 display_path[]; + }; + + /* +@@ -1625,6 +1625,49 @@ struct atom_integrated_system_info_v2_2 + uint32_t reserved4[189]; + }; + ++struct uma_carveout_option { ++ char optionName[29]; //max length of string is 28chars + '\0'. Current design is for "minimum", "Medium", "High". This makes entire struct size 64bits ++ uint8_t memoryCarvedGb; //memory carved out with setting ++ uint8_t memoryRemainingGb; //memory remaining on system ++ union { ++ struct _flags { ++ uint8_t Auto : 1; ++ uint8_t Custom : 1; ++ uint8_t Reserved : 6; ++ } flags; ++ uint8_t all8; ++ } uma_carveout_option_flags; ++}; ++ ++struct atom_integrated_system_info_v2_3 { ++ struct atom_common_table_header table_header; ++ uint32_t vbios_misc; // enum of atom_system_vbiosmisc_def ++ uint32_t gpucapinfo; // enum of atom_system_gpucapinf_def ++ uint32_t system_config; ++ uint32_t cpucapinfo; ++ uint16_t gpuclk_ss_percentage; // unit of 0.001%, 1000 mean 1% ++ uint16_t gpuclk_ss_type; ++ uint16_t dpphy_override; // bit vector, enum of atom_sysinfo_dpphy_override_def ++ uint8_t memorytype; // enum of atom_dmi_t17_mem_type_def, APU memory type indication. ++ uint8_t umachannelnumber; // number of memory channels ++ uint8_t htc_hyst_limit; ++ uint8_t htc_tmp_limit; ++ uint8_t reserved1; // dp_ss_control ++ uint8_t gpu_package_id; ++ struct edp_info_table edp1_info; ++ struct edp_info_table edp2_info; ++ uint32_t reserved2[8]; ++ struct atom_external_display_connection_info extdispconninfo; ++ uint8_t UMACarveoutVersion; ++ uint8_t UMACarveoutIndexMax; ++ uint8_t UMACarveoutTypeDefault; ++ uint8_t UMACarveoutIndexDefault; ++ uint8_t UMACarveoutType; //Auto or Custom ++ uint8_t UMACarveoutIndex; ++ struct uma_carveout_option UMASizeControlOption[20]; ++ uint8_t reserved3[110]; ++}; ++ + // system_config + enum atom_system_vbiosmisc_def{ + INTEGRATED_SYSTEM_INFO__GET_EDID_CALLBACK_FUNC_SUPPORT = 0x01, +@@ -3508,7 +3551,7 @@ struct atom_gpio_voltage_object_v4 + uint8_t phase_delay_us; // phase delay in unit of micro second + uint8_t reserved; + uint32_t gpio_mask_val; // GPIO Mask value +- struct atom_voltage_gpio_map_lut voltage_gpio_lut[1]; ++ struct atom_voltage_gpio_map_lut voltage_gpio_lut[] __counted_by(gpio_entry_num); + }; + + struct atom_svid2_voltage_object_v4 +diff --git a/drivers/gpu/drm/amd/include/mes_v11_api_def.h b/drivers/gpu/drm/amd/include/mes_v11_api_def.h +index b1db2b19018742..e07e93167a82c2 100644 +--- a/drivers/gpu/drm/amd/include/mes_v11_api_def.h ++++ b/drivers/gpu/drm/amd/include/mes_v11_api_def.h +@@ -571,7 +571,8 @@ struct SET_SHADER_DEBUGGER { + struct { + uint32_t single_memop : 1; /* SQ_DEBUG.single_memop */ + uint32_t single_alu_op : 1; /* SQ_DEBUG.single_alu_op */ +- uint32_t reserved : 30; ++ uint32_t reserved : 29; ++ uint32_t process_ctx_flush : 1; + }; + uint32_t u32all; + } flags; +diff --git a/drivers/gpu/drm/amd/include/pptable.h b/drivers/gpu/drm/amd/include/pptable.h +index 0b6a057e0a4c48..5aac8d545bdc6d 100644 +--- a/drivers/gpu/drm/amd/include/pptable.h ++++ b/drivers/gpu/drm/amd/include/pptable.h +@@ -78,7 +78,7 @@ typedef struct _ATOM_PPLIB_THERMALCONTROLLER + typedef struct _ATOM_PPLIB_STATE + { + UCHAR ucNonClockStateIndex; +- UCHAR ucClockStateIndices[1]; // variable-sized ++ UCHAR ucClockStateIndices[]; // variable-sized + } ATOM_PPLIB_STATE; + + +@@ -473,7 +473,7 @@ typedef struct _ATOM_PPLIB_STATE_V2 + /** + * Driver will read the first ucNumDPMLevels in this array + */ +- UCHAR clockInfoIndex[1]; ++ UCHAR clockInfoIndex[]; + } ATOM_PPLIB_STATE_V2; + + typedef struct _StateArray{ +diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c +index 8bb2da13826f16..babb73147adfb3 100644 +--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c ++++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c +@@ -734,7 +734,7 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, + if (adev->in_suspend && !adev->in_runpm) + return -EPERM; + +- if (count > 127) ++ if (count > 127 || count == 0) + return -EINVAL; + + if (*buf == 's') +@@ -754,7 +754,8 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, + else + return -EINVAL; + +- memcpy(buf_cpy, buf, count+1); ++ memcpy(buf_cpy, buf, count); ++ buf_cpy[count] = 0; + + tmp_str = buf_cpy; + +@@ -771,6 +772,9 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, + return -EINVAL; + parameter_size++; + ++ if (!tmp_str) ++ break; ++ + while (isspace(*tmp_str)) + tmp_str++; + } +@@ -1467,9 +1471,9 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev, + return -EINVAL; + } + +-static unsigned int amdgpu_hwmon_get_sensor_generic(struct amdgpu_device *adev, +- enum amd_pp_sensors sensor, +- void *query) ++static int amdgpu_hwmon_get_sensor_generic(struct amdgpu_device *adev, ++ enum amd_pp_sensors sensor, ++ void *query) + { + int r, size = sizeof(uint32_t); + +@@ -2391,6 +2395,7 @@ static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev, + { + struct amdgpu_device *adev = dev_get_drvdata(dev); + int err, ret; ++ u32 pwm_mode; + int value; + + if (amdgpu_in_reset(adev)) +@@ -2402,13 +2407,22 @@ static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev, + if (err) + return err; + ++ if (value == 0) ++ pwm_mode = AMD_FAN_CTRL_NONE; ++ else if (value == 1) ++ pwm_mode = AMD_FAN_CTRL_MANUAL; ++ else if (value == 2) ++ pwm_mode = AMD_FAN_CTRL_AUTO; ++ else ++ return -EINVAL; ++ + ret = pm_runtime_get_sync(adev_to_drm(adev)->dev); + if (ret < 0) { + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + return ret; + } + +- ret = amdgpu_dpm_set_fan_control_mode(adev, value); ++ ret = amdgpu_dpm_set_fan_control_mode(adev, pwm_mode); + + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); +@@ -2773,8 +2787,8 @@ static ssize_t amdgpu_hwmon_show_vddnb_label(struct device *dev, + return sysfs_emit(buf, "vddnb\n"); + } + +-static unsigned int amdgpu_hwmon_get_power(struct device *dev, +- enum amd_pp_sensors sensor) ++static int amdgpu_hwmon_get_power(struct device *dev, ++ enum amd_pp_sensors sensor) + { + struct amdgpu_device *adev = dev_get_drvdata(dev); + unsigned int uw; +@@ -2795,7 +2809,7 @@ static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- unsigned int val; ++ int val; + + val = amdgpu_hwmon_get_power(dev, AMDGPU_PP_SENSOR_GPU_AVG_POWER); + if (val < 0) +@@ -2808,7 +2822,7 @@ static ssize_t amdgpu_hwmon_show_power_input(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- unsigned int val; ++ int val; + + val = amdgpu_hwmon_get_power(dev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER); + if (val < 0) +diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c +index 5d28c951a31972..c8586cb7d0fec5 100644 +--- a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c ++++ b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c +@@ -164,6 +164,8 @@ static void sumo_construct_vid_mapping_table(struct amdgpu_device *adev, + + for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) { + if (table[i].ulSupportedSCLK != 0) { ++ if (table[i].usVoltageIndex >= SUMO_MAX_NUMBER_VOLTAGES) ++ continue; + vid_mapping_table->entries[table[i].usVoltageIndex].vid_7bit = + table[i].usVoltageID; + vid_mapping_table->entries[table[i].usVoltageIndex].vid_2bit = +@@ -2735,10 +2737,8 @@ static int kv_parse_power_table(struct amdgpu_device *adev) + non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) + &non_clock_info_array->nonClockInfo[non_clock_array_index]; + ps = kzalloc(sizeof(struct kv_ps), GFP_KERNEL); +- if (ps == NULL) { +- kfree(adev->pm.dpm.ps); ++ if (ps == NULL) + return -ENOMEM; +- } + adev->pm.dpm.ps[i].ps_priv = ps; + k = 0; + idx = (u8 *)&power_state->v2.clockInfoIndex[0]; +diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c +index 81fb4e5dd804bd..60377747bab4fc 100644 +--- a/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c ++++ b/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c +@@ -272,10 +272,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) + le16_to_cpu(power_info->pplib4.usVddcDependencyOnSCLKOffset)); + ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_sclk, + dep_table); +- if (ret) { +- amdgpu_free_extended_power_table(adev); ++ if (ret) + return ret; +- } + } + if (power_info->pplib4.usVddciDependencyOnMCLKOffset) { + dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) +@@ -283,10 +281,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) + le16_to_cpu(power_info->pplib4.usVddciDependencyOnMCLKOffset)); + ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddci_dependency_on_mclk, + dep_table); +- if (ret) { +- amdgpu_free_extended_power_table(adev); ++ if (ret) + return ret; +- } + } + if (power_info->pplib4.usVddcDependencyOnMCLKOffset) { + dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) +@@ -294,10 +290,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) + le16_to_cpu(power_info->pplib4.usVddcDependencyOnMCLKOffset)); + ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_mclk, + dep_table); +- if (ret) { +- amdgpu_free_extended_power_table(adev); ++ if (ret) + return ret; +- } + } + if (power_info->pplib4.usMvddDependencyOnMCLKOffset) { + dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) +@@ -305,10 +299,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) + le16_to_cpu(power_info->pplib4.usMvddDependencyOnMCLKOffset)); + ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk, + dep_table); +- if (ret) { +- amdgpu_free_extended_power_table(adev); ++ if (ret) + return ret; +- } + } + if (power_info->pplib4.usMaxClockVoltageOnDCOffset) { + ATOM_PPLIB_Clock_Voltage_Limit_Table *clk_v = +@@ -339,10 +331,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) + kcalloc(psl->ucNumEntries, + sizeof(struct amdgpu_phase_shedding_limits_entry), + GFP_KERNEL); +- if (!adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries) { +- amdgpu_free_extended_power_table(adev); ++ if (!adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries) + return -ENOMEM; +- } + + entry = &psl->entries[0]; + for (i = 0; i < psl->ucNumEntries; i++) { +@@ -383,10 +373,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) + ATOM_PPLIB_CAC_Leakage_Record *entry; + u32 size = cac_table->ucNumEntries * sizeof(struct amdgpu_cac_leakage_table); + adev->pm.dpm.dyn_state.cac_leakage_table.entries = kzalloc(size, GFP_KERNEL); +- if (!adev->pm.dpm.dyn_state.cac_leakage_table.entries) { +- amdgpu_free_extended_power_table(adev); ++ if (!adev->pm.dpm.dyn_state.cac_leakage_table.entries) + return -ENOMEM; +- } + entry = &cac_table->entries[0]; + for (i = 0; i < cac_table->ucNumEntries; i++) { + if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) { +@@ -438,10 +426,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) + sizeof(struct amdgpu_vce_clock_voltage_dependency_entry); + adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries = + kzalloc(size, GFP_KERNEL); +- if (!adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries) { +- amdgpu_free_extended_power_table(adev); ++ if (!adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries) + return -ENOMEM; +- } + adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count = + limits->numEntries; + entry = &limits->entries[0]; +@@ -493,10 +479,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) + sizeof(struct amdgpu_uvd_clock_voltage_dependency_entry); + adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries = + kzalloc(size, GFP_KERNEL); +- if (!adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries) { +- amdgpu_free_extended_power_table(adev); ++ if (!adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries) + return -ENOMEM; +- } + adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count = + limits->numEntries; + entry = &limits->entries[0]; +@@ -525,10 +509,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) + sizeof(struct amdgpu_clock_voltage_dependency_entry); + adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries = + kzalloc(size, GFP_KERNEL); +- if (!adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries) { +- amdgpu_free_extended_power_table(adev); ++ if (!adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries) + return -ENOMEM; +- } + adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count = + limits->numEntries; + entry = &limits->entries[0]; +@@ -548,10 +530,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) + le16_to_cpu(ext_hdr->usPPMTableOffset)); + adev->pm.dpm.dyn_state.ppm_table = + kzalloc(sizeof(struct amdgpu_ppm_table), GFP_KERNEL); +- if (!adev->pm.dpm.dyn_state.ppm_table) { +- amdgpu_free_extended_power_table(adev); ++ if (!adev->pm.dpm.dyn_state.ppm_table) + return -ENOMEM; +- } + adev->pm.dpm.dyn_state.ppm_table->ppm_design = ppm->ucPpmDesign; + adev->pm.dpm.dyn_state.ppm_table->cpu_core_number = + le16_to_cpu(ppm->usCpuCoreNumber); +@@ -583,10 +563,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) + sizeof(struct amdgpu_clock_voltage_dependency_entry); + adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries = + kzalloc(size, GFP_KERNEL); +- if (!adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries) { +- amdgpu_free_extended_power_table(adev); ++ if (!adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries) + return -ENOMEM; +- } + adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count = + limits->numEntries; + entry = &limits->entries[0]; +@@ -606,10 +584,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) + ATOM_PowerTune_Table *pt; + adev->pm.dpm.dyn_state.cac_tdp_table = + kzalloc(sizeof(struct amdgpu_cac_tdp_table), GFP_KERNEL); +- if (!adev->pm.dpm.dyn_state.cac_tdp_table) { +- amdgpu_free_extended_power_table(adev); ++ if (!adev->pm.dpm.dyn_state.cac_tdp_table) + return -ENOMEM; +- } + if (rev > 0) { + ATOM_PPLIB_POWERTUNE_Table_V1 *ppt = (ATOM_PPLIB_POWERTUNE_Table_V1 *) + (mode_info->atom_context->bios + data_offset + +@@ -645,10 +621,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) + ret = amdgpu_parse_clk_voltage_dep_table( + &adev->pm.dpm.dyn_state.vddgfx_dependency_on_sclk, + dep_table); +- if (ret) { +- kfree(adev->pm.dpm.dyn_state.vddgfx_dependency_on_sclk.entries); ++ if (ret) + return ret; +- } + } + } + +diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c +index 02e69ccff3bac4..99dde52a429013 100644 +--- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c ++++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c +@@ -6925,6 +6925,23 @@ static int si_dpm_enable(struct amdgpu_device *adev) + return 0; + } + ++static int si_set_temperature_range(struct amdgpu_device *adev) ++{ ++ int ret; ++ ++ ret = si_thermal_enable_alert(adev, false); ++ if (ret) ++ return ret; ++ ret = si_thermal_set_temperature_range(adev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); ++ if (ret) ++ return ret; ++ ret = si_thermal_enable_alert(adev, true); ++ if (ret) ++ return ret; ++ ++ return ret; ++} ++ + static void si_dpm_disable(struct amdgpu_device *adev) + { + struct rv7xx_power_info *pi = rv770_get_pi(adev); +@@ -7379,10 +7396,9 @@ static int si_dpm_init(struct amdgpu_device *adev) + kcalloc(4, + sizeof(struct amdgpu_clock_voltage_dependency_entry), + GFP_KERNEL); +- if (!adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) { +- amdgpu_free_extended_power_table(adev); ++ if (!adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) + return -ENOMEM; +- } ++ + adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count = 4; + adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].clk = 0; + adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].v = 0; +@@ -7609,6 +7625,18 @@ static int si_dpm_process_interrupt(struct amdgpu_device *adev, + + static int si_dpm_late_init(void *handle) + { ++ int ret; ++ struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ ++ if (!adev->pm.dpm_enabled) ++ return 0; ++ ++ ret = si_set_temperature_range(adev); ++ if (ret) ++ return ret; ++#if 0 //TODO ? ++ si_dpm_powergate_uvd(adev, true); ++#endif + return 0; + } + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +index 9e4f8a4104a346..86f95a291d65f6 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +@@ -99,7 +99,7 @@ static void pp_swctf_delayed_work_handler(struct work_struct *work) + struct amdgpu_device *adev = hwmgr->adev; + struct amdgpu_dpm_thermal *range = + &adev->pm.dpm.thermal; +- uint32_t gpu_temperature, size; ++ uint32_t gpu_temperature, size = sizeof(gpu_temperature); + int ret; + + /* +@@ -927,7 +927,7 @@ static int pp_dpm_switch_power_profile(void *handle, + enum PP_SMC_POWER_PROFILE type, bool en) + { + struct pp_hwmgr *hwmgr = handle; +- long workload; ++ long workload[1]; + uint32_t index; + + if (!hwmgr || !hwmgr->pm_en) +@@ -945,12 +945,12 @@ static int pp_dpm_switch_power_profile(void *handle, + hwmgr->workload_mask &= ~(1 << hwmgr->workload_prority[type]); + index = fls(hwmgr->workload_mask); + index = index > 0 && index <= Workload_Policy_Max ? index - 1 : 0; +- workload = hwmgr->workload_setting[index]; ++ workload[0] = hwmgr->workload_setting[index]; + } else { + hwmgr->workload_mask |= (1 << hwmgr->workload_prority[type]); + index = fls(hwmgr->workload_mask); + index = index <= Workload_Policy_Max ? index - 1 : 0; +- workload = hwmgr->workload_setting[index]; ++ workload[0] = hwmgr->workload_setting[index]; + } + + if (type == PP_SMC_POWER_PROFILE_COMPUTE && +@@ -960,7 +960,7 @@ static int pp_dpm_switch_power_profile(void *handle, + } + + if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) +- hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, &workload, 0); ++ hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, workload, 0); + + return 0; + } +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c +index 1d829402cd2e23..18f00038d8441c 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c +@@ -30,9 +30,8 @@ int psm_init_power_state_table(struct pp_hwmgr *hwmgr) + { + int result; + unsigned int i; +- unsigned int table_entries; + struct pp_power_state *state; +- int size; ++ int size, table_entries; + + if (hwmgr->hwmgr_func->get_num_of_pp_table_entries == NULL) + return 0; +@@ -40,15 +39,19 @@ int psm_init_power_state_table(struct pp_hwmgr *hwmgr) + if (hwmgr->hwmgr_func->get_power_state_size == NULL) + return 0; + +- hwmgr->num_ps = table_entries = hwmgr->hwmgr_func->get_num_of_pp_table_entries(hwmgr); ++ table_entries = hwmgr->hwmgr_func->get_num_of_pp_table_entries(hwmgr); + +- hwmgr->ps_size = size = hwmgr->hwmgr_func->get_power_state_size(hwmgr) + ++ size = hwmgr->hwmgr_func->get_power_state_size(hwmgr) + + sizeof(struct pp_power_state); + +- if (table_entries == 0 || size == 0) { ++ if (table_entries <= 0 || size == 0) { + pr_warn("Please check whether power state management is supported on this asic\n"); ++ hwmgr->num_ps = 0; ++ hwmgr->ps_size = 0; + return 0; + } ++ hwmgr->num_ps = table_entries; ++ hwmgr->ps_size = size; + + hwmgr->ps = kcalloc(table_entries, size, GFP_KERNEL); + if (hwmgr->ps == NULL) +@@ -269,7 +272,7 @@ int psm_adjust_power_state_dynamic(struct pp_hwmgr *hwmgr, bool skip_display_set + struct pp_power_state *new_ps) + { + uint32_t index; +- long workload; ++ long workload[1]; + + if (hwmgr->not_vf) { + if (!skip_display_settings) +@@ -294,10 +297,10 @@ int psm_adjust_power_state_dynamic(struct pp_hwmgr *hwmgr, bool skip_display_set + if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) { + index = fls(hwmgr->workload_mask); + index = index > 0 && index <= Workload_Policy_Max ? index - 1 : 0; +- workload = hwmgr->workload_setting[index]; ++ workload[0] = hwmgr->workload_setting[index]; + +- if (hwmgr->power_profile_mode != workload && hwmgr->hwmgr_func->set_power_profile_mode) +- hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, &workload, 0); ++ if (hwmgr->power_profile_mode != workload[0] && hwmgr->hwmgr_func->set_power_profile_mode) ++ hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, workload, 0); + } + + return 0; +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c +index f503e61faa6008..cc3b62f7339417 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c +@@ -73,8 +73,9 @@ static int atomctrl_retrieve_ac_timing( + j++; + } else if ((table->mc_reg_address[i].uc_pre_reg_data & + LOW_NIBBLE_MASK) == DATA_EQU_PREV) { +- table->mc_reg_table_entry[num_ranges].mc_data[i] = +- table->mc_reg_table_entry[num_ranges].mc_data[i-1]; ++ if (i) ++ table->mc_reg_table_entry[num_ranges].mc_data[i] = ++ table->mc_reg_table_entry[num_ranges].mc_data[i-1]; + } + } + num_ranges++; +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pptable_v1_0.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pptable_v1_0.h +index 7a31cfa5e7fb4d..9fcad69a9f3446 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pptable_v1_0.h ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pptable_v1_0.h +@@ -164,7 +164,7 @@ typedef struct _ATOM_Tonga_State { + typedef struct _ATOM_Tonga_State_Array { + UCHAR ucRevId; + UCHAR ucNumEntries; /* Number of entries. */ +- ATOM_Tonga_State entries[1]; /* Dynamically allocate entries. */ ++ ATOM_Tonga_State entries[]; /* Dynamically allocate entries. */ + } ATOM_Tonga_State_Array; + + typedef struct _ATOM_Tonga_MCLK_Dependency_Record { +@@ -179,7 +179,7 @@ typedef struct _ATOM_Tonga_MCLK_Dependency_Record { + typedef struct _ATOM_Tonga_MCLK_Dependency_Table { + UCHAR ucRevId; + UCHAR ucNumEntries; /* Number of entries. */ +- ATOM_Tonga_MCLK_Dependency_Record entries[1]; /* Dynamically allocate entries. */ ++ ATOM_Tonga_MCLK_Dependency_Record entries[]; /* Dynamically allocate entries. */ + } ATOM_Tonga_MCLK_Dependency_Table; + + typedef struct _ATOM_Tonga_SCLK_Dependency_Record { +@@ -194,7 +194,7 @@ typedef struct _ATOM_Tonga_SCLK_Dependency_Record { + typedef struct _ATOM_Tonga_SCLK_Dependency_Table { + UCHAR ucRevId; + UCHAR ucNumEntries; /* Number of entries. */ +- ATOM_Tonga_SCLK_Dependency_Record entries[1]; /* Dynamically allocate entries. */ ++ ATOM_Tonga_SCLK_Dependency_Record entries[]; /* Dynamically allocate entries. */ + } ATOM_Tonga_SCLK_Dependency_Table; + + typedef struct _ATOM_Polaris_SCLK_Dependency_Record { +@@ -210,7 +210,7 @@ typedef struct _ATOM_Polaris_SCLK_Dependency_Record { + typedef struct _ATOM_Polaris_SCLK_Dependency_Table { + UCHAR ucRevId; + UCHAR ucNumEntries; /* Number of entries. */ +- ATOM_Polaris_SCLK_Dependency_Record entries[1]; /* Dynamically allocate entries. */ ++ ATOM_Polaris_SCLK_Dependency_Record entries[]; /* Dynamically allocate entries. */ + } ATOM_Polaris_SCLK_Dependency_Table; + + typedef struct _ATOM_Tonga_PCIE_Record { +@@ -222,7 +222,7 @@ typedef struct _ATOM_Tonga_PCIE_Record { + typedef struct _ATOM_Tonga_PCIE_Table { + UCHAR ucRevId; + UCHAR ucNumEntries; /* Number of entries. */ +- ATOM_Tonga_PCIE_Record entries[1]; /* Dynamically allocate entries. */ ++ ATOM_Tonga_PCIE_Record entries[]; /* Dynamically allocate entries. */ + } ATOM_Tonga_PCIE_Table; + + typedef struct _ATOM_Polaris10_PCIE_Record { +@@ -235,7 +235,7 @@ typedef struct _ATOM_Polaris10_PCIE_Record { + typedef struct _ATOM_Polaris10_PCIE_Table { + UCHAR ucRevId; + UCHAR ucNumEntries; /* Number of entries. */ +- ATOM_Polaris10_PCIE_Record entries[1]; /* Dynamically allocate entries. */ ++ ATOM_Polaris10_PCIE_Record entries[]; /* Dynamically allocate entries. */ + } ATOM_Polaris10_PCIE_Table; + + +@@ -252,7 +252,7 @@ typedef struct _ATOM_Tonga_MM_Dependency_Record { + typedef struct _ATOM_Tonga_MM_Dependency_Table { + UCHAR ucRevId; + UCHAR ucNumEntries; /* Number of entries. */ +- ATOM_Tonga_MM_Dependency_Record entries[1]; /* Dynamically allocate entries. */ ++ ATOM_Tonga_MM_Dependency_Record entries[]; /* Dynamically allocate entries. */ + } ATOM_Tonga_MM_Dependency_Table; + + typedef struct _ATOM_Tonga_Voltage_Lookup_Record { +@@ -265,7 +265,7 @@ typedef struct _ATOM_Tonga_Voltage_Lookup_Record { + typedef struct _ATOM_Tonga_Voltage_Lookup_Table { + UCHAR ucRevId; + UCHAR ucNumEntries; /* Number of entries. */ +- ATOM_Tonga_Voltage_Lookup_Record entries[1]; /* Dynamically allocate entries. */ ++ ATOM_Tonga_Voltage_Lookup_Record entries[]; /* Dynamically allocate entries. */ + } ATOM_Tonga_Voltage_Lookup_Table; + + typedef struct _ATOM_Tonga_Fan_Table { +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c +index f2a55c1413f597..17882f8dfdd34f 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c +@@ -200,7 +200,7 @@ static int get_platform_power_management_table( + struct pp_hwmgr *hwmgr, + ATOM_Tonga_PPM_Table *atom_ppm_table) + { +- struct phm_ppm_table *ptr = kzalloc(sizeof(ATOM_Tonga_PPM_Table), GFP_KERNEL); ++ struct phm_ppm_table *ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); + struct phm_ppt_v1_information *pp_table_information = + (struct phm_ppt_v1_information *)(hwmgr->pptable); + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c +index 5794b64507bf94..56a22575258064 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c +@@ -1185,6 +1185,8 @@ static int init_overdrive_limits(struct pp_hwmgr *hwmgr, + fw_info = smu_atom_get_data_table(hwmgr->adev, + GetIndexIntoMasterTable(DATA, FirmwareInfo), + &size, &frev, &crev); ++ PP_ASSERT_WITH_CODE(fw_info != NULL, ++ "Missing firmware info!", return -EINVAL); + + if ((fw_info->ucTableFormatRevision == 1) + && (le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V1_4))) +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c +index 02ba68d7c6546b..f62381b189ade9 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c +@@ -1036,7 +1036,9 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr, + + switch (type) { + case PP_SCLK: +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetGfxclkFrequency, &now); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetGfxclkFrequency, &now); ++ if (ret) ++ return ret; + + /* driver only know min/max gfx_clk, Add level 1 for all other gfx clks */ + if (now == data->gfx_max_freq_limit/100) +@@ -1057,7 +1059,9 @@ static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr, + i == 2 ? "*" : ""); + break; + case PP_MCLK: +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetFclkFrequency, &now); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetFclkFrequency, &now); ++ if (ret) ++ return ret; + + for (i = 0; i < mclk_table->count; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", +@@ -1550,7 +1554,10 @@ static int smu10_set_fine_grain_clk_vol(struct pp_hwmgr *hwmgr, + } + + if (input[0] == 0) { +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &min_freq); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &min_freq); ++ if (ret) ++ return ret; ++ + if (input[1] < min_freq) { + pr_err("Fine grain setting minimum sclk (%ld) MHz is less than the minimum allowed (%d) MHz\n", + input[1], min_freq); +@@ -1558,7 +1565,10 @@ static int smu10_set_fine_grain_clk_vol(struct pp_hwmgr *hwmgr, + } + smu10_data->gfx_actual_soft_min_freq = input[1]; + } else if (input[0] == 1) { +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &max_freq); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &max_freq); ++ if (ret) ++ return ret; ++ + if (input[1] > max_freq) { + pr_err("Fine grain setting maximum sclk (%ld) MHz is greater than the maximum allowed (%d) MHz\n", + input[1], max_freq); +@@ -1573,10 +1583,15 @@ static int smu10_set_fine_grain_clk_vol(struct pp_hwmgr *hwmgr, + pr_err("Input parameter number not correct\n"); + return -EINVAL; + } +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &min_freq); +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &max_freq); +- ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency, &min_freq); ++ if (ret) ++ return ret; + smu10_data->gfx_actual_soft_min_freq = min_freq; ++ ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency, &max_freq); ++ if (ret) ++ return ret; ++ + smu10_data->gfx_actual_soft_max_freq = max_freq; + } else if (type == PP_OD_COMMIT_DPM_TABLE) { + if (size != 0) { +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +index 5a2371484a58c5..53849fd3615f68 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +@@ -1823,9 +1823,7 @@ static void smu7_init_dpm_defaults(struct pp_hwmgr *hwmgr) + + data->mclk_dpm_key_disabled = hwmgr->feature_mask & PP_MCLK_DPM_MASK ? false : true; + data->sclk_dpm_key_disabled = hwmgr->feature_mask & PP_SCLK_DPM_MASK ? false : true; +- data->pcie_dpm_key_disabled = +- !amdgpu_device_pcie_dynamic_switching_supported() || +- !(hwmgr->feature_mask & PP_PCIE_DPM_MASK); ++ data->pcie_dpm_key_disabled = !(hwmgr->feature_mask & PP_PCIE_DPM_MASK); + /* need to set voltage control types before EVV patching */ + data->voltage_control = SMU7_VOLTAGE_CONTROL_NONE; + data->vddci_control = SMU7_VOLTAGE_CONTROL_NONE; +@@ -2959,6 +2957,7 @@ static int smu7_update_edc_leakage_table(struct pp_hwmgr *hwmgr) + + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + { ++ struct amdgpu_device *adev = hwmgr->adev; + struct smu7_hwmgr *data; + int result = 0; + +@@ -2976,6 +2975,8 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + result = smu7_get_evv_voltages(hwmgr); + if (result) { + pr_info("Get EVV Voltage Failed. Abort Driver loading!\n"); ++ kfree(hwmgr->backend); ++ hwmgr->backend = NULL; + return -EINVAL; + } + } else { +@@ -2993,38 +2994,37 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + /* Initalize Dynamic State Adjustment Rule Settings */ + result = phm_initializa_dynamic_state_adjustment_rule_settings(hwmgr); + +- if (0 == result) { +- struct amdgpu_device *adev = hwmgr->adev; ++ if (result) ++ goto fail; + +- data->is_tlu_enabled = false; ++ data->is_tlu_enabled = false; + +- hwmgr->platform_descriptor.hardwareActivityPerformanceLevels = ++ hwmgr->platform_descriptor.hardwareActivityPerformanceLevels = + SMU7_MAX_HARDWARE_POWERLEVELS; +- hwmgr->platform_descriptor.hardwarePerformanceLevels = 2; +- hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50; ++ hwmgr->platform_descriptor.hardwarePerformanceLevels = 2; ++ hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50; + +- data->pcie_gen_cap = adev->pm.pcie_gen_mask; +- if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) +- data->pcie_spc_cap = 20; +- else +- data->pcie_spc_cap = 16; +- data->pcie_lane_cap = adev->pm.pcie_mlw_mask; +- +- hwmgr->platform_descriptor.vbiosInterruptId = 0x20000400; /* IRQ_SOURCE1_SW_INT */ +-/* The true clock step depends on the frequency, typically 4.5 or 9 MHz. Here we use 5. */ +- hwmgr->platform_descriptor.clockStep.engineClock = 500; +- hwmgr->platform_descriptor.clockStep.memoryClock = 500; +- smu7_thermal_parameter_init(hwmgr); +- } else { +- /* Ignore return value in here, we are cleaning up a mess. */ +- smu7_hwmgr_backend_fini(hwmgr); +- } ++ data->pcie_gen_cap = adev->pm.pcie_gen_mask; ++ if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) ++ data->pcie_spc_cap = 20; ++ else ++ data->pcie_spc_cap = 16; ++ data->pcie_lane_cap = adev->pm.pcie_mlw_mask; ++ ++ hwmgr->platform_descriptor.vbiosInterruptId = 0x20000400; /* IRQ_SOURCE1_SW_INT */ ++ /* The true clock step depends on the frequency, typically 4.5 or 9 MHz. Here we use 5. */ ++ hwmgr->platform_descriptor.clockStep.engineClock = 500; ++ hwmgr->platform_descriptor.clockStep.memoryClock = 500; ++ smu7_thermal_parameter_init(hwmgr); + + result = smu7_update_edc_leakage_table(hwmgr); + if (result) +- return result; ++ goto fail; + + return 0; ++fail: ++ smu7_hwmgr_backend_fini(hwmgr); ++ return result; + } + + static int smu7_force_dpm_highest(struct pp_hwmgr *hwmgr) +@@ -3314,8 +3314,7 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, + const struct pp_power_state *current_ps) + { + struct amdgpu_device *adev = hwmgr->adev; +- struct smu7_power_state *smu7_ps = +- cast_phw_smu7_power_state(&request_ps->hardware); ++ struct smu7_power_state *smu7_ps; + uint32_t sclk; + uint32_t mclk; + struct PP_Clocks minimum_clocks = {0}; +@@ -3332,6 +3331,10 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, + uint32_t latency; + bool latency_allowed = false; + ++ smu7_ps = cast_phw_smu7_power_state(&request_ps->hardware); ++ if (!smu7_ps) ++ return -EINVAL; ++ + data->battery_state = (PP_StateUILabel_Battery == + request_ps->classification.ui_label); + data->mclk_ignore_signal = false; +@@ -3997,6 +4000,7 @@ static int smu7_read_sensor(struct pp_hwmgr *hwmgr, int idx, + uint32_t sclk, mclk, activity_percent; + uint32_t offset, val_vid; + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); ++ struct amdgpu_device *adev = hwmgr->adev; + + /* size must be at least 4 bytes for all sensors */ + if (*size < 4) +@@ -4040,7 +4044,21 @@ static int smu7_read_sensor(struct pp_hwmgr *hwmgr, int idx, + *size = 4; + return 0; + case AMDGPU_PP_SENSOR_GPU_INPUT_POWER: +- return smu7_get_gpu_power(hwmgr, (uint32_t *)value); ++ if ((adev->asic_type != CHIP_HAWAII) && ++ (adev->asic_type != CHIP_BONAIRE) && ++ (adev->asic_type != CHIP_FIJI) && ++ (adev->asic_type != CHIP_TONGA)) ++ return smu7_get_gpu_power(hwmgr, (uint32_t *)value); ++ else ++ return -EOPNOTSUPP; ++ case AMDGPU_PP_SENSOR_GPU_AVG_POWER: ++ if ((adev->asic_type != CHIP_HAWAII) && ++ (adev->asic_type != CHIP_BONAIRE) && ++ (adev->asic_type != CHIP_FIJI) && ++ (adev->asic_type != CHIP_TONGA)) ++ return -EOPNOTSUPP; ++ else ++ return smu7_get_gpu_power(hwmgr, (uint32_t *)value); + case AMDGPU_PP_SENSOR_VDDGFX: + if ((data->vr_config & VRCONF_VDDGFX_MASK) == + (VR_SVI2_PLANE_2 << VRCONF_VDDGFX_SHIFT)) +@@ -5623,7 +5641,7 @@ static int smu7_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uint + mode = input[size]; + switch (mode) { + case PP_SMC_POWER_PROFILE_CUSTOM: +- if (size < 8 && size != 0) ++ if (size != 8 && size != 0) + return -EINVAL; + /* If only CUSTOM is passed in, use the saved values. Check + * that we actually have a CUSTOM profile by ensuring that +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c +index b015a601b385ae..7e119742087325 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c +@@ -584,6 +584,7 @@ static int smu8_init_uvd_limit(struct pp_hwmgr *hwmgr) + hwmgr->dyn_state.uvd_clock_voltage_dependency_table; + unsigned long clock = 0; + uint32_t level; ++ int ret; + + if (NULL == table || table->count <= 0) + return -EINVAL; +@@ -591,7 +592,9 @@ static int smu8_init_uvd_limit(struct pp_hwmgr *hwmgr) + data->uvd_dpm.soft_min_clk = 0; + data->uvd_dpm.hard_min_clk = 0; + +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxUvdLevel, &level); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxUvdLevel, &level); ++ if (ret) ++ return ret; + + if (level < table->count) + clock = table->entries[level].vclk; +@@ -611,6 +614,7 @@ static int smu8_init_vce_limit(struct pp_hwmgr *hwmgr) + hwmgr->dyn_state.vce_clock_voltage_dependency_table; + unsigned long clock = 0; + uint32_t level; ++ int ret; + + if (NULL == table || table->count <= 0) + return -EINVAL; +@@ -618,7 +622,9 @@ static int smu8_init_vce_limit(struct pp_hwmgr *hwmgr) + data->vce_dpm.soft_min_clk = 0; + data->vce_dpm.hard_min_clk = 0; + +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxEclkLevel, &level); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxEclkLevel, &level); ++ if (ret) ++ return ret; + + if (level < table->count) + clock = table->entries[level].ecclk; +@@ -638,6 +644,7 @@ static int smu8_init_acp_limit(struct pp_hwmgr *hwmgr) + hwmgr->dyn_state.acp_clock_voltage_dependency_table; + unsigned long clock = 0; + uint32_t level; ++ int ret; + + if (NULL == table || table->count <= 0) + return -EINVAL; +@@ -645,7 +652,9 @@ static int smu8_init_acp_limit(struct pp_hwmgr *hwmgr) + data->acp_dpm.soft_min_clk = 0; + data->acp_dpm.hard_min_clk = 0; + +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxAclkLevel, &level); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxAclkLevel, &level); ++ if (ret) ++ return ret; + + if (level < table->count) + clock = table->entries[level].acpclk; +@@ -1065,16 +1074,18 @@ static int smu8_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, + struct pp_power_state *prequest_ps, + const struct pp_power_state *pcurrent_ps) + { +- struct smu8_power_state *smu8_ps = +- cast_smu8_power_state(&prequest_ps->hardware); +- +- const struct smu8_power_state *smu8_current_ps = +- cast_const_smu8_power_state(&pcurrent_ps->hardware); +- ++ struct smu8_power_state *smu8_ps; ++ const struct smu8_power_state *smu8_current_ps; + struct smu8_hwmgr *data = hwmgr->backend; + struct PP_Clocks clocks = {0, 0, 0, 0}; + bool force_high; + ++ smu8_ps = cast_smu8_power_state(&prequest_ps->hardware); ++ smu8_current_ps = cast_const_smu8_power_state(&pcurrent_ps->hardware); ++ ++ if (!smu8_ps || !smu8_current_ps) ++ return -EINVAL; ++ + smu8_ps->need_dfs_bypass = true; + + data->battery_state = (PP_StateUILabel_Battery == prequest_ps->classification.ui_label); +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c +index 6d6bc6a380b365..6c87b3d4ab362f 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c +@@ -354,13 +354,13 @@ static int vega10_odn_initial_default_setting(struct pp_hwmgr *hwmgr) + return 0; + } + +-static void vega10_init_dpm_defaults(struct pp_hwmgr *hwmgr) ++static int vega10_init_dpm_defaults(struct pp_hwmgr *hwmgr) + { + struct vega10_hwmgr *data = hwmgr->backend; +- int i; + uint32_t sub_vendor_id, hw_revision; + uint32_t top32, bottom32; + struct amdgpu_device *adev = hwmgr->adev; ++ int ret, i; + + vega10_initialize_power_tune_defaults(hwmgr); + +@@ -485,9 +485,12 @@ static void vega10_init_dpm_defaults(struct pp_hwmgr *hwmgr) + if (data->registry_data.vr0hot_enabled) + data->smu_features[GNLD_VR0HOT].supported = true; + +- smum_send_msg_to_smc(hwmgr, ++ ret = smum_send_msg_to_smc(hwmgr, + PPSMC_MSG_GetSmuVersion, + &hwmgr->smu_version); ++ if (ret) ++ return ret; ++ + /* ACG firmware has major version 5 */ + if ((hwmgr->smu_version & 0xff000000) == 0x5000000) + data->smu_features[GNLD_ACG].supported = true; +@@ -505,10 +508,16 @@ static void vega10_init_dpm_defaults(struct pp_hwmgr *hwmgr) + data->smu_features[GNLD_PCC_LIMIT].supported = true; + + /* Get the SN to turn into a Unique ID */ +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumTop32, &top32); +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumBottom32, &bottom32); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumTop32, &top32); ++ if (ret) ++ return ret; ++ ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumBottom32, &bottom32); ++ if (ret) ++ return ret; + + adev->unique_id = ((uint64_t)bottom32 << 32) | top32; ++ return 0; + } + + #ifdef PPLIB_VEGA10_EVV_SUPPORT +@@ -882,7 +891,9 @@ static int vega10_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + + vega10_set_features_platform_caps(hwmgr); + +- vega10_init_dpm_defaults(hwmgr); ++ result = vega10_init_dpm_defaults(hwmgr); ++ if (result) ++ return result; + + #ifdef PPLIB_VEGA10_EVV_SUPPORT + /* Get leakage voltage based on leakage ID. */ +@@ -2350,15 +2361,20 @@ static int vega10_acg_enable(struct pp_hwmgr *hwmgr) + { + struct vega10_hwmgr *data = hwmgr->backend; + uint32_t agc_btc_response; ++ int ret; + + if (data->smu_features[GNLD_ACG].supported) { + if (0 == vega10_enable_smc_features(hwmgr, true, + data->smu_features[GNLD_DPM_PREFETCHER].smu_feature_bitmap)) + data->smu_features[GNLD_DPM_PREFETCHER].enabled = true; + +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_InitializeAcg, NULL); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_InitializeAcg, NULL); ++ if (ret) ++ return ret; + +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunAcgBtc, &agc_btc_response); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunAcgBtc, &agc_btc_response); ++ if (ret) ++ agc_btc_response = 0; + + if (1 == agc_btc_response) { + if (1 == data->acg_loop_state) +@@ -2571,8 +2587,11 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr) + } + } + +- pp_atomfwctrl_get_voltage_table_v4(hwmgr, VOLTAGE_TYPE_VDDC, ++ result = pp_atomfwctrl_get_voltage_table_v4(hwmgr, VOLTAGE_TYPE_VDDC, + VOLTAGE_OBJ_SVID2, &voltage_table); ++ PP_ASSERT_WITH_CODE(!result, ++ "Failed to get voltage table!", ++ return result); + pp_table->MaxVidStep = voltage_table.max_vid_step; + + pp_table->GfxDpmVoltageMode = +@@ -3259,8 +3278,7 @@ static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, + const struct pp_power_state *current_ps) + { + struct amdgpu_device *adev = hwmgr->adev; +- struct vega10_power_state *vega10_ps = +- cast_phw_vega10_power_state(&request_ps->hardware); ++ struct vega10_power_state *vega10_ps; + uint32_t sclk; + uint32_t mclk; + struct PP_Clocks minimum_clocks = {0}; +@@ -3278,6 +3296,10 @@ static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, + uint32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0; + uint32_t latency; + ++ vega10_ps = cast_phw_vega10_power_state(&request_ps->hardware); ++ if (!vega10_ps) ++ return -EINVAL; ++ + data->battery_state = (PP_StateUILabel_Battery == + request_ps->classification.ui_label); + +@@ -3415,13 +3437,17 @@ static int vega10_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, co + const struct vega10_power_state *vega10_ps = + cast_const_phw_vega10_power_state(states->pnew_state); + struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table); +- uint32_t sclk = vega10_ps->performance_levels +- [vega10_ps->performance_level_count - 1].gfx_clock; + struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table); +- uint32_t mclk = vega10_ps->performance_levels +- [vega10_ps->performance_level_count - 1].mem_clock; ++ uint32_t sclk, mclk; + uint32_t i; + ++ if (vega10_ps == NULL) ++ return -EINVAL; ++ sclk = vega10_ps->performance_levels ++ [vega10_ps->performance_level_count - 1].gfx_clock; ++ mclk = vega10_ps->performance_levels ++ [vega10_ps->performance_level_count - 1].mem_clock; ++ + for (i = 0; i < sclk_table->count; i++) { + if (sclk == sclk_table->dpm_levels[i].value) + break; +@@ -3728,6 +3754,9 @@ static int vega10_generate_dpm_level_enable_mask( + cast_const_phw_vega10_power_state(states->pnew_state); + int i; + ++ if (vega10_ps == NULL) ++ return -EINVAL; ++ + PP_ASSERT_WITH_CODE(!vega10_trim_dpm_states(hwmgr, vega10_ps), + "Attempt to Trim DPM States Failed!", + return -1); +@@ -3900,11 +3929,14 @@ static int vega10_get_gpu_power(struct pp_hwmgr *hwmgr, + uint32_t *query) + { + uint32_t value; ++ int ret; + + if (!query) + return -EINVAL; + +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrPkgPwr, &value); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrPkgPwr, &value); ++ if (ret) ++ return ret; + + /* SMC returning actual watts, keep consistent with legacy asics, low 8 bit as 8 fractional bits */ + *query = value << 8; +@@ -4800,14 +4832,16 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr, + uint32_t gen_speed, lane_width, current_gen_speed, current_lane_width; + PPTable_t *pptable = &(data->smc_state_table.pp_table); + +- int i, now, size = 0, count = 0; ++ int i, ret, now, size = 0, count = 0; + + switch (type) { + case PP_SCLK: + if (data->registry_data.sclk_dpm_key_disabled) + break; + +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentGfxclkIndex, &now); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentGfxclkIndex, &now); ++ if (ret) ++ break; + + if (hwmgr->pp_one_vf && + (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)) +@@ -4823,7 +4857,9 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr, + if (data->registry_data.mclk_dpm_key_disabled) + break; + +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentUclkIndex, &now); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentUclkIndex, &now); ++ if (ret) ++ break; + + for (i = 0; i < mclk_table->count; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", +@@ -4834,7 +4870,9 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr, + if (data->registry_data.socclk_dpm_key_disabled) + break; + +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentSocclkIndex, &now); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentSocclkIndex, &now); ++ if (ret) ++ break; + + for (i = 0; i < soc_table->count; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", +@@ -4845,8 +4883,10 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr, + if (data->registry_data.dcefclk_dpm_key_disabled) + break; + +- smum_send_msg_to_smc_with_parameter(hwmgr, ++ ret = smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_GetClockFreqMHz, CLK_DCEFCLK, &now); ++ if (ret) ++ break; + + for (i = 0; i < dcef_table->count; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", +@@ -4995,6 +5035,8 @@ static int vega10_check_states_equal(struct pp_hwmgr *hwmgr, + + vega10_psa = cast_const_phw_vega10_power_state(pstate1); + vega10_psb = cast_const_phw_vega10_power_state(pstate2); ++ if (vega10_psa == NULL || vega10_psb == NULL) ++ return -EINVAL; + + /* If the two states don't even have the same number of performance levels + * they cannot be the same state. +@@ -5128,6 +5170,8 @@ static int vega10_set_sclk_od(struct pp_hwmgr *hwmgr, uint32_t value) + return -EINVAL; + + vega10_ps = cast_phw_vega10_power_state(&ps->hardware); ++ if (vega10_ps == NULL) ++ return -EINVAL; + + vega10_ps->performance_levels + [vega10_ps->performance_level_count - 1].gfx_clock = +@@ -5179,6 +5223,8 @@ static int vega10_set_mclk_od(struct pp_hwmgr *hwmgr, uint32_t value) + return -EINVAL; + + vega10_ps = cast_phw_vega10_power_state(&ps->hardware); ++ if (vega10_ps == NULL) ++ return -EINVAL; + + vega10_ps->performance_levels + [vega10_ps->performance_level_count - 1].mem_clock = +@@ -5420,6 +5466,9 @@ static void vega10_odn_update_power_state(struct pp_hwmgr *hwmgr) + return; + + vega10_ps = cast_phw_vega10_power_state(&ps->hardware); ++ if (vega10_ps == NULL) ++ return; ++ + max_level = vega10_ps->performance_level_count - 1; + + if (vega10_ps->performance_levels[max_level].gfx_clock != +@@ -5442,6 +5491,9 @@ static void vega10_odn_update_power_state(struct pp_hwmgr *hwmgr) + + ps = (struct pp_power_state *)((unsigned long)(hwmgr->ps) + hwmgr->ps_size * (hwmgr->num_ps - 1)); + vega10_ps = cast_phw_vega10_power_state(&ps->hardware); ++ if (vega10_ps == NULL) ++ return; ++ + max_level = vega10_ps->performance_level_count - 1; + + if (vega10_ps->performance_levels[max_level].gfx_clock != +@@ -5632,6 +5684,8 @@ static int vega10_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_ + return -EINVAL; + + vega10_ps = cast_const_phw_vega10_power_state(state); ++ if (vega10_ps == NULL) ++ return -EINVAL; + + i = index > vega10_ps->performance_level_count - 1 ? + vega10_ps->performance_level_count - 1 : index; +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c +index 460067933de2ef..069c0f5205e004 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c +@@ -293,12 +293,12 @@ static int vega12_set_features_platform_caps(struct pp_hwmgr *hwmgr) + return 0; + } + +-static void vega12_init_dpm_defaults(struct pp_hwmgr *hwmgr) ++static int vega12_init_dpm_defaults(struct pp_hwmgr *hwmgr) + { + struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + struct amdgpu_device *adev = hwmgr->adev; + uint32_t top32, bottom32; +- int i; ++ int i, ret; + + data->smu_features[GNLD_DPM_PREFETCHER].smu_feature_id = + FEATURE_DPM_PREFETCHER_BIT; +@@ -364,10 +364,16 @@ static void vega12_init_dpm_defaults(struct pp_hwmgr *hwmgr) + } + + /* Get the SN to turn into a Unique ID */ +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumTop32, &top32); +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumBottom32, &bottom32); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumTop32, &top32); ++ if (ret) ++ return ret; ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumBottom32, &bottom32); ++ if (ret) ++ return ret; + + adev->unique_id = ((uint64_t)bottom32 << 32) | top32; ++ ++ return 0; + } + + static int vega12_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr) +@@ -410,7 +416,11 @@ static int vega12_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + + vega12_set_features_platform_caps(hwmgr); + +- vega12_init_dpm_defaults(hwmgr); ++ result = vega12_init_dpm_defaults(hwmgr); ++ if (result) { ++ pr_err("%s failed\n", __func__); ++ return result; ++ } + + /* Parse pptable data read from VBIOS */ + vega12_set_private_data_based_on_pptable(hwmgr); +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c +index 3b33af30eb0fbc..9fdb9990d18829 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c +@@ -328,12 +328,12 @@ static int vega20_set_features_platform_caps(struct pp_hwmgr *hwmgr) + return 0; + } + +-static void vega20_init_dpm_defaults(struct pp_hwmgr *hwmgr) ++static int vega20_init_dpm_defaults(struct pp_hwmgr *hwmgr) + { + struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend); + struct amdgpu_device *adev = hwmgr->adev; + uint32_t top32, bottom32; +- int i; ++ int i, ret; + + data->smu_features[GNLD_DPM_PREFETCHER].smu_feature_id = + FEATURE_DPM_PREFETCHER_BIT; +@@ -404,10 +404,17 @@ static void vega20_init_dpm_defaults(struct pp_hwmgr *hwmgr) + } + + /* Get the SN to turn into a Unique ID */ +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumTop32, &top32); +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumBottom32, &bottom32); ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumTop32, &top32); ++ if (ret) ++ return ret; ++ ++ ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ReadSerialNumBottom32, &bottom32); ++ if (ret) ++ return ret; + + adev->unique_id = ((uint64_t)bottom32 << 32) | top32; ++ ++ return 0; + } + + static int vega20_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr) +@@ -427,6 +434,7 @@ static int vega20_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + { + struct vega20_hwmgr *data; + struct amdgpu_device *adev = hwmgr->adev; ++ int result; + + data = kzalloc(sizeof(struct vega20_hwmgr), GFP_KERNEL); + if (data == NULL) +@@ -452,8 +460,11 @@ static int vega20_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + + vega20_set_features_platform_caps(hwmgr); + +- vega20_init_dpm_defaults(hwmgr); +- ++ result = vega20_init_dpm_defaults(hwmgr); ++ if (result) { ++ pr_err("%s failed\n", __func__); ++ return result; ++ } + /* Parse pptable data read from VBIOS */ + vega20_set_private_data_based_on_pptable(hwmgr); + +@@ -4091,9 +4102,11 @@ static int vega20_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, ui + if (power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { + struct vega20_hwmgr *data = + (struct vega20_hwmgr *)(hwmgr->backend); +- if (size == 0 && !data->is_custom_profile_set) ++ ++ if (size != 10 && size != 0) + return -EINVAL; +- if (size < 10 && size != 0) ++ ++ if (size == 0 && !data->is_custom_profile_set) + return -EINVAL; + + result = vega20_get_activity_monitor_coeff(hwmgr, +@@ -4155,6 +4168,8 @@ static int vega20_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, ui + activity_monitor.Fclk_PD_Data_error_coeff = input[8]; + activity_monitor.Fclk_PD_Data_error_rate_coeff = input[9]; + break; ++ default: ++ return -EINVAL; + } + + result = vega20_set_activity_monitor_coeff(hwmgr, +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.c +index a70d7389664904..f9c0f117725dd1 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega10_smumgr.c +@@ -130,13 +130,17 @@ int vega10_get_enabled_smc_features(struct pp_hwmgr *hwmgr, + uint64_t *features_enabled) + { + uint32_t enabled_features; ++ int ret; + + if (features_enabled == NULL) + return -EINVAL; + +- smum_send_msg_to_smc(hwmgr, ++ ret = smum_send_msg_to_smc(hwmgr, + PPSMC_MSG_GetEnabledSmuFeatures, + &enabled_features); ++ if (ret) ++ return ret; ++ + *features_enabled = enabled_features; + + return 0; +diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +index f005a90c35af43..4d17b6958397ed 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +@@ -24,6 +24,7 @@ + + #include + #include ++#include + #include + + #include "amdgpu.h" +@@ -741,16 +742,8 @@ static int smu_late_init(void *handle) + * handle the switch automatically. Driver involvement + * is unnecessary. + */ +- if (!smu->dc_controlled_by_gpio) { +- ret = smu_set_power_source(smu, +- adev->pm.ac_power ? SMU_POWER_SOURCE_AC : +- SMU_POWER_SOURCE_DC); +- if (ret) { +- dev_err(adev->dev, "Failed to switch to %s mode!\n", +- adev->pm.ac_power ? "AC" : "DC"); +- return ret; +- } +- } ++ adev->pm.ac_power = power_supply_is_system_supplied() > 0; ++ smu_set_ac_dc(smu); + + if ((adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 1)) || + (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 3))) +@@ -1232,7 +1225,7 @@ static int smu_smc_hw_setup(struct smu_context *smu) + { + struct smu_feature *feature = &smu->smu_feature; + struct amdgpu_device *adev = smu->adev; +- uint32_t pcie_gen = 0, pcie_width = 0; ++ uint8_t pcie_gen = 0, pcie_width = 0; + uint64_t features_supported; + int ret = 0; + +@@ -1848,12 +1841,13 @@ static int smu_bump_power_profile_mode(struct smu_context *smu, + } + + static int smu_adjust_power_state_dynamic(struct smu_context *smu, +- enum amd_dpm_forced_level level, +- bool skip_display_settings) ++ enum amd_dpm_forced_level level, ++ bool skip_display_settings, ++ bool init) + { + int ret = 0; + int index = 0; +- long workload; ++ long workload[1]; + struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); + + if (!skip_display_settings) { +@@ -1893,10 +1887,10 @@ static int smu_adjust_power_state_dynamic(struct smu_context *smu, + smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) { + index = fls(smu->workload_mask); + index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0; +- workload = smu->workload_setting[index]; ++ workload[0] = smu->workload_setting[index]; + +- if (smu->power_profile_mode != workload) +- smu_bump_power_profile_mode(smu, &workload, 0); ++ if (init || smu->power_profile_mode != workload[0]) ++ smu_bump_power_profile_mode(smu, workload, 0); + } + + return ret; +@@ -1916,11 +1910,13 @@ static int smu_handle_task(struct smu_context *smu, + ret = smu_pre_display_config_changed(smu); + if (ret) + return ret; +- ret = smu_adjust_power_state_dynamic(smu, level, false); ++ ret = smu_adjust_power_state_dynamic(smu, level, false, false); + break; + case AMD_PP_TASK_COMPLETE_INIT: ++ ret = smu_adjust_power_state_dynamic(smu, level, true, true); ++ break; + case AMD_PP_TASK_READJUST_POWER_STATE: +- ret = smu_adjust_power_state_dynamic(smu, level, true); ++ ret = smu_adjust_power_state_dynamic(smu, level, true, false); + break; + default: + break; +@@ -1946,7 +1942,7 @@ static int smu_switch_power_profile(void *handle, + { + struct smu_context *smu = handle; + struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); +- long workload; ++ long workload[1]; + uint32_t index; + + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) +@@ -1959,17 +1955,17 @@ static int smu_switch_power_profile(void *handle, + smu->workload_mask &= ~(1 << smu->workload_prority[type]); + index = fls(smu->workload_mask); + index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0; +- workload = smu->workload_setting[index]; ++ workload[0] = smu->workload_setting[index]; + } else { + smu->workload_mask |= (1 << smu->workload_prority[type]); + index = fls(smu->workload_mask); + index = index <= WORKLOAD_POLICY_MAX ? index - 1 : 0; +- workload = smu->workload_setting[index]; ++ workload[0] = smu->workload_setting[index]; + } + + if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL && + smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) +- smu_bump_power_profile_mode(smu, &workload, 0); ++ smu_bump_power_profile_mode(smu, workload, 0); + + return 0; + } +diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +index 5a52098bcf1664..72ed836328966c 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h ++++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +@@ -844,7 +844,7 @@ struct pptable_funcs { + * &pcie_gen_cap: Maximum allowed PCIe generation. + * &pcie_width_cap: Maximum allowed PCIe width. + */ +- int (*update_pcie_parameters)(struct smu_context *smu, uint32_t pcie_gen_cap, uint32_t pcie_width_cap); ++ int (*update_pcie_parameters)(struct smu_context *smu, uint8_t pcie_gen_cap, uint8_t pcie_width_cap); + + /** + * @i2c_init: Initialize i2c. +diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +index 355c156d871aff..cc02f979e9e984 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h ++++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +@@ -296,8 +296,8 @@ int smu_v13_0_get_pptable_from_firmware(struct smu_context *smu, + uint32_t pptable_id); + + int smu_v13_0_update_pcie_parameters(struct smu_context *smu, +- uint32_t pcie_gen_cap, +- uint32_t pcie_width_cap); ++ uint8_t pcie_gen_cap, ++ uint8_t pcie_width_cap); + + #endif + #endif +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +index 704a2b577a0e2f..4c58c2cd26d886 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +@@ -2356,8 +2356,8 @@ static uint16_t arcturus_get_current_pcie_link_speed(struct smu_context *smu) + + /* TODO: confirm this on real target */ + esm_ctrl = RREG32_PCIE(smnPCIE_ESM_CTRL); +- if ((esm_ctrl >> 15) & 0x1FFFF) +- return (uint16_t)(((esm_ctrl >> 8) & 0x3F) + 128); ++ if ((esm_ctrl >> 15) & 0x1) ++ return (uint16_t)(((esm_ctrl >> 8) & 0x7F) + 128); + + return smu_v11_0_get_current_pcie_link_speed(smu); + } +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +index 18487ae10bcff4..b1b23233635a64 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +@@ -1222,19 +1222,22 @@ static int navi10_get_current_clk_freq_by_table(struct smu_context *smu, + value); + } + +-static bool navi10_is_support_fine_grained_dpm(struct smu_context *smu, enum smu_clk_type clk_type) ++static int navi10_is_support_fine_grained_dpm(struct smu_context *smu, enum smu_clk_type clk_type) + { + PPTable_t *pptable = smu->smu_table.driver_pptable; + DpmDescriptor_t *dpm_desc = NULL; +- uint32_t clk_index = 0; ++ int clk_index = 0; + + clk_index = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); ++ if (clk_index < 0) ++ return clk_index; ++ + dpm_desc = &pptable->DpmDescriptor[clk_index]; + + /* 0 - Fine grained DPM, 1 - Discrete DPM */ +- return dpm_desc->SnapToDiscrete == 0; ++ return dpm_desc->SnapToDiscrete == 0 ? 1 : 0; + } + + static inline bool navi10_od_feature_is_supported(struct smu_11_0_overdrive_table *od_table, enum SMU_11_0_ODFEATURE_CAP cap) +@@ -1290,7 +1293,11 @@ static int navi10_emit_clk_levels(struct smu_context *smu, + if (ret) + return ret; + +- if (!navi10_is_support_fine_grained_dpm(smu, clk_type)) { ++ ret = navi10_is_support_fine_grained_dpm(smu, clk_type); ++ if (ret < 0) ++ return ret; ++ ++ if (!ret) { + for (i = 0; i < count; i++) { + ret = smu_v11_0_get_dpm_freq_by_index(smu, + clk_type, i, &value); +@@ -1499,7 +1506,11 @@ static int navi10_print_clk_levels(struct smu_context *smu, + if (ret) + return size; + +- if (!navi10_is_support_fine_grained_dpm(smu, clk_type)) { ++ ret = navi10_is_support_fine_grained_dpm(smu, clk_type); ++ if (ret < 0) ++ return ret; ++ ++ if (!ret) { + for (i = 0; i < count; i++) { + ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, i, &value); + if (ret) +@@ -1668,7 +1679,11 @@ static int navi10_force_clk_levels(struct smu_context *smu, + case SMU_UCLK: + case SMU_FCLK: + /* There is only 2 levels for fine grained DPM */ +- if (navi10_is_support_fine_grained_dpm(smu, clk_type)) { ++ ret = navi10_is_support_fine_grained_dpm(smu, clk_type); ++ if (ret < 0) ++ return ret; ++ ++ if (ret) { + soft_max_level = (soft_max_level >= 1 ? 1 : 0); + soft_min_level = (soft_min_level >= 1 ? 1 : 0); + } +@@ -2376,8 +2391,8 @@ static int navi10_get_power_limit(struct smu_context *smu, + } + + static int navi10_update_pcie_parameters(struct smu_context *smu, +- uint32_t pcie_gen_cap, +- uint32_t pcie_width_cap) ++ uint8_t pcie_gen_cap, ++ uint8_t pcie_width_cap) + { + struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + PPTable_t *pptable = smu->smu_table.driver_pptable; +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +index da2860da60188e..a7f4f82d23b4b9 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +@@ -2085,14 +2085,14 @@ static int sienna_cichlid_display_disable_memory_clock_switch(struct smu_context + #define MAX(a, b) ((a) > (b) ? (a) : (b)) + + static int sienna_cichlid_update_pcie_parameters(struct smu_context *smu, +- uint32_t pcie_gen_cap, +- uint32_t pcie_width_cap) ++ uint8_t pcie_gen_cap, ++ uint8_t pcie_width_cap) + { + struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_11_0_pcie_table *pcie_table = &dpm_context->dpm_tables.pcie_table; + uint8_t *table_member1, *table_member2; +- uint32_t min_gen_speed, max_gen_speed; +- uint32_t min_lane_width, max_lane_width; ++ uint8_t min_gen_speed, max_gen_speed; ++ uint8_t min_lane_width, max_lane_width; + uint32_t smu_pcie_arg; + int ret, i; + +@@ -2108,7 +2108,7 @@ static int sienna_cichlid_update_pcie_parameters(struct smu_context *smu, + min_lane_width = min_lane_width > max_lane_width ? + max_lane_width : min_lane_width; + +- if (!amdgpu_device_pcie_dynamic_switching_supported()) { ++ if (!(smu->adev->pm.pp_feature & PP_PCIE_DPM_MASK)) { + pcie_table->pcie_gen[0] = max_gen_speed; + pcie_table->pcie_lane[0] = max_lane_width; + } else { +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +index aa4a5498a12f73..123c19bb622808 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +@@ -1441,10 +1441,12 @@ static int smu_v11_0_irq_process(struct amdgpu_device *adev, + case 0x3: + dev_dbg(adev->dev, "Switched to AC mode!\n"); + schedule_work(&smu->interrupt_work); ++ adev->pm.ac_power = true; + break; + case 0x4: + dev_dbg(adev->dev, "Switched to DC mode!\n"); + schedule_work(&smu->interrupt_work); ++ adev->pm.ac_power = false; + break; + case 0x7: + /* +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +index 201cec59984281..f46cda88948312 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +@@ -1009,6 +1009,18 @@ static int vangogh_get_dpm_ultimate_freq(struct smu_context *smu, + } + } + if (min) { ++ ret = vangogh_get_profiling_clk_mask(smu, ++ AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK, ++ NULL, ++ NULL, ++ &mclk_mask, ++ &fclk_mask, ++ &soc_mask); ++ if (ret) ++ goto failed; ++ ++ vclk_mask = dclk_mask = 0; ++ + switch (clk_type) { + case SMU_UCLK: + case SMU_MCLK: +@@ -2481,6 +2493,8 @@ static u32 vangogh_set_gfxoff_residency(struct smu_context *smu, bool start) + + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_LogGfxOffResidency, + start, &residency); ++ if (ret) ++ return ret; + + if (!start) + adev->gfx.gfx_off_residency = residency; +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +index cc3169400c9b08..ded8952d984907 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +@@ -257,8 +257,11 @@ static int aldebaran_tables_init(struct smu_context *smu) + } + + smu_table->ecc_table = kzalloc(tables[SMU_TABLE_ECCINFO].size, GFP_KERNEL); +- if (!smu_table->ecc_table) ++ if (!smu_table->ecc_table) { ++ kfree(smu_table->metrics_table); ++ kfree(smu_table->gpu_metrics_table); + return -ENOMEM; ++ } + + return 0; + } +@@ -1717,8 +1720,8 @@ static int aldebaran_get_current_pcie_link_speed(struct smu_context *smu) + + /* TODO: confirm this on real target */ + esm_ctrl = RREG32_PCIE(smnPCIE_ESM_CTRL); +- if ((esm_ctrl >> 15) & 0x1FFFF) +- return (((esm_ctrl >> 8) & 0x3F) + 128); ++ if ((esm_ctrl >> 15) & 0x1) ++ return (((esm_ctrl >> 8) & 0x7F) + 128); + + return smu_v13_0_get_current_pcie_link_speed(smu); + } +@@ -1928,7 +1931,8 @@ static int aldebaran_mode2_reset(struct smu_context *smu) + + index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, + SMU_MSG_GfxDeviceDriverReset); +- ++ if (index < 0 ) ++ return -EINVAL; + mutex_lock(&smu->message_lock); + if (smu_version >= 0x00441400) { + ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, SMU_RESET_MODE_2); +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +index 0232adb95df3a8..c0adfa46ac7896 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +@@ -79,8 +79,8 @@ MODULE_FIRMWARE("amdgpu/smu_13_0_10.bin"); + #define PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK 0x00000070L + #define PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT 0x4 + #define smnPCIE_LC_SPEED_CNTL 0x11140290 +-#define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK 0xC000 +-#define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT 0xE ++#define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK 0xE0 ++#define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT 0x5 + + static const int link_width[] = {0, 1, 2, 4, 8, 12, 16}; + +@@ -1377,10 +1377,12 @@ static int smu_v13_0_irq_process(struct amdgpu_device *adev, + case 0x3: + dev_dbg(adev->dev, "Switched to AC mode!\n"); + smu_v13_0_ack_ac_dc_interrupt(smu); ++ adev->pm.ac_power = true; + break; + case 0x4: + dev_dbg(adev->dev, "Switched to DC mode!\n"); + smu_v13_0_ack_ac_dc_interrupt(smu); ++ adev->pm.ac_power = false; + break; + case 0x7: + /* +@@ -2420,8 +2422,8 @@ int smu_v13_0_mode1_reset(struct smu_context *smu) + } + + int smu_v13_0_update_pcie_parameters(struct smu_context *smu, +- uint32_t pcie_gen_cap, +- uint32_t pcie_width_cap) ++ uint8_t pcie_gen_cap, ++ uint8_t pcie_width_cap) + { + struct smu_13_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_13_0_pcie_table *pcie_table = +@@ -2430,7 +2432,10 @@ int smu_v13_0_update_pcie_parameters(struct smu_context *smu, + uint32_t smu_pcie_arg; + int ret, i; + +- if (!amdgpu_device_pcie_dynamic_switching_supported()) { ++ if (!num_of_levels) ++ return 0; ++ ++ if (!(smu->adev->pm.pp_feature & PP_PCIE_DPM_MASK)) { + if (pcie_table->pcie_gen[num_of_levels - 1] < pcie_gen_cap) + pcie_gen_cap = pcie_table->pcie_gen[num_of_levels - 1]; + +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 3903a47669e437..4022dd44ebb2b3 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 +@@ -352,12 +352,12 @@ static int smu_v13_0_0_check_powerplay_table(struct smu_context *smu) + if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_HARDWAREDC) + smu->dc_controlled_by_gpio = true; + +- if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_BACO || +- powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_MACO) ++ if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_BACO) { + smu_baco->platform_support = true; + +- if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_MACO) +- smu_baco->maco_support = true; ++ if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_MACO) ++ smu_baco->maco_support = true; ++ } + + /* + * We are in the transition to a new OD mechanism. +@@ -2163,38 +2163,10 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu, + } + } + +- if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE && +- (((smu->adev->pdev->device == 0x744C) && (smu->adev->pdev->revision == 0xC8)) || +- ((smu->adev->pdev->device == 0x744C) && (smu->adev->pdev->revision == 0xCC)))) { +- ret = smu_cmn_update_table(smu, +- SMU_TABLE_ACTIVITY_MONITOR_COEFF, +- WORKLOAD_PPLIB_COMPUTE_BIT, +- (void *)(&activity_monitor_external), +- false); +- if (ret) { +- dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); +- return ret; +- } +- +- ret = smu_cmn_update_table(smu, +- SMU_TABLE_ACTIVITY_MONITOR_COEFF, +- WORKLOAD_PPLIB_CUSTOM_BIT, +- (void *)(&activity_monitor_external), +- true); +- if (ret) { +- dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); +- return ret; +- } +- +- workload_type = smu_cmn_to_asic_specific_index(smu, +- CMN2ASIC_MAPPING_WORKLOAD, +- PP_SMC_POWER_PROFILE_CUSTOM); +- } else { +- /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ +- workload_type = smu_cmn_to_asic_specific_index(smu, ++ /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ ++ workload_type = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_WORKLOAD, + smu->power_profile_mode); +- } + + if (workload_type < 0) + return -EINVAL; +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c +index 626591f54bc497..1fd4702dc63936 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c +@@ -226,8 +226,20 @@ static int smu_v13_0_4_system_features_control(struct smu_context *smu, bool en) + struct amdgpu_device *adev = smu->adev; + int ret = 0; + +- if (!en && !adev->in_s0ix) ++ if (!en && !adev->in_s0ix) { ++ if (adev->in_s4) { ++ /* Adds a GFX reset as workaround just before sending the ++ * MP1_UNLOAD message to prevent GC/RLC/PMFW from entering ++ * an invalid state. ++ */ ++ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, ++ SMU_RESET_MODE_2, NULL); ++ if (ret) ++ return ret; ++ } ++ + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL); ++ } + + return ret; + } +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 de80e191a92c49..44c5f8585f1ee7 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 +@@ -1941,8 +1941,8 @@ static int smu_v13_0_6_get_current_pcie_link_speed(struct smu_context *smu) + + /* TODO: confirm this on real target */ + esm_ctrl = RREG32_PCIE(smnPCIE_ESM_CTRL); +- if ((esm_ctrl >> 15) & 0x1FFFF) +- return (((esm_ctrl >> 8) & 0x3F) + 128); ++ if ((esm_ctrl >> 15) & 0x1) ++ return (((esm_ctrl >> 8) & 0x7F) + 128); + + speed_level = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & + PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) +@@ -1968,8 +1968,10 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table + + metrics = kzalloc(sizeof(MetricsTable_t), GFP_KERNEL); + ret = smu_v13_0_6_get_metrics_table(smu, metrics, true); +- if (ret) ++ if (ret) { ++ kfree(metrics); + return ret; ++ } + + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 3); + +@@ -2037,6 +2039,17 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table + return sizeof(struct gpu_metrics_v1_3); + } + ++static void smu_v13_0_6_restore_pci_config(struct smu_context *smu) ++{ ++ struct amdgpu_device *adev = smu->adev; ++ int i; ++ ++ for (i = 0; i < 16; i++) ++ pci_write_config_dword(adev->pdev, i * 4, ++ adev->pdev->saved_config_space[i]); ++ pci_restore_msi_state(adev->pdev); ++} ++ + static int smu_v13_0_6_mode2_reset(struct smu_context *smu) + { + int ret = 0, index; +@@ -2045,6 +2058,8 @@ static int smu_v13_0_6_mode2_reset(struct smu_context *smu) + + index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, + SMU_MSG_GfxDeviceDriverReset); ++ if (index < 0) ++ return index; + + mutex_lock(&smu->message_lock); + +@@ -2058,6 +2073,20 @@ static int smu_v13_0_6_mode2_reset(struct smu_context *smu) + /* Restore the config space saved during init */ + amdgpu_device_load_pci_state(adev->pdev); + ++ /* Certain platforms have switches which assign virtual BAR values to ++ * devices. OS uses the virtual BAR values and device behind the switch ++ * is assgined another BAR value. When device's config space registers ++ * are queried, switch returns the virtual BAR values. When mode-2 reset ++ * is performed, switch is unaware of it, and will continue to return ++ * the same virtual values to the OS.This affects ++ * pci_restore_config_space() API as it doesn't write the value saved if ++ * the current value read from config space is the same as what is ++ * saved. As a workaround, make sure the config space is restored ++ * always. ++ */ ++ if (!(adev->flags & AMD_IS_APU)) ++ smu_v13_0_6_restore_pci_config(smu); ++ + dev_dbg(smu->adev->dev, "wait for reset ack\n"); + do { + ret = smu_cmn_wait_for_response(smu); +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +index 94ef5b4d116d7c..51ae41cb43ea0e 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +@@ -341,12 +341,13 @@ static int smu_v13_0_7_check_powerplay_table(struct smu_context *smu) + if (powerplay_table->platform_caps & SMU_13_0_7_PP_PLATFORM_CAP_HARDWAREDC) + smu->dc_controlled_by_gpio = true; + +- if (powerplay_table->platform_caps & SMU_13_0_7_PP_PLATFORM_CAP_BACO || +- powerplay_table->platform_caps & SMU_13_0_7_PP_PLATFORM_CAP_MACO) ++ if (powerplay_table->platform_caps & SMU_13_0_7_PP_PLATFORM_CAP_BACO) { + smu_baco->platform_support = true; + +- if (smu_baco->platform_support && (BoardTable->HsrEnabled || BoardTable->VddqOffEnabled)) +- smu_baco->maco_support = true; ++ if ((powerplay_table->platform_caps & SMU_13_0_7_PP_PLATFORM_CAP_MACO) ++ && (BoardTable->HsrEnabled || BoardTable->VddqOffEnabled)) ++ smu_baco->maco_support = true; ++ } + + #if 0 + if (!overdrive_lowerlimits->FeatureCtrlMask || +diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +index 2c661f28410eda..b645c5998230b0 100644 +--- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c ++++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +@@ -5,6 +5,7 @@ + * + */ + #include ++#include + #include + #include + +@@ -610,12 +611,34 @@ get_crtc_primary(struct komeda_kms_dev *kms, struct komeda_crtc *crtc) + return NULL; + } + ++static int komeda_attach_bridge(struct device *dev, ++ struct komeda_pipeline *pipe, ++ struct drm_encoder *encoder) ++{ ++ struct drm_bridge *bridge; ++ int err; ++ ++ bridge = devm_drm_of_get_bridge(dev, pipe->of_node, ++ KOMEDA_OF_PORT_OUTPUT, 0); ++ if (IS_ERR(bridge)) ++ return dev_err_probe(dev, PTR_ERR(bridge), "remote bridge not found for pipe: %s\n", ++ of_node_full_name(pipe->of_node)); ++ ++ err = drm_bridge_attach(encoder, bridge, NULL, 0); ++ if (err) ++ dev_err(dev, "bridge_attach() failed for pipe: %s\n", ++ of_node_full_name(pipe->of_node)); ++ ++ return err; ++} ++ + static int komeda_crtc_add(struct komeda_kms_dev *kms, + struct komeda_crtc *kcrtc) + { + struct drm_crtc *crtc = &kcrtc->base; + struct drm_device *base = &kms->base; +- struct drm_bridge *bridge; ++ struct komeda_pipeline *pipe = kcrtc->master; ++ struct drm_encoder *encoder = &kcrtc->encoder; + int err; + + err = drm_crtc_init_with_planes(base, crtc, +@@ -626,27 +649,25 @@ static int komeda_crtc_add(struct komeda_kms_dev *kms, + + drm_crtc_helper_add(crtc, &komeda_crtc_helper_funcs); + +- crtc->port = kcrtc->master->of_output_port; ++ crtc->port = pipe->of_output_port; + + /* Construct an encoder for each pipeline and attach it to the remote + * bridge + */ + kcrtc->encoder.possible_crtcs = drm_crtc_mask(crtc); +- err = drm_simple_encoder_init(base, &kcrtc->encoder, +- DRM_MODE_ENCODER_TMDS); ++ err = drm_simple_encoder_init(base, encoder, DRM_MODE_ENCODER_TMDS); + if (err) + return err; + +- bridge = devm_drm_of_get_bridge(base->dev, kcrtc->master->of_node, +- KOMEDA_OF_PORT_OUTPUT, 0); +- if (IS_ERR(bridge)) +- return PTR_ERR(bridge); +- +- err = drm_bridge_attach(&kcrtc->encoder, bridge, NULL, 0); ++ if (pipe->of_output_links[0]) { ++ err = komeda_attach_bridge(base->dev, pipe, encoder); ++ if (err) ++ return err; ++ } + + drm_crtc_enable_color_mgmt(crtc, 0, true, KOMEDA_COLOR_LUT_SIZE); + +- return err; ++ return 0; + } + + int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev) +diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c +index 9299026701f348..1a5fa7df284dec 100644 +--- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c ++++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c +@@ -160,6 +160,7 @@ static int komeda_crtc_normalize_zpos(struct drm_crtc *crtc, + struct drm_plane *plane; + struct list_head zorder_list; + int order = 0, err; ++ u32 slave_zpos = 0; + + DRM_DEBUG_ATOMIC("[CRTC:%d:%s] calculating normalized zpos values\n", + crtc->base.id, crtc->name); +@@ -199,10 +200,13 @@ static int komeda_crtc_normalize_zpos(struct drm_crtc *crtc, + plane_st->zpos, plane_st->normalized_zpos); + + /* calculate max slave zorder */ +- if (has_bit(drm_plane_index(plane), kcrtc->slave_planes)) ++ if (has_bit(drm_plane_index(plane), kcrtc->slave_planes)) { ++ slave_zpos = plane_st->normalized_zpos; ++ if (to_kplane_st(plane_st)->layer_split) ++ slave_zpos++; + kcrtc_st->max_slave_zorder = +- max(plane_st->normalized_zpos, +- kcrtc_st->max_slave_zorder); ++ max(slave_zpos, kcrtc_st->max_slave_zorder); ++ } + } + + crtc_st->zpos_changed = true; +diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c +index 4618687a8f4d64..f4e76b46ca327a 100644 +--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c ++++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c +@@ -259,7 +259,7 @@ komeda_component_get_avail_scaler(struct komeda_component *c, + u32 avail_scalers; + + pipe_st = komeda_pipeline_get_state(c->pipeline, state); +- if (!pipe_st) ++ if (IS_ERR_OR_NULL(pipe_st)) + return NULL; + + avail_scalers = (pipe_st->active_comps & KOMEDA_PIPELINE_SCALERS) ^ +@@ -1223,7 +1223,7 @@ int komeda_build_display_data_flow(struct komeda_crtc *kcrtc, + return 0; + } + +-static void ++static int + komeda_pipeline_unbound_components(struct komeda_pipeline *pipe, + struct komeda_pipeline_state *new) + { +@@ -1243,8 +1243,12 @@ komeda_pipeline_unbound_components(struct komeda_pipeline *pipe, + c = komeda_pipeline_get_component(pipe, id); + c_st = komeda_component_get_state_and_set_user(c, + drm_st, NULL, new->crtc); ++ if (PTR_ERR(c_st) == -EDEADLK) ++ return -EDEADLK; + WARN_ON(IS_ERR(c_st)); + } ++ ++ return 0; + } + + /* release unclaimed pipeline resource */ +@@ -1266,9 +1270,8 @@ int komeda_release_unclaimed_resources(struct komeda_pipeline *pipe, + if (WARN_ON(IS_ERR_OR_NULL(st))) + return -EINVAL; + +- komeda_pipeline_unbound_components(pipe, st); ++ return komeda_pipeline_unbound_components(pipe, st); + +- return 0; + } + + /* Since standalone disabled components must be disabled separately and in the +diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c +index 626709bec6f5ff..2577f0cef8fcda 100644 +--- a/drivers/gpu/drm/arm/malidp_mw.c ++++ b/drivers/gpu/drm/arm/malidp_mw.c +@@ -72,7 +72,10 @@ static void malidp_mw_connector_reset(struct drm_connector *connector) + __drm_atomic_helper_connector_destroy_state(connector->state); + + kfree(connector->state); +- __drm_atomic_helper_connector_reset(connector, &mw_state->base); ++ connector->state = NULL; ++ ++ if (mw_state) ++ __drm_atomic_helper_connector_reset(connector, &mw_state->base); + } + + static enum drm_connector_status +diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c +index d207b03f8357c7..78122b35a0cbb3 100644 +--- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c ++++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c +@@ -358,11 +358,18 @@ static void aspeed_gfx_remove(struct platform_device *pdev) + sysfs_remove_group(&pdev->dev.kobj, &aspeed_sysfs_attr_group); + drm_dev_unregister(drm); + aspeed_gfx_unload(drm); ++ drm_atomic_helper_shutdown(drm); ++} ++ ++static void aspeed_gfx_shutdown(struct platform_device *pdev) ++{ ++ drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); + } + + static struct platform_driver aspeed_gfx_platform_driver = { + .probe = aspeed_gfx_probe, + .remove_new = aspeed_gfx_remove, ++ .shutdown = aspeed_gfx_shutdown, + .driver = { + .name = "aspeed_gfx", + .of_match_table = aspeed_gfx_match, +diff --git a/drivers/gpu/drm/ast/ast_dp.c b/drivers/gpu/drm/ast/ast_dp.c +index fdd9a493aa9c08..c6f226b6f08136 100644 +--- a/drivers/gpu/drm/ast/ast_dp.c ++++ b/drivers/gpu/drm/ast/ast_dp.c +@@ -180,6 +180,7 @@ void ast_dp_set_on_off(struct drm_device *dev, bool on) + { + struct ast_device *ast = to_ast_device(dev); + u8 video_on_off = on; ++ u32 i = 0; + + // Video On/Off + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, (u8) ~AST_DP_VIDEO_ENABLE, on); +@@ -192,6 +193,8 @@ void ast_dp_set_on_off(struct drm_device *dev, bool on) + ASTDP_MIRROR_VIDEO_ENABLE) != video_on_off) { + // wait 1 ms + mdelay(1); ++ if (++i > 200) ++ break; + } + } + } +diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h +index 848a9f1403e896..f7053f2972bb92 100644 +--- a/drivers/gpu/drm/ast/ast_drv.h ++++ b/drivers/gpu/drm/ast/ast_drv.h +@@ -172,6 +172,17 @@ to_ast_sil164_connector(struct drm_connector *connector) + return container_of(connector, struct ast_sil164_connector, base); + } + ++struct ast_bmc_connector { ++ struct drm_connector base; ++ struct drm_connector *physical_connector; ++}; ++ ++static inline struct ast_bmc_connector * ++to_ast_bmc_connector(struct drm_connector *connector) ++{ ++ return container_of(connector, struct ast_bmc_connector, base); ++} ++ + /* + * Device + */ +@@ -216,7 +227,7 @@ struct ast_device { + } astdp; + struct { + struct drm_encoder encoder; +- struct drm_connector connector; ++ struct ast_bmc_connector bmc_connector; + } bmc; + } output; + +diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c +index 32f04ec6c386fa..3de0f457fff6ab 100644 +--- a/drivers/gpu/drm/ast/ast_mode.c ++++ b/drivers/gpu/drm/ast/ast_mode.c +@@ -1767,6 +1767,30 @@ static const struct drm_encoder_funcs ast_bmc_encoder_funcs = { + .destroy = drm_encoder_cleanup, + }; + ++static int ast_bmc_connector_helper_detect_ctx(struct drm_connector *connector, ++ struct drm_modeset_acquire_ctx *ctx, ++ bool force) ++{ ++ struct ast_bmc_connector *bmc_connector = to_ast_bmc_connector(connector); ++ struct drm_connector *physical_connector = bmc_connector->physical_connector; ++ ++ /* ++ * Most user-space compositors cannot handle more than one connected ++ * connector per CRTC. Hence, we only mark the BMC as connected if the ++ * physical connector is disconnected. If the physical connector's status ++ * is connected or unknown, the BMC remains disconnected. This has no ++ * effect on the output of the BMC. ++ * ++ * FIXME: Remove this logic once user-space compositors can handle more ++ * than one connector per CRTC. The BMC should always be connected. ++ */ ++ ++ if (physical_connector && physical_connector->status == connector_status_disconnected) ++ return connector_status_connected; ++ ++ return connector_status_disconnected; ++} ++ + static int ast_bmc_connector_helper_get_modes(struct drm_connector *connector) + { + return drm_add_modes_noedid(connector, 4096, 4096); +@@ -1774,6 +1798,7 @@ static int ast_bmc_connector_helper_get_modes(struct drm_connector *connector) + + static const struct drm_connector_helper_funcs ast_bmc_connector_helper_funcs = { + .get_modes = ast_bmc_connector_helper_get_modes, ++ .detect_ctx = ast_bmc_connector_helper_detect_ctx, + }; + + static const struct drm_connector_funcs ast_bmc_connector_funcs = { +@@ -1784,12 +1809,33 @@ static const struct drm_connector_funcs ast_bmc_connector_funcs = { + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + }; + +-static int ast_bmc_output_init(struct ast_device *ast) ++static int ast_bmc_connector_init(struct drm_device *dev, ++ struct ast_bmc_connector *bmc_connector, ++ struct drm_connector *physical_connector) ++{ ++ struct drm_connector *connector = &bmc_connector->base; ++ int ret; ++ ++ ret = drm_connector_init(dev, connector, &ast_bmc_connector_funcs, ++ DRM_MODE_CONNECTOR_VIRTUAL); ++ if (ret) ++ return ret; ++ ++ drm_connector_helper_add(connector, &ast_bmc_connector_helper_funcs); ++ ++ bmc_connector->physical_connector = physical_connector; ++ ++ return 0; ++} ++ ++static int ast_bmc_output_init(struct ast_device *ast, ++ struct drm_connector *physical_connector) + { + struct drm_device *dev = &ast->base; + struct drm_crtc *crtc = &ast->crtc; + struct drm_encoder *encoder = &ast->output.bmc.encoder; +- struct drm_connector *connector = &ast->output.bmc.connector; ++ struct ast_bmc_connector *bmc_connector = &ast->output.bmc.bmc_connector; ++ struct drm_connector *connector = &bmc_connector->base; + int ret; + + ret = drm_encoder_init(dev, encoder, +@@ -1799,13 +1845,10 @@ static int ast_bmc_output_init(struct ast_device *ast) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + +- ret = drm_connector_init(dev, connector, &ast_bmc_connector_funcs, +- DRM_MODE_CONNECTOR_VIRTUAL); ++ ret = ast_bmc_connector_init(dev, bmc_connector, physical_connector); + if (ret) + return ret; + +- drm_connector_helper_add(connector, &ast_bmc_connector_helper_funcs); +- + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) + return ret; +@@ -1864,6 +1907,7 @@ static const struct drm_mode_config_funcs ast_mode_config_funcs = { + int ast_mode_config_init(struct ast_device *ast) + { + struct drm_device *dev = &ast->base; ++ struct drm_connector *physical_connector = NULL; + int ret; + + ret = drmm_mode_config_init(dev); +@@ -1904,23 +1948,27 @@ int ast_mode_config_init(struct ast_device *ast) + ret = ast_vga_output_init(ast); + if (ret) + return ret; ++ physical_connector = &ast->output.vga.vga_connector.base; + } + if (ast->tx_chip_types & AST_TX_SIL164_BIT) { + ret = ast_sil164_output_init(ast); + if (ret) + return ret; ++ physical_connector = &ast->output.sil164.sil164_connector.base; + } + if (ast->tx_chip_types & AST_TX_DP501_BIT) { + ret = ast_dp501_output_init(ast); + if (ret) + return ret; ++ physical_connector = &ast->output.dp501.connector; + } + if (ast->tx_chip_types & AST_TX_ASTDP_BIT) { + ret = ast_astdp_output_init(ast); + if (ret) + return ret; ++ physical_connector = &ast->output.astdp.connector; + } +- ret = ast_bmc_output_init(ast); ++ ret = ast_bmc_output_init(ast, physical_connector); + if (ret) + return ret; + +diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig +index 44a660a4bdbfc4..3e6a4e2044c0eb 100644 +--- a/drivers/gpu/drm/bridge/Kconfig ++++ b/drivers/gpu/drm/bridge/Kconfig +@@ -181,6 +181,7 @@ config DRM_NWL_MIPI_DSI + select DRM_KMS_HELPER + select DRM_MIPI_DSI + select DRM_PANEL_BRIDGE ++ select GENERIC_PHY + select GENERIC_PHY_MIPI_DPHY + select MFD_SYSCON + select MULTIPLEXER +@@ -227,6 +228,7 @@ config DRM_SAMSUNG_DSIM + select DRM_KMS_HELPER + select DRM_MIPI_DSI + select DRM_PANEL_BRIDGE ++ select GENERIC_PHY + select GENERIC_PHY_MIPI_DPHY + help + The Samsung MIPI DSIM bridge controller driver. +@@ -311,6 +313,7 @@ config DRM_TOSHIBA_TC358768 + select REGMAP_I2C + select DRM_PANEL + select DRM_MIPI_DSI ++ select VIDEOMODE_HELPERS + help + Toshiba TC358768AXBG/TC358778XBG DSI bridge chip driver. + +diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +index 2611afd2c1c136..ef2b6ce544d0a8 100644 +--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c ++++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +@@ -1291,17 +1291,6 @@ static int adv7511_probe(struct i2c_client *i2c) + + INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work); + +- if (i2c->irq) { +- init_waitqueue_head(&adv7511->wq); +- +- ret = devm_request_threaded_irq(dev, i2c->irq, NULL, +- adv7511_irq_handler, +- IRQF_ONESHOT, dev_name(dev), +- adv7511); +- if (ret) +- goto err_unregister_cec; +- } +- + adv7511_power_off(adv7511); + + i2c_set_clientdata(i2c, adv7511); +@@ -1325,6 +1314,17 @@ static int adv7511_probe(struct i2c_client *i2c) + + adv7511_audio_init(dev, adv7511); + ++ if (i2c->irq) { ++ init_waitqueue_head(&adv7511->wq); ++ ++ ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ++ adv7511_irq_handler, ++ IRQF_ONESHOT, dev_name(dev), ++ adv7511); ++ if (ret) ++ goto err_unregister_audio; ++ } ++ + if (adv7511->type == ADV7533 || adv7511->type == ADV7535) { + ret = adv7533_attach_dsi(adv7511); + if (ret) +diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +index 6a4f20fccf8417..7b0bc9704eacb1 100644 +--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c ++++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +@@ -1027,7 +1027,6 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, + u32 status_reg; + u8 *buffer = msg->buffer; + unsigned int i; +- int num_transferred = 0; + int ret; + + /* Buffer size of AUX CH is 16 bytes */ +@@ -1079,7 +1078,6 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, + reg = buffer[i]; + writel(reg, dp->reg_base + ANALOGIX_DP_BUF_DATA_0 + + 4 * i); +- num_transferred++; + } + } + +@@ -1127,7 +1125,6 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, + reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 + + 4 * i); + buffer[i] = (unsigned char)reg; +- num_transferred++; + } + } + +@@ -1144,7 +1141,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, + (msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_READ) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + +- return num_transferred > 0 ? num_transferred : -EBUSY; ++ return msg->size; + + aux_error: + /* if aux err happen, reset aux */ +diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c +index 51abe42c639e54..c1191ef5e8e679 100644 +--- a/drivers/gpu/drm/bridge/analogix/anx7625.c ++++ b/drivers/gpu/drm/bridge/analogix/anx7625.c +@@ -1298,10 +1298,32 @@ static void anx7625_config(struct anx7625_data *ctx) + XTAL_FRQ_SEL, XTAL_FRQ_27M); + } + ++static int anx7625_hpd_timer_config(struct anx7625_data *ctx) ++{ ++ int ret; ++ ++ /* Set irq detect window to 2ms */ ++ ret = anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, ++ HPD_DET_TIMER_BIT0_7, HPD_TIME & 0xFF); ++ ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, ++ HPD_DET_TIMER_BIT8_15, ++ (HPD_TIME >> 8) & 0xFF); ++ ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, ++ HPD_DET_TIMER_BIT16_23, ++ (HPD_TIME >> 16) & 0xFF); ++ ++ return ret; ++} ++ ++static int anx7625_read_hpd_gpio_config_status(struct anx7625_data *ctx) ++{ ++ return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, GPIO_CTRL_2); ++} ++ + static void anx7625_disable_pd_protocol(struct anx7625_data *ctx) + { + struct device *dev = ctx->dev; +- int ret; ++ int ret, val; + + /* Reset main ocm */ + ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, 0x88, 0x40); +@@ -1315,6 +1337,19 @@ static void anx7625_disable_pd_protocol(struct anx7625_data *ctx) + DRM_DEV_DEBUG_DRIVER(dev, "disable PD feature fail.\n"); + else + DRM_DEV_DEBUG_DRIVER(dev, "disable PD feature succeeded.\n"); ++ ++ /* ++ * Make sure the HPD GPIO already be configured after OCM release before ++ * setting HPD detect window register. Here we poll the status register ++ * at maximum 40ms, then config HPD irq detect window register ++ */ ++ readx_poll_timeout(anx7625_read_hpd_gpio_config_status, ++ ctx, val, ++ ((val & HPD_SOURCE) || (val < 0)), ++ 2000, 2000 * 20); ++ ++ /* Set HPD irq detect window to 2ms */ ++ anx7625_hpd_timer_config(ctx); + } + + static int anx7625_ocm_loading_check(struct anx7625_data *ctx) +@@ -1437,20 +1472,6 @@ static void anx7625_start_dp_work(struct anx7625_data *ctx) + + static int anx7625_read_hpd_status_p0(struct anx7625_data *ctx) + { +- int ret; +- +- /* Set irq detect window to 2ms */ +- ret = anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, +- HPD_DET_TIMER_BIT0_7, HPD_TIME & 0xFF); +- ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, +- HPD_DET_TIMER_BIT8_15, +- (HPD_TIME >> 8) & 0xFF); +- ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, +- HPD_DET_TIMER_BIT16_23, +- (HPD_TIME >> 16) & 0xFF); +- if (ret < 0) +- return ret; +- + return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, SYSTEM_STSTUS); + } + +@@ -1741,6 +1762,7 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux, + u8 request = msg->request & ~DP_AUX_I2C_MOT; + int ret = 0; + ++ mutex_lock(&ctx->aux_lock); + pm_runtime_get_sync(dev); + msg->reply = 0; + switch (request) { +@@ -1757,6 +1779,7 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux, + msg->size, msg->buffer); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); ++ mutex_unlock(&ctx->aux_lock); + + return ret; + } +@@ -2053,10 +2076,8 @@ static int anx7625_setup_dsi_device(struct anx7625_data *ctx) + }; + + host = of_find_mipi_dsi_host_by_node(ctx->pdata.mipi_host_node); +- if (!host) { +- DRM_DEV_ERROR(dev, "fail to find dsi host.\n"); +- return -EPROBE_DEFER; +- } ++ if (!host) ++ return dev_err_probe(dev, -EPROBE_DEFER, "fail to find dsi host.\n"); + + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); + if (IS_ERR(dsi)) { +@@ -2453,18 +2474,27 @@ static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge, + ctx->connector = NULL; + anx7625_dp_stop(ctx); + +- pm_runtime_put_sync(dev); ++ mutex_lock(&ctx->aux_lock); ++ pm_runtime_put_sync_suspend(dev); ++ mutex_unlock(&ctx->aux_lock); + } + ++static void ++anx7625_audio_update_connector_status(struct anx7625_data *ctx, ++ enum drm_connector_status status); ++ + static enum drm_connector_status + anx7625_bridge_detect(struct drm_bridge *bridge) + { + struct anx7625_data *ctx = bridge_to_anx7625(bridge); + struct device *dev = ctx->dev; ++ enum drm_connector_status status; + + DRM_DEV_DEBUG_DRIVER(dev, "drm bridge detect\n"); + +- return anx7625_sink_detect(ctx); ++ status = anx7625_sink_detect(ctx); ++ anx7625_audio_update_connector_status(ctx, status); ++ return status; + } + + static struct edid *anx7625_bridge_get_edid(struct drm_bridge *bridge, +@@ -2647,6 +2677,7 @@ static int anx7625_i2c_probe(struct i2c_client *client) + + mutex_init(&platform->lock); + mutex_init(&platform->hdcp_wq_lock); ++ mutex_init(&platform->aux_lock); + + INIT_DELAYED_WORK(&platform->hdcp_work, hdcp_check_work_func); + platform->hdcp_workqueue = create_workqueue("hdcp workqueue"); +diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h +index 5af819611ebce8..39ed35d3383633 100644 +--- a/drivers/gpu/drm/bridge/analogix/anx7625.h ++++ b/drivers/gpu/drm/bridge/analogix/anx7625.h +@@ -259,6 +259,10 @@ + #define AP_MIPI_RX_EN BIT(5) /* 1: MIPI RX input in 0: no RX in */ + #define AP_DISABLE_PD BIT(6) + #define AP_DISABLE_DISPLAY BIT(7) ++ ++#define GPIO_CTRL_2 0x49 ++#define HPD_SOURCE BIT(6) ++ + /***************************************************************/ + /* Register definition of device address 0x84 */ + #define MIPI_PHY_CONTROL_3 0x03 +@@ -471,6 +475,8 @@ struct anx7625_data { + struct workqueue_struct *hdcp_workqueue; + /* Lock for hdcp work queue */ + struct mutex hdcp_wq_lock; ++ /* Lock for aux transfer and disable */ ++ struct mutex aux_lock; + char edid_block; + struct display_timing dt; + u8 display_timing_valid; +diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig +index ec35215a20034c..cced81633ddcda 100644 +--- a/drivers/gpu/drm/bridge/cadence/Kconfig ++++ b/drivers/gpu/drm/bridge/cadence/Kconfig +@@ -4,6 +4,7 @@ config DRM_CDNS_DSI + select DRM_KMS_HELPER + select DRM_MIPI_DSI + select DRM_PANEL_BRIDGE ++ select GENERIC_PHY + select GENERIC_PHY_MIPI_DPHY + depends on OF + help +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index 6af565ac307ae3..858f5b6508491f 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -2057,6 +2057,9 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, + mhdp_state = to_cdns_mhdp_bridge_state(new_state); + + mhdp_state->current_mode = drm_mode_duplicate(bridge->dev, mode); ++ if (!mhdp_state->current_mode) ++ return; ++ + drm_mode_set_name(mhdp_state->current_mode); + + dev_dbg(mhdp->dev, "%s: Enabling mode %s\n", __func__, mode->name); +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c +index 946212a9559814..5e3b8edcf79487 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c +@@ -403,7 +403,8 @@ static int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp) + + static int _cdns_mhdp_hdcp_enable(struct cdns_mhdp_device *mhdp, u8 content_type) + { +- int ret, tries = 3; ++ int ret = -EINVAL; ++ int tries = 3; + u32 i; + + for (i = 0; i < tries; i++) { +diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c +index d205e755e524ae..5e295f86f2a73f 100644 +--- a/drivers/gpu/drm/bridge/chipone-icn6211.c ++++ b/drivers/gpu/drm/bridge/chipone-icn6211.c +@@ -563,10 +563,8 @@ static int chipone_dsi_host_attach(struct chipone *icn) + + host = of_find_mipi_dsi_host_by_node(host_node); + of_node_put(host_node); +- if (!host) { +- dev_err(dev, "failed to find dsi host\n"); +- return -EPROBE_DEFER; +- } ++ if (!host) ++ return dev_err_probe(dev, -EPROBE_DEFER, "failed to find dsi host\n"); + + dsi = mipi_dsi_device_register_full(host, &info); + if (IS_ERR(dsi)) { +diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c +index 2f300f5ca051cc..4ad527fe04f27e 100644 +--- a/drivers/gpu/drm/bridge/ite-it6505.c ++++ b/drivers/gpu/drm/bridge/ite-it6505.c +@@ -1306,9 +1306,15 @@ static void it6505_video_reset(struct it6505 *it6505) + it6505_link_reset_step_train(it6505); + it6505_set_bits(it6505, REG_DATA_MUTE_CTRL, EN_VID_MUTE, EN_VID_MUTE); + it6505_set_bits(it6505, REG_INFOFRAME_CTRL, EN_VID_CTRL_PKT, 0x00); +- it6505_set_bits(it6505, REG_RESET_CTRL, VIDEO_RESET, VIDEO_RESET); ++ ++ it6505_set_bits(it6505, REG_VID_BUS_CTRL1, TX_FIFO_RESET, TX_FIFO_RESET); ++ it6505_set_bits(it6505, REG_VID_BUS_CTRL1, TX_FIFO_RESET, 0x00); ++ + it6505_set_bits(it6505, REG_501_FIFO_CTRL, RST_501_FIFO, RST_501_FIFO); + it6505_set_bits(it6505, REG_501_FIFO_CTRL, RST_501_FIFO, 0x00); ++ ++ it6505_set_bits(it6505, REG_RESET_CTRL, VIDEO_RESET, VIDEO_RESET); ++ usleep_range(1000, 2000); + it6505_set_bits(it6505, REG_RESET_CTRL, VIDEO_RESET, 0x00); + } + +@@ -2240,14 +2246,15 @@ static void it6505_link_training_work(struct work_struct *work) + ret = it6505_link_start_auto_train(it6505); + DRM_DEV_DEBUG_DRIVER(dev, "auto train %s, auto_train_retry: %d", + ret ? "pass" : "failed", it6505->auto_train_retry); +- it6505->auto_train_retry--; + + if (ret) { ++ it6505->auto_train_retry = AUTO_TRAIN_RETRY; + it6505_link_train_ok(it6505); +- return; ++ } else { ++ it6505->auto_train_retry--; ++ it6505_dump(it6505); + } + +- it6505_dump(it6505); + } + + static void it6505_plugged_status_to_codec(struct it6505 *it6505) +@@ -2468,31 +2475,53 @@ static void it6505_irq_link_train_fail(struct it6505 *it6505) + schedule_work(&it6505->link_works); + } + +-static void it6505_irq_video_fifo_error(struct it6505 *it6505) ++static bool it6505_test_bit(unsigned int bit, const unsigned int *addr) + { +- struct device *dev = it6505->dev; +- +- DRM_DEV_DEBUG_DRIVER(dev, "video fifo overflow interrupt"); +- it6505->auto_train_retry = AUTO_TRAIN_RETRY; +- flush_work(&it6505->link_works); +- it6505_stop_hdcp(it6505); +- it6505_video_reset(it6505); ++ return 1 & (addr[bit / BITS_PER_BYTE] >> (bit % BITS_PER_BYTE)); + } + +-static void it6505_irq_io_latch_fifo_overflow(struct it6505 *it6505) ++static void it6505_irq_video_handler(struct it6505 *it6505, const int *int_status) + { + struct device *dev = it6505->dev; ++ int reg_0d, reg_int03; + +- DRM_DEV_DEBUG_DRIVER(dev, "IO latch fifo overflow interrupt"); +- it6505->auto_train_retry = AUTO_TRAIN_RETRY; +- flush_work(&it6505->link_works); +- it6505_stop_hdcp(it6505); +- it6505_video_reset(it6505); +-} ++ /* ++ * When video SCDT change with video not stable, ++ * Or video FIFO error, need video reset ++ */ + +-static bool it6505_test_bit(unsigned int bit, const unsigned int *addr) +-{ +- return 1 & (addr[bit / BITS_PER_BYTE] >> (bit % BITS_PER_BYTE)); ++ if ((!it6505_get_video_status(it6505) && ++ (it6505_test_bit(INT_SCDT_CHANGE, (unsigned int *)int_status))) || ++ (it6505_test_bit(BIT_INT_IO_FIFO_OVERFLOW, ++ (unsigned int *)int_status)) || ++ (it6505_test_bit(BIT_INT_VID_FIFO_ERROR, ++ (unsigned int *)int_status))) { ++ it6505->auto_train_retry = AUTO_TRAIN_RETRY; ++ flush_work(&it6505->link_works); ++ it6505_stop_hdcp(it6505); ++ it6505_video_reset(it6505); ++ ++ usleep_range(10000, 11000); ++ ++ /* ++ * Clear FIFO error IRQ to prevent fifo error -> reset loop ++ * HW will trigger SCDT change IRQ again when video stable ++ */ ++ ++ reg_int03 = it6505_read(it6505, INT_STATUS_03); ++ reg_0d = it6505_read(it6505, REG_SYSTEM_STS); ++ ++ reg_int03 &= (BIT(INT_VID_FIFO_ERROR) | BIT(INT_IO_LATCH_FIFO_OVERFLOW)); ++ it6505_write(it6505, INT_STATUS_03, reg_int03); ++ ++ DRM_DEV_DEBUG_DRIVER(dev, "reg08 = 0x%02x", reg_int03); ++ DRM_DEV_DEBUG_DRIVER(dev, "reg0D = 0x%02x", reg_0d); ++ ++ return; ++ } ++ ++ if (it6505_test_bit(INT_SCDT_CHANGE, (unsigned int *)int_status)) ++ it6505_irq_scdt(it6505); + } + + static irqreturn_t it6505_int_threaded_handler(int unused, void *data) +@@ -2505,15 +2534,12 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data) + } irq_vec[] = { + { BIT_INT_HPD, it6505_irq_hpd }, + { BIT_INT_HPD_IRQ, it6505_irq_hpd_irq }, +- { BIT_INT_SCDT, it6505_irq_scdt }, + { BIT_INT_HDCP_FAIL, it6505_irq_hdcp_fail }, + { BIT_INT_HDCP_DONE, it6505_irq_hdcp_done }, + { BIT_INT_AUX_CMD_FAIL, it6505_irq_aux_cmd_fail }, + { BIT_INT_HDCP_KSV_CHECK, it6505_irq_hdcp_ksv_check }, + { BIT_INT_AUDIO_FIFO_ERROR, it6505_irq_audio_fifo_error }, + { BIT_INT_LINK_TRAIN_FAIL, it6505_irq_link_train_fail }, +- { BIT_INT_VID_FIFO_ERROR, it6505_irq_video_fifo_error }, +- { BIT_INT_IO_FIFO_OVERFLOW, it6505_irq_io_latch_fifo_overflow }, + }; + int int_status[3], i; + +@@ -2543,6 +2569,7 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data) + if (it6505_test_bit(irq_vec[i].bit, (unsigned int *)int_status)) + irq_vec[i].handler(it6505); + } ++ it6505_irq_video_handler(it6505, (unsigned int *)int_status); + } + + pm_runtime_put_sync(dev); +diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c +index 466641c77fe911..8f5846b76d5943 100644 +--- a/drivers/gpu/drm/bridge/ite-it66121.c ++++ b/drivers/gpu/drm/bridge/ite-it66121.c +@@ -884,14 +884,14 @@ static struct edid *it66121_bridge_get_edid(struct drm_bridge *bridge, + mutex_lock(&ctx->lock); + ret = it66121_preamble_ddc(ctx); + if (ret) { +- edid = ERR_PTR(ret); ++ edid = NULL; + goto out_unlock; + } + + ret = regmap_write(ctx->regmap, IT66121_DDC_HEADER_REG, + IT66121_DDC_HEADER_EDID); + if (ret) { +- edid = ERR_PTR(ret); ++ edid = NULL; + goto out_unlock; + } + +@@ -1447,10 +1447,14 @@ static int it66121_audio_get_eld(struct device *dev, void *data, + struct it66121_ctx *ctx = dev_get_drvdata(dev); + + mutex_lock(&ctx->lock); +- +- memcpy(buf, ctx->connector->eld, +- min(sizeof(ctx->connector->eld), len)); +- ++ if (!ctx->connector) { ++ /* Pass en empty ELD if connector not available */ ++ dev_dbg(dev, "No connector present, passing empty EDID data"); ++ memset(buf, 0, len); ++ } else { ++ memcpy(buf, ctx->connector->eld, ++ min(sizeof(ctx->connector->eld), len)); ++ } + mutex_unlock(&ctx->lock); + + return 0; +diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c +index 4eaea67fb71c20..5e43a40a5d5221 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt8912b.c ++++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c +@@ -45,7 +45,6 @@ struct lt8912 { + + u8 data_lanes; + bool is_power_on; +- bool is_attached; + }; + + static int lt8912_write_init_config(struct lt8912 *lt) +@@ -412,50 +411,31 @@ static const struct drm_connector_funcs lt8912_connector_funcs = { + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + }; + +-static enum drm_mode_status +-lt8912_connector_mode_valid(struct drm_connector *connector, +- struct drm_display_mode *mode) +-{ +- if (mode->clock > 150000) +- return MODE_CLOCK_HIGH; +- +- if (mode->hdisplay > 1920) +- return MODE_BAD_HVALUE; +- +- if (mode->vdisplay > 1080) +- return MODE_BAD_VVALUE; +- +- return MODE_OK; +-} +- + static int lt8912_connector_get_modes(struct drm_connector *connector) + { +- struct edid *edid; +- int ret = -1; +- int num = 0; ++ const struct drm_edid *drm_edid; + struct lt8912 *lt = connector_to_lt8912(connector); + u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; ++ int ret, num; + +- edid = drm_bridge_get_edid(lt->hdmi_port, connector); +- if (edid) { +- drm_connector_update_edid_property(connector, edid); +- num = drm_add_edid_modes(connector, edid); +- } else { +- return ret; +- } ++ drm_edid = drm_bridge_edid_read(lt->hdmi_port, connector); ++ drm_edid_connector_update(connector, drm_edid); ++ if (!drm_edid) ++ return 0; ++ ++ num = drm_edid_connector_add_modes(connector); + + ret = drm_display_info_set_bus_formats(&connector->display_info, + &bus_format, 1); +- if (ret) +- num = ret; ++ if (ret < 0) ++ num = 0; + +- kfree(edid); ++ drm_edid_free(drm_edid); + return num; + } + + static const struct drm_connector_helper_funcs lt8912_connector_helper_funcs = { + .get_modes = lt8912_connector_get_modes, +- .mode_valid = lt8912_connector_mode_valid, + }; + + static void lt8912_bridge_mode_set(struct drm_bridge *bridge, +@@ -486,10 +466,8 @@ static int lt8912_attach_dsi(struct lt8912 *lt) + }; + + host = of_find_mipi_dsi_host_by_node(lt->host_node); +- if (!host) { +- dev_err(dev, "failed to find dsi host\n"); +- return -EPROBE_DEFER; +- } ++ if (!host) ++ return dev_err_probe(dev, -EPROBE_DEFER, "failed to find dsi host\n"); + + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); + if (IS_ERR(dsi)) { +@@ -559,6 +537,13 @@ static int lt8912_bridge_attach(struct drm_bridge *bridge, + struct lt8912 *lt = bridge_to_lt8912(bridge); + int ret; + ++ ret = drm_bridge_attach(bridge->encoder, lt->hdmi_port, bridge, ++ DRM_BRIDGE_ATTACH_NO_CONNECTOR); ++ if (ret < 0) { ++ dev_err(lt->dev, "Failed to attach next bridge (%d)\n", ret); ++ return ret; ++ } ++ + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { + ret = lt8912_bridge_connector_init(bridge); + if (ret) { +@@ -575,8 +560,6 @@ static int lt8912_bridge_attach(struct drm_bridge *bridge, + if (ret) + goto error; + +- lt->is_attached = true; +- + return 0; + + error: +@@ -588,15 +571,27 @@ static void lt8912_bridge_detach(struct drm_bridge *bridge) + { + struct lt8912 *lt = bridge_to_lt8912(bridge); + +- if (lt->is_attached) { +- lt8912_hard_power_off(lt); ++ lt8912_hard_power_off(lt); + +- if (lt->hdmi_port->ops & DRM_BRIDGE_OP_HPD) +- drm_bridge_hpd_disable(lt->hdmi_port); ++ if (lt->connector.dev && lt->hdmi_port->ops & DRM_BRIDGE_OP_HPD) ++ drm_bridge_hpd_disable(lt->hdmi_port); ++} + +- drm_connector_unregister(<->connector); +- drm_connector_cleanup(<->connector); +- } ++static enum drm_mode_status ++lt8912_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, ++ const struct drm_display_mode *mode) ++{ ++ if (mode->clock > 150000) ++ return MODE_CLOCK_HIGH; ++ ++ if (mode->hdisplay > 1920) ++ return MODE_BAD_HVALUE; ++ ++ if (mode->vdisplay > 1080) ++ return MODE_BAD_VVALUE; ++ ++ return MODE_OK; + } + + static enum drm_connector_status +@@ -629,6 +624,7 @@ static struct edid *lt8912_bridge_get_edid(struct drm_bridge *bridge, + static const struct drm_bridge_funcs lt8912_bridge_funcs = { + .attach = lt8912_bridge_attach, + .detach = lt8912_bridge_detach, ++ .mode_valid = lt8912_bridge_mode_valid, + .mode_set = lt8912_bridge_mode_set, + .enable = lt8912_bridge_enable, + .detect = lt8912_bridge_detect, +@@ -750,7 +746,6 @@ static void lt8912_remove(struct i2c_client *client) + { + struct lt8912 *lt = i2c_get_clientdata(client); + +- lt8912_bridge_detach(<->bridge); + drm_bridge_remove(<->bridge); + lt8912_free_i2c(lt); + lt8912_put_dt(lt); +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index 9663601ce09818..89bdd938757e11 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -760,10 +760,8 @@ static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611, + int ret; + + host = of_find_mipi_dsi_host_by_node(dsi_node); +- if (!host) { +- dev_err(lt9611->dev, "failed to find dsi host\n"); +- return ERR_PTR(-EPROBE_DEFER); +- } ++ if (!host) ++ return ERR_PTR(dev_err_probe(lt9611->dev, -EPROBE_DEFER, "failed to find dsi host\n")); + + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); + if (IS_ERR(dsi)) { +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +index 22c84d29c2bc58..c41ffd0bc04941 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +@@ -265,10 +265,8 @@ static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc, + int ret; + + host = of_find_mipi_dsi_host_by_node(dsi_node); +- if (!host) { +- dev_err(dev, "failed to find dsi host\n"); +- return ERR_PTR(-EPROBE_DEFER); +- } ++ if (!host) ++ return ERR_PTR(dev_err_probe(dev, -EPROBE_DEFER, "failed to find dsi host\n")); + + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); + if (IS_ERR(dsi)) { +@@ -929,9 +927,9 @@ static int lt9611uxc_probe(struct i2c_client *client) + init_waitqueue_head(<9611uxc->wq); + INIT_WORK(<9611uxc->work, lt9611uxc_hpd_work); + +- ret = devm_request_threaded_irq(dev, client->irq, NULL, +- lt9611uxc_irq_thread_handler, +- IRQF_ONESHOT, "lt9611uxc", lt9611uxc); ++ ret = request_threaded_irq(client->irq, NULL, ++ lt9611uxc_irq_thread_handler, ++ IRQF_ONESHOT, "lt9611uxc", lt9611uxc); + if (ret) { + dev_err(dev, "failed to request irq\n"); + goto err_disable_regulators; +@@ -967,6 +965,8 @@ static int lt9611uxc_probe(struct i2c_client *client) + return lt9611uxc_audio_init(dev, lt9611uxc); + + err_remove_bridge: ++ free_irq(client->irq, lt9611uxc); ++ cancel_work_sync(<9611uxc->work); + drm_bridge_remove(<9611uxc->bridge); + + err_disable_regulators: +@@ -983,7 +983,7 @@ static void lt9611uxc_remove(struct i2c_client *client) + { + struct lt9611uxc *lt9611uxc = i2c_get_clientdata(client); + +- disable_irq(client->irq); ++ free_irq(client->irq, lt9611uxc); + cancel_work_sync(<9611uxc->work); + lt9611uxc_audio_exit(lt9611uxc); + drm_bridge_remove(<9611uxc->bridge); +diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c +index d81920227a8aeb..7c0076e499533a 100644 +--- a/drivers/gpu/drm/bridge/nxp-ptn3460.c ++++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c +@@ -54,13 +54,13 @@ static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, + int ret; + + ret = i2c_master_send(ptn_bridge->client, &addr, 1); +- if (ret <= 0) { ++ if (ret < 0) { + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); + return ret; + } + + ret = i2c_master_recv(ptn_bridge->client, buf, len); +- if (ret <= 0) { ++ if (ret < 0) { + DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret); + return ret; + } +@@ -78,7 +78,7 @@ static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr, + buf[1] = val; + + ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf)); +- if (ret <= 0) { ++ if (ret < 0) { + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); + return ret; + } +diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c +index 9316384b44745b..a1dd2ead8dcc4d 100644 +--- a/drivers/gpu/drm/bridge/panel.c ++++ b/drivers/gpu/drm/bridge/panel.c +@@ -360,9 +360,12 @@ EXPORT_SYMBOL(drm_panel_bridge_set_orientation); + + static void devm_drm_panel_bridge_release(struct device *dev, void *res) + { +- struct drm_bridge **bridge = res; ++ struct drm_bridge *bridge = *(struct drm_bridge **)res; + +- drm_panel_bridge_remove(*bridge); ++ if (!bridge) ++ return; ++ ++ drm_bridge_remove(bridge); + } + + /** +diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c +index 8161b1a1a4b12f..14d4dcf239da83 100644 +--- a/drivers/gpu/drm/bridge/parade-ps8640.c ++++ b/drivers/gpu/drm/bridge/parade-ps8640.c +@@ -107,6 +107,7 @@ struct ps8640 { + struct device_link *link; + bool pre_enabled; + bool need_post_hpd_delay; ++ struct mutex aux_lock; + }; + + static const struct regmap_config ps8640_regmap_config[] = { +@@ -210,7 +211,7 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux, + struct ps8640 *ps_bridge = aux_to_ps8640(aux); + struct regmap *map = ps_bridge->regmap[PAGE0_DP_CNTL]; + struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev; +- unsigned int len = msg->size; ++ size_t len = msg->size; + unsigned int data; + unsigned int base; + int ret; +@@ -330,11 +331,12 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux, + return ret; + } + +- buf[i] = data; ++ if (i < msg->size) ++ buf[i] = data; + } + } + +- return len; ++ return min(len, msg->size); + } + + static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux, +@@ -344,11 +346,20 @@ static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux, + struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev; + int ret; + ++ mutex_lock(&ps_bridge->aux_lock); + pm_runtime_get_sync(dev); ++ ret = _ps8640_wait_hpd_asserted(ps_bridge, 200 * 1000); ++ if (ret) { ++ pm_runtime_put_sync_suspend(dev); ++ goto exit; ++ } + ret = ps8640_aux_transfer_msg(aux, msg); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + ++exit: ++ mutex_unlock(&ps_bridge->aux_lock); ++ + return ret; + } + +@@ -469,7 +480,18 @@ static void ps8640_atomic_post_disable(struct drm_bridge *bridge, + ps_bridge->pre_enabled = false; + + ps8640_bridge_vdo_control(ps_bridge, DISABLE); ++ ++ /* ++ * The bridge seems to expect everything to be power cycled at the ++ * disable process, so grab a lock here to make sure ++ * ps8640_aux_transfer() is not holding a runtime PM reference and ++ * preventing the bridge from suspend. ++ */ ++ mutex_lock(&ps_bridge->aux_lock); ++ + pm_runtime_put_sync_suspend(&ps_bridge->page[PAGE0_DP_CNTL]->dev); ++ ++ mutex_unlock(&ps_bridge->aux_lock); + } + + static int ps8640_bridge_attach(struct drm_bridge *bridge, +@@ -618,6 +640,8 @@ static int ps8640_probe(struct i2c_client *client) + if (!ps_bridge) + return -ENOMEM; + ++ mutex_init(&ps_bridge->aux_lock); ++ + ps_bridge->supplies[0].supply = "vdd12"; + ps_bridge->supplies[1].supply = "vdd33"; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies), +diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c +index cf777bdb25d2a4..f24666b4819384 100644 +--- a/drivers/gpu/drm/bridge/samsung-dsim.c ++++ b/drivers/gpu/drm/bridge/samsung-dsim.c +@@ -385,7 +385,7 @@ static const unsigned int imx8mm_dsim_reg_values[] = { + [RESET_TYPE] = DSIM_SWRST, + [PLL_TIMER] = 500, + [STOP_STATE_CNT] = 0xf, +- [PHYCTRL_ULPS_EXIT] = 0, ++ [PHYCTRL_ULPS_EXIT] = DSIM_PHYCTRL_ULPS_EXIT(0xaf), + [PHYCTRL_VREG_LP] = 0, + [PHYCTRL_SLEW_UP] = 0, + [PHYTIMING_LPX] = DSIM_PHYTIMING_LPX(0x06), +@@ -413,6 +413,7 @@ static const struct samsung_dsim_driver_data exynos3_dsi_driver_data = { + .m_min = 41, + .m_max = 125, + .min_freq = 500, ++ .has_broken_fifoctrl_emptyhdr = 1, + }; + + static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { +@@ -429,6 +430,7 @@ static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { + .m_min = 41, + .m_max = 125, + .min_freq = 500, ++ .has_broken_fifoctrl_emptyhdr = 1, + }; + + static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { +@@ -939,10 +941,6 @@ static int samsung_dsim_init_link(struct samsung_dsim *dsi) + reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG); + reg &= ~DSIM_STOP_STATE_CNT_MASK; + reg |= DSIM_STOP_STATE_CNT(driver_data->reg_values[STOP_STATE_CNT]); +- +- if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) +- reg |= DSIM_FORCE_STOP_STATE; +- + samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg); + + reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff); +@@ -1010,8 +1008,20 @@ static int samsung_dsim_wait_for_hdr_fifo(struct samsung_dsim *dsi) + do { + u32 reg = samsung_dsim_read(dsi, DSIM_FIFOCTRL_REG); + +- if (reg & DSIM_SFR_HEADER_EMPTY) +- return 0; ++ if (!dsi->driver_data->has_broken_fifoctrl_emptyhdr) { ++ if (reg & DSIM_SFR_HEADER_EMPTY) ++ return 0; ++ } else { ++ if (!(reg & DSIM_SFR_HEADER_FULL)) { ++ /* ++ * Wait a little bit, so the pending data can ++ * actually leave the FIFO to avoid overflow. ++ */ ++ if (!cond_resched()) ++ usleep_range(950, 1050); ++ return 0; ++ } ++ } + + if (!cond_resched()) + usleep_range(950, 1050); +@@ -1387,18 +1397,6 @@ static void samsung_dsim_disable_irq(struct samsung_dsim *dsi) + disable_irq(dsi->irq); + } + +-static void samsung_dsim_set_stop_state(struct samsung_dsim *dsi, bool enable) +-{ +- u32 reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG); +- +- if (enable) +- reg |= DSIM_FORCE_STOP_STATE; +- else +- reg &= ~DSIM_FORCE_STOP_STATE; +- +- samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg); +-} +- + static int samsung_dsim_init(struct samsung_dsim *dsi) + { + const struct samsung_dsim_driver_data *driver_data = dsi->driver_data; +@@ -1448,9 +1446,6 @@ static void samsung_dsim_atomic_pre_enable(struct drm_bridge *bridge, + ret = samsung_dsim_init(dsi); + if (ret) + return; +- +- samsung_dsim_set_display_mode(dsi); +- samsung_dsim_set_display_enable(dsi, true); + } + } + +@@ -1459,12 +1454,8 @@ static void samsung_dsim_atomic_enable(struct drm_bridge *bridge, + { + struct samsung_dsim *dsi = bridge_to_dsi(bridge); + +- if (samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) { +- samsung_dsim_set_display_mode(dsi); +- samsung_dsim_set_display_enable(dsi, true); +- } else { +- samsung_dsim_set_stop_state(dsi, false); +- } ++ samsung_dsim_set_display_mode(dsi); ++ samsung_dsim_set_display_enable(dsi, true); + + dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; + } +@@ -1477,9 +1468,6 @@ static void samsung_dsim_atomic_disable(struct drm_bridge *bridge, + if (!(dsi->state & DSIM_STATE_ENABLED)) + return; + +- if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) +- samsung_dsim_set_stop_state(dsi, true); +- + dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE; + } + +@@ -1781,8 +1769,6 @@ static ssize_t samsung_dsim_host_transfer(struct mipi_dsi_host *host, + if (ret) + return ret; + +- samsung_dsim_set_stop_state(dsi, false); +- + ret = mipi_dsi_create_packet(&xfer.packet, msg); + if (ret < 0) + return ret; +diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c +index 2bdc5b439bebd5..4560ae9cbce150 100644 +--- a/drivers/gpu/drm/bridge/sii902x.c ++++ b/drivers/gpu/drm/bridge/sii902x.c +@@ -1080,6 +1080,26 @@ static int sii902x_init(struct sii902x *sii902x) + return ret; + } + ++ ret = sii902x_audio_codec_init(sii902x, dev); ++ if (ret) ++ return ret; ++ ++ i2c_set_clientdata(sii902x->i2c, sii902x); ++ ++ sii902x->i2cmux = i2c_mux_alloc(sii902x->i2c->adapter, dev, ++ 1, 0, I2C_MUX_GATE, ++ sii902x_i2c_bypass_select, ++ sii902x_i2c_bypass_deselect); ++ if (!sii902x->i2cmux) { ++ ret = -ENOMEM; ++ goto err_unreg_audio; ++ } ++ ++ sii902x->i2cmux->priv = sii902x; ++ ret = i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0); ++ if (ret) ++ goto err_unreg_audio; ++ + sii902x->bridge.funcs = &sii902x_bridge_funcs; + sii902x->bridge.of_node = dev->of_node; + sii902x->bridge.timings = &default_sii902x_timings; +@@ -1090,19 +1110,13 @@ static int sii902x_init(struct sii902x *sii902x) + + drm_bridge_add(&sii902x->bridge); + +- sii902x_audio_codec_init(sii902x, dev); +- +- i2c_set_clientdata(sii902x->i2c, sii902x); ++ return 0; + +- sii902x->i2cmux = i2c_mux_alloc(sii902x->i2c->adapter, dev, +- 1, 0, I2C_MUX_GATE, +- sii902x_i2c_bypass_select, +- sii902x_i2c_bypass_deselect); +- if (!sii902x->i2cmux) +- return -ENOMEM; ++err_unreg_audio: ++ if (!PTR_ERR_OR_ZERO(sii902x->audio.pdev)) ++ platform_device_unregister(sii902x->audio.pdev); + +- sii902x->i2cmux->priv = sii902x; +- return i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0); ++ return ret; + } + + static int sii902x_probe(struct i2c_client *client) +@@ -1170,12 +1184,14 @@ static int sii902x_probe(struct i2c_client *client) + } + + static void sii902x_remove(struct i2c_client *client) +- + { + struct sii902x *sii902x = i2c_get_clientdata(client); + +- i2c_mux_del_adapters(sii902x->i2cmux); + drm_bridge_remove(&sii902x->bridge); ++ i2c_mux_del_adapters(sii902x->i2cmux); ++ ++ if (!PTR_ERR_OR_ZERO(sii902x->audio.pdev)) ++ platform_device_unregister(sii902x->audio.pdev); + } + + static const struct of_device_id sii902x_dt_ids[] = { +diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c +index b45bffab7c8174..7fd4a5fe03edf6 100644 +--- a/drivers/gpu/drm/bridge/tc358767.c ++++ b/drivers/gpu/drm/bridge/tc358767.c +@@ -2034,7 +2034,7 @@ static irqreturn_t tc_irq_handler(int irq, void *arg) + dev_err(tc->dev, "syserr %x\n", stat); + } + +- if (tc->hpd_pin >= 0 && tc->bridge.dev) { ++ if (tc->hpd_pin >= 0 && tc->bridge.dev && tc->aux.drm_dev) { + /* + * H is triggered when the GPIO goes high. + * +@@ -2273,7 +2273,7 @@ static int tc_probe(struct i2c_client *client) + } else { + if (tc->hpd_pin < 0 || tc->hpd_pin > 1) { + dev_err(dev, "failed to parse HPD number\n"); +- return ret; ++ return -EINVAL; + } + } + +diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c +index 819a4b6ec2a07f..c72d5fbbb0ec40 100644 +--- a/drivers/gpu/drm/bridge/tc358768.c ++++ b/drivers/gpu/drm/bridge/tc358768.c +@@ -9,12 +9,14 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include + #include ++#include + + #include + #include +@@ -156,6 +158,7 @@ struct tc358768_priv { + u32 frs; /* PLL Freqency range for HSCK (post divider) */ + + u32 dsiclk; /* pll_clk / 2 */ ++ u32 pclk; /* incoming pclk rate */ + }; + + static inline struct tc358768_priv *dsi_host_to_tc358768(struct mipi_dsi_host +@@ -216,6 +219,10 @@ static void tc358768_update_bits(struct tc358768_priv *priv, u32 reg, u32 mask, + u32 tmp, orig; + + tc358768_read(priv, reg, &orig); ++ ++ if (priv->error) ++ return; ++ + tmp = orig & ~mask; + tmp |= val & mask; + if (tmp != orig) +@@ -375,6 +382,7 @@ static int tc358768_calc_pll(struct tc358768_priv *priv, + priv->prd = best_prd; + priv->frs = frs; + priv->dsiclk = best_pll / 2; ++ priv->pclk = mode->clock * 1000; + + return 0; + } +@@ -600,7 +608,7 @@ static int tc358768_setup_pll(struct tc358768_priv *priv, + + dev_dbg(priv->dev, "PLL: refclk %lu, fbd %u, prd %u, frs %u\n", + clk_get_rate(priv->refclk), fbd, prd, frs); +- dev_dbg(priv->dev, "PLL: pll_clk: %u, DSIClk %u, DSIByteClk %u\n", ++ dev_dbg(priv->dev, "PLL: pll_clk: %u, DSIClk %u, HSByteClk %u\n", + priv->dsiclk * 2, priv->dsiclk, priv->dsiclk / 4); + dev_dbg(priv->dev, "PLL: pclk %u (panel: %u)\n", + tc358768_pll_to_pclk(priv, priv->dsiclk * 2), +@@ -623,15 +631,36 @@ static int tc358768_setup_pll(struct tc358768_priv *priv, + return tc358768_clear_error(priv); + } + +-#define TC358768_PRECISION 1000 +-static u32 tc358768_ns_to_cnt(u32 ns, u32 period_nsk) ++static u32 tc358768_ns_to_cnt(u32 ns, u32 period_ps) ++{ ++ return DIV_ROUND_UP(ns * 1000, period_ps); ++} ++ ++static u32 tc358768_ps_to_ns(u32 ps) + { +- return (ns * TC358768_PRECISION + period_nsk) / period_nsk; ++ return ps / 1000; + } + +-static u32 tc358768_to_ns(u32 nsk) ++static u32 tc358768_dpi_to_ns(u32 val, u32 pclk) + { +- return (nsk / TC358768_PRECISION); ++ return (u32)div_u64((u64)val * NANO, pclk); ++} ++ ++/* Convert value in DPI pixel clock units to DSI byte count */ ++static u32 tc358768_dpi_to_dsi_bytes(struct tc358768_priv *priv, u32 val) ++{ ++ u64 m = (u64)val * priv->dsiclk / 4 * priv->dsi_lanes; ++ u64 n = priv->pclk; ++ ++ return (u32)div_u64(m + n - 1, n); ++} ++ ++static u32 tc358768_dsi_bytes_to_ns(struct tc358768_priv *priv, u32 val) ++{ ++ u64 m = (u64)val * NANO; ++ u64 n = priv->dsiclk / 4 * priv->dsi_lanes; ++ ++ return (u32)div_u64(m, n); + } + + static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) +@@ -642,13 +671,23 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) + u32 val, val2, lptxcnt, hact, data_type; + s32 raw_val; + const struct drm_display_mode *mode; +- u32 dsibclk_nsk, dsiclk_nsk, ui_nsk; +- u32 dsiclk, dsibclk, video_start; +- const u32 internal_delay = 40; ++ u32 hsbyteclk_ps, dsiclk_ps, ui_ps; ++ u32 dsiclk, hsbyteclk; + int ret, i; ++ struct videomode vm; ++ struct device *dev = priv->dev; ++ /* In pixelclock units */ ++ u32 dpi_htot, dpi_data_start; ++ /* In byte units */ ++ u32 dsi_dpi_htot, dsi_dpi_data_start; ++ u32 dsi_hsw, dsi_hbp, dsi_hact, dsi_hfp; ++ const u32 dsi_hss = 4; /* HSS is a short packet (4 bytes) */ ++ /* In hsbyteclk units */ ++ u32 dsi_vsdly; ++ const u32 internal_dly = 40; + + if (mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) { +- dev_warn_once(priv->dev, "Non-continuous mode unimplemented, falling back to continuous\n"); ++ dev_warn_once(dev, "Non-continuous mode unimplemented, falling back to continuous\n"); + mode_flags &= ~MIPI_DSI_CLOCK_NON_CONTINUOUS; + } + +@@ -656,7 +695,7 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) + + ret = tc358768_sw_reset(priv); + if (ret) { +- dev_err(priv->dev, "Software reset failed: %d\n", ret); ++ dev_err(dev, "Software reset failed: %d\n", ret); + tc358768_hw_disable(priv); + return; + } +@@ -664,53 +703,194 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) + mode = &bridge->encoder->crtc->state->adjusted_mode; + ret = tc358768_setup_pll(priv, mode); + if (ret) { +- dev_err(priv->dev, "PLL setup failed: %d\n", ret); ++ dev_err(dev, "PLL setup failed: %d\n", ret); + tc358768_hw_disable(priv); + return; + } + ++ drm_display_mode_to_videomode(mode, &vm); ++ + dsiclk = priv->dsiclk; +- dsibclk = dsiclk / 4; ++ hsbyteclk = dsiclk / 4; + + /* Data Format Control Register */ + val = BIT(2) | BIT(1) | BIT(0); /* rdswap_en | dsitx_en | txdt_en */ + switch (dsi_dev->format) { + case MIPI_DSI_FMT_RGB888: + val |= (0x3 << 4); +- hact = mode->hdisplay * 3; +- video_start = (mode->htotal - mode->hsync_start) * 3; ++ hact = vm.hactive * 3; + data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; + break; + case MIPI_DSI_FMT_RGB666: + val |= (0x4 << 4); +- hact = mode->hdisplay * 3; +- video_start = (mode->htotal - mode->hsync_start) * 3; ++ hact = vm.hactive * 3; + data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18; + break; + + case MIPI_DSI_FMT_RGB666_PACKED: + val |= (0x4 << 4) | BIT(3); +- hact = mode->hdisplay * 18 / 8; +- video_start = (mode->htotal - mode->hsync_start) * 18 / 8; ++ hact = vm.hactive * 18 / 8; + data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18; + break; + + case MIPI_DSI_FMT_RGB565: + val |= (0x5 << 4); +- hact = mode->hdisplay * 2; +- video_start = (mode->htotal - mode->hsync_start) * 2; ++ hact = vm.hactive * 2; + data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; + break; + default: +- dev_err(priv->dev, "Invalid data format (%u)\n", ++ dev_err(dev, "Invalid data format (%u)\n", + dsi_dev->format); + tc358768_hw_disable(priv); + return; + } + ++ /* ++ * There are three important things to make TC358768 work correctly, ++ * which are not trivial to manage: ++ * ++ * 1. Keep the DPI line-time and the DSI line-time as close to each ++ * other as possible. ++ * 2. TC358768 goes to LP mode after each line's active area. The DSI ++ * HFP period has to be long enough for entering and exiting LP mode. ++ * But it is not clear how to calculate this. ++ * 3. VSDly (video start delay) has to be long enough to ensure that the ++ * DSI TX does not start transmitting until we have started receiving ++ * pixel data from the DPI input. It is not clear how to calculate ++ * this either. ++ */ ++ ++ dpi_htot = vm.hactive + vm.hfront_porch + vm.hsync_len + vm.hback_porch; ++ dpi_data_start = vm.hsync_len + vm.hback_porch; ++ ++ dev_dbg(dev, "dpi horiz timing (pclk): %u + %u + %u + %u = %u\n", ++ vm.hsync_len, vm.hback_porch, vm.hactive, vm.hfront_porch, ++ dpi_htot); ++ ++ dev_dbg(dev, "dpi horiz timing (ns): %u + %u + %u + %u = %u\n", ++ tc358768_dpi_to_ns(vm.hsync_len, vm.pixelclock), ++ tc358768_dpi_to_ns(vm.hback_porch, vm.pixelclock), ++ tc358768_dpi_to_ns(vm.hactive, vm.pixelclock), ++ tc358768_dpi_to_ns(vm.hfront_porch, vm.pixelclock), ++ tc358768_dpi_to_ns(dpi_htot, vm.pixelclock)); ++ ++ dev_dbg(dev, "dpi data start (ns): %u + %u = %u\n", ++ tc358768_dpi_to_ns(vm.hsync_len, vm.pixelclock), ++ tc358768_dpi_to_ns(vm.hback_porch, vm.pixelclock), ++ tc358768_dpi_to_ns(dpi_data_start, vm.pixelclock)); ++ ++ dsi_dpi_htot = tc358768_dpi_to_dsi_bytes(priv, dpi_htot); ++ dsi_dpi_data_start = tc358768_dpi_to_dsi_bytes(priv, dpi_data_start); ++ ++ if (dsi_dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { ++ dsi_hsw = tc358768_dpi_to_dsi_bytes(priv, vm.hsync_len); ++ dsi_hbp = tc358768_dpi_to_dsi_bytes(priv, vm.hback_porch); ++ } else { ++ /* HBP is included in HSW in event mode */ ++ dsi_hbp = 0; ++ dsi_hsw = tc358768_dpi_to_dsi_bytes(priv, ++ vm.hsync_len + ++ vm.hback_porch); ++ ++ /* ++ * The pixel packet includes the actual pixel data, and: ++ * DSI packet header = 4 bytes ++ * DCS code = 1 byte ++ * DSI packet footer = 2 bytes ++ */ ++ dsi_hact = hact + 4 + 1 + 2; ++ ++ dsi_hfp = dsi_dpi_htot - dsi_hact - dsi_hsw - dsi_hss; ++ ++ /* ++ * Here we should check if HFP is long enough for entering LP ++ * and exiting LP, but it's not clear how to calculate that. ++ * Instead, this is a naive algorithm that just adjusts the HFP ++ * and HSW so that HFP is (at least) roughly 2/3 of the total ++ * blanking time. ++ */ ++ if (dsi_hfp < (dsi_hfp + dsi_hsw + dsi_hss) * 2 / 3) { ++ u32 old_hfp = dsi_hfp; ++ u32 old_hsw = dsi_hsw; ++ u32 tot = dsi_hfp + dsi_hsw + dsi_hss; ++ ++ dsi_hsw = tot / 3; ++ ++ /* ++ * Seems like sometimes HSW has to be divisible by num-lanes, but ++ * not always... ++ */ ++ dsi_hsw = roundup(dsi_hsw, priv->dsi_lanes); ++ ++ dsi_hfp = dsi_dpi_htot - dsi_hact - dsi_hsw - dsi_hss; ++ ++ dev_dbg(dev, ++ "hfp too short, adjusting dsi hfp and dsi hsw from %u, %u to %u, %u\n", ++ old_hfp, old_hsw, dsi_hfp, dsi_hsw); ++ } ++ ++ dev_dbg(dev, ++ "dsi horiz timing (bytes): %u, %u + %u + %u + %u = %u\n", ++ dsi_hss, dsi_hsw, dsi_hbp, dsi_hact, dsi_hfp, ++ dsi_hss + dsi_hsw + dsi_hbp + dsi_hact + dsi_hfp); ++ ++ dev_dbg(dev, "dsi horiz timing (ns): %u + %u + %u + %u + %u = %u\n", ++ tc358768_dsi_bytes_to_ns(priv, dsi_hss), ++ tc358768_dsi_bytes_to_ns(priv, dsi_hsw), ++ tc358768_dsi_bytes_to_ns(priv, dsi_hbp), ++ tc358768_dsi_bytes_to_ns(priv, dsi_hact), ++ tc358768_dsi_bytes_to_ns(priv, dsi_hfp), ++ tc358768_dsi_bytes_to_ns(priv, dsi_hss + dsi_hsw + ++ dsi_hbp + dsi_hact + dsi_hfp)); ++ } ++ ++ /* VSDly calculation */ ++ ++ /* Start with the HW internal delay */ ++ dsi_vsdly = internal_dly; ++ ++ /* Convert to byte units as the other variables are in byte units */ ++ dsi_vsdly *= priv->dsi_lanes; ++ ++ /* Do we need more delay, in addition to the internal? */ ++ if (dsi_dpi_data_start > dsi_vsdly + dsi_hss + dsi_hsw + dsi_hbp) { ++ dsi_vsdly = dsi_dpi_data_start - dsi_hss - dsi_hsw - dsi_hbp; ++ dsi_vsdly = roundup(dsi_vsdly, priv->dsi_lanes); ++ } ++ ++ dev_dbg(dev, "dsi data start (bytes) %u + %u + %u + %u = %u\n", ++ dsi_vsdly, dsi_hss, dsi_hsw, dsi_hbp, ++ dsi_vsdly + dsi_hss + dsi_hsw + dsi_hbp); ++ ++ dev_dbg(dev, "dsi data start (ns) %u + %u + %u + %u = %u\n", ++ tc358768_dsi_bytes_to_ns(priv, dsi_vsdly), ++ tc358768_dsi_bytes_to_ns(priv, dsi_hss), ++ tc358768_dsi_bytes_to_ns(priv, dsi_hsw), ++ tc358768_dsi_bytes_to_ns(priv, dsi_hbp), ++ tc358768_dsi_bytes_to_ns(priv, dsi_vsdly + dsi_hss + dsi_hsw + dsi_hbp)); ++ ++ /* Convert back to hsbyteclk */ ++ dsi_vsdly /= priv->dsi_lanes; ++ ++ /* ++ * The docs say that there is an internal delay of 40 cycles. ++ * However, we get underflows if we follow that rule. If we ++ * instead ignore the internal delay, things work. So either ++ * the docs are wrong or the calculations are wrong. ++ * ++ * As a temporary fix, add the internal delay here, to counter ++ * the subtraction when writing the register. ++ */ ++ dsi_vsdly += internal_dly; ++ ++ /* Clamp to the register max */ ++ if (dsi_vsdly - internal_dly > 0x3ff) { ++ dev_warn(dev, "VSDly too high, underflows likely\n"); ++ dsi_vsdly = 0x3ff + internal_dly; ++ } ++ + /* VSDly[9:0] */ +- video_start = max(video_start, internal_delay + 1) - internal_delay; +- tc358768_write(priv, TC358768_VSDLY, video_start); ++ tc358768_write(priv, TC358768_VSDLY, dsi_vsdly - internal_dly); + + tc358768_write(priv, TC358768_DATAFMT, val); + tc358768_write(priv, TC358768_DSITX_DT, data_type); +@@ -722,67 +902,67 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) + tc358768_write(priv, TC358768_D0W_CNTRL + i * 4, 0x0000); + + /* DSI Timings */ +- dsibclk_nsk = (u32)div_u64((u64)1000000000 * TC358768_PRECISION, +- dsibclk); +- dsiclk_nsk = (u32)div_u64((u64)1000000000 * TC358768_PRECISION, dsiclk); +- ui_nsk = dsiclk_nsk / 2; +- dev_dbg(priv->dev, "dsiclk_nsk: %u\n", dsiclk_nsk); +- dev_dbg(priv->dev, "ui_nsk: %u\n", ui_nsk); +- dev_dbg(priv->dev, "dsibclk_nsk: %u\n", dsibclk_nsk); ++ hsbyteclk_ps = (u32)div_u64(PICO, hsbyteclk); ++ dsiclk_ps = (u32)div_u64(PICO, dsiclk); ++ ui_ps = dsiclk_ps / 2; ++ dev_dbg(dev, "dsiclk: %u ps, ui %u ps, hsbyteclk %u ps\n", dsiclk_ps, ++ ui_ps, hsbyteclk_ps); + + /* LP11 > 100us for D-PHY Rx Init */ +- val = tc358768_ns_to_cnt(100 * 1000, dsibclk_nsk) - 1; +- dev_dbg(priv->dev, "LINEINITCNT: 0x%x\n", val); ++ val = tc358768_ns_to_cnt(100 * 1000, hsbyteclk_ps) - 1; ++ dev_dbg(dev, "LINEINITCNT: %u\n", val); + tc358768_write(priv, TC358768_LINEINITCNT, val); + + /* LPTimeCnt > 50ns */ +- val = tc358768_ns_to_cnt(50, dsibclk_nsk) - 1; ++ val = tc358768_ns_to_cnt(50, hsbyteclk_ps) - 1; + lptxcnt = val; +- dev_dbg(priv->dev, "LPTXTIMECNT: 0x%x\n", val); ++ dev_dbg(dev, "LPTXTIMECNT: %u\n", val); + tc358768_write(priv, TC358768_LPTXTIMECNT, val); + + /* 38ns < TCLK_PREPARE < 95ns */ +- val = tc358768_ns_to_cnt(65, dsibclk_nsk) - 1; ++ val = tc358768_ns_to_cnt(65, hsbyteclk_ps) - 1; ++ dev_dbg(dev, "TCLK_PREPARECNT %u\n", val); + /* TCLK_PREPARE + TCLK_ZERO > 300ns */ +- val2 = tc358768_ns_to_cnt(300 - tc358768_to_ns(2 * ui_nsk), +- dsibclk_nsk) - 2; ++ val2 = tc358768_ns_to_cnt(300 - tc358768_ps_to_ns(2 * ui_ps), ++ hsbyteclk_ps) - 2; ++ dev_dbg(dev, "TCLK_ZEROCNT %u\n", val2); + val |= val2 << 8; +- dev_dbg(priv->dev, "TCLK_HEADERCNT: 0x%x\n", val); + tc358768_write(priv, TC358768_TCLK_HEADERCNT, val); + + /* TCLK_TRAIL > 60ns AND TEOT <= 105 ns + 12*UI */ +- raw_val = tc358768_ns_to_cnt(60 + tc358768_to_ns(2 * ui_nsk), dsibclk_nsk) - 5; ++ raw_val = tc358768_ns_to_cnt(60 + tc358768_ps_to_ns(2 * ui_ps), hsbyteclk_ps) - 5; + val = clamp(raw_val, 0, 127); +- dev_dbg(priv->dev, "TCLK_TRAILCNT: 0x%x\n", val); ++ dev_dbg(dev, "TCLK_TRAILCNT: %u\n", val); + tc358768_write(priv, TC358768_TCLK_TRAILCNT, val); + + /* 40ns + 4*UI < THS_PREPARE < 85ns + 6*UI */ +- val = 50 + tc358768_to_ns(4 * ui_nsk); +- val = tc358768_ns_to_cnt(val, dsibclk_nsk) - 1; ++ val = 50 + tc358768_ps_to_ns(4 * ui_ps); ++ val = tc358768_ns_to_cnt(val, hsbyteclk_ps) - 1; ++ dev_dbg(dev, "THS_PREPARECNT %u\n", val); + /* THS_PREPARE + THS_ZERO > 145ns + 10*UI */ +- raw_val = tc358768_ns_to_cnt(145 - tc358768_to_ns(3 * ui_nsk), dsibclk_nsk) - 10; ++ raw_val = tc358768_ns_to_cnt(145 - tc358768_ps_to_ns(3 * ui_ps), hsbyteclk_ps) - 10; + val2 = clamp(raw_val, 0, 127); ++ dev_dbg(dev, "THS_ZEROCNT %u\n", val2); + val |= val2 << 8; +- dev_dbg(priv->dev, "THS_HEADERCNT: 0x%x\n", val); + tc358768_write(priv, TC358768_THS_HEADERCNT, val); + + /* TWAKEUP > 1ms in lptxcnt steps */ +- val = tc358768_ns_to_cnt(1020000, dsibclk_nsk); ++ val = tc358768_ns_to_cnt(1020000, hsbyteclk_ps); + val = val / (lptxcnt + 1) - 1; +- dev_dbg(priv->dev, "TWAKEUP: 0x%x\n", val); ++ dev_dbg(dev, "TWAKEUP: %u\n", val); + tc358768_write(priv, TC358768_TWAKEUP, val); + + /* TCLK_POSTCNT > 60ns + 52*UI */ +- val = tc358768_ns_to_cnt(60 + tc358768_to_ns(52 * ui_nsk), +- dsibclk_nsk) - 3; +- dev_dbg(priv->dev, "TCLK_POSTCNT: 0x%x\n", val); ++ val = tc358768_ns_to_cnt(60 + tc358768_ps_to_ns(52 * ui_ps), ++ hsbyteclk_ps) - 3; ++ dev_dbg(dev, "TCLK_POSTCNT: %u\n", val); + tc358768_write(priv, TC358768_TCLK_POSTCNT, val); + + /* max(60ns + 4*UI, 8*UI) < THS_TRAILCNT < 105ns + 12*UI */ +- raw_val = tc358768_ns_to_cnt(60 + tc358768_to_ns(18 * ui_nsk), +- dsibclk_nsk) - 4; ++ raw_val = tc358768_ns_to_cnt(60 + tc358768_ps_to_ns(18 * ui_ps), ++ hsbyteclk_ps) - 4; + val = clamp(raw_val, 0, 15); +- dev_dbg(priv->dev, "THS_TRAILCNT: 0x%x\n", val); ++ dev_dbg(dev, "THS_TRAILCNT: %u\n", val); + tc358768_write(priv, TC358768_THS_TRAILCNT, val); + + val = BIT(0); +@@ -790,16 +970,17 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) + val |= BIT(i + 1); + tc358768_write(priv, TC358768_HSTXVREGEN, val); + +- if (!(mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)) +- tc358768_write(priv, TC358768_TXOPTIONCNTRL, 0x1); ++ tc358768_write(priv, TC358768_TXOPTIONCNTRL, ++ (mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? 0 : BIT(0)); + + /* TXTAGOCNT[26:16] RXTASURECNT[10:0] */ +- val = tc358768_to_ns((lptxcnt + 1) * dsibclk_nsk * 4); +- val = tc358768_ns_to_cnt(val, dsibclk_nsk) / 4 - 1; +- val2 = tc358768_ns_to_cnt(tc358768_to_ns((lptxcnt + 1) * dsibclk_nsk), +- dsibclk_nsk) - 2; ++ val = tc358768_ps_to_ns((lptxcnt + 1) * hsbyteclk_ps * 4); ++ val = tc358768_ns_to_cnt(val, hsbyteclk_ps) / 4 - 1; ++ dev_dbg(dev, "TXTAGOCNT: %u\n", val); ++ val2 = tc358768_ns_to_cnt(tc358768_ps_to_ns((lptxcnt + 1) * hsbyteclk_ps), ++ hsbyteclk_ps) - 2; ++ dev_dbg(dev, "RXTASURECNT: %u\n", val2); + val = val << 16 | val2; +- dev_dbg(priv->dev, "BTACNTRL1: 0x%x\n", val); + tc358768_write(priv, TC358768_BTACNTRL1, val); + + /* START[0] */ +@@ -810,58 +991,44 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) + tc358768_write(priv, TC358768_DSI_EVENT, 0); + + /* vact */ +- tc358768_write(priv, TC358768_DSI_VACT, mode->vdisplay); ++ tc358768_write(priv, TC358768_DSI_VACT, vm.vactive); + + /* vsw */ +- tc358768_write(priv, TC358768_DSI_VSW, +- mode->vsync_end - mode->vsync_start); ++ tc358768_write(priv, TC358768_DSI_VSW, vm.vsync_len); ++ + /* vbp */ +- tc358768_write(priv, TC358768_DSI_VBPR, +- mode->vtotal - mode->vsync_end); +- +- /* hsw * byteclk * ndl / pclk */ +- val = (u32)div_u64((mode->hsync_end - mode->hsync_start) * +- ((u64)priv->dsiclk / 4) * priv->dsi_lanes, +- mode->clock * 1000); +- tc358768_write(priv, TC358768_DSI_HSW, val); +- +- /* hbp * byteclk * ndl / pclk */ +- val = (u32)div_u64((mode->htotal - mode->hsync_end) * +- ((u64)priv->dsiclk / 4) * priv->dsi_lanes, +- mode->clock * 1000); +- tc358768_write(priv, TC358768_DSI_HBPR, val); ++ tc358768_write(priv, TC358768_DSI_VBPR, vm.vback_porch); + } else { + /* Set event mode */ + tc358768_write(priv, TC358768_DSI_EVENT, 1); + + /* vact */ +- tc358768_write(priv, TC358768_DSI_VACT, mode->vdisplay); ++ tc358768_write(priv, TC358768_DSI_VACT, vm.vactive); + + /* vsw (+ vbp) */ + tc358768_write(priv, TC358768_DSI_VSW, +- mode->vtotal - mode->vsync_start); ++ vm.vsync_len + vm.vback_porch); ++ + /* vbp (not used in event mode) */ + tc358768_write(priv, TC358768_DSI_VBPR, 0); ++ } + +- /* (hsw + hbp) * byteclk * ndl / pclk */ +- val = (u32)div_u64((mode->htotal - mode->hsync_start) * +- ((u64)priv->dsiclk / 4) * priv->dsi_lanes, +- mode->clock * 1000); +- tc358768_write(priv, TC358768_DSI_HSW, val); ++ /* hsw (bytes) */ ++ tc358768_write(priv, TC358768_DSI_HSW, dsi_hsw); + +- /* hbp (not used in event mode) */ +- tc358768_write(priv, TC358768_DSI_HBPR, 0); +- } ++ /* hbp (bytes) */ ++ tc358768_write(priv, TC358768_DSI_HBPR, dsi_hbp); + + /* hact (bytes) */ + tc358768_write(priv, TC358768_DSI_HACT, hact); + + /* VSYNC polarity */ +- if (!(mode->flags & DRM_MODE_FLAG_NVSYNC)) +- tc358768_update_bits(priv, TC358768_CONFCTL, BIT(5), BIT(5)); ++ tc358768_update_bits(priv, TC358768_CONFCTL, BIT(5), ++ (mode->flags & DRM_MODE_FLAG_PVSYNC) ? BIT(5) : 0); ++ + /* HSYNC polarity */ +- if (mode->flags & DRM_MODE_FLAG_PHSYNC) +- tc358768_update_bits(priv, TC358768_PP_MISC, BIT(0), BIT(0)); ++ tc358768_update_bits(priv, TC358768_PP_MISC, BIT(0), ++ (mode->flags & DRM_MODE_FLAG_PHSYNC) ? BIT(0) : 0); + + /* Start DSI Tx */ + tc358768_write(priv, TC358768_DSI_START, 0x1); +@@ -891,7 +1058,7 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge) + + ret = tc358768_clear_error(priv); + if (ret) { +- dev_err(priv->dev, "Bridge pre_enable failed: %d\n", ret); ++ dev_err(dev, "Bridge pre_enable failed: %d\n", ret); + tc358768_bridge_disable(bridge); + tc358768_bridge_post_disable(bridge); + } +diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c +index 90a89d70d83287..c737670631929a 100644 +--- a/drivers/gpu/drm/bridge/tc358775.c ++++ b/drivers/gpu/drm/bridge/tc358775.c +@@ -454,10 +454,6 @@ static void tc_bridge_enable(struct drm_bridge *bridge) + dev_dbg(tc->dev, "bus_formats %04x bpc %d\n", + connector->display_info.bus_formats[0], + tc->bpc); +- /* +- * Default hardware register settings of tc358775 configured +- * with MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA jeida-24 format +- */ + if (connector->display_info.bus_formats[0] == + MEDIA_BUS_FMT_RGB888_1X7X4_SPWG) { + /* VESA-24 */ +@@ -468,14 +464,15 @@ static void tc_bridge_enable(struct drm_bridge *bridge) + d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_B6, LVI_B7, LVI_B1, LVI_B2)); + d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0)); + d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_R6)); +- } else { /* MEDIA_BUS_FMT_RGB666_1X7X3_SPWG - JEIDA-18 */ +- d2l_write(tc->i2c, LV_MX0003, LV_MX(LVI_R0, LVI_R1, LVI_R2, LVI_R3)); +- d2l_write(tc->i2c, LV_MX0407, LV_MX(LVI_R4, LVI_L0, LVI_R5, LVI_G0)); +- d2l_write(tc->i2c, LV_MX0811, LV_MX(LVI_G1, LVI_G2, LVI_L0, LVI_L0)); +- d2l_write(tc->i2c, LV_MX1215, LV_MX(LVI_G3, LVI_G4, LVI_G5, LVI_B0)); +- d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_L0, LVI_L0, LVI_B1, LVI_B2)); +- d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0)); +- d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_L0)); ++ } else { ++ /* JEIDA-18 and JEIDA-24 */ ++ d2l_write(tc->i2c, LV_MX0003, LV_MX(LVI_R2, LVI_R3, LVI_R4, LVI_R5)); ++ d2l_write(tc->i2c, LV_MX0407, LV_MX(LVI_R6, LVI_R1, LVI_R7, LVI_G2)); ++ d2l_write(tc->i2c, LV_MX0811, LV_MX(LVI_G3, LVI_G4, LVI_G0, LVI_G1)); ++ d2l_write(tc->i2c, LV_MX1215, LV_MX(LVI_G5, LVI_G6, LVI_G7, LVI_B2)); ++ d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_B0, LVI_B1, LVI_B3, LVI_B4)); ++ d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B5, LVI_B6, LVI_B7, LVI_L0)); ++ d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_R0)); + } + + d2l_write(tc->i2c, VFUEN, VFUEN_EN); +@@ -610,10 +607,8 @@ static int tc_attach_host(struct tc_data *tc) + }; + + host = of_find_mipi_dsi_host_by_node(tc->host_node); +- if (!host) { +- dev_err(dev, "failed to find dsi host\n"); +- return -EPROBE_DEFER; +- } ++ if (!host) ++ return dev_err_probe(dev, -EPROBE_DEFER, "failed to find dsi host\n"); + + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); + if (IS_ERR(dsi)) { +diff --git a/drivers/gpu/drm/bridge/ti-dlpc3433.c b/drivers/gpu/drm/bridge/ti-dlpc3433.c +index b65632ec7e7daa..3f933ba2946820 100644 +--- a/drivers/gpu/drm/bridge/ti-dlpc3433.c ++++ b/drivers/gpu/drm/bridge/ti-dlpc3433.c +@@ -319,12 +319,11 @@ static int dlpc_host_attach(struct dlpc *dlpc) + .channel = 0, + .node = NULL, + }; ++ int ret; + + host = of_find_mipi_dsi_host_by_node(dlpc->host_node); +- if (!host) { +- DRM_DEV_ERROR(dev, "failed to find dsi host\n"); +- return -EPROBE_DEFER; +- } ++ if (!host) ++ return dev_err_probe(dev, -EPROBE_DEFER, "failed to find dsi host\n"); + + dlpc->dsi = mipi_dsi_device_register_full(host, &info); + if (IS_ERR(dlpc->dsi)) { +@@ -336,7 +335,11 @@ static int dlpc_host_attach(struct dlpc *dlpc) + dlpc->dsi->format = MIPI_DSI_FMT_RGB565; + dlpc->dsi->lanes = dlpc->dsi_lanes; + +- return devm_mipi_dsi_attach(dev, dlpc->dsi); ++ ret = devm_mipi_dsi_attach(dev, dlpc->dsi); ++ if (ret) ++ DRM_DEV_ERROR(dev, "failed to attach dsi host\n"); ++ ++ return ret; + } + + static int dlpc3433_probe(struct i2c_client *client) +@@ -367,10 +370,8 @@ static int dlpc3433_probe(struct i2c_client *client) + drm_bridge_add(&dlpc->bridge); + + ret = dlpc_host_attach(dlpc); +- if (ret) { +- DRM_DEV_ERROR(dev, "failed to attach dsi host\n"); ++ if (ret) + goto err_remove_bridge; +- } + + return 0; + +diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c +index 061e8bd5915de8..8a23116346a8a5 100644 +--- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c ++++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c +@@ -478,7 +478,6 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, + dev_err(ctx->dev, "failed to lock PLL, ret=%i\n", ret); + /* On failure, disable PLL again and exit. */ + regmap_write(ctx->regmap, REG_RC_PLL_EN, 0x00); +- regulator_disable(ctx->vcc); + return; + } + +diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c +index 84148a79414b7f..3309c01fa7153c 100644 +--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c ++++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c +@@ -527,6 +527,7 @@ static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux, + u32 request_val = AUX_CMD_REQ(msg->request); + u8 *buf = msg->buffer; + unsigned int len = msg->size; ++ unsigned int short_len; + unsigned int val; + int ret; + u8 addr_len[SN_AUX_LENGTH_REG + 1 - SN_AUX_ADDR_19_16_REG]; +@@ -600,7 +601,8 @@ static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux, + } + + if (val & AUX_IRQ_STATUS_AUX_SHORT) { +- ret = regmap_read(pdata->regmap, SN_AUX_LENGTH_REG, &len); ++ ret = regmap_read(pdata->regmap, SN_AUX_LENGTH_REG, &short_len); ++ len = min(len, short_len); + if (ret) + goto exit; + } else if (val & AUX_IRQ_STATUS_NAT_I2C_FAIL) { +diff --git a/drivers/gpu/drm/bridge/ti-tpd12s015.c b/drivers/gpu/drm/bridge/ti-tpd12s015.c +index e0e015243a602d..b588fea12502d6 100644 +--- a/drivers/gpu/drm/bridge/ti-tpd12s015.c ++++ b/drivers/gpu/drm/bridge/ti-tpd12s015.c +@@ -179,7 +179,7 @@ static int tpd12s015_probe(struct platform_device *pdev) + return 0; + } + +-static int __exit tpd12s015_remove(struct platform_device *pdev) ++static int tpd12s015_remove(struct platform_device *pdev) + { + struct tpd12s015_device *tpd = platform_get_drvdata(pdev); + +@@ -197,7 +197,7 @@ MODULE_DEVICE_TABLE(of, tpd12s015_of_match); + + static struct platform_driver tpd12s015_driver = { + .probe = tpd12s015_probe, +- .remove = __exit_p(tpd12s015_remove), ++ .remove = tpd12s015_remove, + .driver = { + .name = "tpd12s015", + .of_match_table = tpd12s015_of_match, +diff --git a/drivers/gpu/drm/ci/build.yml b/drivers/gpu/drm/ci/build.yml +index e6503f1c5927bb..17ab38304885cd 100644 +--- a/drivers/gpu/drm/ci/build.yml ++++ b/drivers/gpu/drm/ci/build.yml +@@ -1,6 +1,7 @@ + .build: + extends: + - .build-rules ++ - .container+build-rules + stage: build + artifacts: + paths: +diff --git a/drivers/gpu/drm/ci/gitlab-ci.yml b/drivers/gpu/drm/ci/gitlab-ci.yml +index 2c4df53f5dfe3a..36949243674800 100644 +--- a/drivers/gpu/drm/ci/gitlab-ci.yml ++++ b/drivers/gpu/drm/ci/gitlab-ci.yml +@@ -1,6 +1,6 @@ + variables: + DRM_CI_PROJECT_PATH: &drm-ci-project-path mesa/mesa +- DRM_CI_COMMIT_SHA: &drm-ci-commit-sha 0dc961645c4f0241f8512cb0ec3ad59635842072 ++ DRM_CI_COMMIT_SHA: &drm-ci-commit-sha edfbf74df1d4d6ce54ffe24566108be0e1a98c3d + + UPSTREAM_REPO: git://anongit.freedesktop.org/drm/drm + TARGET_BRANCH: drm-next +@@ -24,7 +24,9 @@ variables: + PIPELINE_ARTIFACTS_BASE: ${S3_HOST}/artifacts/${CI_PROJECT_PATH}/${CI_PIPELINE_ID} + # per-job artifact storage on MinIO + JOB_ARTIFACTS_BASE: ${PIPELINE_ARTIFACTS_BASE}/${CI_JOB_ID} +- ++ # default kernel for rootfs before injecting the current kernel tree ++ KERNEL_IMAGE_BASE: https://${S3_HOST}/mesa-lava/gfx-ci/linux/v6.4.12-for-mesa-ci-f6b4ad45f48d ++ LAVA_TAGS: subset-1-gfx + LAVA_JOB_PRIORITY: 30 + + default: +@@ -86,6 +88,17 @@ include: + - '/.gitlab-ci/container/gitlab-ci.yml' + - '/.gitlab-ci/test/gitlab-ci.yml' + - '/.gitlab-ci/lava/lava-gitlab-ci.yml' ++ - '/src/microsoft/ci/gitlab-ci-inc.yml' ++ - '/src/gallium/drivers/zink/ci/gitlab-ci-inc.yml' ++ - '/src/gallium/drivers/crocus/ci/gitlab-ci-inc.yml' ++ - '/src/gallium/drivers/softpipe/ci/gitlab-ci-inc.yml' ++ - '/src/gallium/drivers/llvmpipe/ci/gitlab-ci-inc.yml' ++ - '/src/gallium/drivers/virgl/ci/gitlab-ci-inc.yml' ++ - '/src/gallium/drivers/nouveau/ci/gitlab-ci-inc.yml' ++ - '/src/gallium/frontends/lavapipe/ci/gitlab-ci-inc.yml' ++ - '/src/intel/ci/gitlab-ci-inc.yml' ++ - '/src/freedreno/ci/gitlab-ci-inc.yml' ++ - '/src/amd/ci/gitlab-ci-inc.yml' + - drivers/gpu/drm/ci/image-tags.yml + - drivers/gpu/drm/ci/container.yml + - drivers/gpu/drm/ci/static-checks.yml +@@ -154,6 +167,11 @@ stages: + # Run automatically once all dependency jobs have passed + - when: on_success + ++# When to automatically run the CI for container jobs ++.container+build-rules: ++ rules: ++ - !reference [.no_scheduled_pipelines-rules, rules] ++ - when: manual + + .ci-deqp-artifacts: + artifacts: +diff --git a/drivers/gpu/drm/ci/image-tags.yml b/drivers/gpu/drm/ci/image-tags.yml +index f051b6c547c531..157d987149f072 100644 +--- a/drivers/gpu/drm/ci/image-tags.yml ++++ b/drivers/gpu/drm/ci/image-tags.yml +@@ -1,5 +1,5 @@ + variables: +- CONTAINER_TAG: "2023-08-10-mesa-uprev" ++ CONTAINER_TAG: "2023-10-11-mesa-uprev" + DEBIAN_X86_64_BUILD_BASE_IMAGE: "debian/x86_64_build-base" + DEBIAN_BASE_TAG: "${CONTAINER_TAG}" + +diff --git a/drivers/gpu/drm/ci/lava-submit.sh b/drivers/gpu/drm/ci/lava-submit.sh +index 0c4456b21b0fc6..379f26ea87cc00 100755 +--- a/drivers/gpu/drm/ci/lava-submit.sh ++++ b/drivers/gpu/drm/ci/lava-submit.sh +@@ -22,7 +22,7 @@ cp "$SCRIPTS_DIR"/setup-test-env.sh results/job-rootfs-overlay/ + + # Prepare env vars for upload. + section_start variables "Variables passed through:" +-KERNEL_IMAGE_BASE_URL="https://${BASE_SYSTEM_HOST_PATH}" \ ++KERNEL_IMAGE_BASE="https://${BASE_SYSTEM_HOST_PATH}" \ + artifacts/ci-common/generate-env.sh | tee results/job-rootfs-overlay/set-job-env-vars.sh + section_end variables + +diff --git a/drivers/gpu/drm/ci/test.yml b/drivers/gpu/drm/ci/test.yml +index 6473cddaa7a962..6f81dc10865b5e 100644 +--- a/drivers/gpu/drm/ci/test.yml ++++ b/drivers/gpu/drm/ci/test.yml +@@ -86,7 +86,7 @@ msm:sc7180: + extends: + - .lava-igt:arm64 + stage: msm +- parallel: 2 ++ parallel: 4 + variables: + DRIVER_NAME: msm + DEVICE_TYPE: sc7180-trogdor-lazor-limozeen +@@ -104,7 +104,10 @@ msm:apq8016: + DRIVER_NAME: msm + BM_DTB: https://${PIPELINE_ARTIFACTS_BASE}/arm64/apq8016-sbc.dtb + GPU_VERSION: apq8016 +- BM_CMDLINE: "ip=dhcp console=ttyMSM0,115200n8 $BM_KERNEL_EXTRA_ARGS root=/dev/nfs rw nfsrootdebug nfsroot=,tcp,nfsvers=4.2 init=/init $BM_KERNELARGS" ++ # disabling unused clocks congests with the MDSS runtime PM trying to ++ # disable those clocks and causes boot to fail. ++ # Reproducer: DRM_MSM=y, DRM_I2C_ADV7511=m ++ BM_KERNEL_EXTRA_ARGS: clk_ignore_unused + RUNNER_TAG: google-freedreno-db410c + script: + - ./install/bare-metal/fastboot.sh +@@ -155,7 +158,7 @@ rockchip:rk3399: + extends: + - .lava-igt:arm64 + stage: rockchip +- parallel: 3 ++ parallel: 2 + variables: + DRIVER_NAME: rockchip + DEVICE_TYPE: rk3399-gru-kevin +@@ -178,7 +181,7 @@ rockchip:rk3399: + i915:apl: + extends: + - .i915 +- parallel: 12 ++ parallel: 3 + variables: + DEVICE_TYPE: asus-C523NA-A20057-coral + GPU_VERSION: apl +@@ -187,7 +190,7 @@ i915:apl: + i915:glk: + extends: + - .i915 +- parallel: 5 ++ parallel: 2 + variables: + DEVICE_TYPE: hp-x360-12b-ca0010nr-n4020-octopus + GPU_VERSION: glk +@@ -196,7 +199,7 @@ i915:glk: + i915:amly: + extends: + - .i915 +- parallel: 8 ++ parallel: 2 + variables: + DEVICE_TYPE: asus-C433TA-AJ0005-rammus + GPU_VERSION: amly +@@ -205,7 +208,7 @@ i915:amly: + i915:kbl: + extends: + - .i915 +- parallel: 5 ++ parallel: 3 + variables: + DEVICE_TYPE: hp-x360-14-G1-sona + GPU_VERSION: kbl +@@ -214,7 +217,7 @@ i915:kbl: + i915:whl: + extends: + - .i915 +- parallel: 8 ++ parallel: 2 + variables: + DEVICE_TYPE: dell-latitude-5400-8665U-sarien + GPU_VERSION: whl +@@ -223,7 +226,7 @@ i915:whl: + i915:cml: + extends: + - .i915 +- parallel: 6 ++ parallel: 2 + variables: + DEVICE_TYPE: asus-C436FA-Flip-hatch + GPU_VERSION: cml +@@ -232,11 +235,11 @@ i915:cml: + i915:tgl: + extends: + - .i915 +- parallel: 6 ++ parallel: 5 + variables: +- DEVICE_TYPE: asus-cx9400-volteer ++ DEVICE_TYPE: acer-cp514-2h-1130g7-volteer + GPU_VERSION: tgl +- RUNNER_TAG: mesa-ci-x86-64-lava-asus-cx9400-volteer ++ RUNNER_TAG: mesa-ci-x86-64-lava-acer-cp514-2h-1130g7-volteer + + .amdgpu: + extends: +@@ -251,6 +254,7 @@ i915:tgl: + amdgpu:stoney: + extends: + - .amdgpu ++ parallel: 2 + variables: + DEVICE_TYPE: hp-11A-G6-EE-grunt + GPU_VERSION: stoney +@@ -269,6 +273,7 @@ amdgpu:stoney: + mediatek:mt8173: + extends: + - .mediatek ++ parallel: 4 + variables: + DEVICE_TYPE: mt8173-elm-hana + GPU_VERSION: mt8173 +@@ -280,6 +285,7 @@ mediatek:mt8173: + mediatek:mt8183: + extends: + - .mediatek ++ parallel: 3 + variables: + DEVICE_TYPE: mt8183-kukui-jacuzzi-juniper-sku16 + GPU_VERSION: mt8183 +@@ -289,6 +295,7 @@ mediatek:mt8183: + .mediatek:mt8192: + extends: + - .mediatek ++ parallel: 3 + variables: + DEVICE_TYPE: mt8192-asurada-spherion-r0 + GPU_VERSION: mt8192 +@@ -307,6 +314,7 @@ mediatek:mt8183: + meson:g12b: + extends: + - .meson ++ parallel: 3 + variables: + DEVICE_TYPE: meson-g12b-a311d-khadas-vim3 + GPU_VERSION: g12b +diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c +index e6a78fd32380a1..851f0baf94600c 100644 +--- a/drivers/gpu/drm/display/drm_dp_helper.c ++++ b/drivers/gpu/drm/display/drm_dp_helper.c +@@ -532,6 +532,15 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, + + mutex_lock(&aux->hw_mutex); + ++ /* ++ * If the device attached to the aux bus is powered down then there's ++ * no reason to attempt a transfer. Error out immediately. ++ */ ++ if (aux->powered_down) { ++ ret = -EBUSY; ++ goto unlock; ++ } ++ + /* + * The specification doesn't give any recommendation on how often to + * retry native transactions. We used to retry 7 times like for +@@ -599,6 +608,29 @@ int drm_dp_dpcd_probe(struct drm_dp_aux *aux, unsigned int offset) + } + EXPORT_SYMBOL(drm_dp_dpcd_probe); + ++/** ++ * drm_dp_dpcd_set_powered() - Set whether the DP device is powered ++ * @aux: DisplayPort AUX channel; for convenience it's OK to pass NULL here ++ * and the function will be a no-op. ++ * @powered: true if powered; false if not ++ * ++ * If the endpoint device on the DP AUX bus is known to be powered down ++ * then this function can be called to make future transfers fail immediately ++ * instead of needing to time out. ++ * ++ * If this function is never called then a device defaults to being powered. ++ */ ++void drm_dp_dpcd_set_powered(struct drm_dp_aux *aux, bool powered) ++{ ++ if (!aux) ++ return; ++ ++ mutex_lock(&aux->hw_mutex); ++ aux->powered_down = !powered; ++ mutex_unlock(&aux->hw_mutex); ++} ++EXPORT_SYMBOL(drm_dp_dpcd_set_powered); ++ + /** + * drm_dp_dpcd_read() - read a series of bytes from the DPCD + * @aux: DisplayPort AUX channel (SST or MST) +@@ -1855,6 +1887,9 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, + struct drm_dp_aux_msg msg; + int err = 0; + ++ if (aux->powered_down) ++ return -EBUSY; ++ + dp_aux_i2c_transfer_size = clamp(dp_aux_i2c_transfer_size, 1, DP_AUX_MAX_PAYLOAD_BYTES); + + memset(&msg, 0, sizeof(msg)); +diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c +index 8c929ef72c72c7..6ead31701e79ea 100644 +--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c ++++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c +@@ -2923,7 +2923,7 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, + + /* FIXME: Actually do some real error handling here */ + ret = drm_dp_mst_wait_tx_reply(mstb, txmsg); +- if (ret <= 0) { ++ if (ret < 0) { + drm_err(mgr->dev, "Sending link address failed with %d\n", ret); + goto out; + } +@@ -2975,7 +2975,7 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, + mutex_unlock(&mgr->lock); + + out: +- if (ret <= 0) ++ if (ret < 0) + mstb->link_address_sent = false; + kfree(txmsg); + return ret < 0 ? ret : changed; +@@ -4024,6 +4024,7 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) + if (up_req->msg.req_type == DP_CONNECTION_STATUS_NOTIFY) { + const struct drm_dp_connection_status_notify *conn_stat = + &up_req->msg.u.conn_stat; ++ bool handle_csn; + + drm_dbg_kms(mgr->dev, "Got CSN: pn: %d ldps:%d ddps: %d mcs: %d ip: %d pdt: %d\n", + conn_stat->port_number, +@@ -4032,6 +4033,16 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) + conn_stat->message_capability_status, + conn_stat->input_port, + conn_stat->peer_device_type); ++ ++ mutex_lock(&mgr->probe_lock); ++ handle_csn = mgr->mst_primary->link_address_sent; ++ mutex_unlock(&mgr->probe_lock); ++ ++ if (!handle_csn) { ++ drm_dbg_kms(mgr->dev, "Got CSN before finish topology probing. Skip it."); ++ kfree(up_req); ++ goto out; ++ } + } else if (up_req->msg.req_type == DP_RESOURCE_STATUS_NOTIFY) { + const struct drm_dp_resource_status_notify *res_stat = + &up_req->msg.u.resource_stat; +@@ -4690,13 +4701,12 @@ EXPORT_SYMBOL(drm_dp_check_act_status); + + /** + * drm_dp_calc_pbn_mode() - Calculate the PBN for a mode. +- * @clock: dot clock for the mode +- * @bpp: bpp for the mode. +- * @dsc: DSC mode. If true, bpp has units of 1/16 of a bit per pixel ++ * @clock: dot clock ++ * @bpp: bpp as .4 binary fixed point + * + * This uses the formula in the spec to calculate the PBN value for a mode. + */ +-int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc) ++int drm_dp_calc_pbn_mode(int clock, int bpp) + { + /* + * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 +@@ -4707,18 +4717,9 @@ int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc) + * peak_kbps *= (1006/1000) + * peak_kbps *= (64/54) + * peak_kbps *= 8 convert to bytes +- * +- * If the bpp is in units of 1/16, further divide by 16. Put this +- * factor in the numerator rather than the denominator to avoid +- * integer overflow + */ +- +- if (dsc) +- return DIV_ROUND_UP_ULL(mul_u32_u32(clock * (bpp / 16), 64 * 1006), +- 8 * 54 * 1000 * 1000); +- +- return DIV_ROUND_UP_ULL(mul_u32_u32(clock * bpp, 64 * 1006), +- 8 * 54 * 1000 * 1000); ++ return DIV_ROUND_UP_ULL(mul_u32_u32(clock * bpp, 64 * 1006 >> 4), ++ 1000 * 8 * 54 * 1000); + } + EXPORT_SYMBOL(drm_dp_calc_pbn_mode); + +diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c +index 60794fcde1d50f..554d4468aa7c08 100644 +--- a/drivers/gpu/drm/drm_atomic_helper.c ++++ b/drivers/gpu/drm/drm_atomic_helper.c +@@ -2012,7 +2012,7 @@ int drm_atomic_helper_commit(struct drm_device *dev, + return ret; + + drm_atomic_helper_async_commit(dev, state); +- drm_atomic_helper_cleanup_planes(dev, state); ++ drm_atomic_helper_unprepare_planes(dev, state); + + return 0; + } +@@ -2072,7 +2072,7 @@ int drm_atomic_helper_commit(struct drm_device *dev, + return 0; + + err: +- drm_atomic_helper_cleanup_planes(dev, state); ++ drm_atomic_helper_unprepare_planes(dev, state); + return ret; + } + EXPORT_SYMBOL(drm_atomic_helper_commit); +@@ -2650,6 +2650,39 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev, + } + EXPORT_SYMBOL(drm_atomic_helper_prepare_planes); + ++/** ++ * drm_atomic_helper_unprepare_planes - release plane resources on aborts ++ * @dev: DRM device ++ * @state: atomic state object with old state structures ++ * ++ * This function cleans up plane state, specifically framebuffers, from the ++ * atomic state. It undoes the effects of drm_atomic_helper_prepare_planes() ++ * when aborting an atomic commit. For cleaning up after a successful commit ++ * use drm_atomic_helper_cleanup_planes(). ++ */ ++void drm_atomic_helper_unprepare_planes(struct drm_device *dev, ++ struct drm_atomic_state *state) ++{ ++ struct drm_plane *plane; ++ struct drm_plane_state *new_plane_state; ++ int i; ++ ++ for_each_new_plane_in_state(state, plane, new_plane_state, i) { ++ const struct drm_plane_helper_funcs *funcs = plane->helper_private; ++ ++ if (funcs->end_fb_access) ++ funcs->end_fb_access(plane, new_plane_state); ++ } ++ ++ for_each_new_plane_in_state(state, plane, new_plane_state, i) { ++ const struct drm_plane_helper_funcs *funcs = plane->helper_private; ++ ++ if (funcs->cleanup_fb) ++ funcs->cleanup_fb(plane, new_plane_state); ++ } ++} ++EXPORT_SYMBOL(drm_atomic_helper_unprepare_planes); ++ + static bool plane_crtc_active(const struct drm_plane_state *state) + { + return state->crtc && state->crtc->state->active; +@@ -2784,6 +2817,17 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, + + funcs->atomic_flush(crtc, old_state); + } ++ ++ /* ++ * Signal end of framebuffer access here before hw_done. After hw_done, ++ * a later commit might have already released the plane state. ++ */ ++ for_each_old_plane_in_state(old_state, plane, old_plane_state, i) { ++ const struct drm_plane_helper_funcs *funcs = plane->helper_private; ++ ++ if (funcs->end_fb_access) ++ funcs->end_fb_access(plane, old_plane_state); ++ } + } + EXPORT_SYMBOL(drm_atomic_helper_commit_planes); + +@@ -2911,40 +2955,22 @@ EXPORT_SYMBOL(drm_atomic_helper_disable_planes_on_crtc); + * configuration. Hence the old configuration must be perserved in @old_state to + * be able to call this function. + * +- * This function must also be called on the new state when the atomic update +- * fails at any point after calling drm_atomic_helper_prepare_planes(). ++ * This function may not be called on the new state when the atomic update ++ * fails at any point after calling drm_atomic_helper_prepare_planes(). Use ++ * drm_atomic_helper_unprepare_planes() in this case. + */ + void drm_atomic_helper_cleanup_planes(struct drm_device *dev, + struct drm_atomic_state *old_state) + { + struct drm_plane *plane; +- struct drm_plane_state *old_plane_state, *new_plane_state; ++ struct drm_plane_state *old_plane_state; + int i; + +- for_each_oldnew_plane_in_state(old_state, plane, old_plane_state, new_plane_state, i) { ++ for_each_old_plane_in_state(old_state, plane, old_plane_state, i) { + const struct drm_plane_helper_funcs *funcs = plane->helper_private; + +- if (funcs->end_fb_access) +- funcs->end_fb_access(plane, new_plane_state); +- } +- +- for_each_oldnew_plane_in_state(old_state, plane, old_plane_state, new_plane_state, i) { +- const struct drm_plane_helper_funcs *funcs; +- struct drm_plane_state *plane_state; +- +- /* +- * This might be called before swapping when commit is aborted, +- * in which case we have to cleanup the new state. +- */ +- if (old_plane_state == plane->state) +- plane_state = new_plane_state; +- else +- plane_state = old_plane_state; +- +- funcs = plane->helper_private; +- + if (funcs->cleanup_fb) +- funcs->cleanup_fb(plane, plane_state); ++ funcs->cleanup_fb(plane, old_plane_state); + } + } + EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes); +diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c +index 98d3b10c08ae19..ab03b08433f8f3 100644 +--- a/drivers/gpu/drm/drm_atomic_uapi.c ++++ b/drivers/gpu/drm/drm_atomic_uapi.c +@@ -585,7 +585,7 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, + &state->fb_damage_clips, + val, + -1, +- sizeof(struct drm_rect), ++ sizeof(struct drm_mode_rect), + &replaced); + return ret; + } else if (property == plane->scaling_filter_property) { +diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c +index cf92a9ae8034c9..6899b3dc1f12a5 100644 +--- a/drivers/gpu/drm/drm_auth.c ++++ b/drivers/gpu/drm/drm_auth.c +@@ -235,7 +235,8 @@ static int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv) + static int + drm_master_check_perm(struct drm_device *dev, struct drm_file *file_priv) + { +- if (file_priv->pid == task_pid(current) && file_priv->was_master) ++ if (file_priv->was_master && ++ rcu_access_pointer(file_priv->pid) == task_tgid(current)) + return 0; + + if (!capable(CAP_SYS_ADMIN)) +diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c +index 39e68e45bb124b..62d8a291c49c7a 100644 +--- a/drivers/gpu/drm/drm_bridge.c ++++ b/drivers/gpu/drm/drm_bridge.c +@@ -27,8 +27,9 @@ + #include + + #include +-#include + #include ++#include ++#include + #include + #include + #include +@@ -686,11 +687,17 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, + */ + list_for_each_entry_from(next, &encoder->bridge_chain, + chain_node) { +- if (next->pre_enable_prev_first) { ++ if (!next->pre_enable_prev_first) { + next = list_prev_entry(next, chain_node); + limit = next; + break; + } ++ ++ if (list_is_last(&next->chain_node, ++ &encoder->bridge_chain)) { ++ limit = next; ++ break; ++ } + } + + /* Call these bridges in reverse order */ +@@ -773,7 +780,7 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, + /* Found first bridge that does NOT + * request prev to be enabled first + */ +- limit = list_prev_entry(next, chain_node); ++ limit = next; + break; + } + } +@@ -1206,6 +1213,47 @@ int drm_bridge_get_modes(struct drm_bridge *bridge, + } + EXPORT_SYMBOL_GPL(drm_bridge_get_modes); + ++/** ++ * drm_bridge_edid_read - read the EDID data of the connected display ++ * @bridge: bridge control structure ++ * @connector: the connector to read EDID for ++ * ++ * If the bridge supports output EDID retrieval, as reported by the ++ * DRM_BRIDGE_OP_EDID bridge ops flag, call &drm_bridge_funcs.edid_read to get ++ * the EDID and return it. Otherwise return NULL. ++ * ++ * If &drm_bridge_funcs.edid_read is not set, fall back to using ++ * drm_bridge_get_edid() and wrapping it in struct drm_edid. ++ * ++ * RETURNS: ++ * The retrieved EDID on success, or NULL otherwise. ++ */ ++const struct drm_edid *drm_bridge_edid_read(struct drm_bridge *bridge, ++ struct drm_connector *connector) ++{ ++ if (!(bridge->ops & DRM_BRIDGE_OP_EDID)) ++ return NULL; ++ ++ /* Transitional: Fall back to ->get_edid. */ ++ if (!bridge->funcs->edid_read) { ++ const struct drm_edid *drm_edid; ++ struct edid *edid; ++ ++ edid = drm_bridge_get_edid(bridge, connector); ++ if (!edid) ++ return NULL; ++ ++ drm_edid = drm_edid_alloc(edid, (edid->extensions + 1) * EDID_LENGTH); ++ ++ kfree(edid); ++ ++ return drm_edid; ++ } ++ ++ return bridge->funcs->edid_read(bridge, connector); ++} ++EXPORT_SYMBOL_GPL(drm_bridge_edid_read); ++ + /** + * drm_bridge_get_edid - get the EDID data of the connected display + * @bridge: bridge control structure +@@ -1215,6 +1263,8 @@ EXPORT_SYMBOL_GPL(drm_bridge_get_modes); + * DRM_BRIDGE_OP_EDID bridge ops flag, call &drm_bridge_funcs.get_edid to + * get the EDID and return it. Otherwise return NULL. + * ++ * Deprecated. Prefer using drm_bridge_edid_read(). ++ * + * RETURNS: + * The retrieved EDID on success, or NULL otherwise. + */ +diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c +index e6f5ba5f4bafd0..d9cbf4e3327cdb 100644 +--- a/drivers/gpu/drm/drm_buddy.c ++++ b/drivers/gpu/drm/drm_buddy.c +@@ -332,6 +332,7 @@ alloc_range_bias(struct drm_buddy *mm, + u64 start, u64 end, + unsigned int order) + { ++ u64 req_size = mm->chunk_size << order; + struct drm_buddy_block *block; + struct drm_buddy_block *buddy; + LIST_HEAD(dfs); +@@ -367,6 +368,15 @@ alloc_range_bias(struct drm_buddy *mm, + if (drm_buddy_block_is_allocated(block)) + continue; + ++ if (block_start < start || block_end > end) { ++ u64 adjusted_start = max(block_start, start); ++ u64 adjusted_end = min(block_end, end); ++ ++ if (round_down(adjusted_end + 1, req_size) <= ++ round_up(adjusted_start, req_size)) ++ continue; ++ } ++ + if (contains(start, end, block_start, block_end) && + order == drm_buddy_block_order(block)) { + /* +diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c +index 871e4e2129d6da..51df7244de7185 100644 +--- a/drivers/gpu/drm/drm_client_modeset.c ++++ b/drivers/gpu/drm/drm_client_modeset.c +@@ -777,6 +777,7 @@ int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, + unsigned int total_modes_count = 0; + struct drm_client_offset *offsets; + unsigned int connector_count = 0; ++ /* points to modes protected by mode_config.mutex */ + struct drm_display_mode **modes; + struct drm_crtc **crtcs; + int i, ret = 0; +@@ -845,7 +846,6 @@ int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, + drm_client_pick_crtcs(client, connectors, connector_count, + crtcs, modes, 0, width, height); + } +- mutex_unlock(&dev->mode_config.mutex); + + drm_client_modeset_release(client); + +@@ -869,12 +869,18 @@ int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, + + kfree(modeset->mode); + modeset->mode = drm_mode_duplicate(dev, mode); ++ if (!modeset->mode) { ++ ret = -ENOMEM; ++ break; ++ } ++ + drm_connector_get(connector); + modeset->connectors[modeset->num_connectors++] = connector; + modeset->x = offset->x; + modeset->y = offset->y; + } + } ++ mutex_unlock(&dev->mode_config.mutex); + + mutex_unlock(&client->modeset_mutex); + out: +diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c +index c44d5bcf12847b..309aad5f0c808d 100644 +--- a/drivers/gpu/drm/drm_connector.c ++++ b/drivers/gpu/drm/drm_connector.c +@@ -2925,7 +2925,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, + dev->mode_config.max_width, + dev->mode_config.max_height); + else +- drm_dbg_kms(dev, "User-space requested a forced probe on [CONNECTOR:%d:%s] but is not the DRM master, demoting to read-only probe", ++ drm_dbg_kms(dev, "User-space requested a forced probe on [CONNECTOR:%d:%s] but is not the DRM master, demoting to read-only probe\n", + connector->base.id, connector->name); + } + +diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c +index df9bf3c9206e71..65f9f66933bba2 100644 +--- a/drivers/gpu/drm/drm_crtc.c ++++ b/drivers/gpu/drm/drm_crtc.c +@@ -715,8 +715,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, + struct drm_mode_set set; + uint32_t __user *set_connectors_ptr; + struct drm_modeset_acquire_ctx ctx; +- int ret; +- int i; ++ int ret, i, num_connectors = 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EOPNOTSUPP; +@@ -871,6 +870,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, + connector->name); + + connector_set[i] = connector; ++ num_connectors++; + } + } + +@@ -879,7 +879,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, + set.y = crtc_req->y; + set.mode = mode; + set.connectors = connector_set; +- set.num_connectors = crtc_req->count_connectors; ++ set.num_connectors = num_connectors; + set.fb = fb; + + if (drm_drv_uses_atomic_modeset(dev)) +@@ -892,7 +892,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, + drm_framebuffer_put(fb); + + if (connector_set) { +- for (i = 0; i < crtc_req->count_connectors; i++) { ++ for (i = 0; i < num_connectors; i++) { + if (connector_set[i]) + drm_connector_put(connector_set[i]); + } +@@ -904,6 +904,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, + connector_set = NULL; + fb = NULL; + mode = NULL; ++ num_connectors = 0; + + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + +diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c +index d8b2955e88fd0a..afb02aae707b4f 100644 +--- a/drivers/gpu/drm/drm_damage_helper.c ++++ b/drivers/gpu/drm/drm_damage_helper.c +@@ -241,7 +241,8 @@ drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter, + iter->plane_src.x2 = (src.x2 >> 16) + !!(src.x2 & 0xFFFF); + iter->plane_src.y2 = (src.y2 >> 16) + !!(src.y2 & 0xFFFF); + +- if (!iter->clips || !drm_rect_equals(&state->src, &old_state->src)) { ++ if (!iter->clips || state->ignore_damage_clips || ++ !drm_rect_equals(&state->src, &old_state->src)) { + iter->clips = NULL; + iter->num_clips = 0; + iter->full_update = true; +diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c +index 2de43ff3ce0a43..41b0682c638ef0 100644 +--- a/drivers/gpu/drm/drm_debugfs.c ++++ b/drivers/gpu/drm/drm_debugfs.c +@@ -92,15 +92,17 @@ static int drm_clients_info(struct seq_file *m, void *data) + */ + mutex_lock(&dev->filelist_mutex); + list_for_each_entry_reverse(priv, &dev->filelist, lhead) { +- struct task_struct *task; + bool is_current_master = drm_is_current_master(priv); ++ struct task_struct *task; ++ struct pid *pid; + +- rcu_read_lock(); /* locks pid_task()->comm */ +- task = pid_task(priv->pid, PIDTYPE_TGID); ++ rcu_read_lock(); /* Locks priv->pid and pid_task()->comm! */ ++ pid = rcu_dereference(priv->pid); ++ task = pid_task(pid, PIDTYPE_TGID); + uid = task ? __task_cred(task)->euid : GLOBAL_ROOT_UID; + seq_printf(m, "%20s %5d %3d %c %c %5d %10u\n", + task ? task->comm : "", +- pid_vnr(priv->pid), ++ pid_vnr(pid), + priv->minor->index, + is_current_master ? 'y' : 'n', + priv->authenticated ? 'y' : 'n', +diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c +index 3eda026ffac6a9..d453d710ef0c10 100644 +--- a/drivers/gpu/drm/drm_drv.c ++++ b/drivers/gpu/drm/drm_drv.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -54,8 +55,7 @@ MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl"); + MODULE_DESCRIPTION("DRM shared core routines"); + MODULE_LICENSE("GPL and additional rights"); + +-static DEFINE_SPINLOCK(drm_minor_lock); +-static struct idr drm_minors_idr; ++DEFINE_XARRAY_ALLOC(drm_minors_xa); + + /* + * If the drm core fails to init for whatever reason, +@@ -83,6 +83,18 @@ DEFINE_STATIC_SRCU(drm_unplug_srcu); + * registered and unregistered dynamically according to device-state. + */ + ++static struct xarray *drm_minor_get_xa(enum drm_minor_type type) ++{ ++ if (type == DRM_MINOR_PRIMARY || type == DRM_MINOR_RENDER) ++ return &drm_minors_xa; ++#if IS_ENABLED(CONFIG_DRM_ACCEL) ++ else if (type == DRM_MINOR_ACCEL) ++ return &accel_minors_xa; ++#endif ++ else ++ return ERR_PTR(-EOPNOTSUPP); ++} ++ + static struct drm_minor **drm_minor_get_slot(struct drm_device *dev, + enum drm_minor_type type) + { +@@ -101,25 +113,31 @@ static struct drm_minor **drm_minor_get_slot(struct drm_device *dev, + static void drm_minor_alloc_release(struct drm_device *dev, void *data) + { + struct drm_minor *minor = data; +- unsigned long flags; + + WARN_ON(dev != minor->dev); + + put_device(minor->kdev); + +- if (minor->type == DRM_MINOR_ACCEL) { +- accel_minor_remove(minor->index); +- } else { +- spin_lock_irqsave(&drm_minor_lock, flags); +- idr_remove(&drm_minors_idr, minor->index); +- spin_unlock_irqrestore(&drm_minor_lock, flags); +- } ++ xa_erase(drm_minor_get_xa(minor->type), minor->index); + } + ++/* ++ * DRM used to support 64 devices, for backwards compatibility we need to maintain the ++ * minor allocation scheme where minors 0-63 are primary nodes, 64-127 are control nodes, ++ * and 128-191 are render nodes. ++ * After reaching the limit, we're allocating minors dynamically - first-come, first-serve. ++ * Accel nodes are using a distinct major, so the minors are allocated in continuous 0-MAX ++ * range. ++ */ ++#define DRM_MINOR_LIMIT(t) ({ \ ++ typeof(t) _t = (t); \ ++ _t == DRM_MINOR_ACCEL ? XA_LIMIT(0, ACCEL_MAX_MINORS) : XA_LIMIT(64 * _t, 64 * _t + 63); \ ++}) ++#define DRM_EXTENDED_MINOR_LIMIT XA_LIMIT(192, (1 << MINORBITS) - 1) ++ + static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type) + { + struct drm_minor *minor; +- unsigned long flags; + int r; + + minor = drmm_kzalloc(dev, sizeof(*minor), GFP_KERNEL); +@@ -129,25 +147,14 @@ static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type) + minor->type = type; + minor->dev = dev; + +- idr_preload(GFP_KERNEL); +- if (type == DRM_MINOR_ACCEL) { +- r = accel_minor_alloc(); +- } else { +- spin_lock_irqsave(&drm_minor_lock, flags); +- r = idr_alloc(&drm_minors_idr, +- NULL, +- 64 * type, +- 64 * (type + 1), +- GFP_NOWAIT); +- spin_unlock_irqrestore(&drm_minor_lock, flags); +- } +- idr_preload_end(); +- ++ r = xa_alloc(drm_minor_get_xa(type), &minor->index, ++ NULL, DRM_MINOR_LIMIT(type), GFP_KERNEL); ++ if (r == -EBUSY && (type == DRM_MINOR_PRIMARY || type == DRM_MINOR_RENDER)) ++ r = xa_alloc(&drm_minors_xa, &minor->index, ++ NULL, DRM_EXTENDED_MINOR_LIMIT, GFP_KERNEL); + if (r < 0) + return r; + +- minor->index = r; +- + r = drmm_add_action_or_reset(dev, drm_minor_alloc_release, minor); + if (r) + return r; +@@ -163,7 +170,7 @@ static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type) + static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type) + { + struct drm_minor *minor; +- unsigned long flags; ++ void *entry; + int ret; + + DRM_DEBUG("\n"); +@@ -187,13 +194,12 @@ static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type) + goto err_debugfs; + + /* replace NULL with @minor so lookups will succeed from now on */ +- if (minor->type == DRM_MINOR_ACCEL) { +- accel_minor_replace(minor, minor->index); +- } else { +- spin_lock_irqsave(&drm_minor_lock, flags); +- idr_replace(&drm_minors_idr, minor, minor->index); +- spin_unlock_irqrestore(&drm_minor_lock, flags); ++ entry = xa_store(drm_minor_get_xa(type), minor->index, minor, GFP_KERNEL); ++ if (xa_is_err(entry)) { ++ ret = xa_err(entry); ++ goto err_debugfs; + } ++ WARN_ON(entry); + + DRM_DEBUG("new minor registered %d\n", minor->index); + return 0; +@@ -206,20 +212,13 @@ static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type) + static void drm_minor_unregister(struct drm_device *dev, enum drm_minor_type type) + { + struct drm_minor *minor; +- unsigned long flags; + + minor = *drm_minor_get_slot(dev, type); + if (!minor || !device_is_registered(minor->kdev)) + return; + + /* replace @minor with NULL so lookups will fail from now on */ +- if (minor->type == DRM_MINOR_ACCEL) { +- accel_minor_replace(NULL, minor->index); +- } else { +- spin_lock_irqsave(&drm_minor_lock, flags); +- idr_replace(&drm_minors_idr, NULL, minor->index); +- spin_unlock_irqrestore(&drm_minor_lock, flags); +- } ++ xa_store(drm_minor_get_xa(type), minor->index, NULL, GFP_KERNEL); + + device_del(minor->kdev); + dev_set_drvdata(minor->kdev, NULL); /* safety belt */ +@@ -235,16 +234,15 @@ static void drm_minor_unregister(struct drm_device *dev, enum drm_minor_type typ + * minor->dev pointer will stay valid! However, the device may get unplugged and + * unregistered while you hold the minor. + */ +-struct drm_minor *drm_minor_acquire(unsigned int minor_id) ++struct drm_minor *drm_minor_acquire(struct xarray *minor_xa, unsigned int minor_id) + { + struct drm_minor *minor; +- unsigned long flags; + +- spin_lock_irqsave(&drm_minor_lock, flags); +- minor = idr_find(&drm_minors_idr, minor_id); ++ xa_lock(minor_xa); ++ minor = xa_load(minor_xa, minor_id); + if (minor) + drm_dev_get(minor->dev); +- spin_unlock_irqrestore(&drm_minor_lock, flags); ++ xa_unlock(minor_xa); + + if (!minor) { + return ERR_PTR(-ENODEV); +@@ -940,8 +938,11 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) + goto err_minors; + } + +- if (drm_core_check_feature(dev, DRIVER_MODESET)) +- drm_modeset_register_all(dev); ++ if (drm_core_check_feature(dev, DRIVER_MODESET)) { ++ ret = drm_modeset_register_all(dev); ++ if (ret) ++ goto err_unload; ++ } + + DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n", + driver->name, driver->major, driver->minor, +@@ -951,6 +952,9 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) + + goto out_unlock; + ++err_unload: ++ if (dev->driver->unload) ++ dev->driver->unload(dev); + err_minors: + remove_compat_control_link(dev); + drm_minor_unregister(dev, DRM_MINOR_ACCEL); +@@ -1032,7 +1036,7 @@ static int drm_stub_open(struct inode *inode, struct file *filp) + + DRM_DEBUG("\n"); + +- minor = drm_minor_acquire(iminor(inode)); ++ minor = drm_minor_acquire(&drm_minors_xa, iminor(inode)); + if (IS_ERR(minor)) + return PTR_ERR(minor); + +@@ -1067,7 +1071,7 @@ static void drm_core_exit(void) + unregister_chrdev(DRM_MAJOR, "drm"); + debugfs_remove(drm_debugfs_root); + drm_sysfs_destroy(); +- idr_destroy(&drm_minors_idr); ++ WARN_ON(!xa_empty(&drm_minors_xa)); + drm_connector_ida_destroy(); + } + +@@ -1076,7 +1080,6 @@ static int __init drm_core_init(void) + int ret; + + drm_connector_ida_init(); +- idr_init(&drm_minors_idr); + drm_memcpy_init_early(); + + ret = drm_sysfs_init(); +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index 4b71040ae5be5c..ee3fab115c4b5b 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -2308,7 +2308,8 @@ int drm_edid_override_connector_update(struct drm_connector *connector) + + override = drm_edid_override_get(connector); + if (override) { +- num_modes = drm_edid_connector_update(connector, override); ++ if (drm_edid_connector_update(connector, override) == 0) ++ num_modes = drm_edid_connector_add_modes(connector); + + drm_edid_free(override); + +@@ -3499,11 +3500,19 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connecto + mode->vsync_end = mode->vsync_start + vsync_pulse_width; + mode->vtotal = mode->vdisplay + vblank; + +- /* Some EDIDs have bogus h/vtotal values */ +- if (mode->hsync_end > mode->htotal) +- mode->htotal = mode->hsync_end + 1; +- if (mode->vsync_end > mode->vtotal) +- mode->vtotal = mode->vsync_end + 1; ++ /* Some EDIDs have bogus h/vsync_end values */ ++ if (mode->hsync_end > mode->htotal) { ++ drm_dbg_kms(dev, "[CONNECTOR:%d:%s] reducing hsync_end %d->%d\n", ++ connector->base.id, connector->name, ++ mode->hsync_end, mode->htotal); ++ mode->hsync_end = mode->htotal; ++ } ++ if (mode->vsync_end > mode->vtotal) { ++ drm_dbg_kms(dev, "[CONNECTOR:%d:%s] reducing vsync_end %d->%d\n", ++ connector->base.id, connector->name, ++ mode->vsync_end, mode->vtotal); ++ mode->vsync_end = mode->vtotal; ++ } + + drm_mode_do_interlace_quirk(mode, pt); + +@@ -7312,7 +7321,7 @@ static void drm_parse_tiled_block(struct drm_connector *connector, + static bool displayid_is_tiled_block(const struct displayid_iter *iter, + const struct displayid_block *block) + { +- return (displayid_version(iter) == DISPLAY_ID_STRUCTURE_VER_12 && ++ return (displayid_version(iter) < DISPLAY_ID_STRUCTURE_VER_20 && + block->tag == DATA_BLOCK_TILED_DISPLAY) || + (displayid_version(iter) == DISPLAY_ID_STRUCTURE_VER_20 && + block->tag == DATA_BLOCK_2_TILED_DISPLAY_TOPOLOGY); +diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c +index d612133e2cf7ec..618b045230336e 100644 +--- a/drivers/gpu/drm/drm_fb_helper.c ++++ b/drivers/gpu/drm/drm_fb_helper.c +@@ -524,6 +524,9 @@ struct fb_info *drm_fb_helper_alloc_info(struct drm_fb_helper *fb_helper) + if (!info) + return ERR_PTR(-ENOMEM); + ++ if (!drm_leak_fbdev_smem) ++ info->flags |= FBINFO_HIDE_SMEM_START; ++ + ret = fb_alloc_cmap(&info->cmap, 256, 0); + if (ret) + goto err_release; +@@ -628,6 +631,17 @@ static void drm_fb_helper_add_damage_clip(struct drm_fb_helper *helper, u32 x, u + static void drm_fb_helper_damage(struct drm_fb_helper *helper, u32 x, u32 y, + u32 width, u32 height) + { ++ /* ++ * This function may be invoked by panic() to flush the frame ++ * buffer, where all CPUs except the panic CPU are stopped. ++ * During the following schedule_work(), the panic CPU needs ++ * the worker_pool lock, which might be held by a stopped CPU, ++ * causing schedule_work() and panic() to block. Return early on ++ * oops_in_progress to prevent this blocking. ++ */ ++ if (oops_in_progress) ++ return; ++ + drm_fb_helper_add_damage_clip(helper, x, y, width, height); + + schedule_work(&helper->damage_work); +@@ -1860,9 +1874,6 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper) + info = fb_helper->info; + info->var.pixclock = 0; + +- if (!drm_leak_fbdev_smem) +- info->flags |= FBINFO_HIDE_SMEM_START; +- + /* Need to drop locks to avoid recursive deadlock in + * register_framebuffer. This is ok because the only thing left to do is + * register the fbdev emulation instance in kernel_fb_helper_list. */ +diff --git a/drivers/gpu/drm/drm_fbdev_dma.c b/drivers/gpu/drm/drm_fbdev_dma.c +index 6c9427bb4053ba..13cd754af311d1 100644 +--- a/drivers/gpu/drm/drm_fbdev_dma.c ++++ b/drivers/gpu/drm/drm_fbdev_dma.c +@@ -130,7 +130,10 @@ static int drm_fbdev_dma_helper_fb_probe(struct drm_fb_helper *fb_helper, + info->flags |= FBINFO_READS_FAST; /* signal caching */ + info->screen_size = sizes->surface_height * fb->pitches[0]; + info->screen_buffer = map.vaddr; +- info->fix.smem_start = page_to_phys(virt_to_page(info->screen_buffer)); ++ if (!(info->flags & FBINFO_HIDE_SMEM_START)) { ++ if (!drm_WARN_ON(dev, is_vmalloc_addr(info->screen_buffer))) ++ info->fix.smem_start = page_to_phys(virt_to_page(info->screen_buffer)); ++ } + info->fix.smem_len = info->screen_size; + + return 0; +diff --git a/drivers/gpu/drm/drm_fbdev_generic.c b/drivers/gpu/drm/drm_fbdev_generic.c +index d647d89764cb98..b4659cd6285ab6 100644 +--- a/drivers/gpu/drm/drm_fbdev_generic.c ++++ b/drivers/gpu/drm/drm_fbdev_generic.c +@@ -113,7 +113,6 @@ static int drm_fbdev_generic_helper_fb_probe(struct drm_fb_helper *fb_helper, + /* screen */ + info->flags |= FBINFO_VIRTFB | FBINFO_READS_FAST; + info->screen_buffer = screen_buffer; +- info->fix.smem_start = page_to_phys(vmalloc_to_page(info->screen_buffer)); + info->fix.smem_len = screen_size; + + /* deferred I/O */ +diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c +index 883d83bc0e3d5f..48af0e2960a226 100644 +--- a/drivers/gpu/drm/drm_file.c ++++ b/drivers/gpu/drm/drm_file.c +@@ -160,7 +160,7 @@ struct drm_file *drm_file_alloc(struct drm_minor *minor) + + /* Get a unique identifier for fdinfo: */ + file->client_id = atomic64_inc_return(&ident); +- file->pid = get_pid(task_tgid(current)); ++ rcu_assign_pointer(file->pid, get_pid(task_tgid(current))); + file->minor = minor; + + /* for compatibility root is always authenticated */ +@@ -200,7 +200,7 @@ struct drm_file *drm_file_alloc(struct drm_minor *minor) + drm_syncobj_release(file); + if (drm_core_check_feature(dev, DRIVER_GEM)) + drm_gem_release(dev, file); +- put_pid(file->pid); ++ put_pid(rcu_access_pointer(file->pid)); + kfree(file); + + return ERR_PTR(ret); +@@ -291,7 +291,7 @@ void drm_file_free(struct drm_file *file) + + WARN_ON(!list_empty(&file->event_list)); + +- put_pid(file->pid); ++ put_pid(rcu_access_pointer(file->pid)); + kfree(file); + } + +@@ -413,7 +413,7 @@ int drm_open(struct inode *inode, struct file *filp) + int retcode; + int need_setup = 0; + +- minor = drm_minor_acquire(iminor(inode)); ++ minor = drm_minor_acquire(&drm_minors_xa, iminor(inode)); + if (IS_ERR(minor)) + return PTR_ERR(minor); + +@@ -505,6 +505,38 @@ int drm_release(struct inode *inode, struct file *filp) + } + EXPORT_SYMBOL(drm_release); + ++void drm_file_update_pid(struct drm_file *filp) ++{ ++ struct drm_device *dev; ++ struct pid *pid, *old; ++ ++ /* ++ * Master nodes need to keep the original ownership in order for ++ * drm_master_check_perm to keep working correctly. (See comment in ++ * drm_auth.c.) ++ */ ++ if (filp->was_master) ++ return; ++ ++ pid = task_tgid(current); ++ ++ /* ++ * Quick unlocked check since the model is a single handover followed by ++ * exclusive repeated use. ++ */ ++ if (pid == rcu_access_pointer(filp->pid)) ++ return; ++ ++ dev = filp->minor->dev; ++ mutex_lock(&dev->filelist_mutex); ++ get_pid(pid); ++ old = rcu_replace_pointer(filp->pid, pid, 1); ++ mutex_unlock(&dev->filelist_mutex); ++ ++ synchronize_rcu(); ++ put_pid(old); ++} ++ + /** + * drm_release_noglobal - release method for DRM file + * @inode: device inode +@@ -924,7 +956,7 @@ void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file) + { + struct drm_gem_object *obj; + struct drm_memory_stats status = {}; +- enum drm_gem_object_status supported_status; ++ enum drm_gem_object_status supported_status = 0; + int id; + + spin_lock(&file->table_lock); +diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c +index aff3746dedfb48..1955eaeba0ab7c 100644 +--- a/drivers/gpu/drm/drm_framebuffer.c ++++ b/drivers/gpu/drm/drm_framebuffer.c +@@ -570,7 +570,7 @@ int drm_mode_getfb2_ioctl(struct drm_device *dev, + struct drm_mode_fb_cmd2 *r = data; + struct drm_framebuffer *fb; + unsigned int i; +- int ret; ++ int ret = 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; +diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c +index e435f986cd135b..1ff0678be7c75b 100644 +--- a/drivers/gpu/drm/drm_gem_shmem_helper.c ++++ b/drivers/gpu/drm/drm_gem_shmem_helper.c +@@ -610,6 +610,9 @@ int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct + return ret; + } + ++ if (is_cow_mapping(vma->vm_flags)) ++ return -EINVAL; ++ + dma_resv_lock(shmem->base.resv, NULL); + ret = drm_gem_shmem_get_pages(shmem); + dma_resv_unlock(shmem->base.resv); +diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h +index ba12acd551390b..0ef5fc2a61f194 100644 +--- a/drivers/gpu/drm/drm_internal.h ++++ b/drivers/gpu/drm/drm_internal.h +@@ -77,10 +77,6 @@ void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv); + void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv, + uint32_t handle); + +-/* drm_drv.c */ +-struct drm_minor *drm_minor_acquire(unsigned int minor_id); +-void drm_minor_release(struct drm_minor *minor); +- + /* drm_managed.c */ + void drm_managed_release(struct drm_device *dev); + void drmm_add_final_kfree(struct drm_device *dev, void *container); +diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c +index f03ffbacfe9b48..77590b0f38fa38 100644 +--- a/drivers/gpu/drm/drm_ioctl.c ++++ b/drivers/gpu/drm/drm_ioctl.c +@@ -776,6 +776,9 @@ long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata, + struct drm_device *dev = file_priv->minor->dev; + int retcode; + ++ /* Update drm_file owner if fd was passed along. */ ++ drm_file_update_pid(file_priv); ++ + if (drm_dev_is_unplugged(dev)) + return -ENODEV; + +diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c +index 150fe155506809..94375c6a542564 100644 +--- a/drivers/gpu/drm/drm_lease.c ++++ b/drivers/gpu/drm/drm_lease.c +@@ -510,8 +510,8 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev, + /* Handle leased objects, if any */ + idr_init(&leases); + if (object_count != 0) { +- object_ids = memdup_user(u64_to_user_ptr(cl->object_ids), +- array_size(object_count, sizeof(__u32))); ++ object_ids = memdup_array_user(u64_to_user_ptr(cl->object_ids), ++ object_count, sizeof(__u32)); + if (IS_ERR(object_ids)) { + ret = PTR_ERR(object_ids); + idr_destroy(&leases); +diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c +index 14201f73aab134..52a93149363b46 100644 +--- a/drivers/gpu/drm/drm_mipi_dsi.c ++++ b/drivers/gpu/drm/drm_mipi_dsi.c +@@ -347,7 +347,8 @@ static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) + { + struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); + +- mipi_dsi_detach(dsi); ++ if (dsi->attached) ++ mipi_dsi_detach(dsi); + mipi_dsi_device_unregister(dsi); + + return 0; +@@ -370,11 +371,18 @@ EXPORT_SYMBOL(mipi_dsi_host_unregister); + int mipi_dsi_attach(struct mipi_dsi_device *dsi) + { + const struct mipi_dsi_host_ops *ops = dsi->host->ops; ++ int ret; + + if (!ops || !ops->attach) + return -ENOSYS; + +- return ops->attach(dsi->host, dsi); ++ ret = ops->attach(dsi->host, dsi); ++ if (ret) ++ return ret; ++ ++ dsi->attached = true; ++ ++ return 0; + } + EXPORT_SYMBOL(mipi_dsi_attach); + +@@ -386,9 +394,14 @@ int mipi_dsi_detach(struct mipi_dsi_device *dsi) + { + const struct mipi_dsi_host_ops *ops = dsi->host->ops; + ++ if (WARN_ON(!dsi->attached)) ++ return -EINVAL; ++ + if (!ops || !ops->detach) + return -ENOSYS; + ++ dsi->attached = false; ++ + return ops->detach(dsi->host, dsi); + } + EXPORT_SYMBOL(mipi_dsi_detach); +@@ -641,7 +654,7 @@ EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size); + * + * Return: 0 on success or a negative error code on failure. + */ +-ssize_t mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable) ++int mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable) + { + /* Note: Needs updating for non-default PPS or algorithm */ + u8 tx[2] = { enable << 0, 0 }; +@@ -666,8 +679,8 @@ EXPORT_SYMBOL(mipi_dsi_compression_mode); + * + * Return: 0 on success or a negative error code on failure. + */ +-ssize_t mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, +- const struct drm_dsc_picture_parameter_set *pps) ++int mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, ++ const struct drm_dsc_picture_parameter_set *pps) + { + struct mipi_dsi_msg msg = { + .channel = dsi->channel, +diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c +index f858dfedf2cfcf..2c582020cb4237 100644 +--- a/drivers/gpu/drm/drm_modeset_helper.c ++++ b/drivers/gpu/drm/drm_modeset_helper.c +@@ -193,13 +193,22 @@ int drm_mode_config_helper_suspend(struct drm_device *dev) + + if (!dev) + return 0; ++ /* ++ * Don't disable polling if it was never initialized ++ */ ++ if (dev->mode_config.poll_enabled) ++ drm_kms_helper_poll_disable(dev); + +- drm_kms_helper_poll_disable(dev); + drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 1); + state = drm_atomic_helper_suspend(dev); + if (IS_ERR(state)) { + drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 0); +- drm_kms_helper_poll_enable(dev); ++ /* ++ * Don't enable polling if it was never initialized ++ */ ++ if (dev->mode_config.poll_enabled) ++ drm_kms_helper_poll_enable(dev); ++ + return PTR_ERR(state); + } + +@@ -239,7 +248,11 @@ int drm_mode_config_helper_resume(struct drm_device *dev) + dev->mode_config.suspend_state = NULL; + + drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 0); +- drm_kms_helper_poll_enable(dev); ++ /* ++ * Don't enable polling if it is not initialized ++ */ ++ if (dev->mode_config.poll_enabled) ++ drm_kms_helper_poll_enable(dev); + + return ret; + } +diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c +index e814020bbcd3b3..cfbe020de54e01 100644 +--- a/drivers/gpu/drm/drm_panel.c ++++ b/drivers/gpu/drm/drm_panel.c +@@ -274,19 +274,24 @@ EXPORT_SYMBOL(drm_panel_disable); + * The modes probed from the panel are automatically added to the connector + * that the panel is attached to. + * +- * Return: The number of modes available from the panel on success or a +- * negative error code on failure. ++ * Return: The number of modes available from the panel on success, or 0 on ++ * failure (no modes). + */ + int drm_panel_get_modes(struct drm_panel *panel, + struct drm_connector *connector) + { + if (!panel) +- return -EINVAL; ++ return 0; + +- if (panel->funcs && panel->funcs->get_modes) +- return panel->funcs->get_modes(panel, connector); ++ if (panel->funcs && panel->funcs->get_modes) { ++ int num; + +- return -EOPNOTSUPP; ++ num = panel->funcs->get_modes(panel, connector); ++ if (num > 0) ++ return num; ++ } ++ ++ return 0; + } + EXPORT_SYMBOL(drm_panel_get_modes); + +diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c +index d5c15292ae9378..5b2506c65e9520 100644 +--- a/drivers/gpu/drm/drm_panel_orientation_quirks.c ++++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c +@@ -117,6 +117,12 @@ static const struct drm_dmi_panel_orientation_data lcd1080x1920_leftside_up = { + .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP, + }; + ++static const struct drm_dmi_panel_orientation_data lcd1080x1920_rightside_up = { ++ .width = 1080, ++ .height = 1920, ++ .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, ++}; ++ + static const struct drm_dmi_panel_orientation_data lcd1200x1920_rightside_up = { + .width = 1200, + .height = 1920, +@@ -196,6 +202,24 @@ static const struct dmi_system_id orientation_data[] = { + DMI_MATCH(DMI_BOARD_NAME, "NEXT"), + }, + .driver_data = (void *)&lcd800x1280_rightside_up, ++ }, { /* AYA NEO KUN */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AYANEO"), ++ DMI_MATCH(DMI_BOARD_NAME, "KUN"), ++ }, ++ .driver_data = (void *)&lcd1600x2560_rightside_up, ++ }, { /* AYN Loki Max */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ayn"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Loki Max"), ++ }, ++ .driver_data = (void *)&lcd1080x1920_leftside_up, ++ }, { /* AYN Loki Zero */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ayn"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Loki Zero"), ++ }, ++ .driver_data = (void *)&lcd1080x1920_leftside_up, + }, { /* Chuwi HiBook (CWI514) */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"), +@@ -279,6 +303,12 @@ static const struct dmi_system_id orientation_data[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G1618-03") + }, + .driver_data = (void *)&lcd720x1280_rightside_up, ++ }, { /* GPD Win Mini */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "GPD"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G1617-01") ++ }, ++ .driver_data = (void *)&lcd1080x1920_rightside_up, + }, { /* I.T.Works TW891 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."), +@@ -336,6 +366,12 @@ static const struct dmi_system_id orientation_data[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "IdeaPad Duet 3 10IGL5"), + }, + .driver_data = (void *)&lcd1200x1920_rightside_up, ++ }, { /* Lenovo Legion Go 8APU1 */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Legion Go 8APU1"), ++ }, ++ .driver_data = (void *)&lcd1600x2560_leftside_up, + }, { /* Lenovo Yoga Book X90F / X90L */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), +@@ -390,6 +426,12 @@ static const struct dmi_system_id orientation_data[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ONE XPLAYER"), + }, + .driver_data = (void *)&lcd1600x2560_leftside_up, ++ }, { /* OrangePi Neo */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "OrangePi"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "NEO-01"), ++ }, ++ .driver_data = (void *)&lcd1200x1920_rightside_up, + }, { /* Samsung GalaxyBook 10.6 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), +@@ -403,6 +445,13 @@ static const struct dmi_system_id orientation_data[] = { + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "1"), + }, + .driver_data = (void *)&lcd800x1280_rightside_up, ++ }, { /* Valve Steam Deck */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Valve"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Galileo"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "1"), ++ }, ++ .driver_data = (void *)&lcd800x1280_rightside_up, + }, { /* VIOS LTH17 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "VIOS"), +diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c +index 24e7998d17313e..311e179904a2ab 100644 +--- a/drivers/gpu/drm/drm_plane.c ++++ b/drivers/gpu/drm/drm_plane.c +@@ -678,6 +678,19 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, + !file_priv->universal_planes) + continue; + ++ /* ++ * If we're running on a virtualized driver then, ++ * unless userspace advertizes support for the ++ * virtualized cursor plane, disable cursor planes ++ * because they'll be broken due to missing cursor ++ * hotspot info. ++ */ ++ if (plane->type == DRM_PLANE_TYPE_CURSOR && ++ drm_core_check_feature(dev, DRIVER_CURSOR_HOTSPOT) && ++ file_priv->atomic && ++ !file_priv->supports_virtualized_cursor_plane) ++ continue; ++ + if (drm_lease_held(file_priv, plane->base.id)) { + if (count < plane_resp->count_planes && + put_user(plane->base.id, plane_ptr + count)) +@@ -1387,6 +1400,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, + out: + if (fb) + drm_framebuffer_put(fb); ++ fb = NULL; + if (plane->old_fb) + drm_framebuffer_put(plane->old_fb); + plane->old_fb = NULL; +diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c +index 63b709a67471b9..03bd3c7bd0dc2c 100644 +--- a/drivers/gpu/drm/drm_prime.c ++++ b/drivers/gpu/drm/drm_prime.c +@@ -278,7 +278,7 @@ void drm_gem_dmabuf_release(struct dma_buf *dma_buf) + } + EXPORT_SYMBOL(drm_gem_dmabuf_release); + +-/* ++/** + * drm_gem_prime_fd_to_handle - PRIME import function for GEM drivers + * @dev: drm_device to import into + * @file_priv: drm file-private structure +@@ -292,9 +292,9 @@ EXPORT_SYMBOL(drm_gem_dmabuf_release); + * + * Returns 0 on success or a negative error code on failure. + */ +-static int drm_gem_prime_fd_to_handle(struct drm_device *dev, +- struct drm_file *file_priv, int prime_fd, +- uint32_t *handle) ++int drm_gem_prime_fd_to_handle(struct drm_device *dev, ++ struct drm_file *file_priv, int prime_fd, ++ uint32_t *handle) + { + struct dma_buf *dma_buf; + struct drm_gem_object *obj; +@@ -360,6 +360,7 @@ static int drm_gem_prime_fd_to_handle(struct drm_device *dev, + dma_buf_put(dma_buf); + return ret; + } ++EXPORT_SYMBOL(drm_gem_prime_fd_to_handle); + + int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +@@ -408,7 +409,7 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev, + return dmabuf; + } + +-/* ++/** + * drm_gem_prime_handle_to_fd - PRIME export function for GEM drivers + * @dev: dev to export the buffer from + * @file_priv: drm file-private structure +@@ -421,10 +422,10 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev, + * The actual exporting from GEM object to a dma-buf is done through the + * &drm_gem_object_funcs.export callback. + */ +-static int drm_gem_prime_handle_to_fd(struct drm_device *dev, +- struct drm_file *file_priv, uint32_t handle, +- uint32_t flags, +- int *prime_fd) ++int drm_gem_prime_handle_to_fd(struct drm_device *dev, ++ struct drm_file *file_priv, uint32_t handle, ++ uint32_t flags, ++ int *prime_fd) + { + struct drm_gem_object *obj; + int ret = 0; +@@ -506,6 +507,7 @@ static int drm_gem_prime_handle_to_fd(struct drm_device *dev, + + return ret; + } ++EXPORT_SYMBOL(drm_gem_prime_handle_to_fd); + + int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +@@ -580,7 +582,12 @@ int drm_gem_map_attach(struct dma_buf *dma_buf, + { + struct drm_gem_object *obj = dma_buf->priv; + +- if (!obj->funcs->get_sg_table) ++ /* ++ * drm_gem_map_dma_buf() requires obj->get_sg_table(), but drivers ++ * that implement their own ->map_dma_buf() do not. ++ */ ++ if (dma_buf->ops->map_dma_buf == drm_gem_map_dma_buf && ++ !obj->funcs->get_sg_table) + return -ENOSYS; + + return drm_gem_pin(obj); +@@ -818,7 +825,7 @@ struct sg_table *drm_prime_pages_to_sg(struct drm_device *dev, + if (max_segment == 0) + max_segment = UINT_MAX; + err = sg_alloc_table_from_pages_segment(sg, pages, nr_pages, 0, +- nr_pages << PAGE_SHIFT, ++ (unsigned long)nr_pages << PAGE_SHIFT, + max_segment, GFP_KERNEL); + if (err) { + kfree(sg); +@@ -864,9 +871,9 @@ EXPORT_SYMBOL(drm_prime_get_contiguous_size); + * @obj: GEM object to export + * @flags: flags like DRM_CLOEXEC and DRM_RDWR + * +- * This is the implementation of the &drm_gem_object_funcs.export functions +- * for GEM drivers using the PRIME helpers. It is used as the default for +- * drivers that do not set their own. ++ * This is the implementation of the &drm_gem_object_funcs.export functions for GEM drivers ++ * using the PRIME helpers. It is used as the default in ++ * drm_gem_prime_handle_to_fd(). + */ + struct dma_buf *drm_gem_prime_export(struct drm_gem_object *obj, + int flags) +@@ -962,9 +969,10 @@ EXPORT_SYMBOL(drm_gem_prime_import_dev); + * @dev: drm_device to import into + * @dma_buf: dma-buf object to import + * +- * This is the implementation of the gem_prime_import functions for GEM +- * drivers using the PRIME helpers. It is the default for drivers that do +- * not set their own &drm_driver.gem_prime_import. ++ * This is the implementation of the gem_prime_import functions for GEM drivers ++ * using the PRIME helpers. Drivers can use this as their ++ * &drm_driver.gem_prime_import implementation. It is used as the default ++ * implementation in drm_gem_prime_fd_to_handle(). + * + * Drivers must arrange to call drm_prime_gem_destroy() from their + * &drm_gem_object_funcs.free hook when using this function. +diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c +index 5b93c11895bb1e..aab76334083e8a 100644 +--- a/drivers/gpu/drm/drm_print.c ++++ b/drivers/gpu/drm/drm_print.c +@@ -100,8 +100,9 @@ void __drm_puts_coredump(struct drm_printer *p, const char *str) + copy = iterator->remain; + + /* Copy out the bit of the string that we need */ +- memcpy(iterator->data, +- str + (iterator->start - iterator->offset), copy); ++ if (iterator->data) ++ memcpy(iterator->data, ++ str + (iterator->start - iterator->offset), copy); + + iterator->offset = iterator->start + copy; + iterator->remain -= copy; +@@ -110,7 +111,8 @@ void __drm_puts_coredump(struct drm_printer *p, const char *str) + + len = min_t(ssize_t, strlen(str), iterator->remain); + +- memcpy(iterator->data + pos, str, len); ++ if (iterator->data) ++ memcpy(iterator->data + pos, str, len); + + iterator->offset += len; + iterator->remain -= len; +@@ -140,8 +142,9 @@ void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf) + if ((iterator->offset >= iterator->start) && (len < iterator->remain)) { + ssize_t pos = iterator->offset - iterator->start; + +- snprintf(((char *) iterator->data) + pos, +- iterator->remain, "%pV", vaf); ++ if (iterator->data) ++ snprintf(((char *) iterator->data) + pos, ++ iterator->remain, "%pV", vaf); + + iterator->offset += len; + iterator->remain -= len; +diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c +index 3f479483d7d80f..c90afb5d089871 100644 +--- a/drivers/gpu/drm/drm_probe_helper.c ++++ b/drivers/gpu/drm/drm_probe_helper.c +@@ -293,14 +293,17 @@ static void reschedule_output_poll_work(struct drm_device *dev) + * Drivers can call this helper from their device resume implementation. It is + * not an error to call this even when output polling isn't enabled. + * ++ * If device polling was never initialized before, this call will trigger a ++ * warning and return. ++ * + * Note that calls to enable and disable polling must be strictly ordered, which + * is automatically the case when they're only call from suspend/resume + * callbacks. + */ + void drm_kms_helper_poll_enable(struct drm_device *dev) + { +- if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll || +- dev->mode_config.poll_running) ++ if (drm_WARN_ON_ONCE(dev, !dev->mode_config.poll_enabled) || ++ !drm_kms_helper_poll || dev->mode_config.poll_running) + return; + + if (drm_kms_helper_enable_hpd(dev) || +@@ -419,6 +422,13 @@ static int drm_helper_probe_get_modes(struct drm_connector *connector) + + count = connector_funcs->get_modes(connector); + ++ /* The .get_modes() callback should not return negative values. */ ++ if (count < 0) { ++ drm_err(connector->dev, ".get_modes() returned %pe\n", ++ ERR_PTR(count)); ++ count = 0; ++ } ++ + /* + * Fallback for when DDC probe failed in drm_get_edid() and thus skipped + * override/firmware EDID. +@@ -619,8 +629,12 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, + 0); + } + +- /* Re-enable polling in case the global poll config changed. */ +- drm_kms_helper_poll_enable(dev); ++ /* ++ * Re-enable polling in case the global poll config changed but polling ++ * is still initialized. ++ */ ++ if (dev->mode_config.poll_enabled) ++ drm_kms_helper_poll_enable(dev); + + if (connector->status == connector_status_disconnected) { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", +@@ -871,12 +885,18 @@ EXPORT_SYMBOL(drm_kms_helper_is_poll_worker); + * not an error to call this even when output polling isn't enabled or already + * disabled. Polling is re-enabled by calling drm_kms_helper_poll_enable(). + * ++ * If however, the polling was never initialized, this call will trigger a ++ * warning and return ++ * + * Note that calls to enable and disable polling must be strictly ordered, which + * is automatically the case when they're only call from suspend/resume + * callbacks. + */ + void drm_kms_helper_poll_disable(struct drm_device *dev) + { ++ if (drm_WARN_ON(dev, !dev->mode_config.poll_enabled)) ++ return; ++ + if (dev->mode_config.poll_running) + drm_kms_helper_disable_hpd(dev); + +diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c +index f7003d1ec5ef1e..7b4ed5ca0a9bd2 100644 +--- a/drivers/gpu/drm/drm_syncobj.c ++++ b/drivers/gpu/drm/drm_syncobj.c +@@ -1034,7 +1034,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs, + uint64_t *points; + uint32_t signaled_count, i; + +- if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) ++ if (flags & (DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | ++ DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE)) + lockdep_assert_none_held_once(); + + points = kmalloc_array(count, sizeof(*points), GFP_KERNEL); +@@ -1069,7 +1070,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs, + fence = drm_syncobj_fence_get(syncobjs[i]); + if (!fence || dma_fence_chain_find_seqno(&fence, points[i])) { + dma_fence_put(fence); +- if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) { ++ if (flags & (DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | ++ DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE)) { + continue; + } else { + timeout = -EINVAL; +@@ -1102,7 +1104,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs, + * fallthough and try a 0 timeout wait! + */ + +- if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) { ++ if (flags & (DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | ++ DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE)) { + for (i = 0; i < count; ++i) + drm_syncobj_fence_add_wait(syncobjs[i], &entries[i]); + } +@@ -1377,10 +1380,21 @@ syncobj_eventfd_entry_func(struct drm_syncobj *syncobj, + + /* This happens inside the syncobj lock */ + fence = dma_fence_get(rcu_dereference_protected(syncobj->fence, 1)); ++ if (!fence) ++ return; ++ + ret = dma_fence_chain_find_seqno(&fence, entry->point); +- if (ret != 0 || !fence) { ++ if (ret != 0) { ++ /* The given seqno has not been submitted yet. */ + dma_fence_put(fence); + return; ++ } else if (!fence) { ++ /* If dma_fence_chain_find_seqno returns 0 but sets the fence ++ * to NULL, it implies that the given seqno is signaled and a ++ * later seqno has already been submitted. Assign a stub fence ++ * so that the eventfd still gets signaled below. ++ */ ++ fence = dma_fence_get_stub(); + } + + list_del_init(&entry->node); +@@ -1407,6 +1421,7 @@ drm_syncobj_eventfd_ioctl(struct drm_device *dev, void *data, + struct drm_syncobj *syncobj; + struct eventfd_ctx *ev_fd_ctx; + struct syncobj_eventfd_entry *entry; ++ int ret; + + if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) + return -EOPNOTSUPP; +@@ -1422,13 +1437,15 @@ drm_syncobj_eventfd_ioctl(struct drm_device *dev, void *data, + return -ENOENT; + + ev_fd_ctx = eventfd_ctx_fdget(args->fd); +- if (IS_ERR(ev_fd_ctx)) +- return PTR_ERR(ev_fd_ctx); ++ if (IS_ERR(ev_fd_ctx)) { ++ ret = PTR_ERR(ev_fd_ctx); ++ goto err_fdget; ++ } + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) { +- eventfd_ctx_put(ev_fd_ctx); +- return -ENOMEM; ++ ret = -ENOMEM; ++ goto err_kzalloc; + } + entry->syncobj = syncobj; + entry->ev_fd_ctx = ev_fd_ctx; +@@ -1439,6 +1456,12 @@ drm_syncobj_eventfd_ioctl(struct drm_device *dev, void *data, + drm_syncobj_put(syncobj); + + return 0; ++ ++err_kzalloc: ++ eventfd_ctx_put(ev_fd_ctx); ++err_fdget: ++ drm_syncobj_put(syncobj); ++ return ret; + } + + int +diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c +index a8d3fa81e4ec5d..f9bc837e22bddc 100644 +--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c ++++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c +@@ -494,7 +494,7 @@ static const struct drm_driver etnaviv_drm_driver = { + .desc = "etnaviv DRM", + .date = "20151214", + .major = 1, +- .minor = 3, ++ .minor = 4, + }; + + /* +diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c +index b5f73502e3dd42..69fccbcd92c622 100644 +--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c ++++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c +@@ -356,9 +356,11 @@ static void *etnaviv_gem_vmap_impl(struct etnaviv_gem_object *obj) + + static inline enum dma_data_direction etnaviv_op_to_dma_dir(u32 op) + { +- if (op & ETNA_PREP_READ) ++ op &= ETNA_PREP_READ | ETNA_PREP_WRITE; ++ ++ if (op == ETNA_PREP_READ) + return DMA_FROM_DEVICE; +- else if (op & ETNA_PREP_WRITE) ++ else if (op == ETNA_PREP_WRITE) + return DMA_TO_DEVICE; + else + return DMA_BIDIRECTIONAL; +diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +index 9276756e1397d3..371e1f2733f6fb 100644 +--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c ++++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +@@ -632,8 +632,8 @@ static void etnaviv_gpu_enable_mlcg(struct etnaviv_gpu *gpu) + /* Disable TX clock gating on affected core revisions. */ + if (etnaviv_is_model_rev(gpu, GC4000, 0x5222) || + etnaviv_is_model_rev(gpu, GC2000, 0x5108) || +- etnaviv_is_model_rev(gpu, GC2000, 0x6202) || +- etnaviv_is_model_rev(gpu, GC2000, 0x6203)) ++ etnaviv_is_model_rev(gpu, GC7000, 0x6202) || ++ etnaviv_is_model_rev(gpu, GC7000, 0x6203)) + pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_TX; + + /* Disable SE and RA clock gating on affected core revisions. */ +diff --git a/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c b/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c +index 67201242438bed..8665f2658d51b3 100644 +--- a/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c ++++ b/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c +@@ -265,6 +265,9 @@ static const struct etnaviv_chip_identity etnaviv_chip_identities[] = { + bool etnaviv_fill_identity_from_hwdb(struct etnaviv_gpu *gpu) + { + struct etnaviv_chip_identity *ident = &gpu->identity; ++ const u32 product_id = ident->product_id; ++ const u32 customer_id = ident->customer_id; ++ const u32 eco_id = ident->eco_id; + int i; + + for (i = 0; i < ARRAY_SIZE(etnaviv_chip_identities); i++) { +@@ -278,6 +281,12 @@ bool etnaviv_fill_identity_from_hwdb(struct etnaviv_gpu *gpu) + etnaviv_chip_identities[i].eco_id == ~0U)) { + memcpy(ident, &etnaviv_chip_identities[i], + sizeof(*ident)); ++ ++ /* Restore some id values as ~0U aka 'don't care' might been used. */ ++ ident->product_id = product_id; ++ ident->customer_id = customer_id; ++ ident->eco_id = eco_id; ++ + return true; + } + } +diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c +index 345fec6cb1a4c1..97e406d9ac06f4 100644 +--- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c ++++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c +@@ -38,9 +38,6 @@ static enum drm_gpu_sched_stat etnaviv_sched_timedout_job(struct drm_sched_job + u32 dma_addr; + int change; + +- /* block scheduler */ +- drm_sched_stop(&gpu->sched, sched_job); +- + /* + * If the GPU managed to complete this jobs fence, the timout is + * spurious. Bail out. +@@ -63,6 +60,9 @@ static enum drm_gpu_sched_stat etnaviv_sched_timedout_job(struct drm_sched_job + goto out_no_timeout; + } + ++ /* block scheduler */ ++ drm_sched_stop(&gpu->sched, sched_job); ++ + if(sched_job) + drm_sched_increase_karma(sched_job); + +@@ -76,8 +76,7 @@ static enum drm_gpu_sched_stat etnaviv_sched_timedout_job(struct drm_sched_job + return DRM_GPU_SCHED_STAT_NOMINAL; + + out_no_timeout: +- /* restart scheduler after GPU is usable again */ +- drm_sched_start(&gpu->sched, true); ++ list_add(&sched_job->list, &sched_job->sched->pending_list); + return DRM_GPU_SCHED_STAT_NOMINAL; + } + +diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +index 4d986077738b9b..bce027552474a6 100644 +--- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c ++++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +@@ -319,9 +319,9 @@ static void decon_win_set_bldmod(struct decon_context *ctx, unsigned int win, + static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, + struct drm_framebuffer *fb) + { +- struct exynos_drm_plane plane = ctx->planes[win]; ++ struct exynos_drm_plane *plane = &ctx->planes[win]; + struct exynos_drm_plane_state *state = +- to_exynos_plane_state(plane.base.state); ++ to_exynos_plane_state(plane->base.state); + unsigned int alpha = state->base.alpha; + unsigned int pixel_alpha; + unsigned long val; +diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c +index 3404ec1367fb92..71ee824c4140bd 100644 +--- a/drivers/gpu/drm/exynos/exynos_dp.c ++++ b/drivers/gpu/drm/exynos/exynos_dp.c +@@ -288,7 +288,6 @@ struct platform_driver dp_driver = { + .remove = exynos_dp_remove, + .driver = { + .name = "exynos-dp", +- .owner = THIS_MODULE, + .pm = pm_ptr(&exynos_dp_pm_ops), + .of_match_table = exynos_dp_match, + }, +diff --git a/drivers/gpu/drm/exynos/exynos_drm_dma.c b/drivers/gpu/drm/exynos/exynos_drm_dma.c +index a971590b813230..e2c7373f20c6b7 100644 +--- a/drivers/gpu/drm/exynos/exynos_drm_dma.c ++++ b/drivers/gpu/drm/exynos/exynos_drm_dma.c +@@ -107,18 +107,16 @@ int exynos_drm_register_dma(struct drm_device *drm, struct device *dev, + return 0; + + if (!priv->mapping) { +- void *mapping; ++ void *mapping = NULL; + + if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) + mapping = arm_iommu_create_mapping(&platform_bus_type, + EXYNOS_DEV_ADDR_START, EXYNOS_DEV_ADDR_SIZE); + else if (IS_ENABLED(CONFIG_IOMMU_DMA)) + mapping = iommu_get_domain_for_dev(priv->dma_dev); +- else +- mapping = ERR_PTR(-ENODEV); + +- if (IS_ERR(mapping)) +- return PTR_ERR(mapping); ++ if (!mapping) ++ return -ENODEV; + priv->mapping = mapping; + } + +diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c +index 8399256cb5c9d7..5380fb6c55ae1e 100644 +--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c ++++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c +@@ -300,6 +300,7 @@ static int exynos_drm_bind(struct device *dev) + drm_mode_config_cleanup(drm); + exynos_drm_cleanup_dma(drm); + kfree(private); ++ dev_set_drvdata(dev, NULL); + err_free_drm: + drm_dev_put(drm); + +@@ -313,6 +314,7 @@ static void exynos_drm_unbind(struct device *dev) + drm_dev_unregister(drm); + + drm_kms_helper_poll_fini(drm); ++ drm_atomic_helper_shutdown(drm); + + component_unbind_all(drm->dev, drm); + drm_mode_config_cleanup(drm); +@@ -350,9 +352,18 @@ static int exynos_drm_platform_remove(struct platform_device *pdev) + return 0; + } + ++static void exynos_drm_platform_shutdown(struct platform_device *pdev) ++{ ++ struct drm_device *drm = platform_get_drvdata(pdev); ++ ++ if (drm) ++ drm_atomic_helper_shutdown(drm); ++} ++ + static struct platform_driver exynos_drm_platform_driver = { + .probe = exynos_drm_platform_probe, + .remove = exynos_drm_platform_remove, ++ .shutdown = exynos_drm_platform_shutdown, + .driver = { + .name = "exynos-drm", + .pm = &exynos_drm_pm_ops, +diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c +index 8dde7b1e9b35d9..5bdc246f5fad09 100644 +--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c ++++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c +@@ -661,9 +661,9 @@ static void fimd_win_set_bldmod(struct fimd_context *ctx, unsigned int win, + static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win, + struct drm_framebuffer *fb, int width) + { +- struct exynos_drm_plane plane = ctx->planes[win]; ++ struct exynos_drm_plane *plane = &ctx->planes[win]; + struct exynos_drm_plane_state *state = +- to_exynos_plane_state(plane.base.state); ++ to_exynos_plane_state(plane->base.state); + uint32_t pixel_format = fb->format->format; + unsigned int alpha = state->base.alpha; + u32 val = WINCONx_ENWIN; +diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c +index 34cdabc30b4f5e..1456abd5b9dde1 100644 +--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c ++++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c +@@ -1173,7 +1173,7 @@ static int gsc_bind(struct device *dev, struct device *master, void *data) + struct exynos_drm_ipp *ipp = &ctx->ipp; + + ctx->drm_dev = drm_dev; +- ctx->drm_dev = drm_dev; ++ ipp->drm_dev = drm_dev; + exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv); + + exynos_drm_ipp_register(dev, ipp, &ipp_funcs, +@@ -1342,7 +1342,7 @@ static int __maybe_unused gsc_runtime_resume(struct device *dev) + for (i = 0; i < ctx->num_clocks; i++) { + ret = clk_prepare_enable(ctx->clocks[i]); + if (ret) { +- while (--i > 0) ++ while (--i >= 0) + clk_disable_unprepare(ctx->clocks[i]); + return ret; + } +diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c +index f5e1adfcaa514e..e17f9c5c9c90e6 100644 +--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c ++++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c +@@ -309,6 +309,7 @@ static int vidi_get_modes(struct drm_connector *connector) + struct vidi_context *ctx = ctx_from_connector(connector); + struct edid *edid; + int edid_len; ++ int count; + + /* + * the edid data comes from user side and it would be set +@@ -316,19 +317,23 @@ static int vidi_get_modes(struct drm_connector *connector) + */ + if (!ctx->raw_edid) { + DRM_DEV_DEBUG_KMS(ctx->dev, "raw_edid is null.\n"); +- return -EFAULT; ++ return 0; + } + + edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH; + edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL); + if (!edid) { + DRM_DEV_DEBUG_KMS(ctx->dev, "failed to allocate edid\n"); +- return -ENOMEM; ++ return 0; + } + + drm_connector_update_edid_property(connector, edid); + +- return drm_add_edid_modes(connector, edid); ++ count = drm_add_edid_modes(connector, edid); ++ ++ kfree(edid); ++ ++ return count; + } + + static const struct drm_connector_helper_funcs vidi_connector_helper_funcs = { +diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c +index f3aaa4ea3e6820..906133331a4424 100644 +--- a/drivers/gpu/drm/exynos/exynos_hdmi.c ++++ b/drivers/gpu/drm/exynos/exynos_hdmi.c +@@ -887,11 +887,11 @@ static int hdmi_get_modes(struct drm_connector *connector) + int ret; + + if (!hdata->ddc_adpt) +- return -ENODEV; ++ goto no_edid; + + edid = drm_get_edid(connector, hdata->ddc_adpt); + if (!edid) +- return -ENODEV; ++ goto no_edid; + + hdata->dvi_mode = !connector->display_info.is_hdmi; + DRM_DEV_DEBUG_KMS(hdata->dev, "%s : width[%d] x height[%d]\n", +@@ -906,6 +906,9 @@ static int hdmi_get_modes(struct drm_connector *connector) + kfree(edid); + + return ret; ++ ++no_edid: ++ return drm_add_modes_noedid(connector, 640, 480); + } + + static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) +@@ -1861,6 +1864,8 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) + return ret; + + crtc = exynos_drm_crtc_get_by_type(drm_dev, EXYNOS_DISPLAY_TYPE_HDMI); ++ if (IS_ERR(crtc)) ++ return PTR_ERR(crtc); + crtc->pipe_clk = &hdata->phy_clk; + + ret = hdmi_create_connector(encoder); +diff --git a/drivers/gpu/drm/gma500/Makefile b/drivers/gpu/drm/gma500/Makefile +index 4f302cd5e1a6ca..58fed80c7392a0 100644 +--- a/drivers/gpu/drm/gma500/Makefile ++++ b/drivers/gpu/drm/gma500/Makefile +@@ -34,7 +34,6 @@ gma500_gfx-y += \ + psb_intel_lvds.o \ + psb_intel_modes.o \ + psb_intel_sdvo.o \ +- psb_lid.o \ + psb_irq.o + + gma500_gfx-$(CONFIG_ACPI) += opregion.o +diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c +index f08a6803dc1849..3adc2c9ab72da0 100644 +--- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c ++++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c +@@ -311,6 +311,9 @@ static int cdv_intel_lvds_get_modes(struct drm_connector *connector) + if (mode_dev->panel_fixed_mode != NULL) { + struct drm_display_mode *mode = + drm_mode_duplicate(dev, mode_dev->panel_fixed_mode); ++ if (!mode) ++ return 0; ++ + drm_mode_probed_add(connector, mode); + return 1; + } +diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c +index dcfcd7b89d4a1d..6dece8f0e380f7 100644 +--- a/drivers/gpu/drm/gma500/psb_device.c ++++ b/drivers/gpu/drm/gma500/psb_device.c +@@ -73,8 +73,7 @@ static int psb_backlight_setup(struct drm_device *dev) + } + + psb_intel_lvds_set_brightness(dev, PSB_MAX_BRIGHTNESS); +- /* This must occur after the backlight is properly initialised */ +- psb_lid_timer_init(dev_priv); ++ + return 0; + } + +@@ -259,8 +258,6 @@ static int psb_chip_setup(struct drm_device *dev) + + static void psb_chip_teardown(struct drm_device *dev) + { +- struct drm_psb_private *dev_priv = to_drm_psb_private(dev); +- psb_lid_timer_takedown(dev_priv); + gma_intel_teardown_gmbus(dev); + } + +diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h +index f7f709df99b498..bb1cd45c085cd6 100644 +--- a/drivers/gpu/drm/gma500/psb_drv.h ++++ b/drivers/gpu/drm/gma500/psb_drv.h +@@ -170,7 +170,6 @@ + + #define PSB_NUM_VBLANKS 2 + #define PSB_WATCHDOG_DELAY (HZ * 2) +-#define PSB_LID_DELAY (HZ / 10) + + #define PSB_MAX_BRIGHTNESS 100 + +@@ -424,6 +423,7 @@ struct drm_psb_private { + uint32_t pipestat[PSB_NUM_PIPE]; + + spinlock_t irqmask_lock; ++ bool irq_enabled; + + /* Power */ + bool pm_initialized; +@@ -498,11 +498,7 @@ struct drm_psb_private { + /* Hotplug handling */ + struct work_struct hotplug_work; + +- /* LID-Switch */ +- spinlock_t lid_lock; +- struct timer_list lid_timer; + struct psb_intel_opregion opregion; +- u32 lid_last_state; + + /* Watchdog */ + uint32_t apm_reg; +@@ -598,10 +594,6 @@ struct psb_ops { + int i2c_bus; /* I2C bus identifier for Moorestown */ + }; + +-/* psb_lid.c */ +-extern void psb_lid_timer_init(struct drm_psb_private *dev_priv); +-extern void psb_lid_timer_takedown(struct drm_psb_private *dev_priv); +- + /* modesetting */ + extern void psb_modeset_init(struct drm_device *dev); + extern void psb_modeset_cleanup(struct drm_device *dev); +diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c +index 8486de230ec91b..8d1be94a443b24 100644 +--- a/drivers/gpu/drm/gma500/psb_intel_lvds.c ++++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c +@@ -504,6 +504,9 @@ static int psb_intel_lvds_get_modes(struct drm_connector *connector) + if (mode_dev->panel_fixed_mode != NULL) { + struct drm_display_mode *mode = + drm_mode_duplicate(dev, mode_dev->panel_fixed_mode); ++ if (!mode) ++ return 0; ++ + drm_mode_probed_add(connector, mode); + return 1; + } +diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c +index 343c51250207d8..7bbb79b0497d8d 100644 +--- a/drivers/gpu/drm/gma500/psb_irq.c ++++ b/drivers/gpu/drm/gma500/psb_irq.c +@@ -327,6 +327,8 @@ int gma_irq_install(struct drm_device *dev) + + gma_irq_postinstall(dev); + ++ dev_priv->irq_enabled = true; ++ + return 0; + } + +@@ -337,6 +339,9 @@ void gma_irq_uninstall(struct drm_device *dev) + unsigned long irqflags; + unsigned int i; + ++ if (!dev_priv->irq_enabled) ++ return; ++ + spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); + + if (dev_priv->ops->hotplug_enable) +diff --git a/drivers/gpu/drm/gma500/psb_lid.c b/drivers/gpu/drm/gma500/psb_lid.c +deleted file mode 100644 +index 58a7fe39263601..00000000000000 +--- a/drivers/gpu/drm/gma500/psb_lid.c ++++ /dev/null +@@ -1,80 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0-only +-/************************************************************************** +- * Copyright (c) 2007, Intel Corporation. +- * +- * Authors: Thomas Hellstrom +- **************************************************************************/ +- +-#include +- +-#include "psb_drv.h" +-#include "psb_intel_reg.h" +-#include "psb_reg.h" +- +-static void psb_lid_timer_func(struct timer_list *t) +-{ +- struct drm_psb_private *dev_priv = from_timer(dev_priv, t, lid_timer); +- struct drm_device *dev = (struct drm_device *)&dev_priv->dev; +- struct timer_list *lid_timer = &dev_priv->lid_timer; +- unsigned long irq_flags; +- u32 __iomem *lid_state = dev_priv->opregion.lid_state; +- u32 pp_status; +- +- if (readl(lid_state) == dev_priv->lid_last_state) +- goto lid_timer_schedule; +- +- if ((readl(lid_state)) & 0x01) { +- /*lid state is open*/ +- REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | POWER_TARGET_ON); +- do { +- pp_status = REG_READ(PP_STATUS); +- } while ((pp_status & PP_ON) == 0 && +- (pp_status & PP_SEQUENCE_MASK) != 0); +- +- if (REG_READ(PP_STATUS) & PP_ON) { +- /*FIXME: should be backlight level before*/ +- psb_intel_lvds_set_brightness(dev, 100); +- } else { +- DRM_DEBUG("LVDS panel never powered up"); +- return; +- } +- } else { +- psb_intel_lvds_set_brightness(dev, 0); +- +- REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) & ~POWER_TARGET_ON); +- do { +- pp_status = REG_READ(PP_STATUS); +- } while ((pp_status & PP_ON) == 0); +- } +- dev_priv->lid_last_state = readl(lid_state); +- +-lid_timer_schedule: +- spin_lock_irqsave(&dev_priv->lid_lock, irq_flags); +- if (!timer_pending(lid_timer)) { +- lid_timer->expires = jiffies + PSB_LID_DELAY; +- add_timer(lid_timer); +- } +- spin_unlock_irqrestore(&dev_priv->lid_lock, irq_flags); +-} +- +-void psb_lid_timer_init(struct drm_psb_private *dev_priv) +-{ +- struct timer_list *lid_timer = &dev_priv->lid_timer; +- unsigned long irq_flags; +- +- spin_lock_init(&dev_priv->lid_lock); +- spin_lock_irqsave(&dev_priv->lid_lock, irq_flags); +- +- timer_setup(lid_timer, psb_lid_timer_func, 0); +- +- lid_timer->expires = jiffies + PSB_LID_DELAY; +- +- add_timer(lid_timer); +- spin_unlock_irqrestore(&dev_priv->lid_lock, irq_flags); +-} +- +-void psb_lid_timer_takedown(struct drm_psb_private *dev_priv) +-{ +- del_timer_sync(&dev_priv->lid_timer); +-} +- +diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile +index 79f65eff6bb2a3..23400313d8a64c 100644 +--- a/drivers/gpu/drm/i915/Makefile ++++ b/drivers/gpu/drm/i915/Makefile +@@ -104,6 +104,7 @@ gt-y += \ + gt/intel_ggtt_fencing.o \ + gt/intel_gt.o \ + gt/intel_gt_buffer_pool.o \ ++ gt/intel_gt_ccs_mode.o \ + gt/intel_gt_clock_utils.o \ + gt/intel_gt_debugfs.o \ + gt/intel_gt_engines_debugfs.o \ +diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c +index 4c7187f7913ea5..e8ee0a08947e8f 100644 +--- a/drivers/gpu/drm/i915/display/g4x_dp.c ++++ b/drivers/gpu/drm/i915/display/g4x_dp.c +@@ -141,7 +141,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder, + + intel_de_rmw(dev_priv, TRANS_DP_CTL(crtc->pipe), + TRANS_DP_ENH_FRAMING, +- drm_dp_enhanced_frame_cap(intel_dp->dpcd) ? ++ pipe_config->enhanced_framing ? + TRANS_DP_ENH_FRAMING : 0); + } else { + if (IS_G4X(dev_priv) && pipe_config->limited_color_range) +@@ -153,7 +153,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder, + intel_dp->DP |= DP_SYNC_VS_HIGH; + intel_dp->DP |= DP_LINK_TRAIN_OFF; + +- if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) ++ if (pipe_config->enhanced_framing) + intel_dp->DP |= DP_ENHANCED_FRAMING; + + if (IS_CHERRYVIEW(dev_priv)) +@@ -351,6 +351,9 @@ static void intel_dp_get_config(struct intel_encoder *encoder, + u32 trans_dp = intel_de_read(dev_priv, + TRANS_DP_CTL(crtc->pipe)); + ++ if (trans_dp & TRANS_DP_ENH_FRAMING) ++ pipe_config->enhanced_framing = true; ++ + if (trans_dp & TRANS_DP_HSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PHSYNC; + else +@@ -361,6 +364,9 @@ static void intel_dp_get_config(struct intel_encoder *encoder, + else + flags |= DRM_MODE_FLAG_NVSYNC; + } else { ++ if (tmp & DP_ENHANCED_FRAMING) ++ pipe_config->enhanced_framing = true; ++ + if (tmp & DP_SYNC_HS_HIGH) + flags |= DRM_MODE_FLAG_PHSYNC; + else +diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c +index ad6488e9c2b2b8..5b8efe8e735a9b 100644 +--- a/drivers/gpu/drm/i915/display/icl_dsi.c ++++ b/drivers/gpu/drm/i915/display/icl_dsi.c +@@ -1440,6 +1440,13 @@ static void gen11_dsi_post_disable(struct intel_atomic_state *state, + static enum drm_mode_status gen11_dsi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) + { ++ struct drm_i915_private *i915 = to_i915(connector->dev); ++ enum drm_mode_status status; ++ ++ status = intel_cpu_transcoder_mode_valid(i915, mode); ++ if (status != MODE_OK) ++ return status; ++ + /* FIXME: DSC? */ + return intel_dsi_mode_valid(connector, mode); + } +diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c +index 7cf51dd8c05670..aaddd8c0cfa0ee 100644 +--- a/drivers/gpu/drm/i915/display/intel_atomic.c ++++ b/drivers/gpu/drm/i915/display/intel_atomic.c +@@ -259,6 +259,7 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc) + drm_property_blob_get(crtc_state->post_csc_lut); + + crtc_state->update_pipe = false; ++ crtc_state->update_m_n = false; + crtc_state->disable_lp_wm = false; + crtc_state->disable_cxsr = false; + crtc_state->update_wm_pre = false; +diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c +index 3d9c9b4f27f802..1cf1674897e9f2 100644 +--- a/drivers/gpu/drm/i915/display/intel_audio.c ++++ b/drivers/gpu/drm/i915/display/intel_audio.c +@@ -75,19 +75,6 @@ struct intel_audio_funcs { + struct intel_crtc_state *crtc_state); + }; + +-/* DP N/M table */ +-#define LC_810M 810000 +-#define LC_540M 540000 +-#define LC_270M 270000 +-#define LC_162M 162000 +- +-struct dp_aud_n_m { +- int sample_rate; +- int clock; +- u16 m; +- u16 n; +-}; +- + struct hdmi_aud_ncts { + int sample_rate; + int clock; +@@ -95,60 +82,6 @@ struct hdmi_aud_ncts { + int cts; + }; + +-/* Values according to DP 1.4 Table 2-104 */ +-static const struct dp_aud_n_m dp_aud_n_m[] = { +- { 32000, LC_162M, 1024, 10125 }, +- { 44100, LC_162M, 784, 5625 }, +- { 48000, LC_162M, 512, 3375 }, +- { 64000, LC_162M, 2048, 10125 }, +- { 88200, LC_162M, 1568, 5625 }, +- { 96000, LC_162M, 1024, 3375 }, +- { 128000, LC_162M, 4096, 10125 }, +- { 176400, LC_162M, 3136, 5625 }, +- { 192000, LC_162M, 2048, 3375 }, +- { 32000, LC_270M, 1024, 16875 }, +- { 44100, LC_270M, 784, 9375 }, +- { 48000, LC_270M, 512, 5625 }, +- { 64000, LC_270M, 2048, 16875 }, +- { 88200, LC_270M, 1568, 9375 }, +- { 96000, LC_270M, 1024, 5625 }, +- { 128000, LC_270M, 4096, 16875 }, +- { 176400, LC_270M, 3136, 9375 }, +- { 192000, LC_270M, 2048, 5625 }, +- { 32000, LC_540M, 1024, 33750 }, +- { 44100, LC_540M, 784, 18750 }, +- { 48000, LC_540M, 512, 11250 }, +- { 64000, LC_540M, 2048, 33750 }, +- { 88200, LC_540M, 1568, 18750 }, +- { 96000, LC_540M, 1024, 11250 }, +- { 128000, LC_540M, 4096, 33750 }, +- { 176400, LC_540M, 3136, 18750 }, +- { 192000, LC_540M, 2048, 11250 }, +- { 32000, LC_810M, 1024, 50625 }, +- { 44100, LC_810M, 784, 28125 }, +- { 48000, LC_810M, 512, 16875 }, +- { 64000, LC_810M, 2048, 50625 }, +- { 88200, LC_810M, 1568, 28125 }, +- { 96000, LC_810M, 1024, 16875 }, +- { 128000, LC_810M, 4096, 50625 }, +- { 176400, LC_810M, 3136, 28125 }, +- { 192000, LC_810M, 2048, 16875 }, +-}; +- +-static const struct dp_aud_n_m * +-audio_config_dp_get_n_m(const struct intel_crtc_state *crtc_state, int rate) +-{ +- int i; +- +- for (i = 0; i < ARRAY_SIZE(dp_aud_n_m); i++) { +- if (rate == dp_aud_n_m[i].sample_rate && +- crtc_state->port_clock == dp_aud_n_m[i].clock) +- return &dp_aud_n_m[i]; +- } +- +- return NULL; +-} +- + static const struct { + int clock; + u32 config; +@@ -386,47 +319,17 @@ hsw_dp_audio_config_update(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) + { + struct drm_i915_private *i915 = to_i915(encoder->base.dev); +- struct i915_audio_component *acomp = i915->display.audio.component; + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; +- enum port port = encoder->port; +- const struct dp_aud_n_m *nm; +- int rate; +- u32 tmp; +- +- rate = acomp ? acomp->aud_sample_rate[port] : 0; +- nm = audio_config_dp_get_n_m(crtc_state, rate); +- if (nm) +- drm_dbg_kms(&i915->drm, "using Maud %u, Naud %u\n", nm->m, +- nm->n); +- else +- drm_dbg_kms(&i915->drm, "using automatic Maud, Naud\n"); +- +- tmp = intel_de_read(i915, HSW_AUD_CFG(cpu_transcoder)); +- tmp &= ~AUD_CONFIG_N_VALUE_INDEX; +- tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK; +- tmp &= ~AUD_CONFIG_N_PROG_ENABLE; +- tmp |= AUD_CONFIG_N_VALUE_INDEX; +- +- if (nm) { +- tmp &= ~AUD_CONFIG_N_MASK; +- tmp |= AUD_CONFIG_N(nm->n); +- tmp |= AUD_CONFIG_N_PROG_ENABLE; +- } +- +- intel_de_write(i915, HSW_AUD_CFG(cpu_transcoder), tmp); +- +- tmp = intel_de_read(i915, HSW_AUD_M_CTS_ENABLE(cpu_transcoder)); +- tmp &= ~AUD_CONFIG_M_MASK; +- tmp &= ~AUD_M_CTS_M_VALUE_INDEX; +- tmp &= ~AUD_M_CTS_M_PROG_ENABLE; + +- if (nm) { +- tmp |= nm->m; +- tmp |= AUD_M_CTS_M_VALUE_INDEX; +- tmp |= AUD_M_CTS_M_PROG_ENABLE; +- } ++ /* Enable time stamps. Let HW calculate Maud/Naud values */ ++ intel_de_rmw(i915, HSW_AUD_CFG(cpu_transcoder), ++ AUD_CONFIG_N_VALUE_INDEX | ++ AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK | ++ AUD_CONFIG_UPPER_N_MASK | ++ AUD_CONFIG_LOWER_N_MASK | ++ AUD_CONFIG_N_PROG_ENABLE, ++ AUD_CONFIG_N_VALUE_INDEX); + +- intel_de_write(i915, HSW_AUD_M_CTS_ENABLE(cpu_transcoder), tmp); + } + + static void +@@ -1348,17 +1251,6 @@ static const struct component_ops i915_audio_component_bind_ops = { + static void i915_audio_component_init(struct drm_i915_private *i915) + { + u32 aud_freq, aud_freq_init; +- int ret; +- +- ret = component_add_typed(i915->drm.dev, +- &i915_audio_component_bind_ops, +- I915_COMPONENT_AUDIO); +- if (ret < 0) { +- drm_err(&i915->drm, +- "failed to add audio component (%d)\n", ret); +- /* continue with reduced functionality */ +- return; +- } + + if (DISPLAY_VER(i915) >= 9) { + aud_freq_init = intel_de_read(i915, AUD_FREQ_CNTRL); +@@ -1381,6 +1273,21 @@ static void i915_audio_component_init(struct drm_i915_private *i915) + + /* init with current cdclk */ + intel_audio_cdclk_change_post(i915); ++} ++ ++static void i915_audio_component_register(struct drm_i915_private *i915) ++{ ++ int ret; ++ ++ ret = component_add_typed(i915->drm.dev, ++ &i915_audio_component_bind_ops, ++ I915_COMPONENT_AUDIO); ++ if (ret < 0) { ++ drm_err(&i915->drm, ++ "failed to add audio component (%d)\n", ret); ++ /* continue with reduced functionality */ ++ return; ++ } + + i915->display.audio.component_registered = true; + } +@@ -1413,6 +1320,12 @@ void intel_audio_init(struct drm_i915_private *i915) + i915_audio_component_init(i915); + } + ++void intel_audio_register(struct drm_i915_private *i915) ++{ ++ if (!i915->display.audio.lpe.platdev) ++ i915_audio_component_register(i915); ++} ++ + /** + * intel_audio_deinit() - deinitialize the audio driver + * @i915: the i915 drm device private data +diff --git a/drivers/gpu/drm/i915/display/intel_audio.h b/drivers/gpu/drm/i915/display/intel_audio.h +index 07d034a981e90e..9779343a371068 100644 +--- a/drivers/gpu/drm/i915/display/intel_audio.h ++++ b/drivers/gpu/drm/i915/display/intel_audio.h +@@ -28,6 +28,7 @@ void intel_audio_codec_get_config(struct intel_encoder *encoder, + void intel_audio_cdclk_change_pre(struct drm_i915_private *dev_priv); + void intel_audio_cdclk_change_post(struct drm_i915_private *dev_priv); + void intel_audio_init(struct drm_i915_private *dev_priv); ++void intel_audio_register(struct drm_i915_private *i915); + void intel_audio_deinit(struct drm_i915_private *dev_priv); + void intel_audio_sdp_split_update(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); +diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c +index 2e8f17c0452223..ff9b9918b0a134 100644 +--- a/drivers/gpu/drm/i915/display/intel_backlight.c ++++ b/drivers/gpu/drm/i915/display/intel_backlight.c +@@ -274,7 +274,7 @@ static void ext_pwm_set_backlight(const struct drm_connector_state *conn_state, + struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel; + + pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); +- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); ++ pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state); + } + + static void +@@ -427,7 +427,7 @@ static void ext_pwm_disable_backlight(const struct drm_connector_state *old_conn + intel_backlight_set_pwm_level(old_conn_state, level); + + panel->backlight.pwm_state.enabled = false; +- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); ++ pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state); + } + + void intel_backlight_disable(const struct drm_connector_state *old_conn_state) +@@ -749,7 +749,7 @@ static void ext_pwm_enable_backlight(const struct intel_crtc_state *crtc_state, + + pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); + panel->backlight.pwm_state.enabled = true; +- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); ++ pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state); + } + + static void __intel_backlight_enable(const struct intel_crtc_state *crtc_state, +diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c +index f735b035436c02..27d1c49b46ec48 100644 +--- a/drivers/gpu/drm/i915/display/intel_bios.c ++++ b/drivers/gpu/drm/i915/display/intel_bios.c +@@ -1035,22 +1035,11 @@ parse_lfp_backlight(struct drm_i915_private *i915, + panel->vbt.backlight.type = INTEL_BACKLIGHT_DISPLAY_DDI; + panel->vbt.backlight.controller = 0; + if (i915->display.vbt.version >= 191) { +- size_t exp_size; ++ const struct lfp_backlight_control_method *method; + +- if (i915->display.vbt.version >= 236) +- exp_size = sizeof(struct bdb_lfp_backlight_data); +- else if (i915->display.vbt.version >= 234) +- exp_size = EXP_BDB_LFP_BL_DATA_SIZE_REV_234; +- else +- exp_size = EXP_BDB_LFP_BL_DATA_SIZE_REV_191; +- +- if (get_blocksize(backlight_data) >= exp_size) { +- const struct lfp_backlight_control_method *method; +- +- method = &backlight_data->backlight_control[panel_type]; +- panel->vbt.backlight.type = method->type; +- panel->vbt.backlight.controller = method->controller; +- } ++ method = &backlight_data->backlight_control[panel_type]; ++ panel->vbt.backlight.type = method->type; ++ panel->vbt.backlight.controller = method->controller; + } + + panel->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; +@@ -1945,16 +1934,12 @@ static int get_init_otp_deassert_fragment_len(struct drm_i915_private *i915, + * these devices we split the init OTP sequence into a deassert sequence and + * the actual init OTP part. + */ +-static void fixup_mipi_sequences(struct drm_i915_private *i915, +- struct intel_panel *panel) ++static void vlv_fixup_mipi_sequences(struct drm_i915_private *i915, ++ struct intel_panel *panel) + { + u8 *init_otp; + int len; + +- /* Limit this to VLV for now. */ +- if (!IS_VALLEYVIEW(i915)) +- return; +- + /* Limit this to v1 vid-mode sequences */ + if (panel->vbt.dsi.config->is_cmd_mode || + panel->vbt.dsi.seq_version != 1) +@@ -1990,6 +1975,41 @@ static void fixup_mipi_sequences(struct drm_i915_private *i915, + panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] = init_otp + len - 1; + } + ++/* ++ * Some machines (eg. Lenovo 82TQ) appear to have broken ++ * VBT sequences: ++ * - INIT_OTP is not present at all ++ * - what should be in INIT_OTP is in DISPLAY_ON ++ * - what should be in DISPLAY_ON is in BACKLIGHT_ON ++ * (along with the actual backlight stuff) ++ * ++ * To make those work we simply swap DISPLAY_ON and INIT_OTP. ++ * ++ * TODO: Do we need to limit this to specific machines, ++ * or examine the contents of the sequences to ++ * avoid false positives? ++ */ ++static void icl_fixup_mipi_sequences(struct drm_i915_private *i915, ++ struct intel_panel *panel) ++{ ++ if (!panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] && ++ panel->vbt.dsi.sequence[MIPI_SEQ_DISPLAY_ON]) { ++ drm_dbg_kms(&i915->drm, "Broken VBT: Swapping INIT_OTP and DISPLAY_ON sequences\n"); ++ ++ swap(panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP], ++ panel->vbt.dsi.sequence[MIPI_SEQ_DISPLAY_ON]); ++ } ++} ++ ++static void fixup_mipi_sequences(struct drm_i915_private *i915, ++ struct intel_panel *panel) ++{ ++ if (DISPLAY_VER(i915) >= 11) ++ icl_fixup_mipi_sequences(i915, panel); ++ else if (IS_VALLEYVIEW(i915)) ++ vlv_fixup_mipi_sequences(i915, panel); ++} ++ + static void + parse_mipi_sequence(struct drm_i915_private *i915, + struct intel_panel *panel) +@@ -3313,6 +3333,9 @@ bool intel_bios_encoder_supports_dp_dual_mode(const struct intel_bios_encoder_da + { + const struct child_device_config *child = &devdata->child; + ++ if (!devdata) ++ return false; ++ + if (!intel_bios_encoder_supports_dp(devdata) || + !intel_bios_encoder_supports_hdmi(devdata)) + return false; +diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c +index 2fb030b1ff1de3..fc3a6eb1de7414 100644 +--- a/drivers/gpu/drm/i915/display/intel_cdclk.c ++++ b/drivers/gpu/drm/i915/display/intel_cdclk.c +@@ -2453,7 +2453,8 @@ intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state) + intel_atomic_get_old_cdclk_state(state); + const struct intel_cdclk_state *new_cdclk_state = + intel_atomic_get_new_cdclk_state(state); +- enum pipe pipe = new_cdclk_state->pipe; ++ struct intel_cdclk_config cdclk_config; ++ enum pipe pipe; + + if (!intel_cdclk_changed(&old_cdclk_state->actual, + &new_cdclk_state->actual)) +@@ -2462,12 +2463,25 @@ intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state) + if (IS_DG2(i915)) + intel_cdclk_pcode_pre_notify(state); + +- if (pipe == INVALID_PIPE || +- old_cdclk_state->actual.cdclk <= new_cdclk_state->actual.cdclk) { +- drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed); ++ if (new_cdclk_state->disable_pipes) { ++ cdclk_config = new_cdclk_state->actual; ++ pipe = INVALID_PIPE; ++ } else { ++ if (new_cdclk_state->actual.cdclk >= old_cdclk_state->actual.cdclk) { ++ cdclk_config = new_cdclk_state->actual; ++ pipe = new_cdclk_state->pipe; ++ } else { ++ cdclk_config = old_cdclk_state->actual; ++ pipe = INVALID_PIPE; ++ } + +- intel_set_cdclk(i915, &new_cdclk_state->actual, pipe); ++ cdclk_config.voltage_level = max(new_cdclk_state->actual.voltage_level, ++ old_cdclk_state->actual.voltage_level); + } ++ ++ drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed); ++ ++ intel_set_cdclk(i915, &cdclk_config, pipe); + } + + /** +@@ -2485,7 +2499,7 @@ intel_set_cdclk_post_plane_update(struct intel_atomic_state *state) + intel_atomic_get_old_cdclk_state(state); + const struct intel_cdclk_state *new_cdclk_state = + intel_atomic_get_new_cdclk_state(state); +- enum pipe pipe = new_cdclk_state->pipe; ++ enum pipe pipe; + + if (!intel_cdclk_changed(&old_cdclk_state->actual, + &new_cdclk_state->actual)) +@@ -2494,12 +2508,15 @@ intel_set_cdclk_post_plane_update(struct intel_atomic_state *state) + if (IS_DG2(i915)) + intel_cdclk_pcode_post_notify(state); + +- if (pipe != INVALID_PIPE && +- old_cdclk_state->actual.cdclk > new_cdclk_state->actual.cdclk) { +- drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed); ++ if (!new_cdclk_state->disable_pipes && ++ new_cdclk_state->actual.cdclk < old_cdclk_state->actual.cdclk) ++ pipe = new_cdclk_state->pipe; ++ else ++ pipe = INVALID_PIPE; + +- intel_set_cdclk(i915, &new_cdclk_state->actual, pipe); +- } ++ drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed); ++ ++ intel_set_cdclk(i915, &new_cdclk_state->actual, pipe); + } + + static int intel_pixel_rate_to_cdclk(const struct intel_crtc_state *crtc_state) +@@ -2688,6 +2705,18 @@ static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state) + for_each_pipe(dev_priv, pipe) + min_cdclk = max(cdclk_state->min_cdclk[pipe], min_cdclk); + ++ /* ++ * Avoid glk_force_audio_cdclk() causing excessive screen ++ * blinking when multiple pipes are active by making sure ++ * CDCLK frequency is always high enough for audio. With a ++ * single active pipe we can always change CDCLK frequency ++ * by changing the cd2x divider (see glk_cdclk_table[]) and ++ * thus a full modeset won't be needed then. ++ */ ++ if (IS_GEMINILAKE(dev_priv) && cdclk_state->active_pipes && ++ !is_power_of_2(cdclk_state->active_pipes)) ++ min_cdclk = max(2 * 96000, min_cdclk); ++ + if (min_cdclk > dev_priv->display.cdclk.max_cdclk_freq) { + drm_dbg_kms(&dev_priv->drm, + "required cdclk (%d kHz) exceeds max (%d kHz)\n", +@@ -2934,6 +2963,7 @@ static struct intel_global_state *intel_cdclk_duplicate_state(struct intel_globa + return NULL; + + cdclk_state->pipe = INVALID_PIPE; ++ cdclk_state->disable_pipes = false; + + return &cdclk_state->base; + } +@@ -3112,6 +3142,8 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state) + if (ret) + return ret; + ++ new_cdclk_state->disable_pipes = true; ++ + drm_dbg_kms(&dev_priv->drm, + "Modeset required for cdclk change\n"); + } +diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.h b/drivers/gpu/drm/i915/display/intel_cdclk.h +index 48fd7d39e0cd9c..71bc032bfef16e 100644 +--- a/drivers/gpu/drm/i915/display/intel_cdclk.h ++++ b/drivers/gpu/drm/i915/display/intel_cdclk.h +@@ -51,6 +51,9 @@ struct intel_cdclk_state { + + /* bitmask of active pipes */ + u8 active_pipes; ++ ++ /* update cdclk with pipes disabled */ ++ bool disable_pipes; + }; + + int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state); +diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c +index 8090747586877e..4352f901776152 100644 +--- a/drivers/gpu/drm/i915/display/intel_crt.c ++++ b/drivers/gpu/drm/i915/display/intel_crt.c +@@ -348,8 +348,13 @@ intel_crt_mode_valid(struct drm_connector *connector, + struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = to_i915(dev); + int max_dotclk = dev_priv->max_dotclk_freq; ++ enum drm_mode_status status; + int max_clock; + ++ status = intel_cpu_transcoder_mode_valid(dev_priv, mode); ++ if (status != MODE_OK) ++ return status; ++ + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + +@@ -451,6 +456,8 @@ static int hsw_crt_compute_config(struct intel_encoder *encoder, + /* FDI must always be 2.7 GHz */ + pipe_config->port_clock = 135000 * 2; + ++ pipe_config->enhanced_framing = true; ++ + adjusted_mode->crtc_clock = lpt_iclkip(pipe_config); + + return 0; +diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c +index 182c6dd64f47cf..cfbfbfed3f5e66 100644 +--- a/drivers/gpu/drm/i915/display/intel_crtc.c ++++ b/drivers/gpu/drm/i915/display/intel_crtc.c +@@ -468,9 +468,56 @@ static int intel_mode_vblank_start(const struct drm_display_mode *mode) + return vblank_start; + } + ++static void intel_crtc_vblank_evade_scanlines(struct intel_atomic_state *state, ++ struct intel_crtc *crtc, ++ int *min, int *max, int *vblank_start) ++{ ++ const struct intel_crtc_state *old_crtc_state = ++ intel_atomic_get_old_crtc_state(state, crtc); ++ const struct intel_crtc_state *new_crtc_state = ++ intel_atomic_get_new_crtc_state(state, crtc); ++ const struct intel_crtc_state *crtc_state; ++ const struct drm_display_mode *adjusted_mode; ++ ++ /* ++ * During fastsets/etc. the transcoder is still ++ * running with the old timings at this point. ++ * ++ * TODO: maybe just use the active timings here? ++ */ ++ if (intel_crtc_needs_modeset(new_crtc_state)) ++ crtc_state = new_crtc_state; ++ else ++ crtc_state = old_crtc_state; ++ ++ adjusted_mode = &crtc_state->hw.adjusted_mode; ++ ++ if (crtc->mode_flags & I915_MODE_FLAG_VRR) { ++ if (intel_vrr_is_push_sent(crtc_state)) ++ *vblank_start = intel_vrr_vmin_vblank_start(crtc_state); ++ else ++ *vblank_start = intel_vrr_vmax_vblank_start(crtc_state); ++ } else { ++ *vblank_start = intel_mode_vblank_start(adjusted_mode); ++ } ++ ++ /* FIXME needs to be calibrated sensibly */ ++ *min = *vblank_start - intel_usecs_to_scanlines(adjusted_mode, ++ VBLANK_EVASION_TIME_US); ++ *max = *vblank_start - 1; ++ ++ /* ++ * M/N is double buffered on the transcoder's undelayed vblank, ++ * so with seamless M/N we must evade both vblanks. ++ */ ++ if (new_crtc_state->update_m_n) ++ *min -= adjusted_mode->crtc_vblank_start - adjusted_mode->crtc_vdisplay; ++} ++ + /** + * intel_pipe_update_start() - start update of a set of display registers +- * @new_crtc_state: the new crtc state ++ * @state: the atomic state ++ * @crtc: the crtc + * + * Mark the start of an update to pipe registers that should be updated + * atomically regarding vblank. If the next vblank will happens within +@@ -480,11 +527,12 @@ static int intel_mode_vblank_start(const struct drm_display_mode *mode) + * until a subsequent call to intel_pipe_update_end(). That is done to + * avoid random delays. + */ +-void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) ++void intel_pipe_update_start(struct intel_atomic_state *state, ++ struct intel_crtc *crtc) + { +- struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); +- const struct drm_display_mode *adjusted_mode = &new_crtc_state->hw.adjusted_mode; ++ struct intel_crtc_state *new_crtc_state = ++ intel_atomic_get_new_crtc_state(state, crtc); + long timeout = msecs_to_jiffies_timeout(1); + int scanline, min, max, vblank_start; + wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); +@@ -500,27 +548,7 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) + if (intel_crtc_needs_vblank_work(new_crtc_state)) + intel_crtc_vblank_work_init(new_crtc_state); + +- if (new_crtc_state->vrr.enable) { +- if (intel_vrr_is_push_sent(new_crtc_state)) +- vblank_start = intel_vrr_vmin_vblank_start(new_crtc_state); +- else +- vblank_start = intel_vrr_vmax_vblank_start(new_crtc_state); +- } else { +- vblank_start = intel_mode_vblank_start(adjusted_mode); +- } +- +- /* FIXME needs to be calibrated sensibly */ +- min = vblank_start - intel_usecs_to_scanlines(adjusted_mode, +- VBLANK_EVASION_TIME_US); +- max = vblank_start - 1; +- +- /* +- * M/N is double buffered on the transcoder's undelayed vblank, +- * so with seamless M/N we must evade both vblanks. +- */ +- if (new_crtc_state->seamless_m_n && intel_crtc_needs_fastset(new_crtc_state)) +- min -= adjusted_mode->crtc_vblank_start - adjusted_mode->crtc_vdisplay; +- ++ intel_crtc_vblank_evade_scanlines(state, crtc, &min, &max, &vblank_start); + if (min <= 0 || max <= 0) + goto irq_disable; + +@@ -631,15 +659,18 @@ static void dbg_vblank_evade(struct intel_crtc *crtc, ktime_t end) {} + + /** + * intel_pipe_update_end() - end update of a set of display registers +- * @new_crtc_state: the new crtc state ++ * @state: the atomic state ++ * @crtc: the crtc + * + * Mark the end of an update started with intel_pipe_update_start(). This + * re-enables interrupts and verifies the update was actually completed + * before a vblank. + */ +-void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) ++void intel_pipe_update_end(struct intel_atomic_state *state, ++ struct intel_crtc *crtc) + { +- struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); ++ struct intel_crtc_state *new_crtc_state = ++ intel_atomic_get_new_crtc_state(state, crtc); + enum pipe pipe = crtc->pipe; + int scanline_end = intel_get_crtc_scanline(crtc); + u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc); +@@ -697,15 +728,6 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) + */ + intel_vrr_send_push(new_crtc_state); + +- /* +- * Seamless M/N update may need to update frame timings. +- * +- * FIXME Should be synchronized with the start of vblank somehow... +- */ +- if (new_crtc_state->seamless_m_n && intel_crtc_needs_fastset(new_crtc_state)) +- intel_crtc_update_active_timings(new_crtc_state, +- new_crtc_state->vrr.enable); +- + local_irq_enable(); + + if (intel_vgpu_active(dev_priv)) +diff --git a/drivers/gpu/drm/i915/display/intel_crtc.h b/drivers/gpu/drm/i915/display/intel_crtc.h +index 51a4c8df9e6574..22d7993d1f0ba9 100644 +--- a/drivers/gpu/drm/i915/display/intel_crtc.h ++++ b/drivers/gpu/drm/i915/display/intel_crtc.h +@@ -36,8 +36,10 @@ void intel_crtc_state_reset(struct intel_crtc_state *crtc_state, + u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc); + void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state); + void intel_crtc_vblank_off(const struct intel_crtc_state *crtc_state); +-void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state); +-void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state); ++void intel_pipe_update_start(struct intel_atomic_state *state, ++ struct intel_crtc *crtc); ++void intel_pipe_update_end(struct intel_atomic_state *state, ++ struct intel_crtc *crtc); + void intel_wait_for_vblank_workers(struct intel_atomic_state *state); + struct intel_crtc *intel_first_crtc(struct drm_i915_private *i915); + struct intel_crtc *intel_crtc_for_pipe(struct drm_i915_private *i915, +diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +index 8d4640d0fd346b..66fe880af8f3f0 100644 +--- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c ++++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +@@ -258,6 +258,9 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, + intel_dump_m_n_config(pipe_config, "dp m2_n2", + pipe_config->lane_count, + &pipe_config->dp_m2_n2); ++ drm_dbg_kms(&i915->drm, "fec: %s, enhanced framing: %s\n", ++ str_enabled_disabled(pipe_config->fec_enable), ++ str_enabled_disabled(pipe_config->enhanced_framing)); + } + + drm_dbg_kms(&i915->drm, "framestart delay: %d, MSA timing delay: %d\n", +diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c +index b342fad180ca5b..61df6cd3f37788 100644 +--- a/drivers/gpu/drm/i915/display/intel_cursor.c ++++ b/drivers/gpu/drm/i915/display/intel_cursor.c +@@ -23,6 +23,8 @@ + #include "intel_psr.h" + #include "skl_watermark.h" + ++#include "gem/i915_gem_object.h" ++ + /* Cursor formats */ + static const u32 intel_cursor_formats[] = { + DRM_FORMAT_ARGB8888, +@@ -32,12 +34,10 @@ static u32 intel_cursor_base(const struct intel_plane_state *plane_state) + { + struct drm_i915_private *dev_priv = + to_i915(plane_state->uapi.plane->dev); +- const struct drm_framebuffer *fb = plane_state->hw.fb; +- const struct drm_i915_gem_object *obj = intel_fb_obj(fb); + u32 base; + + if (DISPLAY_INFO(dev_priv)->cursor_needs_physical) +- base = sg_dma_address(obj->mm.pages->sgl); ++ base = plane_state->phys_dma_addr; + else + base = intel_plane_ggtt_offset(plane_state); + +diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c +index 80e4ec6ee4031b..048e581fda16cb 100644 +--- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c ++++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c +@@ -2420,7 +2420,8 @@ static void intel_program_port_clock_ctl(struct intel_encoder *encoder, + + val |= XELPDP_FORWARD_CLOCK_UNGATE; + +- if (is_hdmi_frl(crtc_state->port_clock)) ++ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) && ++ is_hdmi_frl(crtc_state->port_clock)) + val |= XELPDP_DDI_CLOCK_SELECT(XELPDP_DDI_CLOCK_SELECT_DIV18CLK); + else + val |= XELPDP_DDI_CLOCK_SELECT(XELPDP_DDI_CLOCK_SELECT_MAXPCLK); +diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c +index 84bbf854337aa7..b347f906234945 100644 +--- a/drivers/gpu/drm/i915/display/intel_ddi.c ++++ b/drivers/gpu/drm/i915/display/intel_ddi.c +@@ -3432,7 +3432,7 @@ static void mtl_ddi_prepare_link_retrain(struct intel_dp *intel_dp, + dp_tp_ctl |= DP_TP_CTL_MODE_MST; + } else { + dp_tp_ctl |= DP_TP_CTL_MODE_SST; +- if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) ++ if (crtc_state->enhanced_framing) + dp_tp_ctl |= DP_TP_CTL_ENHANCED_FRAME_ENABLE; + } + intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), dp_tp_ctl); +@@ -3489,7 +3489,7 @@ static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp, + dp_tp_ctl |= DP_TP_CTL_MODE_MST; + } else { + dp_tp_ctl |= DP_TP_CTL_MODE_SST; +- if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) ++ if (crtc_state->enhanced_framing) + dp_tp_ctl |= DP_TP_CTL_ENHANCED_FRAME_ENABLE; + } + intel_de_write(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), dp_tp_ctl); +@@ -3724,17 +3724,14 @@ static void intel_ddi_read_func_ctl(struct intel_encoder *encoder, + intel_cpu_transcoder_get_m2_n2(crtc, cpu_transcoder, + &pipe_config->dp_m2_n2); + +- if (DISPLAY_VER(dev_priv) >= 11) { +- i915_reg_t dp_tp_ctl = dp_tp_ctl_reg(encoder, pipe_config); ++ pipe_config->enhanced_framing = ++ intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, pipe_config)) & ++ DP_TP_CTL_ENHANCED_FRAME_ENABLE; + ++ if (DISPLAY_VER(dev_priv) >= 11) + pipe_config->fec_enable = +- intel_de_read(dev_priv, dp_tp_ctl) & DP_TP_CTL_FEC_ENABLE; +- +- drm_dbg_kms(&dev_priv->drm, +- "[ENCODER:%d:%s] Fec status: %u\n", +- encoder->base.base.id, encoder->base.name, +- pipe_config->fec_enable); +- } ++ intel_de_read(dev_priv, ++ dp_tp_ctl_reg(encoder, pipe_config)) & DP_TP_CTL_FEC_ENABLE; + + if (dig_port->lspcon.active && intel_dp_has_hdmi_sink(&dig_port->dp)) + pipe_config->infoframes.enable |= +@@ -3747,6 +3744,9 @@ static void intel_ddi_read_func_ctl(struct intel_encoder *encoder, + if (!HAS_DP20(dev_priv)) { + /* FDI */ + pipe_config->output_types |= BIT(INTEL_OUTPUT_ANALOG); ++ pipe_config->enhanced_framing = ++ intel_de_read(dev_priv, dp_tp_ctl_reg(encoder, pipe_config)) & ++ DP_TP_CTL_ENHANCED_FRAME_ENABLE; + break; + } + fallthrough; /* 128b/132b */ +@@ -4111,7 +4111,12 @@ static bool m_n_equal(const struct intel_link_m_n *m_n_1, + static bool crtcs_port_sync_compatible(const struct intel_crtc_state *crtc_state1, + const struct intel_crtc_state *crtc_state2) + { ++ /* ++ * FIXME the modeset sequence is currently wrong and ++ * can't deal with bigjoiner + port sync at the same time. ++ */ + return crtc_state1->hw.active && crtc_state2->hw.active && ++ !crtc_state1->bigjoiner_pipes && !crtc_state2->bigjoiner_pipes && + crtc_state1->output_types == crtc_state2->output_types && + crtc_state1->output_format == crtc_state2->output_format && + crtc_state1->lane_count == crtc_state2->lane_count && +diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c +index 763ab569d8f324..1a59fca40252cd 100644 +--- a/drivers/gpu/drm/i915/display/intel_display.c ++++ b/drivers/gpu/drm/i915/display/intel_display.c +@@ -5215,7 +5215,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, + PIPE_CONF_CHECK_X(lane_lat_optim_mask); + + if (HAS_DOUBLE_BUFFERED_M_N(dev_priv)) { +- if (!fastset || !pipe_config->seamless_m_n) ++ if (!fastset || !pipe_config->update_m_n) + PIPE_CONF_CHECK_M_N(dp_m_n); + } else { + PIPE_CONF_CHECK_M_N(dp_m_n); +@@ -5255,6 +5255,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, + PIPE_CONF_CHECK_BOOL(hdmi_scrambling); + PIPE_CONF_CHECK_BOOL(hdmi_high_tmds_clock_ratio); + PIPE_CONF_CHECK_BOOL(has_infoframe); ++ PIPE_CONF_CHECK_BOOL(enhanced_framing); + PIPE_CONF_CHECK_BOOL(fec_enable); + + PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_audio); +@@ -5352,7 +5353,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, + if (IS_G4X(dev_priv) || DISPLAY_VER(dev_priv) >= 5) + PIPE_CONF_CHECK_I(pipe_bpp); + +- if (!fastset || !pipe_config->seamless_m_n) { ++ if (!fastset || !pipe_config->update_m_n) { + PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_clock); + PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_clock); + } +@@ -5447,6 +5448,7 @@ int intel_modeset_all_pipes(struct intel_atomic_state *state, + + crtc_state->uapi.mode_changed = true; + crtc_state->update_pipe = false; ++ crtc_state->update_m_n = false; + + ret = drm_atomic_add_affected_connectors(&state->base, + &crtc->base); +@@ -5564,13 +5566,14 @@ static void intel_crtc_check_fastset(const struct intel_crtc_state *old_crtc_sta + { + struct drm_i915_private *i915 = to_i915(old_crtc_state->uapi.crtc->dev); + +- if (!intel_pipe_config_compare(old_crtc_state, new_crtc_state, true)) { ++ if (!intel_pipe_config_compare(old_crtc_state, new_crtc_state, true)) + drm_dbg_kms(&i915->drm, "fastset requirement not met, forcing full modeset\n"); ++ else ++ new_crtc_state->uapi.mode_changed = false; + +- return; +- } ++ if (intel_crtc_needs_modeset(new_crtc_state)) ++ new_crtc_state->update_m_n = false; + +- new_crtc_state->uapi.mode_changed = false; + if (!intel_crtc_needs_modeset(new_crtc_state)) + new_crtc_state->update_pipe = true; + } +@@ -5976,6 +5979,17 @@ static int intel_async_flip_check_hw(struct intel_atomic_state *state, struct in + return -EINVAL; + } + ++ /* ++ * FIXME: Bigjoiner+async flip is busted currently. ++ * Remove this check once the issues are fixed. ++ */ ++ if (new_crtc_state->bigjoiner_pipes) { ++ drm_dbg_kms(&i915->drm, ++ "[CRTC:%d:%s] async flip disallowed with bigjoiner\n", ++ crtc->base.base.id, crtc->base.name); ++ return -EINVAL; ++ } ++ + for_each_oldnew_intel_plane_in_state(state, plane, old_plane_state, + new_plane_state, i) { + if (plane->pipe != crtc->pipe) +@@ -6285,6 +6299,7 @@ int intel_atomic_check(struct drm_device *dev, + if (intel_cpu_transcoders_need_modeset(state, BIT(master))) { + new_crtc_state->uapi.mode_changed = true; + new_crtc_state->update_pipe = false; ++ new_crtc_state->update_m_n = false; + } + } + +@@ -6297,6 +6312,7 @@ int intel_atomic_check(struct drm_device *dev, + if (intel_cpu_transcoders_need_modeset(state, trans)) { + new_crtc_state->uapi.mode_changed = true; + new_crtc_state->update_pipe = false; ++ new_crtc_state->update_m_n = false; + } + } + +@@ -6304,6 +6320,7 @@ int intel_atomic_check(struct drm_device *dev, + if (intel_pipes_need_modeset(state, new_crtc_state->bigjoiner_pipes)) { + new_crtc_state->uapi.mode_changed = true; + new_crtc_state->update_pipe = false; ++ new_crtc_state->update_m_n = false; + } + } + } +@@ -6482,7 +6499,7 @@ static void intel_pipe_fastset(const struct intel_crtc_state *old_crtc_state, + IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) + hsw_set_linetime_wm(new_crtc_state); + +- if (new_crtc_state->seamless_m_n) ++ if (new_crtc_state->update_m_n) + intel_cpu_transcoder_set_m1_n1(crtc, new_crtc_state->cpu_transcoder, + &new_crtc_state->dp_m_n); + } +@@ -6521,6 +6538,8 @@ static void commit_pipe_post_planes(struct intel_atomic_state *state, + struct intel_crtc *crtc) + { + struct drm_i915_private *dev_priv = to_i915(state->base.dev); ++ const struct intel_crtc_state *old_crtc_state = ++ intel_atomic_get_old_crtc_state(state, crtc); + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + +@@ -6532,6 +6551,9 @@ static void commit_pipe_post_planes(struct intel_atomic_state *state, + if (DISPLAY_VER(dev_priv) >= 9 && + !intel_crtc_needs_modeset(new_crtc_state)) + skl_detach_scalers(new_crtc_state); ++ ++ if (vrr_enabling(old_crtc_state, new_crtc_state)) ++ intel_vrr_enable(new_crtc_state); + } + + static void intel_enable_crtc(struct intel_atomic_state *state, +@@ -6572,12 +6594,6 @@ static void intel_update_crtc(struct intel_atomic_state *state, + intel_dpt_configure(crtc); + } + +- if (vrr_enabling(old_crtc_state, new_crtc_state)) { +- intel_vrr_enable(new_crtc_state); +- intel_crtc_update_active_timings(new_crtc_state, +- new_crtc_state->vrr.enable); +- } +- + if (!modeset) { + if (new_crtc_state->preload_luts && + intel_crtc_needs_color_update(new_crtc_state)) +@@ -6604,7 +6620,7 @@ static void intel_update_crtc(struct intel_atomic_state *state, + intel_crtc_planes_update_noarm(state, crtc); + + /* Perform vblank evasion around commit operation */ +- intel_pipe_update_start(new_crtc_state); ++ intel_pipe_update_start(state, crtc); + + commit_pipe_pre_planes(state, crtc); + +@@ -6612,7 +6628,16 @@ static void intel_update_crtc(struct intel_atomic_state *state, + + commit_pipe_post_planes(state, crtc); + +- intel_pipe_update_end(new_crtc_state); ++ intel_pipe_update_end(state, crtc); ++ ++ /* ++ * VRR/Seamless M/N update may need to update frame timings. ++ * ++ * FIXME Should be synchronized with the start of vblank somehow... ++ */ ++ if (vrr_enabling(old_crtc_state, new_crtc_state) || new_crtc_state->update_m_n) ++ intel_crtc_update_active_timings(new_crtc_state, ++ new_crtc_state->vrr.enable); + + /* + * We usually enable FIFO underrun interrupts as part of the +@@ -6658,10 +6683,11 @@ static void intel_commit_modeset_disables(struct intel_atomic_state *state) + if (!intel_crtc_needs_modeset(new_crtc_state)) + continue; + ++ intel_pre_plane_update(state, crtc); ++ + if (!old_crtc_state->hw.active) + continue; + +- intel_pre_plane_update(state, crtc); + intel_crtc_disable_planes(state, crtc); + } + +@@ -7279,7 +7305,7 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) + intel_color_cleanup_commit(new_crtc_state); + +- drm_atomic_helper_cleanup_planes(dev, &state->base); ++ drm_atomic_helper_unprepare_planes(dev, &state->base); + intel_runtime_pm_put(&dev_priv->runtime_pm, state->wakeref); + return ret; + } +@@ -7660,6 +7686,16 @@ enum drm_mode_status intel_mode_valid(struct drm_device *dev, + mode->vtotal > vtotal_max) + return MODE_V_ILLEGAL; + ++ return MODE_OK; ++} ++ ++enum drm_mode_status intel_cpu_transcoder_mode_valid(struct drm_i915_private *dev_priv, ++ const struct drm_display_mode *mode) ++{ ++ /* ++ * Additional transcoder timing limits, ++ * excluding BXT/GLK DSI transcoders. ++ */ + if (DISPLAY_VER(dev_priv) >= 5) { + if (mode->hdisplay < 64 || + mode->htotal - mode->hdisplay < 32) +diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h +index 49ac8473b988b3..13b0904d42e3df 100644 +--- a/drivers/gpu/drm/i915/display/intel_display.h ++++ b/drivers/gpu/drm/i915/display/intel_display.h +@@ -405,6 +405,9 @@ enum drm_mode_status + intel_mode_valid_max_plane_size(struct drm_i915_private *dev_priv, + const struct drm_display_mode *mode, + bool bigjoiner); ++enum drm_mode_status ++intel_cpu_transcoder_mode_valid(struct drm_i915_private *i915, ++ const struct drm_display_mode *mode); + enum phy intel_port_to_phy(struct drm_i915_private *i915, enum port port); + bool is_trans_port_sync_mode(const struct intel_crtc_state *state); + bool is_trans_port_sync_master(const struct intel_crtc_state *state); +diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h +index 215e682bd8b7a4..5fd07c18177661 100644 +--- a/drivers/gpu/drm/i915/display/intel_display_device.h ++++ b/drivers/gpu/drm/i915/display/intel_display_device.h +@@ -46,6 +46,7 @@ struct drm_printer; + #define HAS_DPT(i915) (DISPLAY_VER(i915) >= 13) + #define HAS_DSB(i915) (DISPLAY_INFO(i915)->has_dsb) + #define HAS_DSC(__i915) (DISPLAY_RUNTIME_INFO(__i915)->has_dsc) ++#define HAS_DSC_MST(__i915) (DISPLAY_VER(__i915) >= 12 && HAS_DSC(__i915)) + #define HAS_FBC(i915) (DISPLAY_RUNTIME_INFO(i915)->fbc_mask != 0) + #define HAS_FPGA_DBG_UNCLAIMED(i915) (DISPLAY_INFO(i915)->has_fpga_dbg) + #define HAS_FW_BLC(i915) (DISPLAY_VER(i915) > 2) +diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c +index 8f144d4d3c3983..26514f931af7a6 100644 +--- a/drivers/gpu/drm/i915/display/intel_display_driver.c ++++ b/drivers/gpu/drm/i915/display/intel_display_driver.c +@@ -386,6 +386,8 @@ void intel_display_driver_register(struct drm_i915_private *i915) + + intel_audio_init(i915); + ++ intel_audio_register(i915); ++ + intel_display_debugfs_register(i915); + + /* +diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c +index 916009894d89c7..1e099908772191 100644 +--- a/drivers/gpu/drm/i915/display/intel_display_power_well.c ++++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c +@@ -246,7 +246,14 @@ static enum phy icl_aux_pw_to_phy(struct drm_i915_private *i915, + enum aux_ch aux_ch = icl_aux_pw_to_ch(power_well); + struct intel_digital_port *dig_port = aux_ch_to_digital_port(i915, aux_ch); + +- return intel_port_to_phy(i915, dig_port->base.port); ++ /* ++ * FIXME should we care about the (VBT defined) dig_port->aux_ch ++ * relationship or should this be purely defined by the hardware layout? ++ * Currently if the port doesn't appear in the VBT, or if it's declared ++ * as HDMI-only and routed to a combo PHY, the encoder either won't be ++ * present at all or it will not have an aux_ch assigned. ++ */ ++ return dig_port ? intel_port_to_phy(i915, dig_port->base.port) : PHY_NONE; + } + + static void hsw_wait_for_power_well_enable(struct drm_i915_private *dev_priv, +@@ -414,7 +421,8 @@ icl_combo_phy_aux_power_well_enable(struct drm_i915_private *dev_priv, + + intel_de_rmw(dev_priv, regs->driver, 0, HSW_PWR_WELL_CTL_REQ(pw_idx)); + +- if (DISPLAY_VER(dev_priv) < 12) ++ /* FIXME this is a mess */ ++ if (phy != PHY_NONE) + intel_de_rmw(dev_priv, ICL_PORT_CL_DW12(phy), + 0, ICL_LANE_ENABLE_AUX); + +@@ -437,7 +445,10 @@ icl_combo_phy_aux_power_well_disable(struct drm_i915_private *dev_priv, + + drm_WARN_ON(&dev_priv->drm, !IS_ICELAKE(dev_priv)); + +- intel_de_rmw(dev_priv, ICL_PORT_CL_DW12(phy), ICL_LANE_ENABLE_AUX, 0); ++ /* FIXME this is a mess */ ++ if (phy != PHY_NONE) ++ intel_de_rmw(dev_priv, ICL_PORT_CL_DW12(phy), ++ ICL_LANE_ENABLE_AUX, 0); + + intel_de_rmw(dev_priv, regs->driver, HSW_PWR_WELL_CTL_REQ(pw_idx), 0); + +diff --git a/drivers/gpu/drm/i915/display/intel_display_trace.h b/drivers/gpu/drm/i915/display/intel_display_trace.h +index 99bdb833591ce1..7862e7cefe0278 100644 +--- a/drivers/gpu/drm/i915/display/intel_display_trace.h ++++ b/drivers/gpu/drm/i915/display/intel_display_trace.h +@@ -411,7 +411,7 @@ TRACE_EVENT(intel_fbc_activate, + struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(plane->base.dev), + plane->pipe); + __assign_str(dev, __dev_name_kms(plane)); +- __assign_str(name, plane->base.name) ++ __assign_str(name, plane->base.name); + __entry->pipe = crtc->pipe; + __entry->frame = intel_crtc_get_vblank_counter(crtc); + __entry->scanline = intel_get_crtc_scanline(crtc); +@@ -438,7 +438,7 @@ TRACE_EVENT(intel_fbc_deactivate, + struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(plane->base.dev), + plane->pipe); + __assign_str(dev, __dev_name_kms(plane)); +- __assign_str(name, plane->base.name) ++ __assign_str(name, plane->base.name); + __entry->pipe = crtc->pipe; + __entry->frame = intel_crtc_get_vblank_counter(crtc); + __entry->scanline = intel_get_crtc_scanline(crtc); +@@ -465,7 +465,7 @@ TRACE_EVENT(intel_fbc_nuke, + struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(plane->base.dev), + plane->pipe); + __assign_str(dev, __dev_name_kms(plane)); +- __assign_str(name, plane->base.name) ++ __assign_str(name, plane->base.name); + __entry->pipe = crtc->pipe; + __entry->frame = intel_crtc_get_vblank_counter(crtc); + __entry->scanline = intel_get_crtc_scanline(crtc); +diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h +index 731f2ec04d5cda..1c23b186aff20c 100644 +--- a/drivers/gpu/drm/i915/display/intel_display_types.h ++++ b/drivers/gpu/drm/i915/display/intel_display_types.h +@@ -701,6 +701,7 @@ struct intel_plane_state { + #define PLANE_HAS_FENCE BIT(0) + + struct intel_fb_view view; ++ u32 phys_dma_addr; /* for cursor_needs_physical */ + + /* Plane pxp decryption state */ + bool decrypt; +@@ -1083,6 +1084,7 @@ struct intel_crtc_state { + + unsigned fb_bits; /* framebuffers to flip */ + bool update_pipe; /* can a fast modeset be performed? */ ++ bool update_m_n; /* update M/N seamlessly during fastset? */ + bool disable_cxsr; + bool update_wm_pre, update_wm_post; /* watermarks are updated */ + bool fifo_changed; /* FIFO split is changed */ +@@ -1195,7 +1197,6 @@ struct intel_crtc_state { + /* m2_n2 for eDP downclock */ + struct intel_link_m_n dp_m2_n2; + bool has_drrs; +- bool seamless_m_n; + + /* PSR is supported but might not be enabled due the lack of enabled planes */ + bool has_psr; +@@ -1362,6 +1363,8 @@ struct intel_crtc_state { + u16 linetime; + u16 ips_linetime; + ++ bool enhanced_framing; ++ + /* Forward Error correction State */ + bool fec_enable; + +diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c +index 5f479f3828bbee..8751973b5730fe 100644 +--- a/drivers/gpu/drm/i915/display/intel_dmc.c ++++ b/drivers/gpu/drm/i915/display/intel_dmc.c +@@ -389,7 +389,7 @@ disable_all_flip_queue_events(struct drm_i915_private *i915) + enum intel_dmc_id dmc_id; + + /* TODO: check if the following applies to all D13+ platforms. */ +- if (!IS_DG2(i915) && !IS_TIGERLAKE(i915)) ++ if (!IS_TIGERLAKE(i915)) + return; + + for_each_dmc_id(dmc_id) { +@@ -493,6 +493,45 @@ void intel_dmc_disable_pipe(struct drm_i915_private *i915, enum pipe pipe) + intel_de_rmw(i915, PIPEDMC_CONTROL(pipe), PIPEDMC_ENABLE, 0); + } + ++static bool is_dmc_evt_ctl_reg(struct drm_i915_private *i915, ++ enum intel_dmc_id dmc_id, i915_reg_t reg) ++{ ++ u32 offset = i915_mmio_reg_offset(reg); ++ u32 start = i915_mmio_reg_offset(DMC_EVT_CTL(i915, dmc_id, 0)); ++ u32 end = i915_mmio_reg_offset(DMC_EVT_CTL(i915, dmc_id, DMC_EVENT_HANDLER_COUNT_GEN12)); ++ ++ return offset >= start && offset < end; ++} ++ ++static bool disable_dmc_evt(struct drm_i915_private *i915, ++ enum intel_dmc_id dmc_id, ++ i915_reg_t reg, u32 data) ++{ ++ if (!is_dmc_evt_ctl_reg(i915, dmc_id, reg)) ++ return false; ++ ++ /* keep all pipe DMC events disabled by default */ ++ if (dmc_id != DMC_FW_MAIN) ++ return true; ++ ++ return false; ++} ++ ++static u32 dmc_mmiodata(struct drm_i915_private *i915, ++ struct intel_dmc *dmc, ++ enum intel_dmc_id dmc_id, int i) ++{ ++ if (disable_dmc_evt(i915, dmc_id, ++ dmc->dmc_info[dmc_id].mmioaddr[i], ++ dmc->dmc_info[dmc_id].mmiodata[i])) ++ return REG_FIELD_PREP(DMC_EVT_CTL_TYPE_MASK, ++ DMC_EVT_CTL_TYPE_EDGE_0_1) | ++ REG_FIELD_PREP(DMC_EVT_CTL_EVENT_ID_MASK, ++ DMC_EVT_CTL_EVENT_ID_FALSE); ++ else ++ return dmc->dmc_info[dmc_id].mmiodata[i]; ++} ++ + /** + * intel_dmc_load_program() - write the firmware from memory to register. + * @i915: i915 drm device. +@@ -532,7 +571,7 @@ void intel_dmc_load_program(struct drm_i915_private *i915) + for_each_dmc_id(dmc_id) { + for (i = 0; i < dmc->dmc_info[dmc_id].mmio_count; i++) { + intel_de_write(i915, dmc->dmc_info[dmc_id].mmioaddr[i], +- dmc->dmc_info[dmc_id].mmiodata[i]); ++ dmc_mmiodata(i915, dmc, dmc_id, i)); + } + } + +diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c +index e0e4cb52928461..c8b6d0f79c9b41 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp.c ++++ b/drivers/gpu/drm/i915/display/intel_dp.c +@@ -393,6 +393,10 @@ bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp) + struct intel_encoder *encoder = &intel_dig_port->base; + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + ++ /* eDP MSO is not compatible with joiner */ ++ if (intel_dp->mso_link_count) ++ return false; ++ + return DISPLAY_VER(dev_priv) >= 12 || + (DISPLAY_VER(dev_priv) == 11 && + encoder->port != PORT_A); +@@ -430,7 +434,7 @@ static int mtl_max_source_rate(struct intel_dp *intel_dp) + enum phy phy = intel_port_to_phy(i915, dig_port->base.port); + + if (intel_is_c10phy(i915, phy)) +- return intel_dp_is_edp(intel_dp) ? 675000 : 810000; ++ return 810000; + + return 2000000; + } +@@ -1127,6 +1131,10 @@ intel_dp_mode_valid(struct drm_connector *_connector, + enum drm_mode_status status; + bool dsc = false, bigjoiner = false; + ++ status = intel_cpu_transcoder_mode_valid(dev_priv, mode); ++ if (status != MODE_OK) ++ return status; ++ + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + return MODE_H_ILLEGAL; + +@@ -1306,13 +1314,14 @@ bool intel_dp_has_hdmi_sink(struct intel_dp *intel_dp) + static bool intel_dp_source_supports_fec(struct intel_dp *intel_dp, + const struct intel_crtc_state *pipe_config) + { ++ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + +- /* On TGL, FEC is supported on all Pipes */ + if (DISPLAY_VER(dev_priv) >= 12) + return true; + +- if (DISPLAY_VER(dev_priv) == 11 && pipe_config->cpu_transcoder != TRANSCODER_A) ++ if (DISPLAY_VER(dev_priv) == 11 && encoder->port != PORT_A && ++ !intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST)) + return true; + + return false; +@@ -2143,8 +2152,12 @@ intel_dp_drrs_compute_config(struct intel_connector *connector, + intel_panel_downclock_mode(connector, &pipe_config->hw.adjusted_mode); + int pixel_clock; + +- if (has_seamless_m_n(connector)) +- pipe_config->seamless_m_n = true; ++ /* ++ * FIXME all joined pipes share the same transcoder. ++ * Need to account for that when updating M/N live. ++ */ ++ if (has_seamless_m_n(connector) && !pipe_config->bigjoiner_pipes) ++ pipe_config->update_m_n = true; + + if (!can_enable_drrs(connector, pipe_config, downclock_mode)) { + if (intel_cpu_transcoder_has_m2_n2(i915, pipe_config->cpu_transcoder)) +@@ -2308,6 +2321,9 @@ intel_dp_compute_config(struct intel_encoder *encoder, + pipe_config->limited_color_range = + intel_dp_limited_color_range(pipe_config, conn_state); + ++ pipe_config->enhanced_framing = ++ drm_dp_enhanced_frame_cap(intel_dp->dpcd); ++ + if (pipe_config->dsc.compression_enable) + output_bpp = pipe_config->dsc.compressed_bpp; + else +@@ -3980,7 +3996,7 @@ static void intel_dp_process_phy_request(struct intel_dp *intel_dp, + intel_dp->train_set, crtc_state->lane_count); + + drm_dp_set_phy_test_pattern(&intel_dp->aux, data, +- link_status[DP_DPCD_REV]); ++ intel_dp->dpcd[DP_DPCD_REV]); + } + + static u8 intel_dp_autotest_phy_pattern(struct intel_dp *intel_dp) +@@ -4358,6 +4374,8 @@ int intel_dp_retrain_link(struct intel_encoder *encoder, + !intel_dp_mst_is_master_trans(crtc_state)) + continue; + ++ intel_dp->link_trained = false; ++ + intel_dp_check_frl_training(intel_dp); + intel_dp_pcon_dsc_configure(intel_dp, crtc_state); + intel_dp_start_link_train(intel_dp, crtc_state); +@@ -5517,8 +5535,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, + * (eg. Acer Chromebook C710), so we'll check it only if multiple + * ports are attempting to use the same AUX CH, according to VBT. + */ +- if (intel_bios_dp_has_shared_aux_ch(encoder->devdata) && +- !intel_digital_port_connected(encoder)) { ++ if (intel_bios_dp_has_shared_aux_ch(encoder->devdata)) { + /* + * If this fails, presume the DPCD answer came + * from some other port using the same AUX CH. +@@ -5526,10 +5543,27 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, + * FIXME maybe cleaner to check this before the + * DPCD read? Would need sort out the VDD handling... + */ +- drm_info(&dev_priv->drm, +- "[ENCODER:%d:%s] HPD is down, disabling eDP\n", +- encoder->base.base.id, encoder->base.name); +- goto out_vdd_off; ++ if (!intel_digital_port_connected(encoder)) { ++ drm_info(&dev_priv->drm, ++ "[ENCODER:%d:%s] HPD is down, disabling eDP\n", ++ encoder->base.base.id, encoder->base.name); ++ goto out_vdd_off; ++ } ++ ++ /* ++ * Unfortunately even the HPD based detection fails on ++ * eg. Asus B360M-A (CFL+CNP), so as a last resort fall ++ * back to checking for a VGA branch device. Only do this ++ * on known affected platforms to minimize false positives. ++ */ ++ if (DISPLAY_VER(dev_priv) == 9 && drm_dp_is_branch(intel_dp->dpcd) && ++ (intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) == ++ DP_DWN_STRM_PORT_TYPE_ANALOG) { ++ drm_info(&dev_priv->drm, ++ "[ENCODER:%d:%s] VGA converter detected, disabling eDP\n", ++ encoder->base.base.id, encoder->base.name); ++ goto out_vdd_off; ++ } + } + + mutex_lock(&dev_priv->drm.mode_config.mutex); +diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c +index a263773f4d68a4..eb5559e1a20024 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c ++++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c +@@ -114,10 +114,24 @@ intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable) + return drm_dp_dpcd_write(&intel_dp->aux, DP_PHY_REPEATER_MODE, &val, 1) == 1; + } + +-static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEIVER_CAP_SIZE]) ++static bool intel_dp_lttpr_transparent_mode_enabled(struct intel_dp *intel_dp) ++{ ++ return intel_dp->lttpr_common_caps[DP_PHY_REPEATER_MODE - ++ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV] == ++ DP_PHY_REPEATER_MODE_TRANSPARENT; ++} ++ ++/* ++ * Read the LTTPR common capabilities and switch the LTTPR PHYs to ++ * non-transparent mode if this is supported. Preserve the ++ * transparent/non-transparent mode on an active link. ++ * ++ * Return the number of detected LTTPRs in non-transparent mode or 0 if the ++ * LTTPRs are in transparent mode or the detection failed. ++ */ ++static int intel_dp_init_lttpr_phys(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + { + int lttpr_count; +- int i; + + if (!intel_dp_read_lttpr_common_caps(intel_dp, dpcd)) + return 0; +@@ -131,6 +145,19 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEI + if (lttpr_count == 0) + return 0; + ++ /* ++ * Don't change the mode on an active link, to prevent a loss of link ++ * synchronization. See DP Standard v2.0 3.6.7. about the LTTPR ++ * resetting its internal state when the mode is changed from ++ * non-transparent to transparent. ++ */ ++ if (intel_dp->link_trained) { ++ if (lttpr_count < 0 || intel_dp_lttpr_transparent_mode_enabled(intel_dp)) ++ goto out_reset_lttpr_count; ++ ++ return lttpr_count; ++ } ++ + /* + * See DP Standard v2.0 3.6.6.1. about the explicit disabling of + * non-transparent mode and the disable->enable non-transparent mode +@@ -151,11 +178,25 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEI + "Switching to LTTPR non-transparent LT mode failed, fall-back to transparent mode\n"); + + intel_dp_set_lttpr_transparent_mode(intel_dp, true); +- intel_dp_reset_lttpr_count(intel_dp); + +- return 0; ++ goto out_reset_lttpr_count; + } + ++ return lttpr_count; ++ ++out_reset_lttpr_count: ++ intel_dp_reset_lttpr_count(intel_dp); ++ ++ return 0; ++} ++ ++static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEIVER_CAP_SIZE]) ++{ ++ int lttpr_count; ++ int i; ++ ++ lttpr_count = intel_dp_init_lttpr_phys(intel_dp, dpcd); ++ + for (i = 0; i < lttpr_count; i++) + intel_dp_read_lttpr_phy_caps(intel_dp, dpcd, DP_PHY_LTTPR(i)); + +@@ -650,19 +691,30 @@ intel_dp_update_link_bw_set(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, + u8 link_bw, u8 rate_select) + { +- u8 link_config[2]; ++ u8 lane_count = crtc_state->lane_count; ++ ++ if (crtc_state->enhanced_framing) ++ lane_count |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + +- /* Write the link configuration data */ +- link_config[0] = link_bw; +- link_config[1] = crtc_state->lane_count; +- if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) +- link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; +- drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2); +- +- /* eDP 1.4 rate select method. */ +- if (!link_bw) +- drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET, +- &rate_select, 1); ++ if (link_bw) { ++ /* DP and eDP v1.3 and earlier link bw set method. */ ++ u8 link_config[] = { link_bw, lane_count }; ++ ++ drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, ++ ARRAY_SIZE(link_config)); ++ } else { ++ /* ++ * eDP v1.4 and later link rate set method. ++ * ++ * eDP v1.4x sinks shall ignore DP_LINK_RATE_SET if ++ * DP_LINK_BW_SET is set. Avoid writing DP_LINK_BW_SET. ++ * ++ * eDP v1.5 sinks allow choosing either, and the last choice ++ * shall be active. ++ */ ++ drm_dp_dpcd_writeb(&intel_dp->aux, DP_LANE_COUNT_SET, lane_count); ++ drm_dp_dpcd_writeb(&intel_dp->aux, DP_LINK_RATE_SET, rate_select); ++ } + } + + /* +@@ -1342,10 +1394,10 @@ void intel_dp_start_link_train(struct intel_dp *intel_dp, + { + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + bool passed; +- + /* +- * TODO: Reiniting LTTPRs here won't be needed once proper connector +- * HW state readout is added. ++ * Reinit the LTTPRs here to ensure that they are switched to ++ * non-transparent mode. During an earlier LTTPR detection this ++ * could've been prevented by an active link. + */ + int lttpr_count = intel_dp_init_lttpr_and_dprx_caps(intel_dp); + +diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c +index e3f176a093d2f3..d2f8f20722d92c 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c ++++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c +@@ -109,8 +109,7 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, + continue; + + crtc_state->pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, +- dsc ? bpp << 4 : bpp, +- dsc); ++ bpp << 4); + + slots = drm_dp_atomic_find_time_slots(state, &intel_dp->mst_mgr, + connector->port, +@@ -921,6 +920,10 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, + return 0; + } + ++ *status = intel_cpu_transcoder_mode_valid(dev_priv, mode); ++ if (*status != MODE_OK) ++ return 0; ++ + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) { + *status = MODE_NO_DBLESCAN; + return 0; +@@ -937,7 +940,7 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, + return ret; + + if (mode_rate > max_rate || mode->clock > max_dotclk || +- drm_dp_calc_pbn_mode(mode->clock, min_bpp, false) > port->full_pbn) { ++ drm_dp_calc_pbn_mode(mode->clock, min_bpp << 4) > port->full_pbn) { + *status = MODE_CLOCK_HIGH; + return 0; + } +@@ -955,9 +958,13 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, + if (intel_dp_need_bigjoiner(intel_dp, mode->hdisplay, target_clock)) { + bigjoiner = true; + max_dotclk *= 2; ++ ++ /* TODO: add support for bigjoiner */ ++ *status = MODE_CLOCK_HIGH; ++ return 0; + } + +- if (DISPLAY_VER(dev_priv) >= 10 && ++ if (HAS_DSC_MST(dev_priv) && + drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd)) { + /* + * TBD pass the connector BPC, +@@ -988,11 +995,15 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, + * Big joiner configuration needs DSC for TGL which is not true for + * XE_LPD where uncompressed joiner is supported. + */ +- if (DISPLAY_VER(dev_priv) < 13 && bigjoiner && !dsc) +- return MODE_CLOCK_HIGH; ++ if (DISPLAY_VER(dev_priv) < 13 && bigjoiner && !dsc) { ++ *status = MODE_CLOCK_HIGH; ++ return 0; ++ } + +- if (mode_rate > max_rate && !dsc) +- return MODE_CLOCK_HIGH; ++ if (mode_rate > max_rate && !dsc) { ++ *status = MODE_CLOCK_HIGH; ++ return 0; ++ } + + *status = intel_mode_valid_max_plane_size(dev_priv, mode, false); + return 0; +diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +index 6d68b36292d361..247e7d675e2b93 100644 +--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c ++++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +@@ -1556,7 +1556,7 @@ static void skl_wrpll_params_populate(struct skl_wrpll_params *params, + } + + static int +-skl_ddi_calculate_wrpll(int clock /* in Hz */, ++skl_ddi_calculate_wrpll(int clock, + int ref_clock, + struct skl_wrpll_params *wrpll_params) + { +@@ -1581,7 +1581,7 @@ skl_ddi_calculate_wrpll(int clock /* in Hz */, + }; + unsigned int dco, d, i; + unsigned int p0, p1, p2; +- u64 afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */ ++ u64 afe_clock = (u64)clock * 1000 * 5; /* AFE Clock is 5x Pixel clock, in Hz */ + + for (d = 0; d < ARRAY_SIZE(dividers); d++) { + for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) { +@@ -1713,7 +1713,7 @@ static int skl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state) + + ctrl1 |= DPLL_CTRL1_HDMI_MODE(0); + +- ret = skl_ddi_calculate_wrpll(crtc_state->port_clock * 1000, ++ ret = skl_ddi_calculate_wrpll(crtc_state->port_clock, + i915->display.dpll.ref_clks.nssc, &wrpll_params); + if (ret) + return ret; +@@ -2462,7 +2462,7 @@ static void icl_wrpll_params_populate(struct skl_wrpll_params *params, + static bool + ehl_combo_pll_div_frac_wa_needed(struct drm_i915_private *i915) + { +- return (((IS_ELKHARTLAKE(i915) || IS_JASPERLAKE(i915)) && ++ return ((IS_ELKHARTLAKE(i915) && + IS_DISPLAY_STEP(i915, STEP_B0, STEP_FOREVER)) || + IS_TIGERLAKE(i915) || IS_ALDERLAKE_S(i915) || IS_ALDERLAKE_P(i915)) && + i915->display.dpll.ref_clks.nssc == 38400; +diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c +index b386894c3a6db2..d1cfa966d48dac 100644 +--- a/drivers/gpu/drm/i915/display/intel_dvo.c ++++ b/drivers/gpu/drm/i915/display/intel_dvo.c +@@ -217,11 +217,17 @@ intel_dvo_mode_valid(struct drm_connector *_connector, + struct drm_display_mode *mode) + { + struct intel_connector *connector = to_intel_connector(_connector); ++ struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_dvo *intel_dvo = intel_attached_dvo(connector); + const struct drm_display_mode *fixed_mode = + intel_panel_fixed_mode(connector, mode); + int max_dotclk = to_i915(connector->base.dev)->max_dotclk_freq; + int target_clock = mode->clock; ++ enum drm_mode_status status; ++ ++ status = intel_cpu_transcoder_mode_valid(i915, mode); ++ if (status != MODE_OK) ++ return status; + + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; +diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c +index 446bbf7986b6f7..689b7c16d30072 100644 +--- a/drivers/gpu/drm/i915/display/intel_fb.c ++++ b/drivers/gpu/drm/i915/display/intel_fb.c +@@ -1370,7 +1370,8 @@ plane_view_scanout_stride(const struct intel_framebuffer *fb, int color_plane, + struct drm_i915_private *i915 = to_i915(fb->base.dev); + unsigned int stride_tiles; + +- if (IS_ALDERLAKE_P(i915) || DISPLAY_VER(i915) >= 14) ++ if ((IS_ALDERLAKE_P(i915) || DISPLAY_VER(i915) >= 14) && ++ src_stride_tiles < dst_stride_tiles) + stride_tiles = src_stride_tiles; + else + stride_tiles = dst_stride_tiles; +@@ -1497,8 +1498,20 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p + + size += remap_info->size; + } else { +- unsigned int dst_stride = plane_view_dst_stride_tiles(fb, color_plane, +- remap_info->width); ++ unsigned int dst_stride; ++ ++ /* ++ * The hardware automagically calculates the CCS AUX surface ++ * stride from the main surface stride so can't really remap a ++ * smaller subset (unless we'd remap in whole AUX page units). ++ */ ++ if (intel_fb_needs_pot_stride_remap(fb) && ++ intel_fb_is_ccs_modifier(fb->base.modifier)) ++ dst_stride = remap_info->src_stride; ++ else ++ dst_stride = remap_info->width; ++ ++ dst_stride = plane_view_dst_stride_tiles(fb, color_plane, dst_stride); + + assign_chk_ovf(i915, remap_info->dst_stride, dst_stride); + color_plane_info->mapping_stride = dst_stride * +diff --git a/drivers/gpu/drm/i915/display/intel_fb_pin.c b/drivers/gpu/drm/i915/display/intel_fb_pin.c +index fffd568070d414..a131656757f2b6 100644 +--- a/drivers/gpu/drm/i915/display/intel_fb_pin.c ++++ b/drivers/gpu/drm/i915/display/intel_fb_pin.c +@@ -254,6 +254,16 @@ int intel_plane_pin_fb(struct intel_plane_state *plane_state) + return PTR_ERR(vma); + + plane_state->ggtt_vma = vma; ++ ++ /* ++ * Pre-populate the dma address before we enter the vblank ++ * evade critical section as i915_gem_object_get_dma_address() ++ * will trigger might_sleep() even if it won't actually sleep, ++ * which is the case when the fb has already been pinned. ++ */ ++ if (phys_cursor) ++ plane_state->phys_dma_addr = ++ i915_gem_object_get_dma_address(intel_fb_obj(fb), 0); + } else { + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + +diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c +index a42549fa96918e..cb99839afcd03a 100644 +--- a/drivers/gpu/drm/i915/display/intel_hdcp.c ++++ b/drivers/gpu/drm/i915/display/intel_hdcp.c +@@ -1005,7 +1005,8 @@ static void intel_hdcp_update_value(struct intel_connector *connector, + hdcp->value = value; + if (update_property) { + drm_connector_get(&connector->base); +- queue_work(i915->unordered_wq, &hdcp->prop_work); ++ if (!queue_work(i915->unordered_wq, &hdcp->prop_work)) ++ drm_connector_put(&connector->base); + } + } + +@@ -2480,7 +2481,8 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state, + mutex_lock(&hdcp->mutex); + hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED; + drm_connector_get(&connector->base); +- queue_work(i915->unordered_wq, &hdcp->prop_work); ++ if (!queue_work(i915->unordered_wq, &hdcp->prop_work)) ++ drm_connector_put(&connector->base); + mutex_unlock(&hdcp->mutex); + } + +@@ -2497,7 +2499,9 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state, + */ + if (!desired_and_not_enabled && !content_protection_type_changed) { + drm_connector_get(&connector->base); +- queue_work(i915->unordered_wq, &hdcp->prop_work); ++ if (!queue_work(i915->unordered_wq, &hdcp->prop_work)) ++ drm_connector_put(&connector->base); ++ + } + } + +diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_regs.h b/drivers/gpu/drm/i915/display/intel_hdcp_regs.h +index 8023c85c7fa0ea..74059384892af8 100644 +--- a/drivers/gpu/drm/i915/display/intel_hdcp_regs.h ++++ b/drivers/gpu/drm/i915/display/intel_hdcp_regs.h +@@ -249,7 +249,7 @@ + #define HDCP2_STREAM_STATUS(dev_priv, trans, port) \ + (GRAPHICS_VER(dev_priv) >= 12 ? \ + TRANS_HDCP2_STREAM_STATUS(trans) : \ +- PIPE_HDCP2_STREAM_STATUS(pipe)) ++ PIPE_HDCP2_STREAM_STATUS(port)) + + #define _PORTA_HDCP2_AUTH_STREAM 0x66F00 + #define _PORTB_HDCP2_AUTH_STREAM 0x66F04 +diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c +index 94a7e1537f4278..bc975918e0eb45 100644 +--- a/drivers/gpu/drm/i915/display/intel_hdmi.c ++++ b/drivers/gpu/drm/i915/display/intel_hdmi.c +@@ -1986,6 +1986,10 @@ intel_hdmi_mode_valid(struct drm_connector *connector, + bool ycbcr_420_only; + enum intel_output_format sink_format; + ++ status = intel_cpu_transcoder_mode_valid(dev_priv, mode); ++ if (status != MODE_OK) ++ return status; ++ + if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) + clock *= 2; + +diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c +index 3ace56979b70e0..dcb07d9a739d95 100644 +--- a/drivers/gpu/drm/i915/display/intel_lvds.c ++++ b/drivers/gpu/drm/i915/display/intel_lvds.c +@@ -389,11 +389,16 @@ intel_lvds_mode_valid(struct drm_connector *_connector, + struct drm_display_mode *mode) + { + struct intel_connector *connector = to_intel_connector(_connector); ++ struct drm_i915_private *i915 = to_i915(connector->base.dev); + const struct drm_display_mode *fixed_mode = + intel_panel_fixed_mode(connector, mode); + int max_pixclk = to_i915(connector->base.dev)->max_dotclk_freq; + enum drm_mode_status status; + ++ status = intel_cpu_transcoder_mode_valid(i915, mode); ++ if (status != MODE_OK) ++ return status; ++ + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + +diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c +index 97d5eef10130df..5cf3db7058b98c 100644 +--- a/drivers/gpu/drm/i915/display/intel_psr.c ++++ b/drivers/gpu/drm/i915/display/intel_psr.c +@@ -674,7 +674,9 @@ static void hsw_activate_psr1(struct intel_dp *intel_dp) + + val |= EDP_PSR_IDLE_FRAMES(psr_compute_idle_frames(intel_dp)); + +- val |= EDP_PSR_MAX_SLEEP_TIME(max_sleep_time); ++ if (DISPLAY_VER(dev_priv) < 20) ++ val |= EDP_PSR_MAX_SLEEP_TIME(max_sleep_time); ++ + if (IS_HASWELL(dev_priv)) + val |= EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES; + +@@ -1398,9 +1400,21 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, + * can rely on frontbuffer tracking. + */ + mask = EDP_PSR_DEBUG_MASK_MEMUP | +- EDP_PSR_DEBUG_MASK_HPD | +- EDP_PSR_DEBUG_MASK_LPSP | +- EDP_PSR_DEBUG_MASK_MAX_SLEEP; ++ EDP_PSR_DEBUG_MASK_HPD; ++ ++ /* ++ * For some unknown reason on HSW non-ULT (or at least on ++ * Dell Latitude E6540) external displays start to flicker ++ * when PSR is enabled on the eDP. SR/PC6 residency is much ++ * higher than should be possible with an external display. ++ * As a workaround leave LPSP unmasked to prevent PSR entry ++ * when external displays are active. ++ */ ++ if (DISPLAY_VER(dev_priv) >= 8 || IS_HASWELL_ULT(dev_priv)) ++ mask |= EDP_PSR_DEBUG_MASK_LPSP; ++ ++ if (DISPLAY_VER(dev_priv) < 20) ++ mask |= EDP_PSR_DEBUG_MASK_MAX_SLEEP; + + /* + * No separate pipe reg write mask on hsw/bdw, so have to unmask all +diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c +index 7d25a64698e2f5..18ae41d5f4f988 100644 +--- a/drivers/gpu/drm/i915/display/intel_sdvo.c ++++ b/drivers/gpu/drm/i915/display/intel_sdvo.c +@@ -1212,7 +1212,7 @@ static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_tv_format format; + u32 format_map; + +- format_map = 1 << conn_state->tv.mode; ++ format_map = 1 << conn_state->tv.legacy_mode; + memset(&format, 0, sizeof(format)); + memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map))); + +@@ -1906,13 +1906,19 @@ static enum drm_mode_status + intel_sdvo_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) + { ++ struct drm_i915_private *i915 = to_i915(connector->dev); + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector)); + struct intel_sdvo_connector *intel_sdvo_connector = + to_intel_sdvo_connector(connector); +- int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; + bool has_hdmi_sink = intel_has_hdmi_sink(intel_sdvo_connector, connector->state); ++ int max_dotclk = i915->max_dotclk_freq; ++ enum drm_mode_status status; + int clock = mode->clock; + ++ status = intel_cpu_transcoder_mode_valid(i915, mode); ++ if (status != MODE_OK) ++ return status; ++ + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + +@@ -2289,7 +2295,7 @@ static int intel_sdvo_get_tv_modes(struct drm_connector *connector) + * Read the list of supported input resolutions for the selected TV + * format. + */ +- format_map = 1 << conn_state->tv.mode; ++ format_map = 1 << conn_state->tv.legacy_mode; + memcpy(&tv_res, &format_map, + min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request))); + +@@ -2354,7 +2360,7 @@ intel_sdvo_connector_atomic_get_property(struct drm_connector *connector, + int i; + + for (i = 0; i < intel_sdvo_connector->format_supported_num; i++) +- if (state->tv.mode == intel_sdvo_connector->tv_format_supported[i]) { ++ if (state->tv.legacy_mode == intel_sdvo_connector->tv_format_supported[i]) { + *val = i; + + return 0; +@@ -2410,7 +2416,7 @@ intel_sdvo_connector_atomic_set_property(struct drm_connector *connector, + struct intel_sdvo_connector_state *sdvo_state = to_intel_sdvo_connector_state(state); + + if (property == intel_sdvo_connector->tv_format) { +- state->tv.mode = intel_sdvo_connector->tv_format_supported[val]; ++ state->tv.legacy_mode = intel_sdvo_connector->tv_format_supported[val]; + + if (state->crtc) { + struct drm_crtc_state *crtc_state = +@@ -3065,7 +3071,7 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, + drm_property_add_enum(intel_sdvo_connector->tv_format, i, + tv_format_names[intel_sdvo_connector->tv_format_supported[i]]); + +- intel_sdvo_connector->base.base.state->tv.mode = intel_sdvo_connector->tv_format_supported[0]; ++ intel_sdvo_connector->base.base.state->tv.legacy_mode = intel_sdvo_connector->tv_format_supported[0]; + drm_object_attach_property(&intel_sdvo_connector->base.base.base, + intel_sdvo_connector->tv_format, 0); + return true; +diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c +index 3ebf41859043e9..cdf2455440beaf 100644 +--- a/drivers/gpu/drm/i915/display/intel_tc.c ++++ b/drivers/gpu/drm/i915/display/intel_tc.c +@@ -58,7 +58,7 @@ struct intel_tc_port { + struct delayed_work link_reset_work; + int link_refcount; + bool legacy_port:1; +- char port_name[8]; ++ const char *port_name; + enum tc_port_mode mode; + enum tc_port_mode init_mode; + enum phy_fia phy_fia; +@@ -1841,8 +1841,12 @@ int intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy) + else + tc->phy_ops = &icl_tc_phy_ops; + +- snprintf(tc->port_name, sizeof(tc->port_name), +- "%c/TC#%d", port_name(port), tc_port + 1); ++ tc->port_name = kasprintf(GFP_KERNEL, "%c/TC#%d", port_name(port), ++ tc_port + 1); ++ if (!tc->port_name) { ++ kfree(tc); ++ return -ENOMEM; ++ } + + mutex_init(&tc->lock); + /* TODO: Combine the two works */ +@@ -1863,6 +1867,7 @@ void intel_tc_port_cleanup(struct intel_digital_port *dig_port) + { + intel_tc_port_suspend(dig_port); + ++ kfree(dig_port->tc->port_name); + kfree(dig_port->tc); + dig_port->tc = NULL; + } +diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c +index 36b479b46b6004..042ed966807edb 100644 +--- a/drivers/gpu/drm/i915/display/intel_tv.c ++++ b/drivers/gpu/drm/i915/display/intel_tv.c +@@ -949,7 +949,7 @@ intel_disable_tv(struct intel_atomic_state *state, + + static const struct tv_mode *intel_tv_mode_find(const struct drm_connector_state *conn_state) + { +- int format = conn_state->tv.mode; ++ int format = conn_state->tv.legacy_mode; + + return &tv_modes[format]; + } +@@ -958,8 +958,14 @@ static enum drm_mode_status + intel_tv_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) + { ++ struct drm_i915_private *i915 = to_i915(connector->dev); + const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state); +- int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; ++ int max_dotclk = i915->max_dotclk_freq; ++ enum drm_mode_status status; ++ ++ status = intel_cpu_transcoder_mode_valid(i915, mode); ++ if (status != MODE_OK) ++ return status; + + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; +@@ -1704,7 +1710,7 @@ static void intel_tv_find_better_format(struct drm_connector *connector) + break; + } + +- connector->state->tv.mode = i; ++ connector->state->tv.legacy_mode = i; + } + + static int +@@ -1859,7 +1865,7 @@ static int intel_tv_atomic_check(struct drm_connector *connector, + old_state = drm_atomic_get_old_connector_state(state, connector); + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc); + +- if (old_state->tv.mode != new_state->tv.mode || ++ if (old_state->tv.legacy_mode != new_state->tv.legacy_mode || + old_state->tv.margins.left != new_state->tv.margins.left || + old_state->tv.margins.right != new_state->tv.margins.right || + old_state->tv.margins.top != new_state->tv.margins.top || +@@ -1896,7 +1902,7 @@ static void intel_tv_add_properties(struct drm_connector *connector) + conn_state->tv.margins.right = 46; + conn_state->tv.margins.bottom = 37; + +- conn_state->tv.mode = 0; ++ conn_state->tv.legacy_mode = 0; + + /* Create TV properties then attach current values */ + for (i = 0; i < ARRAY_SIZE(tv_modes); i++) { +@@ -1910,7 +1916,7 @@ static void intel_tv_add_properties(struct drm_connector *connector) + + drm_object_attach_property(&connector->base, + i915->drm.mode_config.legacy_tv_mode_property, +- conn_state->tv.mode); ++ conn_state->tv.legacy_mode); + drm_object_attach_property(&connector->base, + i915->drm.mode_config.tv_left_margin_property, + conn_state->tv.margins.left); +diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h +index a9f44abfc9fc28..b50cd0dcabda90 100644 +--- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h ++++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h +@@ -897,11 +897,6 @@ struct lfp_brightness_level { + u16 reserved; + } __packed; + +-#define EXP_BDB_LFP_BL_DATA_SIZE_REV_191 \ +- offsetof(struct bdb_lfp_backlight_data, brightness_level) +-#define EXP_BDB_LFP_BL_DATA_SIZE_REV_234 \ +- offsetof(struct bdb_lfp_backlight_data, brightness_precision_bits) +- + struct bdb_lfp_backlight_data { + u8 entry_size; + struct lfp_backlight_data_entry data[16]; +diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c +index 88e4759b538b64..b844bdd16de99a 100644 +--- a/drivers/gpu/drm/i915/display/intel_vrr.c ++++ b/drivers/gpu/drm/i915/display/intel_vrr.c +@@ -111,6 +111,13 @@ intel_vrr_compute_config(struct intel_crtc_state *crtc_state, + if (!intel_vrr_is_capable(connector)) + return; + ++ /* ++ * FIXME all joined pipes share the same transcoder. ++ * Need to account for that during VRR toggle/push/etc. ++ */ ++ if (crtc_state->bigjoiner_pipes) ++ return; ++ + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + return; + +diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c +index 1e7c97243fcf55..8a934bada6245d 100644 +--- a/drivers/gpu/drm/i915/display/skl_scaler.c ++++ b/drivers/gpu/drm/i915/display/skl_scaler.c +@@ -504,7 +504,6 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv, + { + struct drm_plane *plane = NULL; + struct intel_plane *intel_plane; +- struct intel_plane_state *plane_state = NULL; + struct intel_crtc_scaler_state *scaler_state = + &crtc_state->scaler_state; + struct drm_atomic_state *drm_state = crtc_state->uapi.state; +@@ -536,6 +535,7 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv, + + /* walkthrough scaler_users bits and start assigning scalers */ + for (i = 0; i < sizeof(scaler_state->scaler_users) * 8; i++) { ++ struct intel_plane_state *plane_state = NULL; + int *scaler_id; + const char *name; + int idx, ret; +diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c +index ffc15d278a39d3..d557ecd4e1ebe1 100644 +--- a/drivers/gpu/drm/i915/display/skl_universal_plane.c ++++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c +@@ -20,6 +20,7 @@ + #include "skl_scaler.h" + #include "skl_universal_plane.h" + #include "skl_watermark.h" ++#include "gt/intel_gt.h" + #include "pxp/intel_pxp.h" + + static const u32 skl_plane_formats[] = { +@@ -2169,8 +2170,8 @@ static bool skl_plane_has_rc_ccs(struct drm_i915_private *i915, + enum pipe pipe, enum plane_id plane_id) + { + /* Wa_14017240301 */ +- if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || +- IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) ++ if (IS_GFX_GT_IP_STEP(to_gt(i915), IP_VER(12, 70), STEP_A0, STEP_B0) || ++ IS_GFX_GT_IP_STEP(to_gt(i915), IP_VER(12, 71), STEP_A0, STEP_B0)) + return false; + + /* Wa_22011186057 */ +diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c +index a96e7d028c5c61..d778b88413b777 100644 +--- a/drivers/gpu/drm/i915/display/vlv_dsi.c ++++ b/drivers/gpu/drm/i915/display/vlv_dsi.c +@@ -1540,9 +1540,25 @@ static const struct drm_encoder_funcs intel_dsi_funcs = { + .destroy = intel_dsi_encoder_destroy, + }; + ++static enum drm_mode_status vlv_dsi_mode_valid(struct drm_connector *connector, ++ struct drm_display_mode *mode) ++{ ++ struct drm_i915_private *i915 = to_i915(connector->dev); ++ ++ if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { ++ enum drm_mode_status status; ++ ++ status = intel_cpu_transcoder_mode_valid(i915, mode); ++ if (status != MODE_OK) ++ return status; ++ } ++ ++ return intel_dsi_mode_valid(connector, mode); ++} ++ + static const struct drm_connector_helper_funcs intel_dsi_connector_helper_funcs = { + .get_modes = intel_dsi_get_modes, +- .mode_valid = intel_dsi_mode_valid, ++ .mode_valid = vlv_dsi_mode_valid, + .atomic_check = intel_digital_connector_atomic_check, + }; + +diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c +index 9a9ff84c90d7e6..e38f06a6e56ebc 100644 +--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c ++++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c +@@ -844,6 +844,7 @@ static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv, + if (idx >= pc->num_user_engines) + return -EINVAL; + ++ idx = array_index_nospec(idx, pc->num_user_engines); + pe = &pc->user_engines[idx]; + + /* Only render engine supports RPCS configuration. */ +diff --git a/drivers/gpu/drm/i915/gem/i915_gem_create.c b/drivers/gpu/drm/i915/gem/i915_gem_create.c +index d24c0ce8805c70..19156ba4b9ef40 100644 +--- a/drivers/gpu/drm/i915/gem/i915_gem_create.c ++++ b/drivers/gpu/drm/i915/gem/i915_gem_create.c +@@ -405,8 +405,8 @@ static int ext_set_pat(struct i915_user_extension __user *base, void *data) + BUILD_BUG_ON(sizeof(struct drm_i915_gem_create_ext_set_pat) != + offsetofend(struct drm_i915_gem_create_ext_set_pat, rsvd)); + +- /* Limiting the extension only to Meteor Lake */ +- if (!IS_METEORLAKE(i915)) ++ /* Limiting the extension only to Xe_LPG and beyond */ ++ if (GRAPHICS_VER_FULL(i915) < IP_VER(12, 70)) + return -ENODEV; + + if (copy_from_user(&ext, base, sizeof(ext))) +diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c +index 310654542b42c1..a59c17ec7fa366 100644 +--- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c ++++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c +@@ -290,6 +290,41 @@ static vm_fault_t vm_fault_cpu(struct vm_fault *vmf) + return i915_error_to_vmf_fault(err); + } + ++static void set_address_limits(struct vm_area_struct *area, ++ struct i915_vma *vma, ++ unsigned long obj_offset, ++ unsigned long *start_vaddr, ++ unsigned long *end_vaddr) ++{ ++ unsigned long vm_start, vm_end, vma_size; /* user's memory parameters */ ++ long start, end; /* memory boundaries */ ++ ++ /* ++ * Let's move into the ">> PAGE_SHIFT" ++ * domain to be sure not to lose bits ++ */ ++ vm_start = area->vm_start >> PAGE_SHIFT; ++ vm_end = area->vm_end >> PAGE_SHIFT; ++ vma_size = vma->size >> PAGE_SHIFT; ++ ++ /* ++ * Calculate the memory boundaries by considering the offset ++ * provided by the user during memory mapping and the offset ++ * provided for the partial mapping. ++ */ ++ start = vm_start; ++ start -= obj_offset; ++ start += vma->gtt_view.partial.offset; ++ end = start + vma_size; ++ ++ start = max_t(long, start, vm_start); ++ end = min_t(long, end, vm_end); ++ ++ /* Let's move back into the "<< PAGE_SHIFT" domain */ ++ *start_vaddr = (unsigned long)start << PAGE_SHIFT; ++ *end_vaddr = (unsigned long)end << PAGE_SHIFT; ++} ++ + static vm_fault_t vm_fault_gtt(struct vm_fault *vmf) + { + #define MIN_CHUNK_PAGES (SZ_1M >> PAGE_SHIFT) +@@ -302,14 +337,18 @@ static vm_fault_t vm_fault_gtt(struct vm_fault *vmf) + struct i915_ggtt *ggtt = to_gt(i915)->ggtt; + bool write = area->vm_flags & VM_WRITE; + struct i915_gem_ww_ctx ww; ++ unsigned long obj_offset; ++ unsigned long start, end; /* memory boundaries */ + intel_wakeref_t wakeref; + struct i915_vma *vma; + pgoff_t page_offset; ++ unsigned long pfn; + int srcu; + int ret; + +- /* We don't use vmf->pgoff since that has the fake offset */ ++ obj_offset = area->vm_pgoff - drm_vma_node_start(&mmo->vma_node); + page_offset = (vmf->address - area->vm_start) >> PAGE_SHIFT; ++ page_offset += obj_offset; + + trace_i915_gem_object_fault(obj, page_offset, true, write); + +@@ -402,12 +441,14 @@ static vm_fault_t vm_fault_gtt(struct vm_fault *vmf) + if (ret) + goto err_unpin; + ++ set_address_limits(area, vma, obj_offset, &start, &end); ++ ++ pfn = (ggtt->gmadr.start + i915_ggtt_offset(vma)) >> PAGE_SHIFT; ++ pfn += (start - area->vm_start) >> PAGE_SHIFT; ++ pfn += obj_offset - vma->gtt_view.partial.offset; ++ + /* Finally, remap it using the new GTT offset */ +- ret = remap_io_mapping(area, +- area->vm_start + (vma->gtt_view.partial.offset << PAGE_SHIFT), +- (ggtt->gmadr.start + i915_ggtt_offset(vma)) >> PAGE_SHIFT, +- min_t(u64, vma->size, area->vm_end - area->vm_start), +- &ggtt->iomap); ++ ret = remap_io_mapping(area, start, pfn, end - start, &ggtt->iomap); + if (ret) + goto err_fence; + +@@ -1088,6 +1129,8 @@ int i915_gem_fb_mmap(struct drm_i915_gem_object *obj, struct vm_area_struct *vma + mmo = mmap_offset_attach(obj, mmap_type, NULL); + if (IS_ERR(mmo)) + return PTR_ERR(mmo); ++ ++ vma->vm_pgoff += drm_vma_node_start(&mmo->vma_node); + } + + /* +diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h +index f607b87890ddd6..c096fcdb2f1ed4 100644 +--- a/drivers/gpu/drm/i915/gem/i915_gem_object.h ++++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h +@@ -285,7 +285,9 @@ bool i915_gem_object_has_iomem(const struct drm_i915_gem_object *obj); + static inline bool + i915_gem_object_is_shrinkable(const struct drm_i915_gem_object *obj) + { +- return i915_gem_object_type_has(obj, I915_GEM_OBJECT_IS_SHRINKABLE); ++ /* TODO: make DPT shrinkable when it has no bound vmas */ ++ return i915_gem_object_type_has(obj, I915_GEM_OBJECT_IS_SHRINKABLE) && ++ !obj->is_dpt; + } + + static inline bool +diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +index 9227f8146a583f..6dc097a2ac07b3 100644 +--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c ++++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +@@ -1136,7 +1136,7 @@ static vm_fault_t vm_fault_ttm(struct vm_fault *vmf) + GEM_WARN_ON(!i915_ttm_cpu_maps_iomem(bo->resource)); + } + +- if (wakeref & CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND) ++ if (wakeref && CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND != 0) + intel_wakeref_auto(&to_i915(obj->base.dev)->runtime_pm.userfault_wakeref, + msecs_to_jiffies_timeout(CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND)); + +diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c +index 1d3ebdf4069b5d..c08b67593565c5 100644 +--- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c ++++ b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c +@@ -379,6 +379,9 @@ i915_gem_userptr_release(struct drm_i915_gem_object *obj) + { + GEM_WARN_ON(obj->userptr.page_ref); + ++ if (!obj->userptr.notifier.mm) ++ return; ++ + mmu_interval_notifier_remove(&obj->userptr.notifier); + obj->userptr.notifier.mm = NULL; + } +diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c +index 7ad36198aab2a4..cddf8c16e9a726 100644 +--- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c ++++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c +@@ -4,9 +4,9 @@ + */ + + #include "gen8_engine_cs.h" +-#include "i915_drv.h" + #include "intel_engine_regs.h" + #include "intel_gpu_commands.h" ++#include "intel_gt.h" + #include "intel_lrc.h" + #include "intel_ring.h" + +@@ -226,8 +226,8 @@ u32 *gen12_emit_aux_table_inv(struct intel_engine_cs *engine, u32 *cs) + static int mtl_dummy_pipe_control(struct i915_request *rq) + { + /* Wa_14016712196 */ +- if (IS_MTL_GRAPHICS_STEP(rq->i915, M, STEP_A0, STEP_B0) || +- IS_MTL_GRAPHICS_STEP(rq->i915, P, STEP_A0, STEP_B0)) { ++ if (IS_GFX_GT_IP_RANGE(rq->engine->gt, IP_VER(12, 70), IP_VER(12, 74)) || ++ IS_DG2(rq->i915)) { + u32 *cs; + + /* dummy PIPE_CONTROL + depth flush */ +@@ -808,6 +808,7 @@ u32 *gen12_emit_fini_breadcrumb_xcs(struct i915_request *rq, u32 *cs) + u32 *gen12_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs) + { + struct drm_i915_private *i915 = rq->i915; ++ struct intel_gt *gt = rq->engine->gt; + u32 flags = (PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_TLB_INVALIDATE | + PIPE_CONTROL_TILE_CACHE_FLUSH | +@@ -818,8 +819,7 @@ u32 *gen12_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs) + PIPE_CONTROL_FLUSH_ENABLE); + + /* Wa_14016712196 */ +- if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || +- IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) ++ if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74)) || IS_DG2(i915)) + /* dummy PIPE_CONTROL + depth flush */ + cs = gen12_emit_pipe_control(cs, 0, + PIPE_CONTROL_DEPTH_CACHE_FLUSH, 0); +diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c +index ecc990ec1b9526..f2973cd1a8aaef 100644 +--- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c ++++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c +@@ -258,8 +258,13 @@ static void signal_irq_work(struct irq_work *work) + i915_request_put(rq); + } + ++ /* Lazy irq enabling after HW submission */ + if (!READ_ONCE(b->irq_armed) && !list_empty(&b->signalers)) + intel_breadcrumbs_arm_irq(b); ++ ++ /* And confirm that we still want irqs enabled before we yield */ ++ if (READ_ONCE(b->irq_armed) && !atomic_read(&b->active)) ++ intel_breadcrumbs_disarm_irq(b); + } + + struct intel_breadcrumbs * +@@ -310,13 +315,7 @@ void __intel_breadcrumbs_park(struct intel_breadcrumbs *b) + return; + + /* Kick the work once more to drain the signalers, and disarm the irq */ +- irq_work_sync(&b->irq_work); +- while (READ_ONCE(b->irq_armed) && !atomic_read(&b->active)) { +- local_irq_disable(); +- signal_irq_work(&b->irq_work); +- local_irq_enable(); +- cond_resched(); +- } ++ irq_work_queue(&b->irq_work); + } + + void intel_breadcrumbs_free(struct kref *kref) +@@ -399,7 +398,7 @@ static void insert_breadcrumb(struct i915_request *rq) + * the request as it may have completed and raised the interrupt as + * we were attaching it into the lists. + */ +- if (!b->irq_armed || __i915_request_is_complete(rq)) ++ if (!READ_ONCE(b->irq_armed) || __i915_request_is_complete(rq)) + irq_work_queue(&b->irq_work); + } + +diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c +index e85d70a62123f9..d9bb352b8baab7 100644 +--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c ++++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c +@@ -912,6 +912,29 @@ static intel_engine_mask_t init_engine_mask(struct intel_gt *gt) + info->engine_mask &= ~BIT(GSC0); + } + ++ /* ++ * Do not create the command streamer for CCS slices beyond the first. ++ * All the workload submitted to the first engine will be shared among ++ * all the slices. ++ * ++ * Once the user will be allowed to customize the CCS mode, then this ++ * check needs to be removed. ++ */ ++ if (IS_DG2(gt->i915)) { ++ u8 first_ccs = __ffs(CCS_MASK(gt)); ++ ++ /* ++ * Store the number of active cslices before ++ * changing the CCS engine configuration ++ */ ++ gt->ccs.cslices = CCS_MASK(gt); ++ ++ /* Mask off all the CCS engine */ ++ info->engine_mask &= ~GENMASK(CCS3, CCS0); ++ /* Put back in the first CCS engine */ ++ info->engine_mask |= BIT(_CCS(first_ccs)); ++ } ++ + return info->engine_mask; + } + +@@ -1616,9 +1639,7 @@ static int __intel_engine_stop_cs(struct intel_engine_cs *engine, + * Wa_22011802037: Prior to doing a reset, ensure CS is + * stopped, set ring stop bit and prefetch disable bit to halt CS + */ +- if (IS_MTL_GRAPHICS_STEP(engine->i915, M, STEP_A0, STEP_B0) || +- (GRAPHICS_VER(engine->i915) >= 11 && +- GRAPHICS_VER_FULL(engine->i915) < IP_VER(12, 70))) ++ if (intel_engine_reset_needs_wa_22011802037(engine->gt)) + intel_uncore_write_fw(uncore, RING_MODE_GEN7(engine->mmio_base), + _MASKED_BIT_ENABLE(GEN12_GFX_PREFETCH_DISABLE)); + +diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i915/gt/intel_engine_pm.c +index b538b5c04948f6..5a3a5b29d15077 100644 +--- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c ++++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c +@@ -21,7 +21,7 @@ static void intel_gsc_idle_msg_enable(struct intel_engine_cs *engine) + { + struct drm_i915_private *i915 = engine->i915; + +- if (IS_METEORLAKE(i915) && engine->id == GSC0) { ++ if (MEDIA_VER(i915) >= 13 && engine->id == GSC0) { + intel_uncore_write(engine->gt->uncore, + RC_PSMI_CTRL_GSCCS, + _MASKED_BIT_DISABLE(IDLE_MSG_DISABLE)); +@@ -278,9 +278,6 @@ static int __engine_park(struct intel_wakeref *wf) + intel_engine_park_heartbeat(engine); + intel_breadcrumbs_park(engine->breadcrumbs); + +- /* Must be reset upon idling, or we may miss the busy wakeup. */ +- GEM_BUG_ON(engine->sched_engine->queue_priority_hint != INT_MIN); +- + if (engine->park) + engine->park(engine); + +diff --git a/drivers/gpu/drm/i915/gt/intel_engine_user.c b/drivers/gpu/drm/i915/gt/intel_engine_user.c +index dcedff41a825fc..d304e0a948f0d1 100644 +--- a/drivers/gpu/drm/i915/gt/intel_engine_user.c ++++ b/drivers/gpu/drm/i915/gt/intel_engine_user.c +@@ -42,12 +42,15 @@ void intel_engine_add_user(struct intel_engine_cs *engine) + (struct llist_head *)&engine->i915->uabi_engines); + } + +-static const u8 uabi_classes[] = { ++#define I915_NO_UABI_CLASS ((u16)(-1)) ++ ++static const u16 uabi_classes[] = { + [RENDER_CLASS] = I915_ENGINE_CLASS_RENDER, + [COPY_ENGINE_CLASS] = I915_ENGINE_CLASS_COPY, + [VIDEO_DECODE_CLASS] = I915_ENGINE_CLASS_VIDEO, + [VIDEO_ENHANCEMENT_CLASS] = I915_ENGINE_CLASS_VIDEO_ENHANCE, + [COMPUTE_CLASS] = I915_ENGINE_CLASS_COMPUTE, ++ [OTHER_CLASS] = I915_NO_UABI_CLASS, /* Not exposed to users, no uabi class. */ + }; + + static int engine_cmp(void *priv, const struct list_head *A, +@@ -202,6 +205,7 @@ static void engine_rename(struct intel_engine_cs *engine, const char *name, u16 + + void intel_engines_driver_register(struct drm_i915_private *i915) + { ++ u16 name_instance, other_instance = 0; + struct legacy_ring ring = {}; + struct list_head *it, *next; + struct rb_node **p, *prev; +@@ -219,27 +223,28 @@ void intel_engines_driver_register(struct drm_i915_private *i915) + if (intel_gt_has_unrecoverable_error(engine->gt)) + continue; /* ignore incomplete engines */ + +- /* +- * We don't want to expose the GSC engine to the users, but we +- * still rename it so it is easier to identify in the debug logs +- */ +- if (engine->id == GSC0) { +- engine_rename(engine, "gsc", 0); +- continue; +- } +- + GEM_BUG_ON(engine->class >= ARRAY_SIZE(uabi_classes)); + engine->uabi_class = uabi_classes[engine->class]; ++ if (engine->uabi_class == I915_NO_UABI_CLASS) { ++ name_instance = other_instance++; ++ } else { ++ GEM_BUG_ON(engine->uabi_class >= ++ ARRAY_SIZE(i915->engine_uabi_class_count)); ++ name_instance = ++ i915->engine_uabi_class_count[engine->uabi_class]++; ++ } ++ engine->uabi_instance = name_instance; + +- GEM_BUG_ON(engine->uabi_class >= +- ARRAY_SIZE(i915->engine_uabi_class_count)); +- engine->uabi_instance = +- i915->engine_uabi_class_count[engine->uabi_class]++; +- +- /* Replace the internal name with the final user facing name */ ++ /* ++ * Replace the internal name with the final user and log facing ++ * name. ++ */ + engine_rename(engine, + intel_engine_class_repr(engine->class), +- engine->uabi_instance); ++ name_instance); ++ ++ if (engine->uabi_class == I915_NO_UABI_CLASS) ++ continue; + + rb_link_node(&engine->uabi_node, prev, p); + rb_insert_color(&engine->uabi_node, &i915->uabi_engines); +diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +index 3292524469d509..2065be5a196bf6 100644 +--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c ++++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +@@ -3001,9 +3001,7 @@ static void execlists_reset_prepare(struct intel_engine_cs *engine) + * Wa_22011802037: In addition to stopping the cs, we need + * to wait for any pending mi force wakeups + */ +- if (IS_MTL_GRAPHICS_STEP(engine->i915, M, STEP_A0, STEP_B0) || +- (GRAPHICS_VER(engine->i915) >= 11 && +- GRAPHICS_VER_FULL(engine->i915) < IP_VER(12, 70))) ++ if (intel_engine_reset_needs_wa_22011802037(engine->gt)) + intel_engine_wait_for_pending_mi_fw(engine); + + engine->execlists.reset_ccid = active_ccid(engine); +@@ -3274,6 +3272,9 @@ static void execlists_park(struct intel_engine_cs *engine) + { + cancel_timer(&engine->execlists.timer); + cancel_timer(&engine->execlists.preempt); ++ ++ /* Reset upon idling, or we may delay the busy wakeup. */ ++ WRITE_ONCE(engine->sched_engine->queue_priority_hint, INT_MIN); + } + + static void add_to_engine(struct i915_request *rq) +@@ -3314,11 +3315,7 @@ static void remove_from_engine(struct i915_request *rq) + + static bool can_preempt(struct intel_engine_cs *engine) + { +- if (GRAPHICS_VER(engine->i915) > 8) +- return true; +- +- /* GPGPU on bdw requires extra w/a; not implemented */ +- return engine->class != RENDER_CLASS; ++ return GRAPHICS_VER(engine->i915) > 8; + } + + static void kick_execlists(const struct i915_request *rq, int prio) +diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c +index da21f2786b5d7d..b20d8fe8aa95d5 100644 +--- a/drivers/gpu/drm/i915/gt/intel_ggtt.c ++++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c +@@ -190,6 +190,21 @@ void gen6_ggtt_invalidate(struct i915_ggtt *ggtt) + spin_unlock_irq(&uncore->lock); + } + ++static bool needs_wc_ggtt_mapping(struct drm_i915_private *i915) ++{ ++ /* ++ * On BXT+/ICL+ writes larger than 64 bit to the GTT pagetable range ++ * will be dropped. For WC mappings in general we have 64 byte burst ++ * writes when the WC buffer is flushed, so we can't use it, but have to ++ * resort to an uncached mapping. The WC issue is easily caught by the ++ * readback check when writing GTT PTE entries. ++ */ ++ if (!IS_GEN9_LP(i915) && GRAPHICS_VER(i915) < 11) ++ return true; ++ ++ return false; ++} ++ + static void gen8_ggtt_invalidate(struct i915_ggtt *ggtt) + { + struct intel_uncore *uncore = ggtt->vm.gt->uncore; +@@ -197,8 +212,12 @@ static void gen8_ggtt_invalidate(struct i915_ggtt *ggtt) + /* + * Note that as an uncached mmio write, this will flush the + * WCB of the writes into the GGTT before it triggers the invalidate. ++ * ++ * Only perform this when GGTT is mapped as WC, see ggtt_probe_common(). + */ +- intel_uncore_write_fw(uncore, GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN); ++ if (needs_wc_ggtt_mapping(ggtt->vm.i915)) ++ intel_uncore_write_fw(uncore, GFX_FLSH_CNTL_GEN6, ++ GFX_FLSH_CNTL_EN); + } + + static void guc_ggtt_invalidate(struct i915_ggtt *ggtt) +@@ -902,17 +921,11 @@ static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size) + GEM_WARN_ON(pci_resource_len(pdev, GEN4_GTTMMADR_BAR) != gen6_gttmmadr_size(i915)); + phys_addr = pci_resource_start(pdev, GEN4_GTTMMADR_BAR) + gen6_gttadr_offset(i915); + +- /* +- * On BXT+/ICL+ writes larger than 64 bit to the GTT pagetable range +- * will be dropped. For WC mappings in general we have 64 byte burst +- * writes when the WC buffer is flushed, so we can't use it, but have to +- * resort to an uncached mapping. The WC issue is easily caught by the +- * readback check when writing GTT PTE entries. +- */ +- if (IS_GEN9_LP(i915) || GRAPHICS_VER(i915) >= 11) +- ggtt->gsm = ioremap(phys_addr, size); +- else ++ if (needs_wc_ggtt_mapping(i915)) + ggtt->gsm = ioremap_wc(phys_addr, size); ++ else ++ ggtt->gsm = ioremap(phys_addr, size); ++ + if (!ggtt->gsm) { + drm_err(&i915->drm, "Failed to map the ggtt page table\n"); + return -ENOMEM; +diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c b/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c +index 40371b8a9bbbd7..93bc1cc1ee7e64 100644 +--- a/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c ++++ b/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c +@@ -298,6 +298,7 @@ void i915_vma_revoke_fence(struct i915_vma *vma) + return; + + GEM_BUG_ON(fence->vma != vma); ++ i915_active_wait(&fence->active); + GEM_BUG_ON(!i915_active_is_idle(&fence->active)); + GEM_BUG_ON(atomic_read(&fence->pin_count)); + +diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c +index 449f0b7fc84343..95631e8f39e7b6 100644 +--- a/drivers/gpu/drm/i915/gt/intel_gt.c ++++ b/drivers/gpu/drm/i915/gt/intel_gt.c +@@ -967,8 +967,6 @@ int intel_gt_probe_all(struct drm_i915_private *i915) + + err: + i915_probe_error(i915, "Failed to initialize %s! (%d)\n", gtdef->name, ret); +- intel_gt_release_all(i915); +- + return ret; + } + +@@ -987,15 +985,6 @@ int intel_gt_tiles_init(struct drm_i915_private *i915) + return 0; + } + +-void intel_gt_release_all(struct drm_i915_private *i915) +-{ +- struct intel_gt *gt; +- unsigned int id; +- +- for_each_gt(gt, i915, id) +- i915->gt[id] = NULL; +-} +- + void intel_gt_info_print(const struct intel_gt_info *info, + struct drm_printer *p) + { +diff --git a/drivers/gpu/drm/i915/gt/intel_gt.h b/drivers/gpu/drm/i915/gt/intel_gt.h +index 6c34547b58b59f..6e63b46682f76b 100644 +--- a/drivers/gpu/drm/i915/gt/intel_gt.h ++++ b/drivers/gpu/drm/i915/gt/intel_gt.h +@@ -14,6 +14,37 @@ + struct drm_i915_private; + struct drm_printer; + ++/* ++ * Check that the GT is a graphics GT and has an IP version within the ++ * specified range (inclusive). ++ */ ++#define IS_GFX_GT_IP_RANGE(gt, from, until) ( \ ++ BUILD_BUG_ON_ZERO((from) < IP_VER(2, 0)) + \ ++ BUILD_BUG_ON_ZERO((until) < (from)) + \ ++ ((gt)->type != GT_MEDIA && \ ++ GRAPHICS_VER_FULL((gt)->i915) >= (from) && \ ++ GRAPHICS_VER_FULL((gt)->i915) <= (until))) ++ ++/* ++ * Check that the GT is a graphics GT with a specific IP version and has ++ * a stepping in the range [from, until). The lower stepping bound is ++ * inclusive, the upper bound is exclusive. The most common use-case of this ++ * macro is for checking bounds for workarounds, which usually have a stepping ++ * ("from") at which the hardware issue is first present and another stepping ++ * ("until") at which a hardware fix is present and the software workaround is ++ * no longer necessary. E.g., ++ * ++ * IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) ++ * IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_B1, STEP_FOREVER) ++ * ++ * "STEP_FOREVER" can be passed as "until" for workarounds that have no upper ++ * stepping bound for the specified IP version. ++ */ ++#define IS_GFX_GT_IP_STEP(gt, ipver, from, until) ( \ ++ BUILD_BUG_ON_ZERO((until) <= (from)) + \ ++ (IS_GFX_GT_IP_RANGE((gt), (ipver), (ipver)) && \ ++ IS_GRAPHICS_STEP((gt)->i915, (from), (until)))) ++ + #define GT_TRACE(gt, fmt, ...) do { \ + const struct intel_gt *gt__ __maybe_unused = (gt); \ + GEM_TRACE("%s " fmt, dev_name(gt__->i915->drm.dev), \ +diff --git a/drivers/gpu/drm/i915/gt/intel_gt_ccs_mode.c b/drivers/gpu/drm/i915/gt/intel_gt_ccs_mode.c +new file mode 100644 +index 00000000000000..3c62a44e9106ce +--- /dev/null ++++ b/drivers/gpu/drm/i915/gt/intel_gt_ccs_mode.c +@@ -0,0 +1,39 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * Copyright © 2024 Intel Corporation ++ */ ++ ++#include "i915_drv.h" ++#include "intel_gt.h" ++#include "intel_gt_ccs_mode.h" ++#include "intel_gt_regs.h" ++ ++unsigned int intel_gt_apply_ccs_mode(struct intel_gt *gt) ++{ ++ int cslice; ++ u32 mode = 0; ++ int first_ccs = __ffs(CCS_MASK(gt)); ++ ++ if (!IS_DG2(gt->i915)) ++ return 0; ++ ++ /* Build the value for the fixed CCS load balancing */ ++ for (cslice = 0; cslice < I915_MAX_CCS; cslice++) { ++ if (gt->ccs.cslices & BIT(cslice)) ++ /* ++ * If available, assign the cslice ++ * to the first available engine... ++ */ ++ mode |= XEHP_CCS_MODE_CSLICE(cslice, first_ccs); ++ ++ else ++ /* ++ * ... otherwise, mark the cslice as ++ * unavailable if no CCS dispatches here ++ */ ++ mode |= XEHP_CCS_MODE_CSLICE(cslice, ++ XEHP_CCS_MODE_CSLICE_MASK); ++ } ++ ++ return mode; ++} +diff --git a/drivers/gpu/drm/i915/gt/intel_gt_ccs_mode.h b/drivers/gpu/drm/i915/gt/intel_gt_ccs_mode.h +new file mode 100644 +index 00000000000000..55547f2ff426a4 +--- /dev/null ++++ b/drivers/gpu/drm/i915/gt/intel_gt_ccs_mode.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: MIT */ ++/* ++ * Copyright © 2024 Intel Corporation ++ */ ++ ++#ifndef __INTEL_GT_CCS_MODE_H__ ++#define __INTEL_GT_CCS_MODE_H__ ++ ++struct intel_gt; ++ ++unsigned int intel_gt_apply_ccs_mode(struct intel_gt *gt); ++ ++#endif /* __INTEL_GT_CCS_MODE_H__ */ +diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c +index 2c0f1f3e28ff89..c6dec485aefbec 100644 +--- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c ++++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c +@@ -3,8 +3,7 @@ + * Copyright © 2022 Intel Corporation + */ + +-#include "i915_drv.h" +- ++#include "intel_gt.h" + #include "intel_gt_mcr.h" + #include "intel_gt_print.h" + #include "intel_gt_regs.h" +@@ -166,8 +165,8 @@ void intel_gt_mcr_init(struct intel_gt *gt) + gt->steering_table[OADDRM] = xelpmp_oaddrm_steering_table; + } else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) { + /* Wa_14016747170 */ +- if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || +- IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) ++ if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || ++ IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0)) + fuse = REG_FIELD_GET(MTL_GT_L3_EXC_MASK, + intel_uncore_read(gt->uncore, + MTL_GT_ACTIVITY_FACTOR)); +diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h +index 2cdfb2f713d026..64acab146b52f8 100644 +--- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h ++++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h +@@ -1468,8 +1468,14 @@ + #define ECOBITS_PPGTT_CACHE4B (0 << 8) + + #define GEN12_RCU_MODE _MMIO(0x14800) ++#define XEHP_RCU_MODE_FIXED_SLICE_CCS_MODE REG_BIT(1) + #define GEN12_RCU_MODE_CCS_ENABLE REG_BIT(0) + ++#define XEHP_CCS_MODE _MMIO(0x14804) ++#define XEHP_CCS_MODE_CSLICE_MASK REG_GENMASK(2, 0) /* CCS0-3 + rsvd */ ++#define XEHP_CCS_MODE_CSLICE_WIDTH ilog2(XEHP_CCS_MODE_CSLICE_MASK + 1) ++#define XEHP_CCS_MODE_CSLICE(cslice, ccs) (ccs << (cslice * XEHP_CCS_MODE_CSLICE_WIDTH)) ++ + #define CHV_FUSE_GT _MMIO(VLV_GUNIT_BASE + 0x2168) + #define CHV_FGT_DISABLE_SS0 (1 << 10) + #define CHV_FGT_DISABLE_SS1 (1 << 11) +diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h +index def7dd0eb6f196..cfdd2ad5e9549c 100644 +--- a/drivers/gpu/drm/i915/gt/intel_gt_types.h ++++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h +@@ -207,6 +207,14 @@ struct intel_gt { + [MAX_ENGINE_INSTANCE + 1]; + enum intel_submission_method submission_method; + ++ struct { ++ /* ++ * Mask of the non fused CCS slices ++ * to be used for the load balancing ++ */ ++ intel_engine_mask_t cslices; ++ } ccs; ++ + /* + * Default address space (either GGTT or ppGTT depending on arch). + * +diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c +index c378cc7c953c47..b99efa348ad1ec 100644 +--- a/drivers/gpu/drm/i915/gt/intel_lrc.c ++++ b/drivers/gpu/drm/i915/gt/intel_lrc.c +@@ -1316,29 +1316,6 @@ gen12_emit_cmd_buf_wa(const struct intel_context *ce, u32 *cs) + return cs; + } + +-/* +- * On DG2 during context restore of a preempted context in GPGPU mode, +- * RCS restore hang is detected. This is extremely timing dependent. +- * To address this below sw wabb is implemented for DG2 A steppings. +- */ +-static u32 * +-dg2_emit_rcs_hang_wabb(const struct intel_context *ce, u32 *cs) +-{ +- *cs++ = MI_LOAD_REGISTER_IMM(1); +- *cs++ = i915_mmio_reg_offset(GEN12_STATE_ACK_DEBUG(ce->engine->mmio_base)); +- *cs++ = 0x21; +- +- *cs++ = MI_LOAD_REGISTER_REG; +- *cs++ = i915_mmio_reg_offset(RING_NOPID(ce->engine->mmio_base)); +- *cs++ = i915_mmio_reg_offset(XEHP_CULLBIT1); +- +- *cs++ = MI_LOAD_REGISTER_REG; +- *cs++ = i915_mmio_reg_offset(RING_NOPID(ce->engine->mmio_base)); +- *cs++ = i915_mmio_reg_offset(XEHP_CULLBIT2); +- +- return cs; +-} +- + /* + * The bspec's tuning guide asks us to program a vertical watermark value of + * 0x3FF. However this register is not saved/restored properly by the +@@ -1363,21 +1340,15 @@ gen12_emit_indirect_ctx_rcs(const struct intel_context *ce, u32 *cs) + cs = gen12_emit_cmd_buf_wa(ce, cs); + cs = gen12_emit_restore_scratch(ce, cs); + +- /* Wa_22011450934:dg2 */ +- if (IS_DG2_GRAPHICS_STEP(ce->engine->i915, G10, STEP_A0, STEP_B0) || +- IS_DG2_GRAPHICS_STEP(ce->engine->i915, G11, STEP_A0, STEP_B0)) +- cs = dg2_emit_rcs_hang_wabb(ce, cs); +- + /* Wa_16013000631:dg2 */ +- if (IS_DG2_GRAPHICS_STEP(ce->engine->i915, G10, STEP_B0, STEP_C0) || +- IS_DG2_G11(ce->engine->i915)) ++ if (IS_DG2_G11(ce->engine->i915)) + cs = gen8_emit_pipe_control(cs, PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE, 0); + + cs = gen12_emit_aux_table_inv(ce->engine, cs); + + /* Wa_16014892111 */ +- if (IS_MTL_GRAPHICS_STEP(ce->engine->i915, M, STEP_A0, STEP_B0) || +- IS_MTL_GRAPHICS_STEP(ce->engine->i915, P, STEP_A0, STEP_B0) || ++ if (IS_GFX_GT_IP_STEP(ce->engine->gt, IP_VER(12, 70), STEP_A0, STEP_B0) || ++ IS_GFX_GT_IP_STEP(ce->engine->gt, IP_VER(12, 71), STEP_A0, STEP_B0) || + IS_DG2(ce->engine->i915)) + cs = dg2_emit_draw_watermark_setting(cs); + +@@ -1391,8 +1362,7 @@ gen12_emit_indirect_ctx_xcs(const struct intel_context *ce, u32 *cs) + cs = gen12_emit_restore_scratch(ce, cs); + + /* Wa_16013000631:dg2 */ +- if (IS_DG2_GRAPHICS_STEP(ce->engine->i915, G10, STEP_B0, STEP_C0) || +- IS_DG2_G11(ce->engine->i915)) ++ if (IS_DG2_G11(ce->engine->i915)) + if (ce->engine->class == COMPUTE_CLASS) + cs = gen8_emit_pipe_control(cs, + PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE, +diff --git a/drivers/gpu/drm/i915/gt/intel_mocs.c b/drivers/gpu/drm/i915/gt/intel_mocs.c +index 2c014407225ccb..07269ff3be136d 100644 +--- a/drivers/gpu/drm/i915/gt/intel_mocs.c ++++ b/drivers/gpu/drm/i915/gt/intel_mocs.c +@@ -404,18 +404,6 @@ static const struct drm_i915_mocs_entry dg2_mocs_table[] = { + MOCS_ENTRY(3, 0, L3_3_WB | L3_LKUP(1)), + }; + +-static const struct drm_i915_mocs_entry dg2_mocs_table_g10_ax[] = { +- /* Wa_14011441408: Set Go to Memory for MOCS#0 */ +- MOCS_ENTRY(0, 0, L3_1_UC | L3_GLBGO(1) | L3_LKUP(1)), +- /* UC - Coherent; GO:Memory */ +- MOCS_ENTRY(1, 0, L3_1_UC | L3_GLBGO(1) | L3_LKUP(1)), +- /* UC - Non-Coherent; GO:Memory */ +- MOCS_ENTRY(2, 0, L3_1_UC | L3_GLBGO(1)), +- +- /* WB - LC */ +- MOCS_ENTRY(3, 0, L3_3_WB | L3_LKUP(1)), +-}; +- + static const struct drm_i915_mocs_entry pvc_mocs_table[] = { + /* Error */ + MOCS_ENTRY(0, 0, L3_3_WB), +@@ -507,7 +495,7 @@ static unsigned int get_mocs_settings(const struct drm_i915_private *i915, + memset(table, 0, sizeof(struct drm_i915_mocs_table)); + + table->unused_entries_index = I915_MOCS_PTE; +- if (IS_METEORLAKE(i915)) { ++ if (IS_GFX_GT_IP_RANGE(&i915->gt0, IP_VER(12, 70), IP_VER(12, 71))) { + table->size = ARRAY_SIZE(mtl_mocs_table); + table->table = mtl_mocs_table; + table->n_entries = MTL_NUM_MOCS_ENTRIES; +@@ -521,13 +509,8 @@ static unsigned int get_mocs_settings(const struct drm_i915_private *i915, + table->wb_index = 2; + table->unused_entries_index = 2; + } else if (IS_DG2(i915)) { +- if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) { +- table->size = ARRAY_SIZE(dg2_mocs_table_g10_ax); +- table->table = dg2_mocs_table_g10_ax; +- } else { +- table->size = ARRAY_SIZE(dg2_mocs_table); +- table->table = dg2_mocs_table; +- } ++ table->size = ARRAY_SIZE(dg2_mocs_table); ++ table->table = dg2_mocs_table; + table->uc_index = 1; + table->n_entries = GEN9_NUM_MOCS_ENTRIES; + table->unused_entries_index = 3; +diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c +index 58bb1c55294c93..9e113e9473260a 100644 +--- a/drivers/gpu/drm/i915/gt/intel_rc6.c ++++ b/drivers/gpu/drm/i915/gt/intel_rc6.c +@@ -118,14 +118,12 @@ static void gen11_rc6_enable(struct intel_rc6 *rc6) + GEN6_RC_CTL_EI_MODE(1); + + /* +- * Wa_16011777198 and BSpec 52698 - Render powergating must be off. ++ * BSpec 52698 - Render powergating must be off. + * FIXME BSpec is outdated, disabling powergating for MTL is just + * temporary wa and should be removed after fixing real cause + * of forcewake timeouts. + */ +- if (IS_METEORLAKE(gt->i915) || +- IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_C0) || +- IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_B0)) ++ if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71))) + pg_enable = + GEN9_MEDIA_PG_ENABLE | + GEN11_MEDIA_SAMPLER_PG_ENABLE; +@@ -584,19 +582,23 @@ static void __intel_rc6_disable(struct intel_rc6 *rc6) + + static void rc6_res_reg_init(struct intel_rc6 *rc6) + { +- memset(rc6->res_reg, INVALID_MMIO_REG.reg, sizeof(rc6->res_reg)); ++ i915_reg_t res_reg[INTEL_RC6_RES_MAX] = { ++ [0 ... INTEL_RC6_RES_MAX - 1] = INVALID_MMIO_REG, ++ }; + + switch (rc6_to_gt(rc6)->type) { + case GT_MEDIA: +- rc6->res_reg[INTEL_RC6_RES_RC6] = MTL_MEDIA_MC6; ++ res_reg[INTEL_RC6_RES_RC6] = MTL_MEDIA_MC6; + break; + default: +- rc6->res_reg[INTEL_RC6_RES_RC6_LOCKED] = GEN6_GT_GFX_RC6_LOCKED; +- rc6->res_reg[INTEL_RC6_RES_RC6] = GEN6_GT_GFX_RC6; +- rc6->res_reg[INTEL_RC6_RES_RC6p] = GEN6_GT_GFX_RC6p; +- rc6->res_reg[INTEL_RC6_RES_RC6pp] = GEN6_GT_GFX_RC6pp; ++ res_reg[INTEL_RC6_RES_RC6_LOCKED] = GEN6_GT_GFX_RC6_LOCKED; ++ res_reg[INTEL_RC6_RES_RC6] = GEN6_GT_GFX_RC6; ++ res_reg[INTEL_RC6_RES_RC6p] = GEN6_GT_GFX_RC6p; ++ res_reg[INTEL_RC6_RES_RC6pp] = GEN6_GT_GFX_RC6pp; + break; + } ++ ++ memcpy(rc6->res_reg, res_reg, sizeof(res_reg)); + } + + void intel_rc6_init(struct intel_rc6 *rc6) +diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c +index cc6bd21a3e51f1..13fb8e5042c584 100644 +--- a/drivers/gpu/drm/i915/gt/intel_reset.c ++++ b/drivers/gpu/drm/i915/gt/intel_reset.c +@@ -705,7 +705,7 @@ static int __reset_guc(struct intel_gt *gt) + + static bool needs_wa_14015076503(struct intel_gt *gt, intel_engine_mask_t engine_mask) + { +- if (!IS_METEORLAKE(gt->i915) || !HAS_ENGINE(gt, GSC0)) ++ if (MEDIA_VER_FULL(gt->i915) != IP_VER(13, 0) || !HAS_ENGINE(gt, GSC0)) + return false; + + if (!__HAS_ENGINE(engine_mask, GSC0)) +@@ -1297,7 +1297,7 @@ int __intel_engine_reset_bh(struct intel_engine_cs *engine, const char *msg) + if (msg) + drm_notice(&engine->i915->drm, + "Resetting %s for %s\n", engine->name, msg); +- atomic_inc(&engine->i915->gpu_error.reset_engine_count[engine->uabi_class]); ++ i915_increase_reset_engine_count(&engine->i915->gpu_error, engine); + + ret = intel_gt_reset_engine(engine); + if (ret) { +@@ -1632,6 +1632,24 @@ void __intel_fini_wedge(struct intel_wedge_me *w) + w->gt = NULL; + } + ++/* ++ * Wa_22011802037 requires that we (or the GuC) ensure that no command ++ * streamers are executing MI_FORCE_WAKE while an engine reset is initiated. ++ */ ++bool intel_engine_reset_needs_wa_22011802037(struct intel_gt *gt) ++{ ++ if (GRAPHICS_VER(gt->i915) < 11) ++ return false; ++ ++ if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0)) ++ return true; ++ ++ if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70)) ++ return false; ++ ++ return true; ++} ++ + #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) + #include "selftest_reset.c" + #include "selftest_hangcheck.c" +diff --git a/drivers/gpu/drm/i915/gt/intel_reset.h b/drivers/gpu/drm/i915/gt/intel_reset.h +index 25c975b6e8fc01..f615b30b81c594 100644 +--- a/drivers/gpu/drm/i915/gt/intel_reset.h ++++ b/drivers/gpu/drm/i915/gt/intel_reset.h +@@ -78,4 +78,6 @@ void __intel_fini_wedge(struct intel_wedge_me *w); + bool intel_has_gpu_reset(const struct intel_gt *gt); + bool intel_has_reset_engine(const struct intel_gt *gt); + ++bool intel_engine_reset_needs_wa_22011802037(struct intel_gt *gt); ++ + #endif /* I915_RESET_H */ +diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c +index 092542f53aad9c..4feef874e6d695 100644 +--- a/drivers/gpu/drm/i915/gt/intel_rps.c ++++ b/drivers/gpu/drm/i915/gt/intel_rps.c +@@ -1161,7 +1161,7 @@ void gen6_rps_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *c + { + struct drm_i915_private *i915 = rps_to_i915(rps); + +- if (IS_METEORLAKE(i915)) ++ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) + return mtl_get_freq_caps(rps, caps); + else + return __gen6_rps_get_freq_caps(rps, caps); +diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c +index 3ae0dbd39eaa3c..8fbb0686c5348d 100644 +--- a/drivers/gpu/drm/i915/gt/intel_workarounds.c ++++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c +@@ -10,6 +10,7 @@ + #include "intel_engine_regs.h" + #include "intel_gpu_commands.h" + #include "intel_gt.h" ++#include "intel_gt_ccs_mode.h" + #include "intel_gt_mcr.h" + #include "intel_gt_regs.h" + #include "intel_ring.h" +@@ -50,7 +51,8 @@ + * registers belonging to BCS, VCS or VECS should be implemented in + * xcs_engine_wa_init(). Workarounds for registers not belonging to a specific + * engine's MMIO range but that are part of of the common RCS/CCS reset domain +- * should be implemented in general_render_compute_wa_init(). ++ * should be implemented in general_render_compute_wa_init(). The settings ++ * about the CCS load balancing should be added in ccs_engine_wa_mode(). + * + * - GT workarounds: the list of these WAs is applied whenever these registers + * revert to their default values: on GPU reset, suspend/resume [1]_, etc. +@@ -764,39 +766,15 @@ static void dg2_ctx_workarounds_init(struct intel_engine_cs *engine, + { + dg2_ctx_gt_tuning_init(engine, wal); + +- /* Wa_16011186671:dg2_g11 */ +- if (IS_DG2_GRAPHICS_STEP(engine->i915, G11, STEP_A0, STEP_B0)) { +- wa_mcr_masked_dis(wal, VFLSKPD, DIS_MULT_MISS_RD_SQUASH); +- wa_mcr_masked_en(wal, VFLSKPD, DIS_OVER_FETCH_CACHE); +- } +- +- if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0)) { +- /* Wa_14010469329:dg2_g10 */ +- wa_mcr_masked_en(wal, XEHP_COMMON_SLICE_CHICKEN3, +- XEHP_DUAL_SIMD8_SEQ_MERGE_DISABLE); +- +- /* +- * Wa_22010465075:dg2_g10 +- * Wa_22010613112:dg2_g10 +- * Wa_14010698770:dg2_g10 +- */ +- wa_mcr_masked_en(wal, XEHP_COMMON_SLICE_CHICKEN3, +- GEN12_DISABLE_CPS_AWARE_COLOR_PIPE); +- } +- + /* Wa_16013271637:dg2 */ + wa_mcr_masked_en(wal, XEHP_SLICE_COMMON_ECO_CHICKEN1, + MSC_MSAA_REODER_BUF_BYPASS_DISABLE); + + /* Wa_14014947963:dg2 */ +- if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_B0, STEP_FOREVER) || +- IS_DG2_G11(engine->i915) || IS_DG2_G12(engine->i915)) +- wa_masked_field_set(wal, VF_PREEMPTION, PREEMPTION_VERTEX_COUNT, 0x4000); ++ wa_masked_field_set(wal, VF_PREEMPTION, PREEMPTION_VERTEX_COUNT, 0x4000); + + /* Wa_18018764978:dg2 */ +- if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_C0, STEP_FOREVER) || +- IS_DG2_G11(engine->i915) || IS_DG2_G12(engine->i915)) +- wa_mcr_masked_en(wal, XEHP_PSS_MODE2, SCOREBOARD_STALL_FLUSH_CONTROL); ++ wa_mcr_masked_en(wal, XEHP_PSS_MODE2, SCOREBOARD_STALL_FLUSH_CONTROL); + + /* Wa_15010599737:dg2 */ + wa_mcr_masked_en(wal, CHICKEN_RASTER_1, DIS_SF_ROUND_NEAREST_EVEN); +@@ -805,27 +783,32 @@ static void dg2_ctx_workarounds_init(struct intel_engine_cs *engine, + wa_masked_en(wal, CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE); + } + +-static void mtl_ctx_gt_tuning_init(struct intel_engine_cs *engine, +- struct i915_wa_list *wal) ++static void xelpg_ctx_gt_tuning_init(struct intel_engine_cs *engine, ++ struct i915_wa_list *wal) + { +- struct drm_i915_private *i915 = engine->i915; ++ struct intel_gt *gt = engine->gt; + + dg2_ctx_gt_tuning_init(engine, wal); + +- if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_B0, STEP_FOREVER) || +- IS_MTL_GRAPHICS_STEP(i915, P, STEP_B0, STEP_FOREVER)) ++ /* ++ * Due to Wa_16014892111, the DRAW_WATERMARK tuning must be done in ++ * gen12_emit_indirect_ctx_rcs() rather than here on some early ++ * steppings. ++ */ ++ if (!(IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || ++ IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0))) + wa_add(wal, DRAW_WATERMARK, VERT_WM_VAL, 0x3FF, 0, false); + } + +-static void mtl_ctx_workarounds_init(struct intel_engine_cs *engine, +- struct i915_wa_list *wal) ++static void xelpg_ctx_workarounds_init(struct intel_engine_cs *engine, ++ struct i915_wa_list *wal) + { +- struct drm_i915_private *i915 = engine->i915; ++ struct intel_gt *gt = engine->gt; + +- mtl_ctx_gt_tuning_init(engine, wal); ++ xelpg_ctx_gt_tuning_init(engine, wal); + +- if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || +- IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) { ++ if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || ++ IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0)) { + /* Wa_14014947963 */ + wa_masked_field_set(wal, VF_PREEMPTION, + PREEMPTION_VERTEX_COUNT, 0x4000); +@@ -931,8 +914,8 @@ __intel_engine_init_ctx_wa(struct intel_engine_cs *engine, + if (engine->class != RENDER_CLASS) + goto done; + +- if (IS_METEORLAKE(i915)) +- mtl_ctx_workarounds_init(engine, wal); ++ if (IS_GFX_GT_IP_RANGE(engine->gt, IP_VER(12, 70), IP_VER(12, 74))) ++ xelpg_ctx_workarounds_init(engine, wal); + else if (IS_PONTEVECCHIO(i915)) + ; /* noop; none at this time */ + else if (IS_DG2(i915)) +@@ -1606,31 +1589,11 @@ xehpsdv_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) + static void + dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) + { +- struct intel_engine_cs *engine; +- int id; +- + xehp_init_mcr(gt, wal); + + /* Wa_14011060649:dg2 */ + wa_14011060649(gt, wal); + +- /* +- * Although there are per-engine instances of these registers, +- * they technically exist outside the engine itself and are not +- * impacted by engine resets. Furthermore, they're part of the +- * GuC blacklist so trying to treat them as engine workarounds +- * will result in GuC initialization failure and a wedged GPU. +- */ +- for_each_engine(engine, gt, id) { +- if (engine->class != VIDEO_DECODE_CLASS) +- continue; +- +- /* Wa_16010515920:dg2_g10 */ +- if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_B0)) +- wa_write_or(wal, VDBOX_CGCTL3F18(engine->mmio_base), +- ALNUNIT_CLKGATE_DIS); +- } +- + if (IS_DG2_G10(gt->i915)) { + /* Wa_22010523718:dg2 */ + wa_write_or(wal, UNSLICE_UNIT_LEVEL_CLKGATE, +@@ -1641,65 +1604,6 @@ dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) + DSS_ROUTER_CLKGATE_DIS); + } + +- if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_B0) || +- IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_B0)) { +- /* Wa_14012362059:dg2 */ +- wa_mcr_write_or(wal, XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB); +- } +- +- if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_B0)) { +- /* Wa_14010948348:dg2_g10 */ +- wa_write_or(wal, UNSLCGCTL9430, MSQDUNIT_CLKGATE_DIS); +- +- /* Wa_14011037102:dg2_g10 */ +- wa_write_or(wal, UNSLCGCTL9444, LTCDD_CLKGATE_DIS); +- +- /* Wa_14011371254:dg2_g10 */ +- wa_mcr_write_or(wal, XEHP_SLICE_UNIT_LEVEL_CLKGATE, NODEDSS_CLKGATE_DIS); +- +- /* Wa_14011431319:dg2_g10 */ +- wa_write_or(wal, UNSLCGCTL9440, GAMTLBOACS_CLKGATE_DIS | +- GAMTLBVDBOX7_CLKGATE_DIS | +- GAMTLBVDBOX6_CLKGATE_DIS | +- GAMTLBVDBOX5_CLKGATE_DIS | +- GAMTLBVDBOX4_CLKGATE_DIS | +- GAMTLBVDBOX3_CLKGATE_DIS | +- GAMTLBVDBOX2_CLKGATE_DIS | +- GAMTLBVDBOX1_CLKGATE_DIS | +- GAMTLBVDBOX0_CLKGATE_DIS | +- GAMTLBKCR_CLKGATE_DIS | +- GAMTLBGUC_CLKGATE_DIS | +- GAMTLBBLT_CLKGATE_DIS); +- wa_write_or(wal, UNSLCGCTL9444, GAMTLBGFXA0_CLKGATE_DIS | +- GAMTLBGFXA1_CLKGATE_DIS | +- GAMTLBCOMPA0_CLKGATE_DIS | +- GAMTLBCOMPA1_CLKGATE_DIS | +- GAMTLBCOMPB0_CLKGATE_DIS | +- GAMTLBCOMPB1_CLKGATE_DIS | +- GAMTLBCOMPC0_CLKGATE_DIS | +- GAMTLBCOMPC1_CLKGATE_DIS | +- GAMTLBCOMPD0_CLKGATE_DIS | +- GAMTLBCOMPD1_CLKGATE_DIS | +- GAMTLBMERT_CLKGATE_DIS | +- GAMTLBVEBOX3_CLKGATE_DIS | +- GAMTLBVEBOX2_CLKGATE_DIS | +- GAMTLBVEBOX1_CLKGATE_DIS | +- GAMTLBVEBOX0_CLKGATE_DIS); +- +- /* Wa_14010569222:dg2_g10 */ +- wa_write_or(wal, UNSLICE_UNIT_LEVEL_CLKGATE, +- GAMEDIA_CLKGATE_DIS); +- +- /* Wa_14011028019:dg2_g10 */ +- wa_mcr_write_or(wal, SSMCGCTL9530, RTFUNIT_CLKGATE_DIS); +- +- /* Wa_14010680813:dg2_g10 */ +- wa_mcr_write_or(wal, XEHP_GAMSTLB_CTRL, +- CONTROL_BLOCK_CLKGATE_DIS | +- EGRESS_BLOCK_CLKGATE_DIS | +- TAG_BLOCK_CLKGATE_DIS); +- } +- + /* Wa_14014830051:dg2 */ + wa_mcr_write_clr(wal, SARB_CHICKEN1, COMP_CKN_IN); + +@@ -1741,14 +1645,15 @@ pvc_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) + static void + xelpg_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) + { +- /* Wa_14018778641 / Wa_18018781329 */ ++ /* Wa_14018575942 / Wa_18018781329 */ ++ wa_mcr_write_or(wal, RENDER_MOD_CTRL, FORCE_MISS_FTLB); + wa_mcr_write_or(wal, COMP_MOD_CTRL, FORCE_MISS_FTLB); + + /* Wa_22016670082 */ + wa_write_or(wal, GEN12_SQCNT1, GEN12_STRICT_RAR_ENABLE); + +- if (IS_MTL_GRAPHICS_STEP(gt->i915, M, STEP_A0, STEP_B0) || +- IS_MTL_GRAPHICS_STEP(gt->i915, P, STEP_A0, STEP_B0)) { ++ if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || ++ IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0)) { + /* Wa_14014830051 */ + wa_mcr_write_clr(wal, SARB_CHICKEN1, COMP_CKN_IN); + +@@ -1791,10 +1696,8 @@ xelpmp_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) + */ + static void gt_tuning_settings(struct intel_gt *gt, struct i915_wa_list *wal) + { +- if (IS_METEORLAKE(gt->i915)) { +- if (gt->type != GT_MEDIA) +- wa_mcr_write_or(wal, XEHP_L3SCQREG7, BLEND_FILL_CACHING_OPT_DIS); +- ++ if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74))) { ++ wa_mcr_write_or(wal, XEHP_L3SCQREG7, BLEND_FILL_CACHING_OPT_DIS); + wa_mcr_write_or(wal, XEHP_SQCM, EN_32B_ACCESS); + } + +@@ -1826,7 +1729,7 @@ gt_init_workarounds(struct intel_gt *gt, struct i915_wa_list *wal) + return; + } + +- if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) ++ if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74))) + xelpg_gt_workarounds_init(gt, wal); + else if (IS_PONTEVECCHIO(i915)) + pvc_gt_workarounds_init(gt, wal); +@@ -2242,29 +2145,10 @@ static void dg2_whitelist_build(struct intel_engine_cs *engine) + + switch (engine->class) { + case RENDER_CLASS: +- /* +- * Wa_1507100340:dg2_g10 +- * +- * This covers 4 registers which are next to one another : +- * - PS_INVOCATION_COUNT +- * - PS_INVOCATION_COUNT_UDW +- * - PS_DEPTH_COUNT +- * - PS_DEPTH_COUNT_UDW +- */ +- if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0)) +- whitelist_reg_ext(w, PS_INVOCATION_COUNT, +- RING_FORCE_TO_NONPRIV_ACCESS_RD | +- RING_FORCE_TO_NONPRIV_RANGE_4); +- + /* Required by recommended tuning setting (not a workaround) */ + whitelist_mcr_reg(w, XEHP_COMMON_SLICE_CHICKEN3); + + break; +- case COMPUTE_CLASS: +- /* Wa_16011157294:dg2_g10 */ +- if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0)) +- whitelist_reg(w, GEN9_CTX_PREEMPT_REG); +- break; + default: + break; + } +@@ -2294,7 +2178,7 @@ static void pvc_whitelist_build(struct intel_engine_cs *engine) + blacklist_trtt(engine); + } + +-static void mtl_whitelist_build(struct intel_engine_cs *engine) ++static void xelpg_whitelist_build(struct intel_engine_cs *engine) + { + struct i915_wa_list *w = &engine->whitelist; + +@@ -2316,8 +2200,10 @@ void intel_engine_init_whitelist(struct intel_engine_cs *engine) + + wa_init_start(w, engine->gt, "whitelist", engine->name); + +- if (IS_METEORLAKE(i915)) +- mtl_whitelist_build(engine); ++ if (engine->gt->type == GT_MEDIA) ++ ; /* none yet */ ++ else if (IS_GFX_GT_IP_RANGE(engine->gt, IP_VER(12, 70), IP_VER(12, 74))) ++ xelpg_whitelist_build(engine); + else if (IS_PONTEVECCHIO(i915)) + pvc_whitelist_build(engine); + else if (IS_DG2(i915)) +@@ -2415,62 +2301,35 @@ engine_fake_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) + } + } + +-static bool needs_wa_1308578152(struct intel_engine_cs *engine) +-{ +- return intel_sseu_find_first_xehp_dss(&engine->gt->info.sseu, 0, 0) >= +- GEN_DSS_PER_GSLICE; +-} +- + static void + rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) + { + struct drm_i915_private *i915 = engine->i915; ++ struct intel_gt *gt = engine->gt; + +- if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || +- IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) { ++ if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || ++ IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0)) { + /* Wa_22014600077 */ + wa_mcr_masked_en(wal, GEN10_CACHE_MODE_SS, + ENABLE_EU_COUNT_FOR_TDL_FLUSH); + } + +- if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || +- IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0) || +- IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) || +- IS_DG2_G11(i915) || IS_DG2_G12(i915)) { ++ if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || ++ IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0) || ++ IS_DG2(i915)) { + /* Wa_1509727124 */ + wa_mcr_masked_en(wal, GEN10_SAMPLER_MODE, + SC_DISABLE_POWER_OPTIMIZATION_EBB); + } + +- if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) || +- IS_DG2_G11(i915) || IS_DG2_G12(i915) || +- IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0)) { ++ if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || ++ IS_DG2(i915)) { + /* Wa_22012856258 */ + wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2, + GEN12_DISABLE_READ_SUPPRESSION); + } + +- if (IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) { +- /* Wa_14013392000:dg2_g11 */ +- wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2, GEN12_ENABLE_LARGE_GRF_MODE); +- } +- +- if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0) || +- IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) { +- /* Wa_14012419201:dg2 */ +- wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, +- GEN12_DISABLE_HDR_PAST_PAYLOAD_HOLD_FIX); +- } +- +- /* Wa_1308578152:dg2_g10 when first gslice is fused off */ +- if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_C0) && +- needs_wa_1308578152(engine)) { +- wa_masked_dis(wal, GEN12_CS_DEBUG_MODE1_CCCSUNIT_BE_COMMON, +- GEN12_REPLAY_MODE_GRANULARITY); +- } +- +- if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) || +- IS_DG2_G11(i915) || IS_DG2_G12(i915)) { ++ if (IS_DG2(i915)) { + /* + * Wa_22010960976:dg2 + * Wa_14013347512:dg2 +@@ -2479,34 +2338,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) + LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK); + } + +- if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) { +- /* +- * Wa_1608949956:dg2_g10 +- * Wa_14010198302:dg2_g10 +- */ +- wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN, +- MDQ_ARBITRATION_MODE | UGM_BACKUP_MODE); +- } +- +- if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) +- /* Wa_22010430635:dg2 */ +- wa_mcr_masked_en(wal, +- GEN9_ROW_CHICKEN4, +- GEN12_DISABLE_GRF_CLEAR); +- +- /* Wa_14013202645:dg2 */ +- if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_C0) || +- IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) +- wa_mcr_write_or(wal, RT_CTRL, DIS_NULL_QUERY); +- +- /* Wa_22012532006:dg2 */ +- if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_C0) || +- IS_DG2_GRAPHICS_STEP(engine->i915, G11, STEP_A0, STEP_B0)) +- wa_mcr_masked_en(wal, GEN9_HALF_SLICE_CHICKEN7, +- DG2_DISABLE_ROUND_ENABLE_ALLOW_FOR_SSLA); +- +- if (IS_DG2_GRAPHICS_STEP(i915, G11, STEP_B0, STEP_FOREVER) || +- IS_DG2_G10(i915)) { ++ if (IS_DG2_G11(i915) || IS_DG2_G10(i915)) { + /* Wa_22014600077:dg2 */ + wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0, + _MASKED_BIT_ENABLE(ENABLE_EU_COUNT_FOR_TDL_FLUSH), +@@ -2514,6 +2346,19 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) + true); + } + ++ if (IS_DG2(i915) || IS_ALDERLAKE_P(i915) || IS_ALDERLAKE_S(i915) || ++ IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { ++ /* ++ * Wa_1606700617:tgl,dg1,adl-p ++ * Wa_22010271021:tgl,rkl,dg1,adl-s,adl-p ++ * Wa_14010826681:tgl,dg1,rkl,adl-p ++ * Wa_18019627453:dg2 ++ */ ++ wa_masked_en(wal, ++ GEN9_CS_DEBUG_MODE1, ++ FF_DOP_CLOCK_GATE_DISABLE); ++ } ++ + if (IS_ALDERLAKE_P(i915) || IS_ALDERLAKE_S(i915) || IS_DG1(i915) || + IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { + /* Wa_1606931601:tgl,rkl,dg1,adl-s,adl-p */ +@@ -2527,19 +2372,11 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) + */ + wa_write_or(wal, GEN7_FF_THREAD_MODE, + GEN12_FF_TESSELATION_DOP_GATE_DISABLE); +- } + +- if (IS_ALDERLAKE_P(i915) || IS_DG2(i915) || IS_ALDERLAKE_S(i915) || +- IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { +- /* +- * Wa_1606700617:tgl,dg1,adl-p +- * Wa_22010271021:tgl,rkl,dg1,adl-s,adl-p +- * Wa_14010826681:tgl,dg1,rkl,adl-p +- * Wa_18019627453:dg2 +- */ +- wa_masked_en(wal, +- GEN9_CS_DEBUG_MODE1, +- FF_DOP_CLOCK_GATE_DISABLE); ++ /* Wa_1406941453:tgl,rkl,dg1,adl-s,adl-p */ ++ wa_mcr_masked_en(wal, ++ GEN10_SAMPLER_MODE, ++ ENABLE_SMALLPL); + } + + if (IS_ALDERLAKE_P(i915) || IS_ALDERLAKE_S(i915) || +@@ -2566,14 +2403,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) + GEN8_RC_SEMA_IDLE_MSG_DISABLE); + } + +- if (IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915) || +- IS_ALDERLAKE_S(i915) || IS_ALDERLAKE_P(i915)) { +- /* Wa_1406941453:tgl,rkl,dg1,adl-s,adl-p */ +- wa_mcr_masked_en(wal, +- GEN10_SAMPLER_MODE, +- ENABLE_SMALLPL); +- } +- + if (GRAPHICS_VER(i915) == 11) { + /* This is not an Wa. Enable for better image quality */ + wa_masked_en(wal, +@@ -2975,10 +2804,12 @@ ccs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) + * function invoked by __intel_engine_init_ctx_wa(). + */ + static void +-add_render_compute_tuning_settings(struct drm_i915_private *i915, ++add_render_compute_tuning_settings(struct intel_gt *gt, + struct i915_wa_list *wal) + { +- if (IS_METEORLAKE(i915) || IS_DG2(i915)) ++ struct drm_i915_private *i915 = gt->i915; ++ ++ if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74)) || IS_DG2(i915)) + wa_mcr_write_clr_set(wal, RT_CTRL, STACKID_CTRL, STACKID_CTRL_512); + + /* +@@ -2994,6 +2825,30 @@ add_render_compute_tuning_settings(struct drm_i915_private *i915, + wa_write_clr(wal, GEN8_GARBCNTL, GEN12_BUS_HASH_CTL_BIT_EXC); + } + ++static void ccs_engine_wa_mode(struct intel_engine_cs *engine, struct i915_wa_list *wal) ++{ ++ struct intel_gt *gt = engine->gt; ++ u32 mode; ++ ++ if (!IS_DG2(gt->i915)) ++ return; ++ ++ /* ++ * Wa_14019159160: This workaround, along with others, leads to ++ * significant challenges in utilizing load balancing among the ++ * CCS slices. Consequently, an architectural decision has been ++ * made to completely disable automatic CCS load balancing. ++ */ ++ wa_masked_en(wal, GEN12_RCU_MODE, XEHP_RCU_MODE_FIXED_SLICE_CCS_MODE); ++ ++ /* ++ * After having disabled automatic load balancing we need to ++ * assign all slices to a single CCS. We will call it CCS mode 1 ++ */ ++ mode = intel_gt_apply_ccs_mode(gt); ++ wa_masked_en(wal, XEHP_CCS_MODE, mode); ++} ++ + /* + * The workarounds in this function apply to shared registers in + * the general render reset domain that aren't tied to a +@@ -3007,8 +2862,9 @@ static void + general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) + { + struct drm_i915_private *i915 = engine->i915; ++ struct intel_gt *gt = engine->gt; + +- add_render_compute_tuning_settings(i915, wal); ++ add_render_compute_tuning_settings(gt, wal); + + if (GRAPHICS_VER(i915) >= 11) { + /* This is not a Wa (although referred to as +@@ -3029,13 +2885,14 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li + GEN11_INDIRECT_STATE_BASE_ADDR_OVERRIDE); + } + +- if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_B0, STEP_FOREVER) || +- IS_MTL_GRAPHICS_STEP(i915, P, STEP_B0, STEP_FOREVER)) ++ if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_B0, STEP_FOREVER) || ++ IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_B0, STEP_FOREVER) || ++ IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 74), IP_VER(12, 74))) + /* Wa_14017856879 */ + wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN3, MTL_DISABLE_FIX_FOR_EOT_FLUSH); + +- if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || +- IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) ++ if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || ++ IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0)) + /* + * Wa_14017066071 + * Wa_14017654203 +@@ -3043,37 +2900,47 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li + wa_mcr_masked_en(wal, GEN10_SAMPLER_MODE, + MTL_DISABLE_SAMPLER_SC_OOO); + +- if (IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) ++ if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0)) + /* Wa_22015279794 */ + wa_mcr_masked_en(wal, GEN10_CACHE_MODE_SS, + DISABLE_PREFETCH_INTO_IC); + +- if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || +- IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0) || +- IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) || +- IS_DG2_G11(i915) || IS_DG2_G12(i915)) { ++ if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || ++ IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0) || ++ IS_DG2(i915)) { + /* Wa_22013037850 */ + wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, + DISABLE_128B_EVICTION_COMMAND_UDW); ++ ++ /* Wa_18017747507 */ ++ wa_masked_en(wal, VFG_PREEMPTION_CHICKEN, POLYGON_TRIFAN_LINELOOP_DISABLE); + } + +- if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || +- IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0) || ++ if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || ++ IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0) || + IS_PONTEVECCHIO(i915) || + IS_DG2(i915)) { + /* Wa_22014226127 */ + wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0, DISABLE_D8_D16_COASLESCE); + } + +- if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || +- IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0) || +- IS_DG2(i915)) { +- /* Wa_18017747507 */ +- wa_masked_en(wal, VFG_PREEMPTION_CHICKEN, POLYGON_TRIFAN_LINELOOP_DISABLE); ++ if (IS_PONTEVECCHIO(i915) || IS_DG2(i915)) { ++ /* Wa_14015227452:dg2,pvc */ ++ wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, XEHP_DIS_BBL_SYSPIPE); ++ ++ /* Wa_16015675438:dg2,pvc */ ++ wa_masked_en(wal, FF_SLICE_CS_CHICKEN2, GEN12_PERF_FIX_BALANCING_CFE_DISABLE); ++ } ++ ++ if (IS_DG2(i915)) { ++ /* ++ * Wa_16011620976:dg2_g11 ++ * Wa_22015475538:dg2 ++ */ ++ wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, DIS_CHAIN_2XSIMD8); + } + +- if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_C0) || +- IS_DG2_G11(i915)) { ++ if (IS_DG2_G11(i915)) { + /* + * Wa_22012826095:dg2 + * Wa_22013059131:dg2 +@@ -3085,18 +2952,18 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li + /* Wa_22013059131:dg2 */ + wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0, + FORCE_1_SUB_MESSAGE_PER_FRAGMENT); +- } + +- if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) { + /* +- * Wa_14010918519:dg2_g10 ++ * Wa_22012654132 + * +- * LSC_CHICKEN_BIT_0 always reads back as 0 is this stepping, +- * so ignoring verification. ++ * Note that register 0xE420 is write-only and cannot be read ++ * back for verification on DG2 (due to Wa_14012342262), so ++ * we need to explicitly skip the readback. + */ +- wa_mcr_add(wal, LSC_CHICKEN_BIT_0_UDW, 0, +- FORCE_SLM_FENCE_SCOPE_TO_TILE | FORCE_UGM_FENCE_SCOPE_TO_TILE, +- 0, false); ++ wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0, ++ _MASKED_BIT_ENABLE(ENABLE_PREFETCH_INTO_IC), ++ 0 /* write-only, so skip validation */, ++ true); + } + + if (IS_XEHPSDV(i915)) { +@@ -3114,35 +2981,6 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li + wa_mcr_masked_en(wal, GEN8_HALF_SLICE_CHICKEN1, + GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE); + } +- +- if (IS_DG2(i915) || IS_PONTEVECCHIO(i915)) { +- /* Wa_14015227452:dg2,pvc */ +- wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, XEHP_DIS_BBL_SYSPIPE); +- +- /* Wa_16015675438:dg2,pvc */ +- wa_masked_en(wal, FF_SLICE_CS_CHICKEN2, GEN12_PERF_FIX_BALANCING_CFE_DISABLE); +- } +- +- if (IS_DG2(i915)) { +- /* +- * Wa_16011620976:dg2_g11 +- * Wa_22015475538:dg2 +- */ +- wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, DIS_CHAIN_2XSIMD8); +- } +- +- if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_C0) || IS_DG2_G11(i915)) +- /* +- * Wa_22012654132 +- * +- * Note that register 0xE420 is write-only and cannot be read +- * back for verification on DG2 (due to Wa_14012342262), so +- * we need to explicitly skip the readback. +- */ +- wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0, +- _MASKED_BIT_ENABLE(ENABLE_PREFETCH_INTO_IC), +- 0 /* write-only, so skip validation */, +- true); + } + + static void +@@ -3158,8 +2996,10 @@ engine_init_workarounds(struct intel_engine_cs *engine, struct i915_wa_list *wal + * to a single RCS/CCS engine's workaround list since + * they're reset as part of the general render domain reset. + */ +- if (engine->flags & I915_ENGINE_FIRST_RENDER_COMPUTE) ++ if (engine->flags & I915_ENGINE_FIRST_RENDER_COMPUTE) { + general_render_compute_wa_init(engine, wal); ++ ccs_engine_wa_mode(engine, wal); ++ } + + if (engine->class == COMPUTE_CLASS) + ccs_engine_wa_init(engine, wal); +diff --git a/drivers/gpu/drm/i915/gt/selftest_migrate.c b/drivers/gpu/drm/i915/gt/selftest_migrate.c +index 3def5ca72decfd..0fb07f073baa61 100644 +--- a/drivers/gpu/drm/i915/gt/selftest_migrate.c ++++ b/drivers/gpu/drm/i915/gt/selftest_migrate.c +@@ -719,11 +719,9 @@ static int threaded_migrate(struct intel_migrate *migrate, + if (IS_ERR_OR_NULL(tsk)) + continue; + +- status = kthread_stop(tsk); ++ status = kthread_stop_put(tsk); + if (status && !err) + err = status; +- +- put_task_struct(tsk); + } + + kfree(thread); +diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h b/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h +index 58012edd4eb0ec..4f4f53c42a9c56 100644 +--- a/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h ++++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h +@@ -29,9 +29,9 @@ + */ + + #define GUC_KLV_LEN_MIN 1u +-#define GUC_KLV_0_KEY (0xffff << 16) +-#define GUC_KLV_0_LEN (0xffff << 0) +-#define GUC_KLV_n_VALUE (0xffffffff << 0) ++#define GUC_KLV_0_KEY (0xffffu << 16) ++#define GUC_KLV_0_LEN (0xffffu << 0) ++#define GUC_KLV_n_VALUE (0xffffffffu << 0) + + /** + * DOC: GuC Self Config KLVs +diff --git a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c +index 0d3b22a7436595..e251e061d1adb7 100644 +--- a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c ++++ b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c +@@ -304,7 +304,7 @@ void intel_gsc_uc_load_start(struct intel_gsc_uc *gsc) + { + struct intel_gt *gt = gsc_uc_to_gt(gsc); + +- if (!intel_uc_fw_is_loadable(&gsc->fw)) ++ if (!intel_uc_fw_is_loadable(&gsc->fw) || intel_uc_fw_is_in_error(&gsc->fw)) + return; + + if (intel_gsc_uc_fw_init_done(gsc)) +diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c +index 569b5fe94c416f..861d0c58388cfc 100644 +--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c ++++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c +@@ -272,18 +272,14 @@ static u32 guc_ctl_wa_flags(struct intel_guc *guc) + GRAPHICS_VER_FULL(gt->i915) < IP_VER(12, 50)) + flags |= GUC_WA_POLLCS; + +- /* Wa_16011759253:dg2_g10:a0 */ +- if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_B0)) +- flags |= GUC_WA_GAM_CREDITS; +- + /* Wa_14014475959 */ +- if (IS_MTL_GRAPHICS_STEP(gt->i915, M, STEP_A0, STEP_B0) || ++ if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || + IS_DG2(gt->i915)) + flags |= GUC_WA_HOLD_CCS_SWITCHOUT; + + /* +- * Wa_14012197797:dg2_g10:a0,dg2_g11:a0 +- * Wa_22011391025:dg2_g10,dg2_g11,dg2_g12 ++ * Wa_14012197797 ++ * Wa_22011391025 + * + * The same WA bit is used for both and 22011391025 is applicable to + * all DG2. +@@ -292,22 +288,14 @@ static u32 guc_ctl_wa_flags(struct intel_guc *guc) + flags |= GUC_WA_DUAL_QUEUE; + + /* Wa_22011802037: graphics version 11/12 */ +- if (IS_MTL_GRAPHICS_STEP(gt->i915, M, STEP_A0, STEP_B0) || +- (GRAPHICS_VER(gt->i915) >= 11 && +- GRAPHICS_VER_FULL(gt->i915) < IP_VER(12, 70))) ++ if (intel_engine_reset_needs_wa_22011802037(gt)) + flags |= GUC_WA_PRE_PARSER; + +- /* Wa_16011777198:dg2 */ +- if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_C0) || +- IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_B0)) +- flags |= GUC_WA_RCS_RESET_BEFORE_RC6; +- + /* +- * Wa_22012727170:dg2_g10[a0-c0), dg2_g11[a0..) +- * Wa_22012727685:dg2_g11[a0..) ++ * Wa_22012727170 ++ * Wa_22012727685 + */ +- if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_C0) || +- IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_FOREVER)) ++ if (IS_DG2_G11(gt->i915)) + flags |= GUC_WA_CONTEXT_ISOLATION; + + /* Wa_16015675438 */ +diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +index dc7b40e06e38af..236dfff81fea43 100644 +--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c ++++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +@@ -1690,9 +1690,7 @@ static void guc_engine_reset_prepare(struct intel_engine_cs *engine) + * Wa_22011802037: In addition to stopping the cs, we need + * to wait for any pending mi force wakeups + */ +- if (IS_MTL_GRAPHICS_STEP(engine->i915, M, STEP_A0, STEP_B0) || +- (GRAPHICS_VER(engine->i915) >= 11 && +- GRAPHICS_VER_FULL(engine->i915) < IP_VER(12, 70))) { ++ if (intel_engine_reset_needs_wa_22011802037(engine->gt)) { + intel_engine_stop_cs(engine); + intel_engine_wait_for_pending_mi_fw(engine); + } +@@ -2697,9 +2695,9 @@ static void prepare_context_registration_info_v70(struct intel_context *ce, + ce->parallel.guc.wqi_tail = 0; + ce->parallel.guc.wqi_head = 0; + +- wq_desc_offset = i915_ggtt_offset(ce->state) + ++ wq_desc_offset = (u64)i915_ggtt_offset(ce->state) + + __get_parent_scratch_offset(ce); +- wq_base_offset = i915_ggtt_offset(ce->state) + ++ wq_base_offset = (u64)i915_ggtt_offset(ce->state) + + __get_wq_offset(ce); + info->wq_desc_lo = lower_32_bits(wq_desc_offset); + info->wq_desc_hi = upper_32_bits(wq_desc_offset); +@@ -4299,7 +4297,7 @@ static void guc_default_vfuncs(struct intel_engine_cs *engine) + + /* Wa_14014475959:dg2 */ + if (engine->class == COMPUTE_CLASS) +- if (IS_MTL_GRAPHICS_STEP(engine->i915, M, STEP_A0, STEP_B0) || ++ if (IS_GFX_GT_IP_STEP(engine->gt, IP_VER(12, 70), STEP_A0, STEP_B0) || + IS_DG2(engine->i915)) + engine->flags |= I915_ENGINE_USES_WA_HOLD_CCS_SWITCHOUT; + +@@ -4774,7 +4772,8 @@ static void capture_error_state(struct intel_guc *guc, + if (match) { + intel_engine_set_hung_context(e, ce); + engine_mask |= e->mask; +- atomic_inc(&i915->gpu_error.reset_engine_count[e->uabi_class]); ++ i915_increase_reset_engine_count(&i915->gpu_error, ++ e); + } + } + +@@ -4786,7 +4785,7 @@ static void capture_error_state(struct intel_guc *guc, + } else { + intel_engine_set_hung_context(ce->engine, ce); + engine_mask = ce->engine->mask; +- atomic_inc(&i915->gpu_error.reset_engine_count[ce->engine->uabi_class]); ++ i915_increase_reset_engine_count(&i915->gpu_error, ce->engine); + } + + with_intel_runtime_pm(&i915->runtime_pm, wakeref) +diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h +index 9a431726c8d5b1..ac7b3aad2222e8 100644 +--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h ++++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h +@@ -258,6 +258,11 @@ static inline bool intel_uc_fw_is_running(struct intel_uc_fw *uc_fw) + return __intel_uc_fw_status(uc_fw) == INTEL_UC_FIRMWARE_RUNNING; + } + ++static inline bool intel_uc_fw_is_in_error(struct intel_uc_fw *uc_fw) ++{ ++ return intel_uc_fw_status_to_error(__intel_uc_fw_status(uc_fw)) != 0; ++} ++ + static inline bool intel_uc_fw_is_overridden(const struct intel_uc_fw *uc_fw) + { + return uc_fw->user_overridden; +diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c +index a9f7fa9b90bdad..d30f8814d9b106 100644 +--- a/drivers/gpu/drm/i915/gvt/handlers.c ++++ b/drivers/gpu/drm/i915/gvt/handlers.c +@@ -2850,8 +2850,7 @@ static int handle_mmio(struct intel_gvt_mmio_table_iter *iter, u32 offset, + for (i = start; i < end; i += 4) { + p = intel_gvt_find_mmio_info(gvt, i); + if (p) { +- WARN(1, "dup mmio definition offset %x\n", +- info->offset); ++ WARN(1, "dup mmio definition offset %x\n", i); + + /* We return -EEXIST here to make GVT-g load fail. + * So duplicated MMIO can be found as soon as +diff --git a/drivers/gpu/drm/i915/gvt/interrupt.c b/drivers/gpu/drm/i915/gvt/interrupt.c +index 68eca023bbc68b..80301472ac9881 100644 +--- a/drivers/gpu/drm/i915/gvt/interrupt.c ++++ b/drivers/gpu/drm/i915/gvt/interrupt.c +@@ -405,7 +405,7 @@ static void init_irq_map(struct intel_gvt_irq *irq) + #define MSI_CAP_DATA(offset) (offset + 8) + #define MSI_CAP_EN 0x1 + +-static int inject_virtual_interrupt(struct intel_vgpu *vgpu) ++static void inject_virtual_interrupt(struct intel_vgpu *vgpu) + { + unsigned long offset = vgpu->gvt->device_info.msi_cap_offset; + u16 control, data; +@@ -417,10 +417,10 @@ static int inject_virtual_interrupt(struct intel_vgpu *vgpu) + + /* Do not generate MSI if MSIEN is disabled */ + if (!(control & MSI_CAP_EN)) +- return 0; ++ return; + + if (WARN(control & GENMASK(15, 1), "only support one MSI format\n")) +- return -EINVAL; ++ return; + + trace_inject_msi(vgpu->id, addr, data); + +@@ -434,10 +434,9 @@ static int inject_virtual_interrupt(struct intel_vgpu *vgpu) + * returned and don't inject interrupt into guest. + */ + if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) +- return -ESRCH; +- if (vgpu->msi_trigger && eventfd_signal(vgpu->msi_trigger, 1) != 1) +- return -EFAULT; +- return 0; ++ return; ++ if (vgpu->msi_trigger) ++ eventfd_signal(vgpu->msi_trigger, 1); + } + + static void propagate_event(struct intel_gvt_irq *irq, +diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c +index 4de44cf1026dce..7a90a2e32c9f1b 100644 +--- a/drivers/gpu/drm/i915/i915_debugfs.c ++++ b/drivers/gpu/drm/i915/i915_debugfs.c +@@ -144,7 +144,7 @@ static const char *i915_cache_level_str(struct drm_i915_gem_object *obj) + { + struct drm_i915_private *i915 = obj_to_i915(obj); + +- if (IS_METEORLAKE(i915)) { ++ if (IS_GFX_GT_IP_RANGE(to_gt(i915), IP_VER(12, 70), IP_VER(12, 71))) { + switch (obj->pat_index) { + case 0: return " WB"; + case 1: return " WT"; +diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c +index ec4d26b3c17cc1..8dc5f85b7747b4 100644 +--- a/drivers/gpu/drm/i915/i915_driver.c ++++ b/drivers/gpu/drm/i915/i915_driver.c +@@ -777,7 +777,7 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + + ret = i915_driver_mmio_probe(i915); + if (ret < 0) +- goto out_tiles_cleanup; ++ goto out_runtime_pm_put; + + ret = i915_driver_hw_probe(i915); + if (ret < 0) +@@ -837,8 +837,6 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + i915_ggtt_driver_late_release(i915); + out_cleanup_mmio: + i915_driver_mmio_release(i915); +-out_tiles_cleanup: +- intel_gt_release_all(i915); + out_runtime_pm_put: + enable_rpm_wakeref_asserts(&i915->runtime_pm); + i915_driver_late_release(i915); +diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h +index 7a8ce7239bc9e3..e0e0493d6c1f0d 100644 +--- a/drivers/gpu/drm/i915/i915_drv.h ++++ b/drivers/gpu/drm/i915/i915_drv.h +@@ -658,10 +658,6 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, + #define IS_XEHPSDV_GRAPHICS_STEP(__i915, since, until) \ + (IS_XEHPSDV(__i915) && IS_GRAPHICS_STEP(__i915, since, until)) + +-#define IS_MTL_GRAPHICS_STEP(__i915, variant, since, until) \ +- (IS_SUBPLATFORM(__i915, INTEL_METEORLAKE, INTEL_SUBPLATFORM_##variant) && \ +- IS_GRAPHICS_STEP(__i915, since, until)) +- + #define IS_MTL_DISPLAY_STEP(__i915, since, until) \ + (IS_METEORLAKE(__i915) && \ + IS_DISPLAY_STEP(__i915, since, until)) +diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h +index 9f5971f5e98014..48f6c00402c47a 100644 +--- a/drivers/gpu/drm/i915/i915_gpu_error.h ++++ b/drivers/gpu/drm/i915/i915_gpu_error.h +@@ -16,6 +16,7 @@ + + #include "display/intel_display_device.h" + #include "gt/intel_engine.h" ++#include "gt/intel_engine_types.h" + #include "gt/intel_gt_types.h" + #include "gt/uc/intel_uc_fw.h" + +@@ -232,7 +233,7 @@ struct i915_gpu_error { + atomic_t reset_count; + + /** Number of times an engine has been reset */ +- atomic_t reset_engine_count[I915_NUM_ENGINES]; ++ atomic_t reset_engine_count[MAX_ENGINE_CLASS]; + }; + + struct drm_i915_error_state_buf { +@@ -255,7 +256,14 @@ static inline u32 i915_reset_count(struct i915_gpu_error *error) + static inline u32 i915_reset_engine_count(struct i915_gpu_error *error, + const struct intel_engine_cs *engine) + { +- return atomic_read(&error->reset_engine_count[engine->uabi_class]); ++ return atomic_read(&error->reset_engine_count[engine->class]); ++} ++ ++static inline void ++i915_increase_reset_engine_count(struct i915_gpu_error *error, ++ const struct intel_engine_cs *engine) ++{ ++ atomic_inc(&error->reset_engine_count[engine->class]); + } + + #define CORE_DUMP_FLAG_NONE 0x0 +diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c +index 975da8e7f2a9f8..c0662a022f59c1 100644 +--- a/drivers/gpu/drm/i915/i915_hwmon.c ++++ b/drivers/gpu/drm/i915/i915_hwmon.c +@@ -72,12 +72,13 @@ hwm_locked_with_pm_intel_uncore_rmw(struct hwm_drvdata *ddat, + struct intel_uncore *uncore = ddat->uncore; + intel_wakeref_t wakeref; + +- mutex_lock(&hwmon->hwmon_lock); ++ with_intel_runtime_pm(uncore->rpm, wakeref) { ++ mutex_lock(&hwmon->hwmon_lock); + +- with_intel_runtime_pm(uncore->rpm, wakeref) + intel_uncore_rmw(uncore, reg, clear, set); + +- mutex_unlock(&hwmon->hwmon_lock); ++ mutex_unlock(&hwmon->hwmon_lock); ++ } + } + + /* +@@ -136,20 +137,21 @@ hwm_energy(struct hwm_drvdata *ddat, long *energy) + else + rgaddr = hwmon->rg.energy_status_all; + +- mutex_lock(&hwmon->hwmon_lock); ++ with_intel_runtime_pm(uncore->rpm, wakeref) { ++ mutex_lock(&hwmon->hwmon_lock); + +- with_intel_runtime_pm(uncore->rpm, wakeref) + reg_val = intel_uncore_read(uncore, rgaddr); + +- if (reg_val >= ei->reg_val_prev) +- ei->accum_energy += reg_val - ei->reg_val_prev; +- else +- ei->accum_energy += UINT_MAX - ei->reg_val_prev + reg_val; +- ei->reg_val_prev = reg_val; ++ if (reg_val >= ei->reg_val_prev) ++ ei->accum_energy += reg_val - ei->reg_val_prev; ++ else ++ ei->accum_energy += UINT_MAX - ei->reg_val_prev + reg_val; ++ ei->reg_val_prev = reg_val; + +- *energy = mul_u64_u32_shr(ei->accum_energy, SF_ENERGY, +- hwmon->scl_shift_energy); +- mutex_unlock(&hwmon->hwmon_lock); ++ *energy = mul_u64_u32_shr(ei->accum_energy, SF_ENERGY, ++ hwmon->scl_shift_energy); ++ mutex_unlock(&hwmon->hwmon_lock); ++ } + } + + static ssize_t +@@ -175,7 +177,7 @@ hwm_power1_max_interval_show(struct device *dev, struct device_attribute *attr, + * tau4 = (4 | x) << y + * but add 2 when doing the final right shift to account for units + */ +- tau4 = ((1 << x_w) | x) << y; ++ tau4 = (u64)((1 << x_w) | x) << y; + /* val in hwmon interface units (millisec) */ + out = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w); + +@@ -211,7 +213,7 @@ hwm_power1_max_interval_store(struct device *dev, + r = FIELD_PREP(PKG_MAX_WIN, PKG_MAX_WIN_DEFAULT); + x = REG_FIELD_GET(PKG_MAX_WIN_X, r); + y = REG_FIELD_GET(PKG_MAX_WIN_Y, r); +- tau4 = ((1 << x_w) | x) << y; ++ tau4 = (u64)((1 << x_w) | x) << y; + max_win = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w); + + if (val > max_win) +@@ -404,6 +406,7 @@ hwm_power_max_write(struct hwm_drvdata *ddat, long val) + + /* Block waiting for GuC reset to complete when needed */ + for (;;) { ++ wakeref = intel_runtime_pm_get(ddat->uncore->rpm); + mutex_lock(&hwmon->hwmon_lock); + + prepare_to_wait(&ddat->waitq, &wait, TASK_INTERRUPTIBLE); +@@ -417,14 +420,13 @@ hwm_power_max_write(struct hwm_drvdata *ddat, long val) + } + + mutex_unlock(&hwmon->hwmon_lock); ++ intel_runtime_pm_put(ddat->uncore->rpm, wakeref); + + schedule(); + } + finish_wait(&ddat->waitq, &wait); + if (ret) +- goto unlock; +- +- wakeref = intel_runtime_pm_get(ddat->uncore->rpm); ++ goto exit; + + /* Disable PL1 limit and verify, because the limit cannot be disabled on all platforms */ + if (val == PL1_DISABLE) { +@@ -444,9 +446,8 @@ hwm_power_max_write(struct hwm_drvdata *ddat, long val) + intel_uncore_rmw(ddat->uncore, hwmon->rg.pkg_rapl_limit, + PKG_PWR_LIM_1_EN | PKG_PWR_LIM_1, nval); + exit: +- intel_runtime_pm_put(ddat->uncore->rpm, wakeref); +-unlock: + mutex_unlock(&hwmon->hwmon_lock); ++ intel_runtime_pm_put(ddat->uncore->rpm, wakeref); + return ret; + } + +@@ -792,7 +793,7 @@ void i915_hwmon_register(struct drm_i915_private *i915) + if (!IS_DGFX(i915)) + return; + +- hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL); ++ hwmon = kzalloc(sizeof(*hwmon), GFP_KERNEL); + if (!hwmon) + return; + +@@ -818,14 +819,12 @@ void i915_hwmon_register(struct drm_i915_private *i915) + hwm_get_preregistration_info(i915); + + /* hwmon_dev points to device hwmon */ +- hwmon_dev = devm_hwmon_device_register_with_info(dev, ddat->name, +- ddat, +- &hwm_chip_info, +- hwm_groups); +- if (IS_ERR(hwmon_dev)) { +- i915->hwmon = NULL; +- return; +- } ++ hwmon_dev = hwmon_device_register_with_info(dev, ddat->name, ++ ddat, ++ &hwm_chip_info, ++ hwm_groups); ++ if (IS_ERR(hwmon_dev)) ++ goto err; + + ddat->hwmon_dev = hwmon_dev; + +@@ -838,16 +837,36 @@ void i915_hwmon_register(struct drm_i915_private *i915) + if (!hwm_gt_is_visible(ddat_gt, hwmon_energy, hwmon_energy_input, 0)) + continue; + +- hwmon_dev = devm_hwmon_device_register_with_info(dev, ddat_gt->name, +- ddat_gt, +- &hwm_gt_chip_info, +- NULL); ++ hwmon_dev = hwmon_device_register_with_info(dev, ddat_gt->name, ++ ddat_gt, ++ &hwm_gt_chip_info, ++ NULL); + if (!IS_ERR(hwmon_dev)) + ddat_gt->hwmon_dev = hwmon_dev; + } ++ return; ++err: ++ i915_hwmon_unregister(i915); + } + + void i915_hwmon_unregister(struct drm_i915_private *i915) + { +- fetch_and_zero(&i915->hwmon); ++ struct i915_hwmon *hwmon = i915->hwmon; ++ struct intel_gt *gt; ++ int i; ++ ++ if (!hwmon) ++ return; ++ ++ for_each_gt(gt, i915, i) ++ if (hwmon->ddat_gt[i].hwmon_dev) ++ hwmon_device_unregister(hwmon->ddat_gt[i].hwmon_dev); ++ ++ if (hwmon->ddat.hwmon_dev) ++ hwmon_device_unregister(hwmon->ddat.hwmon_dev); ++ ++ mutex_destroy(&hwmon->hwmon_lock); ++ ++ kfree(i915->hwmon); ++ i915->hwmon = NULL; + } +diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c +index 59e1e21df27104..0808b54d3c5185 100644 +--- a/drivers/gpu/drm/i915/i915_perf.c ++++ b/drivers/gpu/drm/i915/i915_perf.c +@@ -785,10 +785,6 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream, + * The reason field includes flags identifying what + * triggered this specific report (mostly timer + * triggered or e.g. due to a context switch). +- * +- * In MMIO triggered reports, some platforms do not set the +- * reason bit in this field and it is valid to have a reason +- * field of zero. + */ + reason = oa_report_reason(stream, report); + ctx_id = oa_context_id(stream, report32); +@@ -800,8 +796,41 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream, + * + * Note: that we don't clear the valid_ctx_bit so userspace can + * understand that the ID has been squashed by the kernel. ++ * ++ * Update: ++ * ++ * On XEHP platforms the behavior of context id valid bit has ++ * changed compared to prior platforms. To describe this, we ++ * define a few terms: ++ * ++ * context-switch-report: This is a report with the reason type ++ * being context-switch. It is generated when a context switches ++ * out. ++ * ++ * context-valid-bit: A bit that is set in the report ID field ++ * to indicate that a valid context has been loaded. ++ * ++ * gpu-idle: A condition characterized by a ++ * context-switch-report with context-valid-bit set to 0. ++ * ++ * On prior platforms, context-id-valid bit is set to 0 only ++ * when GPU goes idle. In all other reports, it is set to 1. ++ * ++ * On XEHP platforms, context-valid-bit is set to 1 in a context ++ * switch report if a new context switched in. For all other ++ * reports it is set to 0. ++ * ++ * This change in behavior causes an issue with MMIO triggered ++ * reports. MMIO triggered reports have the markers in the ++ * context ID field and the context-valid-bit is 0. The logic ++ * below to squash the context ID would render the report ++ * useless since the user will not be able to find it in the OA ++ * buffer. Since MMIO triggered reports exist only on XEHP, ++ * we should avoid squashing these for XEHP platforms. + */ +- if (oa_report_ctx_invalid(stream, report)) { ++ ++ if (oa_report_ctx_invalid(stream, report) && ++ GRAPHICS_VER_FULL(stream->engine->i915) < IP_VER(12, 50)) { + ctx_id = INVALID_CTX_ID; + oa_context_id_squash(stream, report32); + } +@@ -2752,26 +2781,6 @@ oa_configure_all_contexts(struct i915_perf_stream *stream, + return 0; + } + +-static int +-gen12_configure_all_contexts(struct i915_perf_stream *stream, +- const struct i915_oa_config *oa_config, +- struct i915_active *active) +-{ +- struct flex regs[] = { +- { +- GEN8_R_PWR_CLK_STATE(RENDER_RING_BASE), +- CTX_R_PWR_CLK_STATE, +- }, +- }; +- +- if (stream->engine->class != RENDER_CLASS) +- return 0; +- +- return oa_configure_all_contexts(stream, +- regs, ARRAY_SIZE(regs), +- active); +-} +- + static int + lrc_configure_all_contexts(struct i915_perf_stream *stream, + const struct i915_oa_config *oa_config, +@@ -2878,7 +2887,6 @@ gen12_enable_metric_set(struct i915_perf_stream *stream, + { + struct drm_i915_private *i915 = stream->perf->i915; + struct intel_uncore *uncore = stream->uncore; +- struct i915_oa_config *oa_config = stream->oa_config; + bool periodic = stream->periodic; + u32 period_exponent = stream->period_exponent; + u32 sqcnt1; +@@ -2922,15 +2930,6 @@ gen12_enable_metric_set(struct i915_perf_stream *stream, + + intel_uncore_rmw(uncore, GEN12_SQCNT1, 0, sqcnt1); + +- /* +- * Update all contexts prior writing the mux configurations as we need +- * to make sure all slices/subslices are ON before writing to NOA +- * registers. +- */ +- ret = gen12_configure_all_contexts(stream, oa_config, active); +- if (ret) +- return ret; +- + /* + * For Gen12, performance counters are context + * saved/restored. Only enable it for the context that +@@ -2985,9 +2984,6 @@ static void gen12_disable_metric_set(struct i915_perf_stream *stream) + _MASKED_BIT_DISABLE(GEN12_DISABLE_DOP_GATING)); + } + +- /* Reset all contexts' slices/subslices configurations. */ +- gen12_configure_all_contexts(stream, NULL, NULL); +- + /* disable the context save/restore or OAR counters */ + if (stream->ctx) + gen12_configure_oar_context(stream, NULL); +@@ -3226,11 +3222,10 @@ get_sseu_config(struct intel_sseu *out_sseu, + */ + u32 i915_perf_oa_timestamp_frequency(struct drm_i915_private *i915) + { +- /* +- * Wa_18013179988:dg2 +- * Wa_14015846243:mtl +- */ +- if (IS_DG2(i915) || IS_METEORLAKE(i915)) { ++ struct intel_gt *gt = to_gt(i915); ++ ++ /* Wa_18013179988 */ ++ if (IS_DG2(i915) || IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 74))) { + intel_wakeref_t wakeref; + u32 reg, shift; + +@@ -4286,11 +4281,8 @@ int i915_perf_open_ioctl(struct drm_device *dev, void *data, + u32 known_open_flags; + int ret; + +- if (!perf->i915) { +- drm_dbg(&perf->i915->drm, +- "i915 perf interface not available for this system\n"); ++ if (!perf->i915) + return -ENOTSUPP; +- } + + known_open_flags = I915_PERF_FLAG_FD_CLOEXEC | + I915_PERF_FLAG_FD_NONBLOCK | +@@ -4538,7 +4530,7 @@ static bool xehp_is_valid_b_counter_addr(struct i915_perf *perf, u32 addr) + + static bool gen12_is_valid_mux_addr(struct i915_perf *perf, u32 addr) + { +- if (IS_METEORLAKE(perf->i915)) ++ if (GRAPHICS_VER_FULL(perf->i915) >= IP_VER(12, 70)) + return reg_in_range_table(addr, mtl_oa_mux_regs); + else + return reg_in_range_table(addr, gen12_oa_mux_regs); +@@ -4666,11 +4658,8 @@ int i915_perf_add_config_ioctl(struct drm_device *dev, void *data, + struct i915_oa_reg *regs; + int err, id; + +- if (!perf->i915) { +- drm_dbg(&perf->i915->drm, +- "i915 perf interface not available for this system\n"); ++ if (!perf->i915) + return -ENOTSUPP; +- } + + if (!perf->metrics_kobj) { + drm_dbg(&perf->i915->drm, +@@ -4832,11 +4821,8 @@ int i915_perf_remove_config_ioctl(struct drm_device *dev, void *data, + struct i915_oa_config *oa_config; + int ret; + +- if (!perf->i915) { +- drm_dbg(&perf->i915->drm, +- "i915 perf interface not available for this system\n"); ++ if (!perf->i915) + return -ENOTSUPP; +- } + + if (i915_perf_stream_paranoid && !perfmon_capable()) { + drm_dbg(&perf->i915->drm, +diff --git a/drivers/gpu/drm/i915/i915_sw_fence.c b/drivers/gpu/drm/i915/i915_sw_fence.c +index 8a9aad523eec2c..1d4cc91c0e40d5 100644 +--- a/drivers/gpu/drm/i915/i915_sw_fence.c ++++ b/drivers/gpu/drm/i915/i915_sw_fence.c +@@ -51,7 +51,7 @@ static inline void debug_fence_init(struct i915_sw_fence *fence) + debug_object_init(fence, &i915_sw_fence_debug_descr); + } + +-static inline void debug_fence_init_onstack(struct i915_sw_fence *fence) ++static inline __maybe_unused void debug_fence_init_onstack(struct i915_sw_fence *fence) + { + debug_object_init_on_stack(fence, &i915_sw_fence_debug_descr); + } +@@ -77,7 +77,7 @@ static inline void debug_fence_destroy(struct i915_sw_fence *fence) + debug_object_destroy(fence, &i915_sw_fence_debug_descr); + } + +-static inline void debug_fence_free(struct i915_sw_fence *fence) ++static inline __maybe_unused void debug_fence_free(struct i915_sw_fence *fence) + { + debug_object_free(fence, &i915_sw_fence_debug_descr); + smp_wmb(); /* flush the change in state before reallocation */ +@@ -94,7 +94,7 @@ static inline void debug_fence_init(struct i915_sw_fence *fence) + { + } + +-static inline void debug_fence_init_onstack(struct i915_sw_fence *fence) ++static inline __maybe_unused void debug_fence_init_onstack(struct i915_sw_fence *fence) + { + } + +@@ -115,7 +115,7 @@ static inline void debug_fence_destroy(struct i915_sw_fence *fence) + { + } + +-static inline void debug_fence_free(struct i915_sw_fence *fence) ++static inline __maybe_unused void debug_fence_free(struct i915_sw_fence *fence) + { + } + +diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c +index 6f180ee138531d..46e4a45e3c72ae 100644 +--- a/drivers/gpu/drm/i915/i915_vma.c ++++ b/drivers/gpu/drm/i915/i915_vma.c +@@ -33,6 +33,7 @@ + #include "gt/intel_engine.h" + #include "gt/intel_engine_heartbeat.h" + #include "gt/intel_gt.h" ++#include "gt/intel_gt_pm.h" + #include "gt/intel_gt_requests.h" + #include "gt/intel_tlb.h" + +@@ -102,12 +103,34 @@ static inline struct i915_vma *active_to_vma(struct i915_active *ref) + + static int __i915_vma_active(struct i915_active *ref) + { +- return i915_vma_tryget(active_to_vma(ref)) ? 0 : -ENOENT; ++ struct i915_vma *vma = active_to_vma(ref); ++ ++ if (!i915_vma_tryget(vma)) ++ return -ENOENT; ++ ++ /* ++ * Exclude global GTT VMA from holding a GT wakeref ++ * while active, otherwise GPU never goes idle. ++ */ ++ if (!i915_vma_is_ggtt(vma)) ++ intel_gt_pm_get(vma->vm->gt); ++ ++ return 0; + } + + static void __i915_vma_retire(struct i915_active *ref) + { +- i915_vma_put(active_to_vma(ref)); ++ struct i915_vma *vma = active_to_vma(ref); ++ ++ if (!i915_vma_is_ggtt(vma)) { ++ /* ++ * Since we can be called from atomic contexts, ++ * use an async variant of intel_gt_pm_put(). ++ */ ++ intel_gt_pm_put_async(vma->vm->gt); ++ } ++ ++ i915_vma_put(vma); + } + + static struct i915_vma * +@@ -1403,7 +1426,7 @@ int i915_vma_pin_ww(struct i915_vma *vma, struct i915_gem_ww_ctx *ww, + struct i915_vma_work *work = NULL; + struct dma_fence *moving = NULL; + struct i915_vma_resource *vma_res = NULL; +- intel_wakeref_t wakeref = 0; ++ intel_wakeref_t wakeref; + unsigned int bound; + int err; + +@@ -1423,8 +1446,14 @@ int i915_vma_pin_ww(struct i915_vma *vma, struct i915_gem_ww_ctx *ww, + if (err) + return err; + +- if (flags & PIN_GLOBAL) +- wakeref = intel_runtime_pm_get(&vma->vm->i915->runtime_pm); ++ /* ++ * In case of a global GTT, we must hold a runtime-pm wakeref ++ * while global PTEs are updated. In other cases, we hold ++ * the rpm reference while the VMA is active. Since runtime ++ * resume may require allocations, which are forbidden inside ++ * vm->mutex, get the first rpm wakeref outside of the mutex. ++ */ ++ wakeref = intel_runtime_pm_get(&vma->vm->i915->runtime_pm); + + if (flags & vma->vm->bind_async_flags) { + /* lock VM */ +@@ -1560,8 +1589,7 @@ int i915_vma_pin_ww(struct i915_vma *vma, struct i915_gem_ww_ctx *ww, + if (work) + dma_fence_work_commit_imm(&work->base); + err_rpm: +- if (wakeref) +- intel_runtime_pm_put(&vma->vm->i915->runtime_pm, wakeref); ++ intel_runtime_pm_put(&vma->vm->i915->runtime_pm, wakeref); + + if (moving) + dma_fence_put(moving); +diff --git a/drivers/gpu/drm/i915/intel_clock_gating.c b/drivers/gpu/drm/i915/intel_clock_gating.c +index 81a4d32734e946..c66eb6abd4a2ee 100644 +--- a/drivers/gpu/drm/i915/intel_clock_gating.c ++++ b/drivers/gpu/drm/i915/intel_clock_gating.c +@@ -396,14 +396,6 @@ static void dg2_init_clock_gating(struct drm_i915_private *i915) + /* Wa_22010954014:dg2 */ + intel_uncore_rmw(&i915->uncore, XEHP_CLOCK_GATE_DIS, 0, + SGSI_SIDECLK_DIS); +- +- /* +- * Wa_14010733611:dg2_g10 +- * Wa_22010146351:dg2_g10 +- */ +- if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) +- intel_uncore_rmw(&i915->uncore, XEHP_CLOCK_GATE_DIS, 0, +- SGR_DIS | SGGI_DIS); + } + + static void pvc_init_clock_gating(struct drm_i915_private *i915) +diff --git a/drivers/gpu/drm/i915/selftests/igt_live_test.c b/drivers/gpu/drm/i915/selftests/igt_live_test.c +index 4ddc6d902752af..7d41874a49c589 100644 +--- a/drivers/gpu/drm/i915/selftests/igt_live_test.c ++++ b/drivers/gpu/drm/i915/selftests/igt_live_test.c +@@ -37,8 +37,9 @@ int igt_live_test_begin(struct igt_live_test *t, + } + + for_each_engine(engine, gt, id) +- t->reset_engine[id] = +- i915_reset_engine_count(&i915->gpu_error, engine); ++ t->reset_engine[i][id] = ++ i915_reset_engine_count(&i915->gpu_error, ++ engine); + } + + t->reset_global = i915_reset_count(&i915->gpu_error); +@@ -66,14 +67,14 @@ int igt_live_test_end(struct igt_live_test *t) + + for_each_gt(gt, i915, i) { + for_each_engine(engine, gt, id) { +- if (t->reset_engine[id] == ++ if (t->reset_engine[i][id] == + i915_reset_engine_count(&i915->gpu_error, engine)) + continue; + + gt_err(gt, "%s(%s): engine '%s' was reset %d times!\n", + t->func, t->name, engine->name, + i915_reset_engine_count(&i915->gpu_error, engine) - +- t->reset_engine[id]); ++ t->reset_engine[i][id]); + return -EIO; + } + } +diff --git a/drivers/gpu/drm/i915/selftests/igt_live_test.h b/drivers/gpu/drm/i915/selftests/igt_live_test.h +index 36ed42736c5216..83e3ad430922fe 100644 +--- a/drivers/gpu/drm/i915/selftests/igt_live_test.h ++++ b/drivers/gpu/drm/i915/selftests/igt_live_test.h +@@ -7,6 +7,7 @@ + #ifndef IGT_LIVE_TEST_H + #define IGT_LIVE_TEST_H + ++#include "gt/intel_gt_defines.h" /* for I915_MAX_GT */ + #include "gt/intel_engine.h" /* for I915_NUM_ENGINES */ + + struct drm_i915_private; +@@ -17,7 +18,7 @@ struct igt_live_test { + const char *name; + + unsigned int reset_global; +- unsigned int reset_engine[I915_NUM_ENGINES]; ++ unsigned int reset_engine[I915_MAX_GT][I915_NUM_ENGINES]; + }; + + /* +diff --git a/drivers/gpu/drm/imx/ipuv3/parallel-display.c b/drivers/gpu/drm/imx/ipuv3/parallel-display.c +index 0fa0b590830b66..c62df2557dc65e 100644 +--- a/drivers/gpu/drm/imx/ipuv3/parallel-display.c ++++ b/drivers/gpu/drm/imx/ipuv3/parallel-display.c +@@ -72,14 +72,14 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) + int ret; + + if (!mode) +- return -EINVAL; ++ return 0; + + ret = of_get_drm_display_mode(np, &imxpd->mode, + &imxpd->bus_flags, + OF_USE_NATIVE_MODE); + if (ret) { + drm_mode_destroy(connector->dev, mode); +- return ret; ++ return 0; + } + + drm_mode_copy(mode, &imxpd->mode); +diff --git a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c +index 22b65f4a0e3034..4beb3b4bd6942c 100644 +--- a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c ++++ b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c +@@ -342,21 +342,12 @@ static const struct drm_mode_config_helper_funcs imx_lcdc_mode_config_helpers = + .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, + }; + +-static void imx_lcdc_release(struct drm_device *drm) +-{ +- struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(drm); +- +- drm_kms_helper_poll_fini(drm); +- kfree(lcdc); +-} +- + DEFINE_DRM_GEM_DMA_FOPS(imx_lcdc_drm_fops); + + static struct drm_driver imx_lcdc_drm_driver = { + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, + .fops = &imx_lcdc_drm_fops, + DRM_GEM_DMA_DRIVER_OPS_VMAP, +- .release = imx_lcdc_release, + .name = "imx-lcdc", + .desc = "i.MX LCDC driver", + .date = "20200716", +diff --git a/drivers/gpu/drm/lima/lima_bcast.c b/drivers/gpu/drm/lima/lima_bcast.c +index fbc43f243c54d2..6d000504e1a4ee 100644 +--- a/drivers/gpu/drm/lima/lima_bcast.c ++++ b/drivers/gpu/drm/lima/lima_bcast.c +@@ -43,6 +43,18 @@ void lima_bcast_suspend(struct lima_ip *ip) + + } + ++int lima_bcast_mask_irq(struct lima_ip *ip) ++{ ++ bcast_write(LIMA_BCAST_BROADCAST_MASK, 0); ++ bcast_write(LIMA_BCAST_INTERRUPT_MASK, 0); ++ return 0; ++} ++ ++int lima_bcast_reset(struct lima_ip *ip) ++{ ++ return lima_bcast_hw_init(ip); ++} ++ + int lima_bcast_init(struct lima_ip *ip) + { + int i; +diff --git a/drivers/gpu/drm/lima/lima_bcast.h b/drivers/gpu/drm/lima/lima_bcast.h +index 465ee587bceb2f..cd08841e47879c 100644 +--- a/drivers/gpu/drm/lima/lima_bcast.h ++++ b/drivers/gpu/drm/lima/lima_bcast.h +@@ -13,4 +13,7 @@ void lima_bcast_fini(struct lima_ip *ip); + + void lima_bcast_enable(struct lima_device *dev, int num_pp); + ++int lima_bcast_mask_irq(struct lima_ip *ip); ++int lima_bcast_reset(struct lima_ip *ip); ++ + #endif +diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c +index 10fd9154cc4653..8c9b656eeb59d2 100644 +--- a/drivers/gpu/drm/lima/lima_drv.c ++++ b/drivers/gpu/drm/lima/lima_drv.c +@@ -486,3 +486,4 @@ module_platform_driver(lima_platform_driver); + MODULE_AUTHOR("Lima Project Developers"); + MODULE_DESCRIPTION("Lima DRM Driver"); + MODULE_LICENSE("GPL v2"); ++MODULE_SOFTDEP("pre: governor_simpleondemand"); +diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c +index 4f9736e5f929be..7ea244d876ca63 100644 +--- a/drivers/gpu/drm/lima/lima_gem.c ++++ b/drivers/gpu/drm/lima/lima_gem.c +@@ -75,29 +75,34 @@ int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm) + } else { + bo->base.sgt = kmalloc(sizeof(*bo->base.sgt), GFP_KERNEL); + if (!bo->base.sgt) { +- sg_free_table(&sgt); +- return -ENOMEM; ++ ret = -ENOMEM; ++ goto err_out0; + } + } + + ret = dma_map_sgtable(dev, &sgt, DMA_BIDIRECTIONAL, 0); +- if (ret) { +- sg_free_table(&sgt); +- kfree(bo->base.sgt); +- bo->base.sgt = NULL; +- return ret; +- } ++ if (ret) ++ goto err_out1; + + *bo->base.sgt = sgt; + + if (vm) { + ret = lima_vm_map_bo(vm, bo, old_size >> PAGE_SHIFT); + if (ret) +- return ret; ++ goto err_out2; + } + + bo->heap_size = new_size; + return 0; ++ ++err_out2: ++ dma_unmap_sgtable(dev, &sgt, DMA_BIDIRECTIONAL, 0); ++err_out1: ++ kfree(bo->base.sgt); ++ bo->base.sgt = NULL; ++err_out0: ++ sg_free_table(&sgt); ++ return ret; + } + + int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file, +diff --git a/drivers/gpu/drm/lima/lima_gp.c b/drivers/gpu/drm/lima/lima_gp.c +index 8dd501b7a3d0d8..82071835ec9ed2 100644 +--- a/drivers/gpu/drm/lima/lima_gp.c ++++ b/drivers/gpu/drm/lima/lima_gp.c +@@ -166,6 +166,11 @@ static void lima_gp_task_run(struct lima_sched_pipe *pipe, + gp_write(LIMA_GP_CMD, cmd); + } + ++static int lima_gp_bus_stop_poll(struct lima_ip *ip) ++{ ++ return !!(gp_read(LIMA_GP_STATUS) & LIMA_GP_STATUS_BUS_STOPPED); ++} ++ + static int lima_gp_hard_reset_poll(struct lima_ip *ip) + { + gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0xC01A0000); +@@ -179,6 +184,13 @@ static int lima_gp_hard_reset(struct lima_ip *ip) + + gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0xC0FFE000); + gp_write(LIMA_GP_INT_MASK, 0); ++ ++ gp_write(LIMA_GP_CMD, LIMA_GP_CMD_STOP_BUS); ++ ret = lima_poll_timeout(ip, lima_gp_bus_stop_poll, 10, 100); ++ if (ret) { ++ dev_err(dev->dev, "%s bus stop timeout\n", lima_ip_name(ip)); ++ return ret; ++ } + gp_write(LIMA_GP_CMD, LIMA_GP_CMD_RESET); + ret = lima_poll_timeout(ip, lima_gp_hard_reset_poll, 10, 100); + if (ret) { +@@ -212,6 +224,13 @@ static void lima_gp_task_mmu_error(struct lima_sched_pipe *pipe) + lima_sched_pipe_task_done(pipe); + } + ++static void lima_gp_task_mask_irq(struct lima_sched_pipe *pipe) ++{ ++ struct lima_ip *ip = pipe->processor[0]; ++ ++ gp_write(LIMA_GP_INT_MASK, 0); ++} ++ + static int lima_gp_task_recover(struct lima_sched_pipe *pipe) + { + struct lima_ip *ip = pipe->processor[0]; +@@ -317,7 +336,9 @@ int lima_gp_init(struct lima_ip *ip) + + void lima_gp_fini(struct lima_ip *ip) + { ++ struct lima_device *dev = ip->dev; + ++ devm_free_irq(dev->dev, ip->irq, ip); + } + + int lima_gp_pipe_init(struct lima_device *dev) +@@ -344,6 +365,7 @@ int lima_gp_pipe_init(struct lima_device *dev) + pipe->task_error = lima_gp_task_error; + pipe->task_mmu_error = lima_gp_task_mmu_error; + pipe->task_recover = lima_gp_task_recover; ++ pipe->task_mask_irq = lima_gp_task_mask_irq; + + return 0; + } +diff --git a/drivers/gpu/drm/lima/lima_mmu.c b/drivers/gpu/drm/lima/lima_mmu.c +index a1ae6c252dc2b5..8ca7047adbaca9 100644 +--- a/drivers/gpu/drm/lima/lima_mmu.c ++++ b/drivers/gpu/drm/lima/lima_mmu.c +@@ -118,7 +118,12 @@ int lima_mmu_init(struct lima_ip *ip) + + void lima_mmu_fini(struct lima_ip *ip) + { ++ struct lima_device *dev = ip->dev; ++ ++ if (ip->id == lima_ip_ppmmu_bcast) ++ return; + ++ devm_free_irq(dev->dev, ip->irq, ip); + } + + void lima_mmu_flush_tlb(struct lima_ip *ip) +diff --git a/drivers/gpu/drm/lima/lima_pp.c b/drivers/gpu/drm/lima/lima_pp.c +index a5c95bed08c09c..d34c9e8840f454 100644 +--- a/drivers/gpu/drm/lima/lima_pp.c ++++ b/drivers/gpu/drm/lima/lima_pp.c +@@ -266,7 +266,9 @@ int lima_pp_init(struct lima_ip *ip) + + void lima_pp_fini(struct lima_ip *ip) + { ++ struct lima_device *dev = ip->dev; + ++ devm_free_irq(dev->dev, ip->irq, ip); + } + + int lima_pp_bcast_resume(struct lima_ip *ip) +@@ -299,7 +301,9 @@ int lima_pp_bcast_init(struct lima_ip *ip) + + void lima_pp_bcast_fini(struct lima_ip *ip) + { ++ struct lima_device *dev = ip->dev; + ++ devm_free_irq(dev->dev, ip->irq, ip); + } + + static int lima_pp_task_validate(struct lima_sched_pipe *pipe, +@@ -408,6 +412,9 @@ static void lima_pp_task_error(struct lima_sched_pipe *pipe) + + lima_pp_hard_reset(ip); + } ++ ++ if (pipe->bcast_processor) ++ lima_bcast_reset(pipe->bcast_processor); + } + + static void lima_pp_task_mmu_error(struct lima_sched_pipe *pipe) +@@ -416,6 +423,20 @@ static void lima_pp_task_mmu_error(struct lima_sched_pipe *pipe) + lima_sched_pipe_task_done(pipe); + } + ++static void lima_pp_task_mask_irq(struct lima_sched_pipe *pipe) ++{ ++ int i; ++ ++ for (i = 0; i < pipe->num_processor; i++) { ++ struct lima_ip *ip = pipe->processor[i]; ++ ++ pp_write(LIMA_PP_INT_MASK, 0); ++ } ++ ++ if (pipe->bcast_processor) ++ lima_bcast_mask_irq(pipe->bcast_processor); ++} ++ + static struct kmem_cache *lima_pp_task_slab; + static int lima_pp_task_slab_refcnt; + +@@ -447,6 +468,7 @@ int lima_pp_pipe_init(struct lima_device *dev) + pipe->task_fini = lima_pp_task_fini; + pipe->task_error = lima_pp_task_error; + pipe->task_mmu_error = lima_pp_task_mmu_error; ++ pipe->task_mask_irq = lima_pp_task_mask_irq; + + return 0; + } +diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c +index ffd91a5ee29901..1114bffe38c837 100644 +--- a/drivers/gpu/drm/lima/lima_sched.c ++++ b/drivers/gpu/drm/lima/lima_sched.c +@@ -402,6 +402,13 @@ static enum drm_gpu_sched_stat lima_sched_timedout_job(struct drm_sched_job *job + struct lima_sched_task *task = to_lima_task(job); + struct lima_device *ldev = pipe->ldev; + ++ /* ++ * The task might still finish while this timeout handler runs. ++ * To prevent a race condition on its completion, mask all irqs ++ * on the running core until the next hard reset completes. ++ */ ++ pipe->task_mask_irq(pipe); ++ + if (!pipe->error) + DRM_ERROR("lima job timeout\n"); + +diff --git a/drivers/gpu/drm/lima/lima_sched.h b/drivers/gpu/drm/lima/lima_sched.h +index 6a11764d87b389..edf205be436998 100644 +--- a/drivers/gpu/drm/lima/lima_sched.h ++++ b/drivers/gpu/drm/lima/lima_sched.h +@@ -80,6 +80,7 @@ struct lima_sched_pipe { + void (*task_error)(struct lima_sched_pipe *pipe); + void (*task_mmu_error)(struct lima_sched_pipe *pipe); + int (*task_recover)(struct lima_sched_pipe *pipe); ++ void (*task_mask_irq)(struct lima_sched_pipe *pipe); + + struct work_struct recover_work; + }; +diff --git a/drivers/gpu/drm/loongson/lsdc_pixpll.c b/drivers/gpu/drm/loongson/lsdc_pixpll.c +index 04c15b4697e218..2609a2256da4bf 100644 +--- a/drivers/gpu/drm/loongson/lsdc_pixpll.c ++++ b/drivers/gpu/drm/loongson/lsdc_pixpll.c +@@ -120,12 +120,14 @@ static int lsdc_pixel_pll_setup(struct lsdc_pixpll * const this) + struct lsdc_pixpll_parms *pparms; + + this->mmio = ioremap(this->reg_base, this->reg_size); +- if (IS_ERR_OR_NULL(this->mmio)) ++ if (!this->mmio) + return -ENOMEM; + + pparms = kzalloc(sizeof(*pparms), GFP_KERNEL); +- if (IS_ERR_OR_NULL(pparms)) ++ if (!pparms) { ++ iounmap(this->mmio); + return -ENOMEM; ++ } + + pparms->ref_clock = LSDC_PLL_REF_CLK_KHZ; + +diff --git a/drivers/gpu/drm/mediatek/mtk_disp_merge.c b/drivers/gpu/drm/mediatek/mtk_disp_merge.c +index e525a6b9e5b0bc..22f768d923d5ab 100644 +--- a/drivers/gpu/drm/mediatek/mtk_disp_merge.c ++++ b/drivers/gpu/drm/mediatek/mtk_disp_merge.c +@@ -103,7 +103,7 @@ void mtk_merge_stop_cmdq(struct device *dev, struct cmdq_pkt *cmdq_pkt) + mtk_ddp_write(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs, + DISP_REG_MERGE_CTRL); + +- if (priv->async_clk) ++ if (!cmdq_pkt && priv->async_clk) + reset_control_reset(priv->reset_ctl); + } + +diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c +index 2bffe424546667..6f15069da8b020 100644 +--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c ++++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c +@@ -38,6 +38,7 @@ + #define DISP_REG_OVL_PITCH_MSB(n) (0x0040 + 0x20 * (n)) + #define OVL_PITCH_MSB_2ND_SUBBUF BIT(16) + #define DISP_REG_OVL_PITCH(n) (0x0044 + 0x20 * (n)) ++#define OVL_CONST_BLEND BIT(28) + #define DISP_REG_OVL_RDMA_CTRL(n) (0x00c0 + 0x20 * (n)) + #define DISP_REG_OVL_RDMA_GMC(n) (0x00c8 + 0x20 * (n)) + #define DISP_REG_OVL_ADDR_MT2701 0x0040 +@@ -71,6 +72,8 @@ + #define OVL_CON_VIRT_FLIP BIT(9) + #define OVL_CON_HORZ_FLIP BIT(10) + ++#define OVL_COLOR_ALPHA GENMASK(31, 24) ++ + static const u32 mt8173_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, +@@ -273,7 +276,13 @@ void mtk_ovl_config(struct device *dev, unsigned int w, + if (w != 0 && h != 0) + mtk_ddp_write_relaxed(cmdq_pkt, h << 16 | w, &ovl->cmdq_reg, ovl->regs, + DISP_REG_OVL_ROI_SIZE); +- mtk_ddp_write_relaxed(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_ROI_BGCLR); ++ ++ /* ++ * The background color must be opaque black (ARGB), ++ * otherwise the alpha blending will have no effect ++ */ ++ mtk_ddp_write_relaxed(cmdq_pkt, OVL_COLOR_ALPHA, &ovl->cmdq_reg, ++ ovl->regs, DISP_REG_OVL_ROI_BGCLR); + + mtk_ddp_write(cmdq_pkt, 0x1, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST); + mtk_ddp_write(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST); +@@ -407,6 +416,7 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx, + unsigned int fmt = pending->format; + unsigned int offset = (pending->y << 16) | pending->x; + unsigned int src_size = (pending->height << 16) | pending->width; ++ unsigned int ignore_pixel_alpha = 0; + unsigned int con; + bool is_afbc = pending->modifier != DRM_FORMAT_MOD_LINEAR; + union overlay_pitch { +@@ -428,6 +438,14 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx, + if (state->base.fb && state->base.fb->format->has_alpha) + con |= OVL_CON_AEN | OVL_CON_ALPHA; + ++ /* CONST_BLD must be enabled for XRGB formats although the alpha channel ++ * can be ignored, or OVL will still read the value from memory. ++ * For RGB888 related formats, whether CONST_BLD is enabled or not won't ++ * affect the result. Therefore we use !has_alpha as the condition. ++ */ ++ if (state->base.fb && !state->base.fb->format->has_alpha) ++ ignore_pixel_alpha = OVL_CONST_BLEND; ++ + if (pending->rotation & DRM_MODE_REFLECT_Y) { + con |= OVL_CON_VIRT_FLIP; + addr += (pending->height - 1) * pending->pitch; +@@ -443,8 +461,8 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx, + + mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl->regs, + DISP_REG_OVL_CON(idx)); +- mtk_ddp_write_relaxed(cmdq_pkt, overlay_pitch.split_pitch.lsb, &ovl->cmdq_reg, ovl->regs, +- DISP_REG_OVL_PITCH(idx)); ++ mtk_ddp_write_relaxed(cmdq_pkt, overlay_pitch.split_pitch.lsb | ignore_pixel_alpha, ++ &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH(idx)); + mtk_ddp_write_relaxed(cmdq_pkt, src_size, &ovl->cmdq_reg, ovl->regs, + DISP_REG_OVL_SRC_SIZE(idx)); + mtk_ddp_write_relaxed(cmdq_pkt, offset, &ovl->cmdq_reg, ovl->regs, +diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c +index 6bf6367853fbae..036028b8f5248d 100644 +--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c ++++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c +@@ -111,7 +111,7 @@ void mtk_ovl_adaptor_layer_config(struct device *dev, unsigned int idx, + merge = ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_MERGE0 + idx]; + ethdr = ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0]; + +- if (!pending->enable) { ++ if (!pending->enable || !pending->width || !pending->height) { + mtk_merge_stop_cmdq(merge, cmdq_pkt); + mtk_mdp_rdma_stop(rdma_l, cmdq_pkt); + mtk_mdp_rdma_stop(rdma_r, cmdq_pkt); +@@ -436,8 +436,10 @@ static int ovl_adaptor_comp_init(struct device *dev, struct component_match **ma + } + + comp_pdev = of_find_device_by_node(node); +- if (!comp_pdev) ++ if (!comp_pdev) { ++ of_node_put(node); + return -EPROBE_DEFER; ++ } + + priv->ovl_adaptor_comp[id] = &comp_pdev->dev; + +diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c +index 2cb47f6637568b..48a4defbc66cc8 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dp.c ++++ b/drivers/gpu/drm/mediatek/mtk_dp.c +@@ -2027,21 +2027,20 @@ static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge *bridge) + return ret; + } + +-static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge, +- struct drm_connector *connector) ++static const struct drm_edid *mtk_dp_edid_read(struct drm_bridge *bridge, ++ struct drm_connector *connector) + { + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge); + bool enabled = mtk_dp->enabled; +- struct edid *new_edid = NULL; ++ const struct drm_edid *drm_edid; + struct mtk_dp_audio_cfg *audio_caps = &mtk_dp->info.audio_cur_cfg; +- struct cea_sad *sads; + + if (!enabled) { + drm_atomic_bridge_chain_pre_enable(bridge, connector->state->state); + mtk_dp_aux_panel_poweron(mtk_dp, true); + } + +- new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc); ++ drm_edid = drm_edid_read_ddc(connector, &mtk_dp->aux.ddc); + + /* + * Parse capability here to let atomic_get_input_bus_fmts and +@@ -2049,12 +2048,32 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge, + */ + if (mtk_dp_parse_capabilities(mtk_dp)) { + drm_err(mtk_dp->drm_dev, "Can't parse capabilities\n"); +- new_edid = NULL; ++ drm_edid_free(drm_edid); ++ drm_edid = NULL; + } + +- if (new_edid) { +- audio_caps->sad_count = drm_edid_to_sad(new_edid, &sads); +- audio_caps->detect_monitor = drm_detect_monitor_audio(new_edid); ++ if (drm_edid) { ++ /* ++ * FIXME: get rid of drm_edid_raw() ++ */ ++ const struct edid *edid = drm_edid_raw(drm_edid); ++ struct cea_sad *sads; ++ int ret; ++ ++ ret = drm_edid_to_sad(edid, &sads); ++ /* Ignore any errors */ ++ if (ret < 0) ++ ret = 0; ++ if (ret) ++ kfree(sads); ++ audio_caps->sad_count = ret; ++ ++ /* ++ * FIXME: This should use connector->display_info.has_audio from ++ * a path that has read the EDID and called ++ * drm_edid_connector_update(). ++ */ ++ audio_caps->detect_monitor = drm_detect_monitor_audio(edid); + } + + if (!enabled) { +@@ -2062,7 +2081,7 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge, + drm_atomic_bridge_chain_post_disable(bridge, connector->state->state); + } + +- return new_edid; ++ return drm_edid; + } + + static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux *mtk_aux, +@@ -2076,7 +2095,7 @@ static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux *mtk_aux, + + if (mtk_dp->bridge.type != DRM_MODE_CONNECTOR_eDP && + !mtk_dp->train_info.cable_plugged_in) { +- ret = -EAGAIN; ++ ret = -EIO; + goto err; + } + +@@ -2414,7 +2433,7 @@ static const struct drm_bridge_funcs mtk_dp_bridge_funcs = { + .atomic_enable = mtk_dp_bridge_atomic_enable, + .atomic_disable = mtk_dp_bridge_atomic_disable, + .mode_valid = mtk_dp_bridge_mode_valid, +- .get_edid = mtk_dp_get_edid, ++ .edid_read = mtk_dp_edid_read, + .detect = mtk_dp_bdg_detect, + }; + +@@ -2780,3 +2799,4 @@ MODULE_AUTHOR("Markus Schneider-Pargmann "); + MODULE_AUTHOR("Bo-Chen Chen "); + MODULE_DESCRIPTION("MediaTek DisplayPort Driver"); + MODULE_LICENSE("GPL"); ++MODULE_SOFTDEP("pre: phy_mtk_dp"); +diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c +index 2f931e4e2b6009..bc073a6b367e5b 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dpi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dpi.c +@@ -957,20 +957,6 @@ static const struct mtk_dpi_conf mt8186_conf = { + .csc_enable_bit = CSC_ENABLE, + }; + +-static const struct mtk_dpi_conf mt8188_dpintf_conf = { +- .cal_factor = mt8195_dpintf_calculate_factor, +- .max_clock_khz = 600000, +- .output_fmts = mt8195_output_fmts, +- .num_output_fmts = ARRAY_SIZE(mt8195_output_fmts), +- .pixels_per_iter = 4, +- .input_2pixel = false, +- .dimension_mask = DPINTF_HPW_MASK, +- .hvsize_mask = DPINTF_HSIZE_MASK, +- .channel_swap_shift = DPINTF_CH_SWAP, +- .yuv422_en_bit = DPINTF_YUV422_EN, +- .csc_enable_bit = DPINTF_CSC_ENABLE, +-}; +- + static const struct mtk_dpi_conf mt8192_conf = { + .cal_factor = mt8183_calculate_factor, + .reg_h_fre_con = 0xe0, +@@ -1094,7 +1080,7 @@ static const struct of_device_id mtk_dpi_of_ids[] = { + { .compatible = "mediatek,mt8173-dpi", .data = &mt8173_conf }, + { .compatible = "mediatek,mt8183-dpi", .data = &mt8183_conf }, + { .compatible = "mediatek,mt8186-dpi", .data = &mt8186_conf }, +- { .compatible = "mediatek,mt8188-dp-intf", .data = &mt8188_dpintf_conf }, ++ { .compatible = "mediatek,mt8188-dp-intf", .data = &mt8195_dpintf_conf }, + { .compatible = "mediatek,mt8192-dpi", .data = &mt8192_conf }, + { .compatible = "mediatek,mt8195-dp-intf", .data = &mt8195_dpintf_conf }, + { /* sentinel */ }, +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +index b6fa4ad2f94dc0..659112da47b692 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +@@ -67,6 +67,8 @@ struct mtk_drm_crtc { + /* lock for display hardware access */ + struct mutex hw_lock; + bool config_updating; ++ /* lock for config_updating to cmd buffer */ ++ spinlock_t config_lock; + }; + + struct mtk_crtc_state { +@@ -93,20 +95,27 @@ static void mtk_drm_crtc_finish_page_flip(struct mtk_drm_crtc *mtk_crtc) + struct drm_crtc *crtc = &mtk_crtc->base; + unsigned long flags; + +- spin_lock_irqsave(&crtc->dev->event_lock, flags); +- drm_crtc_send_vblank_event(crtc, mtk_crtc->event); +- drm_crtc_vblank_put(crtc); +- mtk_crtc->event = NULL; +- spin_unlock_irqrestore(&crtc->dev->event_lock, flags); ++ if (mtk_crtc->event) { ++ spin_lock_irqsave(&crtc->dev->event_lock, flags); ++ drm_crtc_send_vblank_event(crtc, mtk_crtc->event); ++ drm_crtc_vblank_put(crtc); ++ mtk_crtc->event = NULL; ++ spin_unlock_irqrestore(&crtc->dev->event_lock, flags); ++ } + } + + static void mtk_drm_finish_page_flip(struct mtk_drm_crtc *mtk_crtc) + { ++ unsigned long flags; ++ + drm_crtc_handle_vblank(&mtk_crtc->base); ++ ++ spin_lock_irqsave(&mtk_crtc->config_lock, flags); + if (!mtk_crtc->config_updating && mtk_crtc->pending_needs_vblank) { + mtk_drm_crtc_finish_page_flip(mtk_crtc); + mtk_crtc->pending_needs_vblank = false; + } ++ spin_unlock_irqrestore(&mtk_crtc->config_lock, flags); + } + + #if IS_REACHABLE(CONFIG_MTK_CMDQ) +@@ -289,12 +298,19 @@ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg) + struct mtk_drm_crtc *mtk_crtc = container_of(cmdq_cl, struct mtk_drm_crtc, cmdq_client); + struct mtk_crtc_state *state; + unsigned int i; ++ unsigned long flags; + + if (data->sta < 0) + return; + + state = to_mtk_crtc_state(mtk_crtc->base.state); + ++ spin_lock_irqsave(&mtk_crtc->config_lock, flags); ++ if (mtk_crtc->config_updating) { ++ spin_unlock_irqrestore(&mtk_crtc->config_lock, flags); ++ goto ddp_cmdq_cb_out; ++ } ++ + state->pending_config = false; + + if (mtk_crtc->pending_planes) { +@@ -321,6 +337,10 @@ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg) + mtk_crtc->pending_async_planes = false; + } + ++ spin_unlock_irqrestore(&mtk_crtc->config_lock, flags); ++ ++ddp_cmdq_cb_out: ++ + mtk_crtc->cmdq_vblank_cnt = 0; + wake_up(&mtk_crtc->cb_blocking_queue); + } +@@ -408,6 +428,9 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc) + unsigned int local_layer; + + plane_state = to_mtk_plane_state(plane->state); ++ ++ /* should not enable layer before crtc enabled */ ++ plane_state->pending.enable = false; + comp = mtk_drm_ddp_comp_for_plane(crtc, plane, &local_layer); + if (comp) + mtk_ddp_comp_layer_config(comp, local_layer, +@@ -427,6 +450,7 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc) + { + struct drm_device *drm = mtk_crtc->base.dev; + struct drm_crtc *crtc = &mtk_crtc->base; ++ unsigned long flags; + int i; + + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { +@@ -458,10 +482,10 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc) + pm_runtime_put(drm->dev); + + if (crtc->state->event && !crtc->state->active) { +- spin_lock_irq(&crtc->dev->event_lock); ++ spin_lock_irqsave(&crtc->dev->event_lock, flags); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + crtc->state->event = NULL; +- spin_unlock_irq(&crtc->dev->event_lock); ++ spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + } + } + +@@ -550,9 +574,14 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc, + struct mtk_drm_private *priv = crtc->dev->dev_private; + unsigned int pending_planes = 0, pending_async_planes = 0; + int i; ++ unsigned long flags; + + mutex_lock(&mtk_crtc->hw_lock); ++ ++ spin_lock_irqsave(&mtk_crtc->config_lock, flags); + mtk_crtc->config_updating = true; ++ spin_unlock_irqrestore(&mtk_crtc->config_lock, flags); ++ + if (needs_vblank) + mtk_crtc->pending_needs_vblank = true; + +@@ -606,7 +635,10 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc, + mbox_client_txdone(mtk_crtc->cmdq_client.chan, 0); + } + #endif ++ spin_lock_irqsave(&mtk_crtc->config_lock, flags); + mtk_crtc->config_updating = false; ++ spin_unlock_irqrestore(&mtk_crtc->config_lock, flags); ++ + mutex_unlock(&mtk_crtc->hw_lock); + } + +@@ -744,6 +776,7 @@ static void mtk_drm_crtc_atomic_begin(struct drm_crtc *crtc, + crtc); + struct mtk_crtc_state *mtk_crtc_state = to_mtk_crtc_state(crtc_state); + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); ++ unsigned long flags; + + if (mtk_crtc->event && mtk_crtc_state->base.event) + DRM_ERROR("new event while there is still a pending event\n"); +@@ -751,7 +784,11 @@ static void mtk_drm_crtc_atomic_begin(struct drm_crtc *crtc, + if (mtk_crtc_state->base.event) { + mtk_crtc_state->base.event->pipe = drm_crtc_index(crtc); + WARN_ON(drm_crtc_vblank_get(crtc) != 0); ++ ++ spin_lock_irqsave(&crtc->dev->event_lock, flags); + mtk_crtc->event = mtk_crtc_state->base.event; ++ spin_unlock_irqrestore(&crtc->dev->event_lock, flags); ++ + mtk_crtc_state->base.event = NULL; + } + } +@@ -877,7 +914,14 @@ static int mtk_drm_crtc_init_comp_planes(struct drm_device *drm_dev, + + struct device *mtk_drm_crtc_dma_dev_get(struct drm_crtc *crtc) + { +- struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); ++ struct mtk_drm_crtc *mtk_crtc = NULL; ++ ++ if (!crtc) ++ return NULL; ++ ++ mtk_crtc = to_mtk_crtc(crtc); ++ if (!mtk_crtc) ++ return NULL; + + return mtk_crtc->dma_dev; + } +@@ -997,6 +1041,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, + drm_mode_crtc_set_gamma_size(&mtk_crtc->base, gamma_lut_size); + drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, has_ctm, gamma_lut_size); + mutex_init(&mtk_crtc->hw_lock); ++ spin_lock_init(&mtk_crtc->config_lock); + + #if IS_REACHABLE(CONFIG_MTK_CMDQ) + i = priv->mbox_index++; +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +index 771f4e1733539c..66ccde966e3c10 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +@@ -553,7 +553,7 @@ int mtk_ddp_comp_init(struct device_node *node, struct mtk_ddp_comp *comp, + int ret; + #endif + +- if (comp_id < 0 || comp_id >= DDP_COMPONENT_DRM_ID_MAX) ++ if (comp_id >= DDP_COMPONENT_DRM_ID_MAX) + return -EINVAL; + + type = mtk_ddp_matches[comp_id].type; +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c +index 93552d76b6e778..ffe016d6cbcfe0 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c +@@ -288,6 +288,7 @@ static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = { + static const struct mtk_mmsys_driver_data mt8188_vdosys0_driver_data = { + .main_path = mt8188_mtk_ddp_main, + .main_len = ARRAY_SIZE(mt8188_mtk_ddp_main), ++ .mmsys_dev_num = 1, + }; + + static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = { +@@ -420,6 +421,7 @@ static int mtk_drm_kms_init(struct drm_device *drm) + struct mtk_drm_private *private = drm->dev_private; + struct mtk_drm_private *priv_n; + struct device *dma_dev = NULL; ++ struct drm_crtc *crtc; + int ret, i, j; + + if (drm_firmware_drivers_only()) +@@ -494,7 +496,9 @@ static int mtk_drm_kms_init(struct drm_device *drm) + } + + /* Use OVL device for all DMA memory allocations */ +- dma_dev = mtk_drm_crtc_dma_dev_get(drm_crtc_from_index(drm, 0)); ++ crtc = drm_crtc_from_index(drm, 0); ++ if (crtc) ++ dma_dev = mtk_drm_crtc_dma_dev_get(crtc); + if (!dma_dev) { + ret = -ENODEV; + dev_err(drm->dev, "Need at least one OVL device\n"); +@@ -715,6 +719,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = { + .data = (void *)MTK_DISP_OVL }, + { .compatible = "mediatek,mt8192-disp-ovl", + .data = (void *)MTK_DISP_OVL }, ++ { .compatible = "mediatek,mt8195-disp-ovl", ++ .data = (void *)MTK_DISP_OVL }, + { .compatible = "mediatek,mt8183-disp-ovl-2l", + .data = (void *)MTK_DISP_OVL_2L }, + { .compatible = "mediatek,mt8192-disp-ovl-2l", +@@ -922,6 +928,13 @@ static void mtk_drm_remove(struct platform_device *pdev) + of_node_put(private->comp_node[i]); + } + ++static void mtk_drm_shutdown(struct platform_device *pdev) ++{ ++ struct mtk_drm_private *private = platform_get_drvdata(pdev); ++ ++ drm_atomic_helper_shutdown(private->drm); ++} ++ + static int mtk_drm_sys_prepare(struct device *dev) + { + struct mtk_drm_private *private = dev_get_drvdata(dev); +@@ -953,6 +966,7 @@ static const struct dev_pm_ops mtk_drm_pm_ops = { + static struct platform_driver mtk_drm_platform_driver = { + .probe = mtk_drm_probe, + .remove_new = mtk_drm_remove, ++ .shutdown = mtk_drm_shutdown, + .driver = { + .name = "mediatek-drm", + .pm = &mtk_drm_pm_ops, +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c b/drivers/gpu/drm/mediatek/mtk_drm_gem.c +index 0e0a41b2f57f05..1bf229615b0188 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c +@@ -38,6 +38,9 @@ static struct mtk_drm_gem_obj *mtk_drm_gem_init(struct drm_device *dev, + + size = round_up(size, PAGE_SIZE); + ++ if (size == 0) ++ return ERR_PTR(-EINVAL); ++ + mtk_gem_obj = kzalloc(sizeof(*mtk_gem_obj), GFP_KERNEL); + if (!mtk_gem_obj) + return ERR_PTR(-ENOMEM); +@@ -121,7 +124,14 @@ int mtk_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, + int ret; + + args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8); +- args->size = args->pitch * args->height; ++ ++ /* ++ * Multiply 2 variables of different types, ++ * for example: args->size = args->spacing * args->height; ++ * may cause coverity issue with unintentional overflow. ++ */ ++ args->size = args->pitch; ++ args->size *= args->height; + + mtk_gem = mtk_drm_gem_create(dev, args->size, false); + if (IS_ERR(mtk_gem)) +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c +index db2f70ae060d6f..f10d4cc6c2234f 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c +@@ -141,6 +141,7 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state, + dma_addr_t addr; + dma_addr_t hdr_addr = 0; + unsigned int hdr_pitch = 0; ++ int offset; + + gem = fb->obj[0]; + mtk_gem = to_mtk_gem_obj(gem); +@@ -150,8 +151,15 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state, + modifier = fb->modifier; + + if (modifier == DRM_FORMAT_MOD_LINEAR) { +- addr += (new_state->src.x1 >> 16) * fb->format->cpp[0]; +- addr += (new_state->src.y1 >> 16) * pitch; ++ /* ++ * Using dma_addr_t variable to calculate with multiplier of different types, ++ * for example: addr += (new_state->src.x1 >> 16) * fb->format->cpp[0]; ++ * may cause coverity issue with unintentional overflow. ++ */ ++ offset = (new_state->src.x1 >> 16) * fb->format->cpp[0]; ++ addr += offset; ++ offset = (new_state->src.y1 >> 16) * pitch; ++ addr += offset; + } else { + int width_in_blocks = ALIGN(fb->width, AFBC_DATA_BLOCK_WIDTH) + / AFBC_DATA_BLOCK_WIDTH; +@@ -159,21 +167,34 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state, + / AFBC_DATA_BLOCK_HEIGHT; + int x_offset_in_blocks = (new_state->src.x1 >> 16) / AFBC_DATA_BLOCK_WIDTH; + int y_offset_in_blocks = (new_state->src.y1 >> 16) / AFBC_DATA_BLOCK_HEIGHT; +- int hdr_size; ++ int hdr_size, hdr_offset; + + hdr_pitch = width_in_blocks * AFBC_HEADER_BLOCK_SIZE; + pitch = width_in_blocks * AFBC_DATA_BLOCK_WIDTH * + AFBC_DATA_BLOCK_HEIGHT * fb->format->cpp[0]; + + hdr_size = ALIGN(hdr_pitch * height_in_blocks, AFBC_HEADER_ALIGNMENT); ++ hdr_offset = hdr_pitch * y_offset_in_blocks + ++ AFBC_HEADER_BLOCK_SIZE * x_offset_in_blocks; ++ ++ /* ++ * Using dma_addr_t variable to calculate with multiplier of different types, ++ * for example: addr += hdr_pitch * y_offset_in_blocks; ++ * may cause coverity issue with unintentional overflow. ++ */ ++ hdr_addr = addr + hdr_offset; + +- hdr_addr = addr + hdr_pitch * y_offset_in_blocks + +- AFBC_HEADER_BLOCK_SIZE * x_offset_in_blocks; + /* The data plane is offset by 1 additional block. */ +- addr = addr + hdr_size + +- pitch * y_offset_in_blocks + +- AFBC_DATA_BLOCK_WIDTH * AFBC_DATA_BLOCK_HEIGHT * +- fb->format->cpp[0] * (x_offset_in_blocks + 1); ++ offset = pitch * y_offset_in_blocks + ++ AFBC_DATA_BLOCK_WIDTH * AFBC_DATA_BLOCK_HEIGHT * ++ fb->format->cpp[0] * (x_offset_in_blocks + 1); ++ ++ /* ++ * Using dma_addr_t variable to calculate with multiplier of different types, ++ * for example: addr += pitch * y_offset_in_blocks; ++ * may cause coverity issue with unintentional overflow. ++ */ ++ addr = addr + hdr_size + offset; + } + + mtk_plane_state->pending.enable = true; +@@ -206,9 +227,11 @@ static void mtk_plane_atomic_async_update(struct drm_plane *plane, + plane->state->src_y = new_state->src_y; + plane->state->src_h = new_state->src_h; + plane->state->src_w = new_state->src_w; +- swap(plane->state->fb, new_state->fb); ++ plane->state->dst.x1 = new_state->dst.x1; ++ plane->state->dst.y1 = new_state->dst.y1; + + mtk_plane_update_new_state(new_state, new_plane_state); ++ swap(plane->state->fb, new_state->fb); + wmb(); /* Make sure the above parameters are set before update */ + new_plane_state->pending.async_dirty = true; + mtk_drm_crtc_async_update(new_state->crtc, plane, state); +diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c +index d8bfc2cce54dc6..0d96264ec5c6da 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dsi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c +@@ -71,8 +71,8 @@ + #define DSI_PS_WC 0x3fff + #define DSI_PS_SEL (3 << 16) + #define PACKED_PS_16BIT_RGB565 (0 << 16) +-#define LOOSELY_PS_18BIT_RGB666 (1 << 16) +-#define PACKED_PS_18BIT_RGB666 (2 << 16) ++#define PACKED_PS_18BIT_RGB666 (1 << 16) ++#define LOOSELY_PS_24BIT_RGB666 (2 << 16) + #define PACKED_PS_24BIT_RGB888 (3 << 16) + + #define DSI_VSA_NL 0x20 +@@ -367,10 +367,10 @@ static void mtk_dsi_ps_control_vact(struct mtk_dsi *dsi) + ps_bpp_mode |= PACKED_PS_24BIT_RGB888; + break; + case MIPI_DSI_FMT_RGB666: +- ps_bpp_mode |= PACKED_PS_18BIT_RGB666; ++ ps_bpp_mode |= LOOSELY_PS_24BIT_RGB666; + break; + case MIPI_DSI_FMT_RGB666_PACKED: +- ps_bpp_mode |= LOOSELY_PS_18BIT_RGB666; ++ ps_bpp_mode |= PACKED_PS_18BIT_RGB666; + break; + case MIPI_DSI_FMT_RGB565: + ps_bpp_mode |= PACKED_PS_16BIT_RGB565; +@@ -407,7 +407,7 @@ static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi) + if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) + tmp_reg |= HSTX_CKLP_EN; + +- if (!(dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)) ++ if (dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET) + tmp_reg |= DIS_EOT; + + writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL); +@@ -424,7 +424,7 @@ static void mtk_dsi_ps_control(struct mtk_dsi *dsi) + dsi_tmp_buf_bpp = 3; + break; + case MIPI_DSI_FMT_RGB666: +- tmp_reg = LOOSELY_PS_18BIT_RGB666; ++ tmp_reg = LOOSELY_PS_24BIT_RGB666; + dsi_tmp_buf_bpp = 3; + break; + case MIPI_DSI_FMT_RGB666_PACKED: +@@ -484,7 +484,7 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi) + timing->da_hs_zero + timing->da_hs_exit + 3; + + delta = dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST ? 18 : 12; +- delta += dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET ? 2 : 0; ++ delta += dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET ? 0 : 2; + + horizontal_frontporch_byte = vm->hfront_porch * dsi_tmp_buf_bpp; + horizontal_front_back_byte = horizontal_frontporch_byte + horizontal_backporch_byte; +diff --git a/drivers/gpu/drm/mediatek/mtk_ethdr.c b/drivers/gpu/drm/mediatek/mtk_ethdr.c +index db7ac666ec5e11..0cf8c889941565 100644 +--- a/drivers/gpu/drm/mediatek/mtk_ethdr.c ++++ b/drivers/gpu/drm/mediatek/mtk_ethdr.c +@@ -50,7 +50,6 @@ + + #define MIXER_INX_MODE_BYPASS 0 + #define MIXER_INX_MODE_EVEN_EXTEND 1 +-#define DEFAULT_9BIT_ALPHA 0x100 + #define MIXER_ALPHA_AEN BIT(8) + #define MIXER_ALPHA 0xff + #define ETHDR_CLK_NUM 13 +@@ -154,13 +153,19 @@ void mtk_ethdr_layer_config(struct device *dev, unsigned int idx, + unsigned int offset = (pending->x & 1) << 31 | pending->y << 16 | pending->x; + unsigned int align_width = ALIGN_DOWN(pending->width, 2); + unsigned int alpha_con = 0; ++ bool replace_src_a = false; + + dev_dbg(dev, "%s+ idx:%d", __func__, idx); + + if (idx >= 4) + return; + +- if (!pending->enable) { ++ if (!pending->enable || !pending->width || !pending->height) { ++ /* ++ * instead of disabling layer with MIX_SRC_CON directly ++ * set the size to 0 to avoid screen shift due to mixer ++ * mode switch (hardware behavior) ++ */ + mtk_ddp_write(cmdq_pkt, 0, &mixer->cmdq_base, mixer->regs, MIX_L_SRC_SIZE(idx)); + return; + } +@@ -168,8 +173,16 @@ void mtk_ethdr_layer_config(struct device *dev, unsigned int idx, + if (state->base.fb && state->base.fb->format->has_alpha) + alpha_con = MIXER_ALPHA_AEN | MIXER_ALPHA; + +- mtk_mmsys_mixer_in_config(priv->mmsys_dev, idx + 1, alpha_con ? false : true, +- DEFAULT_9BIT_ALPHA, ++ if (state->base.fb && !state->base.fb->format->has_alpha) { ++ /* ++ * Mixer doesn't support CONST_BLD mode, ++ * use a trick to make the output equivalent ++ */ ++ replace_src_a = true; ++ } ++ ++ mtk_mmsys_mixer_in_config(priv->mmsys_dev, idx + 1, replace_src_a, ++ MIXER_ALPHA, + pending->x & 1 ? MIXER_INX_MODE_EVEN_EXTEND : + MIXER_INX_MODE_BYPASS, align_width / 2 - 1, cmdq_pkt); + +diff --git a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c +index c3adaeefd551a2..c7233d0ac210f1 100644 +--- a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c ++++ b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c +@@ -246,8 +246,7 @@ int mtk_mdp_rdma_clk_enable(struct device *dev) + { + struct mtk_mdp_rdma *rdma = dev_get_drvdata(dev); + +- clk_prepare_enable(rdma->clk); +- return 0; ++ return clk_prepare_enable(rdma->clk); + } + + void mtk_mdp_rdma_clk_disable(struct device *dev) +diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c +index cb674966e9aca7..095f634ff7c799 100644 +--- a/drivers/gpu/drm/meson/meson_drv.c ++++ b/drivers/gpu/drm/meson/meson_drv.c +@@ -250,29 +250,20 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) + if (ret) + goto free_drm; + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0); +- if (ret) { +- meson_canvas_free(priv->canvas, priv->canvas_id_osd1); +- goto free_drm; +- } ++ if (ret) ++ goto free_canvas_osd1; + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_1); +- if (ret) { +- meson_canvas_free(priv->canvas, priv->canvas_id_osd1); +- meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); +- goto free_drm; +- } ++ if (ret) ++ goto free_canvas_vd1_0; + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_2); +- if (ret) { +- meson_canvas_free(priv->canvas, priv->canvas_id_osd1); +- meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); +- meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1); +- goto free_drm; +- } ++ if (ret) ++ goto free_canvas_vd1_1; + + priv->vsync_irq = platform_get_irq(pdev, 0); + + ret = drm_vblank_init(drm, 1); + if (ret) +- goto free_drm; ++ goto free_canvas_vd1_2; + + /* Assign limits per soc revision/package */ + for (i = 0 ; i < ARRAY_SIZE(meson_drm_soc_attrs) ; ++i) { +@@ -288,11 +279,11 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) + */ + ret = drm_aperture_remove_framebuffers(&meson_driver); + if (ret) +- goto free_drm; ++ goto free_canvas_vd1_2; + + ret = drmm_mode_config_init(drm); + if (ret) +- goto free_drm; ++ goto free_canvas_vd1_2; + drm->mode_config.max_width = 3840; + drm->mode_config.max_height = 2160; + drm->mode_config.funcs = &meson_mode_config_funcs; +@@ -307,7 +298,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) + if (priv->afbcd.ops) { + ret = priv->afbcd.ops->init(priv); + if (ret) +- goto free_drm; ++ goto free_canvas_vd1_2; + } + + /* Encoder Initialization */ +@@ -371,6 +362,14 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) + exit_afbcd: + if (priv->afbcd.ops) + priv->afbcd.ops->exit(priv); ++free_canvas_vd1_2: ++ meson_canvas_free(priv->canvas, priv->canvas_id_vd1_2); ++free_canvas_vd1_1: ++ meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1); ++free_canvas_vd1_0: ++ meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); ++free_canvas_osd1: ++ meson_canvas_free(priv->canvas, priv->canvas_id_osd1); + free_drm: + drm_dev_put(drm); + +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index 5a9538bc0e26f8..5565f7777529f8 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -106,6 +106,8 @@ + #define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 */ + #define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 */ + #define HHI_HDMI_PHY_CNTL1 0x3a4 /* 0xe9 */ ++#define PHY_CNTL1_INIT 0x03900000 ++#define PHY_INVERT BIT(17) + #define HHI_HDMI_PHY_CNTL2 0x3a8 /* 0xea */ + #define HHI_HDMI_PHY_CNTL3 0x3ac /* 0xeb */ + #define HHI_HDMI_PHY_CNTL4 0x3b0 /* 0xec */ +@@ -130,6 +132,8 @@ struct meson_dw_hdmi_data { + unsigned int addr); + void (*dwc_write)(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr, unsigned int data); ++ u32 cntl0_init; ++ u32 cntl1_init; + }; + + struct meson_dw_hdmi { +@@ -384,26 +388,6 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, + dw_hdmi_bus_fmt_is_420(hdmi)) + mode_is_420 = true; + +- /* Enable clocks */ +- regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); +- +- /* Bring HDMITX MEM output of power down */ +- regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); +- +- /* Bring out of reset */ +- dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0); +- +- /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */ +- dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, +- 0x3, 0x3); +- +- /* Enable cec_clk and hdcp22_tmdsclk_en */ +- dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, +- 0x3 << 4, 0x3 << 4); +- +- /* Enable normal output to PHY */ +- dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); +- + /* TMDS pattern setup */ + if (mode->clock > 340000 && !mode_is_420) { + dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, +@@ -425,20 +409,6 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, + /* Setup PHY parameters */ + meson_hdmi_phy_setup_mode(dw_hdmi, mode, mode_is_420); + +- /* Setup PHY */ +- regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, +- 0xffff << 16, 0x0390 << 16); +- +- /* BIT_INVERT */ +- if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || +- dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi") || +- dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-g12a-dw-hdmi")) +- regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, +- BIT(17), 0); +- else +- regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, +- BIT(17), BIT(17)); +- + /* Disable clock, fifo, fifo_wr */ + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0); + +@@ -492,7 +462,9 @@ static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi, + + DRM_DEBUG_DRIVER("\n"); + +- regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0); ++ /* Fallback to init mode */ ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL1, dw_hdmi->data->cntl1_init); ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, dw_hdmi->data->cntl0_init); + } + + static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi, +@@ -610,11 +582,22 @@ static const struct regmap_config meson_dw_hdmi_regmap_config = { + .fast_io = true, + }; + +-static const struct meson_dw_hdmi_data meson_dw_hdmi_gx_data = { ++static const struct meson_dw_hdmi_data meson_dw_hdmi_gxbb_data = { + .top_read = dw_hdmi_top_read, + .top_write = dw_hdmi_top_write, + .dwc_read = dw_hdmi_dwc_read, + .dwc_write = dw_hdmi_dwc_write, ++ .cntl0_init = 0x0, ++ .cntl1_init = PHY_CNTL1_INIT | PHY_INVERT, ++}; ++ ++static const struct meson_dw_hdmi_data meson_dw_hdmi_gxl_data = { ++ .top_read = dw_hdmi_top_read, ++ .top_write = dw_hdmi_top_write, ++ .dwc_read = dw_hdmi_dwc_read, ++ .dwc_write = dw_hdmi_dwc_write, ++ .cntl0_init = 0x0, ++ .cntl1_init = PHY_CNTL1_INIT, + }; + + static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = { +@@ -622,6 +605,8 @@ static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = { + .top_write = dw_hdmi_g12a_top_write, + .dwc_read = dw_hdmi_g12a_dwc_read, + .dwc_write = dw_hdmi_g12a_dwc_write, ++ .cntl0_init = 0x000b4242, /* Bandgap */ ++ .cntl1_init = PHY_CNTL1_INIT, + }; + + static void meson_dw_hdmi_init(struct meson_dw_hdmi *meson_dw_hdmi) +@@ -656,6 +641,13 @@ static void meson_dw_hdmi_init(struct meson_dw_hdmi *meson_dw_hdmi) + meson_dw_hdmi->data->top_write(meson_dw_hdmi, + HDMITX_TOP_CLK_CNTL, 0xff); + ++ /* Enable normal output to PHY */ ++ meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); ++ ++ /* Setup PHY */ ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL1, meson_dw_hdmi->data->cntl1_init); ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, meson_dw_hdmi->data->cntl0_init); ++ + /* Enable HDMI-TX Interrupt */ + meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, + HDMITX_TOP_INTR_CORE); +@@ -865,11 +857,11 @@ static const struct dev_pm_ops meson_dw_hdmi_pm_ops = { + + static const struct of_device_id meson_dw_hdmi_of_table[] = { + { .compatible = "amlogic,meson-gxbb-dw-hdmi", +- .data = &meson_dw_hdmi_gx_data }, ++ .data = &meson_dw_hdmi_gxbb_data }, + { .compatible = "amlogic,meson-gxl-dw-hdmi", +- .data = &meson_dw_hdmi_gx_data }, ++ .data = &meson_dw_hdmi_gxl_data }, + { .compatible = "amlogic,meson-gxm-dw-hdmi", +- .data = &meson_dw_hdmi_gx_data }, ++ .data = &meson_dw_hdmi_gxl_data }, + { .compatible = "amlogic,meson-g12a-dw-hdmi", + .data = &meson_dw_hdmi_g12a_data }, + { } +diff --git a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c +index e5fe4e994f43b1..72abe2057ec31e 100644 +--- a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c ++++ b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c +@@ -95,6 +95,7 @@ static int dw_mipi_dsi_phy_init(void *priv_data) + return ret; + } + ++ clk_disable_unprepare(mipi_dsi->px_clk); + ret = clk_set_rate(mipi_dsi->px_clk, mipi_dsi->mode->clock * 1000); + + if (ret) { +@@ -103,6 +104,12 @@ static int dw_mipi_dsi_phy_init(void *priv_data) + return ret; + } + ++ ret = clk_prepare_enable(mipi_dsi->px_clk); ++ if (ret) { ++ dev_err(mipi_dsi->dev, "Failed to enable DSI Pixel clock (ret %d)\n", ret); ++ return ret; ++ } ++ + switch (mipi_dsi->dsi_device->format) { + case MIPI_DSI_FMT_RGB888: + dpi_data_format = DPI_COLOR_24BIT; +diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c +index 3f73b211fa8e3e..3407450435e205 100644 +--- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c ++++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c +@@ -294,6 +294,5 @@ void meson_encoder_cvbs_remove(struct meson_drm *priv) + if (priv->encoders[MESON_ENC_CVBS]) { + meson_encoder_cvbs = priv->encoders[MESON_ENC_CVBS]; + drm_bridge_remove(&meson_encoder_cvbs->bridge); +- drm_bridge_remove(meson_encoder_cvbs->next_bridge); + } + } +diff --git a/drivers/gpu/drm/meson/meson_encoder_dsi.c b/drivers/gpu/drm/meson/meson_encoder_dsi.c +index 3f93c70488cad1..311b91630fbe53 100644 +--- a/drivers/gpu/drm/meson/meson_encoder_dsi.c ++++ b/drivers/gpu/drm/meson/meson_encoder_dsi.c +@@ -168,6 +168,5 @@ void meson_encoder_dsi_remove(struct meson_drm *priv) + if (priv->encoders[MESON_ENC_DSI]) { + meson_encoder_dsi = priv->encoders[MESON_ENC_DSI]; + drm_bridge_remove(&meson_encoder_dsi->bridge); +- drm_bridge_remove(meson_encoder_dsi->next_bridge); + } + } +diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c +index 25ea765586908f..c4686568c9ca5d 100644 +--- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c +@@ -474,6 +474,5 @@ void meson_encoder_hdmi_remove(struct meson_drm *priv) + if (priv->encoders[MESON_ENC_HDMI]) { + meson_encoder_hdmi = priv->encoders[MESON_ENC_HDMI]; + drm_bridge_remove(&meson_encoder_hdmi->bridge); +- drm_bridge_remove(meson_encoder_hdmi->next_bridge); + } + } +diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c +index 815dfe30492b6c..b43ac61201f312 100644 +--- a/drivers/gpu/drm/meson/meson_plane.c ++++ b/drivers/gpu/drm/meson/meson_plane.c +@@ -534,6 +534,7 @@ int meson_plane_create(struct meson_drm *priv) + struct meson_plane *meson_plane; + struct drm_plane *plane; + const uint64_t *format_modifiers = format_modifiers_default; ++ int ret; + + meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane), + GFP_KERNEL); +@@ -548,12 +549,16 @@ int meson_plane_create(struct meson_drm *priv) + else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) + format_modifiers = format_modifiers_afbc_g12a; + +- drm_universal_plane_init(priv->drm, plane, 0xFF, +- &meson_plane_funcs, +- supported_drm_formats, +- ARRAY_SIZE(supported_drm_formats), +- format_modifiers, +- DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane"); ++ ret = drm_universal_plane_init(priv->drm, plane, 0xFF, ++ &meson_plane_funcs, ++ supported_drm_formats, ++ ARRAY_SIZE(supported_drm_formats), ++ format_modifiers, ++ DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane"); ++ if (ret) { ++ devm_kfree(priv->drm->dev, meson_plane); ++ return ret; ++ } + + drm_plane_helper_add(plane, &meson_plane_helper_funcs); + +diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c +index 2a82119eb58ed8..2a942dc6a6dc23 100644 +--- a/drivers/gpu/drm/meson/meson_vclk.c ++++ b/drivers/gpu/drm/meson/meson_vclk.c +@@ -790,13 +790,13 @@ meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq, + FREQ_1000_1001(params[i].pixel_freq)); + DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n", + i, params[i].phy_freq, +- FREQ_1000_1001(params[i].phy_freq/10)*10); ++ FREQ_1000_1001(params[i].phy_freq/1000)*1000); + /* Match strict frequency */ + if (phy_freq == params[i].phy_freq && + vclk_freq == params[i].vclk_freq) + return MODE_OK; + /* Match 1000/1001 variant */ +- if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) && ++ if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/1000)*1000) && + vclk_freq == FREQ_1000_1001(params[i].vclk_freq)) + return MODE_OK; + } +@@ -1070,7 +1070,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, + + for (freq = 0 ; params[freq].pixel_freq ; ++freq) { + if ((phy_freq == params[freq].phy_freq || +- phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) && ++ phy_freq == FREQ_1000_1001(params[freq].phy_freq/1000)*1000) && + (vclk_freq == params[freq].vclk_freq || + vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) { + if (vclk_freq != params[freq].vclk_freq) +diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c +index abddf37f0ea119..2fb18b782b0536 100644 +--- a/drivers/gpu/drm/mgag200/mgag200_drv.c ++++ b/drivers/gpu/drm/mgag200/mgag200_drv.c +@@ -10,6 +10,7 @@ + #include + + #include ++#include + #include + #include + #include +@@ -278,6 +279,12 @@ static void mgag200_pci_remove(struct pci_dev *pdev) + struct drm_device *dev = pci_get_drvdata(pdev); + + drm_dev_unregister(dev); ++ drm_atomic_helper_shutdown(dev); ++} ++ ++static void mgag200_pci_shutdown(struct pci_dev *pdev) ++{ ++ drm_atomic_helper_shutdown(pci_get_drvdata(pdev)); + } + + static struct pci_driver mgag200_pci_driver = { +@@ -285,6 +292,7 @@ static struct pci_driver mgag200_pci_driver = { + .id_table = mgag200_pciidlist, + .probe = mgag200_pci_probe, + .remove = mgag200_pci_remove, ++ .shutdown = mgag200_pci_shutdown, + }; + + drm_module_pci_driver_if_modeset(mgag200_pci_driver, mgag200_modeset); +diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h +index 57c7edcab6029a..765e49fd891112 100644 +--- a/drivers/gpu/drm/mgag200/mgag200_drv.h ++++ b/drivers/gpu/drm/mgag200/mgag200_drv.h +@@ -392,6 +392,11 @@ void mgag200_primary_plane_helper_atomic_disable(struct drm_plane *plane, + .destroy = drm_plane_cleanup, \ + DRM_GEM_SHADOW_PLANE_FUNCS + ++void mgag200_crtc_set_gamma_linear(struct mga_device *mdev, const struct drm_format_info *format); ++void mgag200_crtc_set_gamma(struct mga_device *mdev, ++ const struct drm_format_info *format, ++ struct drm_color_lut *lut); ++ + enum drm_mode_status mgag200_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode); + int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state); +diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c +index bce267e0f7de3c..8d4538b7104776 100644 +--- a/drivers/gpu/drm/mgag200/mgag200_g200er.c ++++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c +@@ -202,6 +202,11 @@ static void mgag200_g200er_crtc_helper_atomic_enable(struct drm_crtc *crtc, + + mgag200_g200er_reset_tagfifo(mdev); + ++ if (crtc_state->gamma_lut) ++ mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data); ++ else ++ mgag200_crtc_set_gamma_linear(mdev, format); ++ + mgag200_enable_display(mdev); + + if (funcs->enable_vidrst) +diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c +index ac957f42abe182..56e6f986bff311 100644 +--- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c ++++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c +@@ -203,6 +203,11 @@ static void mgag200_g200ev_crtc_helper_atomic_enable(struct drm_crtc *crtc, + + mgag200_g200ev_set_hiprilvl(mdev); + ++ if (crtc_state->gamma_lut) ++ mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data); ++ else ++ mgag200_crtc_set_gamma_linear(mdev, format); ++ + mgag200_enable_display(mdev); + + if (funcs->enable_vidrst) +diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c +index bd6e573c9a1a31..ff2b3c6622e7aa 100644 +--- a/drivers/gpu/drm/mgag200/mgag200_g200se.c ++++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c +@@ -334,6 +334,11 @@ static void mgag200_g200se_crtc_helper_atomic_enable(struct drm_crtc *crtc, + + mgag200_g200se_set_hiprilvl(mdev, adjusted_mode, format); + ++ if (crtc_state->gamma_lut) ++ mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data); ++ else ++ mgag200_crtc_set_gamma_linear(mdev, format); ++ + mgag200_enable_display(mdev); + + if (funcs->enable_vidrst) +diff --git a/drivers/gpu/drm/mgag200/mgag200_i2c.c b/drivers/gpu/drm/mgag200/mgag200_i2c.c +index 0c48bdf3e7f800..f5c5d06d0d4bb7 100644 +--- a/drivers/gpu/drm/mgag200/mgag200_i2c.c ++++ b/drivers/gpu/drm/mgag200/mgag200_i2c.c +@@ -31,6 +31,8 @@ + #include + #include + ++#include ++ + #include "mgag200_drv.h" + + static int mga_i2c_read_gpio(struct mga_device *mdev) +@@ -86,7 +88,7 @@ static int mga_gpio_getscl(void *data) + return (mga_i2c_read_gpio(mdev) & i2c->clock) ? 1 : 0; + } + +-static void mgag200_i2c_release(void *res) ++static void mgag200_i2c_release(struct drm_device *dev, void *res) + { + struct mga_i2c_chan *i2c = res; + +@@ -115,7 +117,7 @@ int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c) + i2c->adapter.algo_data = &i2c->bit; + + i2c->bit.udelay = 10; +- i2c->bit.timeout = 2; ++ i2c->bit.timeout = usecs_to_jiffies(2200); + i2c->bit.data = i2c; + i2c->bit.setsda = mga_gpio_setsda; + i2c->bit.setscl = mga_gpio_setscl; +@@ -126,5 +128,5 @@ int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c) + if (ret) + return ret; + +- return devm_add_action_or_reset(dev->dev, mgag200_i2c_release, i2c); ++ return drmm_add_action_or_reset(dev, mgag200_i2c_release, i2c); + } +diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c +index af3ce5a6a636ac..0f0d59938c3a07 100644 +--- a/drivers/gpu/drm/mgag200/mgag200_mode.c ++++ b/drivers/gpu/drm/mgag200/mgag200_mode.c +@@ -28,8 +28,8 @@ + * This file contains setup code for the CRTC. + */ + +-static void mgag200_crtc_set_gamma_linear(struct mga_device *mdev, +- const struct drm_format_info *format) ++void mgag200_crtc_set_gamma_linear(struct mga_device *mdev, ++ const struct drm_format_info *format) + { + int i; + +@@ -65,9 +65,9 @@ static void mgag200_crtc_set_gamma_linear(struct mga_device *mdev, + } + } + +-static void mgag200_crtc_set_gamma(struct mga_device *mdev, +- const struct drm_format_info *format, +- struct drm_color_lut *lut) ++void mgag200_crtc_set_gamma(struct mga_device *mdev, ++ const struct drm_format_info *format, ++ struct drm_color_lut *lut) + { + int i; + +diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +index e5916c10679679..8c2758a18a19cf 100644 +--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +@@ -65,6 +65,8 @@ void a5xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring, + + static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit *submit) + { ++ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); ++ struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + struct msm_ringbuffer *ring = submit->ring; + struct drm_gem_object *obj; + uint32_t *ptr, dwords; +@@ -109,6 +111,7 @@ static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit *submit + } + } + ++ a5xx_gpu->last_seqno[ring->id] = submit->seqno; + a5xx_flush(gpu, ring, true); + a5xx_preempt_trigger(gpu); + +@@ -150,9 +153,13 @@ static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) + OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); + OUT_RING(ring, 1); + +- /* Enable local preemption for finegrain preemption */ ++ /* ++ * Disable local preemption by default because it requires ++ * user-space to be aware of it and provide additional handling ++ * to restore rendering state or do various flushes on switch. ++ */ + OUT_PKT7(ring, CP_PREEMPT_ENABLE_LOCAL, 1); +- OUT_RING(ring, 0x1); ++ OUT_RING(ring, 0x0); + + /* Allow CP_CONTEXT_SWITCH_YIELD packets in the IB2 */ + OUT_PKT7(ring, CP_YIELD_ENABLE, 1); +@@ -206,6 +213,7 @@ static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) + /* Write the fence to the scratch register */ + OUT_PKT4(ring, REG_A5XX_CP_SCRATCH_REG(2), 1); + OUT_RING(ring, submit->seqno); ++ a5xx_gpu->last_seqno[ring->id] = submit->seqno; + + /* + * Execute a CACHE_FLUSH_TS event. This will ensure that the +diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h +index c7187bcc5e9082..9c0d701fe4b85b 100644 +--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h ++++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h +@@ -34,8 +34,10 @@ struct a5xx_gpu { + struct drm_gem_object *preempt_counters_bo[MSM_GPU_MAX_RINGS]; + struct a5xx_preempt_record *preempt[MSM_GPU_MAX_RINGS]; + uint64_t preempt_iova[MSM_GPU_MAX_RINGS]; ++ uint32_t last_seqno[MSM_GPU_MAX_RINGS]; + + atomic_t preempt_state; ++ spinlock_t preempt_start_lock; + struct timer_list preempt_timer; + + struct drm_gem_object *shadow_bo; +diff --git a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c +index f58dd564d122ba..0469fea5501083 100644 +--- a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c ++++ b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c +@@ -55,6 +55,8 @@ static inline void update_wptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring) + /* Return the highest priority ringbuffer with something in it */ + static struct msm_ringbuffer *get_next_ring(struct msm_gpu *gpu) + { ++ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); ++ struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); + unsigned long flags; + int i; + +@@ -64,6 +66,8 @@ static struct msm_ringbuffer *get_next_ring(struct msm_gpu *gpu) + + spin_lock_irqsave(&ring->preempt_lock, flags); + empty = (get_wptr(ring) == gpu->funcs->get_rptr(gpu, ring)); ++ if (!empty && ring == a5xx_gpu->cur_ring) ++ empty = ring->memptrs->fence == a5xx_gpu->last_seqno[i]; + spin_unlock_irqrestore(&ring->preempt_lock, flags); + + if (!empty) +@@ -97,12 +101,19 @@ void a5xx_preempt_trigger(struct msm_gpu *gpu) + if (gpu->nr_rings == 1) + return; + ++ /* ++ * Serialize preemption start to ensure that we always make ++ * decision on latest state. Otherwise we can get stuck in ++ * lower priority or empty ring. ++ */ ++ spin_lock_irqsave(&a5xx_gpu->preempt_start_lock, flags); ++ + /* + * Try to start preemption by moving from NONE to START. If + * unsuccessful, a preemption is already in flight + */ + if (!try_preempt_state(a5xx_gpu, PREEMPT_NONE, PREEMPT_START)) +- return; ++ goto out; + + /* Get the next ring to preempt to */ + ring = get_next_ring(gpu); +@@ -127,9 +138,11 @@ void a5xx_preempt_trigger(struct msm_gpu *gpu) + set_preempt_state(a5xx_gpu, PREEMPT_ABORT); + update_wptr(gpu, a5xx_gpu->cur_ring); + set_preempt_state(a5xx_gpu, PREEMPT_NONE); +- return; ++ goto out; + } + ++ spin_unlock_irqrestore(&a5xx_gpu->preempt_start_lock, flags); ++ + /* Make sure the wptr doesn't update while we're in motion */ + spin_lock_irqsave(&ring->preempt_lock, flags); + a5xx_gpu->preempt[ring->id]->wptr = get_wptr(ring); +@@ -152,6 +165,10 @@ void a5xx_preempt_trigger(struct msm_gpu *gpu) + + /* And actually start the preemption */ + gpu_write(gpu, REG_A5XX_CP_CONTEXT_SWITCH_CNTL, 1); ++ return; ++ ++out: ++ spin_unlock_irqrestore(&a5xx_gpu->preempt_start_lock, flags); + } + + void a5xx_preempt_irq(struct msm_gpu *gpu) +@@ -188,6 +205,12 @@ void a5xx_preempt_irq(struct msm_gpu *gpu) + update_wptr(gpu, a5xx_gpu->cur_ring); + + set_preempt_state(a5xx_gpu, PREEMPT_NONE); ++ ++ /* ++ * Try to trigger preemption again in case there was a submit or ++ * retire during ring switch ++ */ ++ a5xx_preempt_trigger(gpu); + } + + void a5xx_preempt_hw_init(struct msm_gpu *gpu) +@@ -204,6 +227,8 @@ void a5xx_preempt_hw_init(struct msm_gpu *gpu) + return; + + for (i = 0; i < gpu->nr_rings; i++) { ++ a5xx_gpu->preempt[i]->data = 0; ++ a5xx_gpu->preempt[i]->info = 0; + a5xx_gpu->preempt[i]->wptr = 0; + a5xx_gpu->preempt[i]->rptr = 0; + a5xx_gpu->preempt[i]->rbase = gpu->rb[i]->iova; +@@ -298,5 +323,6 @@ void a5xx_preempt_init(struct msm_gpu *gpu) + } + } + ++ spin_lock_init(&a5xx_gpu->preempt_start_lock); + timer_setup(&a5xx_gpu->preempt_timer, a5xx_preempt_timer, 0); + } +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +index d4e85e24002fb7..3664c1476a83ad 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +@@ -2237,7 +2237,7 @@ static int a6xx_set_supported_hw(struct device *dev, const struct adreno_info *i + DRM_DEV_ERROR(dev, + "missing support for speed-bin: %u. Some OPPs may not be supported by hardware\n", + speedbin); +- return UINT_MAX; ++ supp_hw = BIT(0); /* Default */ + } + + ret = devm_pm_opp_set_supported_hw(dev, &supp_hw, 1); +@@ -2343,7 +2343,8 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) + + ret = a6xx_set_supported_hw(&pdev->dev, config->info); + if (ret) { +- a6xx_destroy(&(a6xx_gpu->base.base)); ++ a6xx_llc_slices_destroy(a6xx_gpu); ++ kfree(a6xx_gpu); + return ERR_PTR(ret); + } + +diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c +index 575e7c56219ff1..b7b527e21dac8a 100644 +--- a/drivers/gpu/drm/msm/adreno/adreno_device.c ++++ b/drivers/gpu/drm/msm/adreno/adreno_device.c +@@ -331,7 +331,7 @@ static const struct adreno_info gpulist[] = { + ), + }, { + .machine = "qcom,sm6375", +- .chip_ids = ADRENO_CHIP_IDS(0x06010900), ++ .chip_ids = ADRENO_CHIP_IDS(0x06010901), + .family = ADRENO_6XX_GEN1, + .revn = 619, + .fw = { +@@ -462,7 +462,7 @@ static const struct adreno_info gpulist[] = { + { 190, 1 }, + ), + }, { +- .chip_ids = ADRENO_CHIP_IDS(0x06080000), ++ .chip_ids = ADRENO_CHIP_IDS(0x06080001), + .family = ADRENO_6XX_GEN2, + .revn = 680, + .fw = { +diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c +index 8090dde0328082..a2df8bd7aa940f 100644 +--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c +@@ -99,7 +99,7 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname, + * was a bad idea, and is only provided for backwards + * compatibility for older targets. + */ +- return -ENODEV; ++ return -ENOENT; + } + + if (IS_ERR(fw)) { +@@ -468,7 +468,7 @@ adreno_request_fw(struct adreno_gpu *adreno_gpu, const char *fwname) + ret = request_firmware_direct(&fw, fwname, drm->dev); + if (!ret) { + DRM_DEV_INFO(drm->dev, "loaded %s from legacy location\n", +- newname); ++ fwname); + adreno_gpu->fwloc = FW_LOCATION_LEGACY; + goto out; + } else if (adreno_gpu->fwloc != FW_LOCATION_UNKNOWN) { +@@ -1071,6 +1071,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, + adreno_gpu->chip_id = config->chip_id; + + gpu->allow_relocs = config->info->family < ADRENO_6XX_GEN1; ++ gpu->pdev = pdev; + + /* Only handle the core clock when GMU is not in use (or is absent). */ + if (adreno_has_gmu_wrapper(adreno_gpu) || +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 99acaf917e4304..f0c3804f425879 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 +@@ -77,7 +77,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x4000, .len = 0x1f0, + .features = VIG_SDM845_MASK, +- .sblk = &sdm845_vig_sblk_0, ++ .sblk = &sm8150_vig_sblk_0, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG0, +@@ -85,7 +85,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { + .name = "sspp_1", .id = SSPP_VIG1, + .base = 0x6000, .len = 0x1f0, + .features = VIG_SDM845_MASK, +- .sblk = &sdm845_vig_sblk_1, ++ .sblk = &sm8150_vig_sblk_1, + .xin_id = 4, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG1, +@@ -93,7 +93,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { + .name = "sspp_2", .id = SSPP_VIG2, + .base = 0x8000, .len = 0x1f0, + .features = VIG_SDM845_MASK, +- .sblk = &sdm845_vig_sblk_2, ++ .sblk = &sm8150_vig_sblk_2, + .xin_id = 8, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG2, +@@ -101,7 +101,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { + .name = "sspp_3", .id = SSPP_VIG3, + .base = 0xa000, .len = 0x1f0, + .features = VIG_SDM845_MASK, +- .sblk = &sdm845_vig_sblk_3, ++ .sblk = &sm8150_vig_sblk_3, + .xin_id = 12, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG3, +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 f3de21025ca734..47de71e71e3108 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 +@@ -76,7 +76,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x4000, .len = 0x1f0, + .features = VIG_SDM845_MASK, +- .sblk = &sdm845_vig_sblk_0, ++ .sblk = &sm8150_vig_sblk_0, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG0, +@@ -84,7 +84,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { + .name = "sspp_1", .id = SSPP_VIG1, + .base = 0x6000, .len = 0x1f0, + .features = VIG_SDM845_MASK, +- .sblk = &sdm845_vig_sblk_1, ++ .sblk = &sm8150_vig_sblk_1, + .xin_id = 4, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG1, +@@ -92,7 +92,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { + .name = "sspp_2", .id = SSPP_VIG2, + .base = 0x8000, .len = 0x1f0, + .features = VIG_SDM845_MASK, +- .sblk = &sdm845_vig_sblk_2, ++ .sblk = &sm8150_vig_sblk_2, + .xin_id = 8, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG2, +@@ -100,7 +100,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { + .name = "sspp_3", .id = SSPP_VIG3, + .base = 0xa000, .len = 0x1f0, + .features = VIG_SDM845_MASK, +- .sblk = &sdm845_vig_sblk_3, ++ .sblk = &sm8150_vig_sblk_3, + .xin_id = 12, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG3, +@@ -377,6 +377,7 @@ static const struct dpu_perf_cfg sc8180x_perf_data = { + .min_llcc_ib = 800000, + .min_dram_ib = 800000, + .danger_lut_tbl = {0xf, 0xffff, 0x0}, ++ .safe_lut_tbl = {0xfff0, 0xf000, 0xffff}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(sc7180_qos_linear), + .entries = sc7180_qos_linear +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 5f9b437b82a689..ee781037ada93e 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 +@@ -32,7 +32,7 @@ static const struct dpu_mdp_cfg sm8250_mdp = { + [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2bc, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA3] = { .reg_off = 0x2c4, .bit_off = 8 }, + [DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20 }, +- [DPU_CLK_CTRL_WB2] = { .reg_off = 0x3b8, .bit_off = 24 }, ++ [DPU_CLK_CTRL_WB2] = { .reg_off = 0x2bc, .bit_off = 16 }, + }, + }; + +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 d030c08636b4c3..69d3f7e5e095b0 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 +@@ -25,7 +25,7 @@ static const struct dpu_mdp_cfg sc7180_mdp = { + [DPU_CLK_CTRL_DMA0] = { .reg_off = 0x2ac, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2c4, .bit_off = 8 }, +- [DPU_CLK_CTRL_WB2] = { .reg_off = 0x3b8, .bit_off = 24 }, ++ [DPU_CLK_CTRL_WB2] = { .reg_off = 0x2bc, .bit_off = 16 }, + }, + }; + +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 f8d16f9bf528d8..428bcbcfbf1925 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 +@@ -31,6 +31,7 @@ static const struct dpu_mdp_cfg sm8350_mdp = { + [DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2bc, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA3] = { .reg_off = 0x2c4, .bit_off = 8 }, ++ [DPU_CLK_CTRL_WB2] = { .reg_off = 0x2bc, .bit_off = 16 }, + [DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20 }, + }, + }; +@@ -304,6 +305,21 @@ static const struct dpu_dsc_cfg sm8350_dsc[] = { + }, + }; + ++static const struct dpu_wb_cfg sm8350_wb[] = { ++ { ++ .name = "wb_2", .id = WB_2, ++ .base = 0x65000, .len = 0x2c8, ++ .features = WB_SM8250_MASK, ++ .format_list = wb2_formats, ++ .num_formats = ARRAY_SIZE(wb2_formats), ++ .clk_ctrl = DPU_CLK_CTRL_WB2, ++ .xin_id = 6, ++ .vbif_idx = VBIF_RT, ++ .maxlinewidth = 4096, ++ .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), ++ }, ++}; ++ + static const struct dpu_intf_cfg sm8350_intf[] = { + { + .name = "intf_0", .id = INTF_0, +@@ -401,6 +417,8 @@ const struct dpu_mdss_cfg dpu_sm8350_cfg = { + .dsc = sm8350_dsc, + .merge_3d_count = ARRAY_SIZE(sm8350_merge_3d), + .merge_3d = sm8350_merge_3d, ++ .wb_count = ARRAY_SIZE(sm8350_wb), ++ .wb = sm8350_wb, + .intf_count = ARRAY_SIZE(sm8350_intf), + .intf = sm8350_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +index 3b5061c4402a67..9195cb996f444b 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +@@ -25,7 +25,7 @@ static const struct dpu_mdp_cfg sc7280_mdp = { + [DPU_CLK_CTRL_DMA0] = { .reg_off = 0x2ac, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2c4, .bit_off = 8 }, +- [DPU_CLK_CTRL_WB2] = { .reg_off = 0x3b8, .bit_off = 24 }, ++ [DPU_CLK_CTRL_WB2] = { .reg_off = 0x2bc, .bit_off = 16 }, + }, + }; + +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 58f5e25679b153..ff9adb8000acdb 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 +@@ -419,6 +419,7 @@ static const struct dpu_perf_cfg sc8280xp_perf_data = { + .min_llcc_ib = 0, + .min_dram_ib = 800000, + .danger_lut_tbl = {0xf, 0xffff, 0x0}, ++ .safe_lut_tbl = {0xfe00, 0xfe00, 0xffff}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(sc8180x_qos_linear), + .entries = sc8180x_qos_linear +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 1b12178dfbcab7..72a1726371cae2 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 +@@ -32,6 +32,7 @@ static const struct dpu_mdp_cfg sm8450_mdp = { + [DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2bc, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA3] = { .reg_off = 0x2c4, .bit_off = 8 }, ++ [DPU_CLK_CTRL_WB2] = { .reg_off = 0x2bc, .bit_off = 16 }, + [DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20 }, + }, + }; +@@ -76,7 +77,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x4000, .len = 0x32c, + .features = VIG_SC7180_MASK, +- .sblk = &sm8250_vig_sblk_0, ++ .sblk = &sm8450_vig_sblk_0, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG0, +@@ -84,7 +85,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { + .name = "sspp_1", .id = SSPP_VIG1, + .base = 0x6000, .len = 0x32c, + .features = VIG_SC7180_MASK, +- .sblk = &sm8250_vig_sblk_1, ++ .sblk = &sm8450_vig_sblk_1, + .xin_id = 4, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG1, +@@ -92,7 +93,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { + .name = "sspp_2", .id = SSPP_VIG2, + .base = 0x8000, .len = 0x32c, + .features = VIG_SC7180_MASK, +- .sblk = &sm8250_vig_sblk_2, ++ .sblk = &sm8450_vig_sblk_2, + .xin_id = 8, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG2, +@@ -100,7 +101,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { + .name = "sspp_3", .id = SSPP_VIG3, + .base = 0xa000, .len = 0x32c, + .features = VIG_SC7180_MASK, +- .sblk = &sm8250_vig_sblk_3, ++ .sblk = &sm8450_vig_sblk_3, + .xin_id = 12, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG3, +@@ -326,6 +327,21 @@ static const struct dpu_dsc_cfg sm8450_dsc[] = { + }, + }; + ++static const struct dpu_wb_cfg sm8450_wb[] = { ++ { ++ .name = "wb_2", .id = WB_2, ++ .base = 0x65000, .len = 0x2c8, ++ .features = WB_SM8250_MASK, ++ .format_list = wb2_formats, ++ .num_formats = ARRAY_SIZE(wb2_formats), ++ .clk_ctrl = DPU_CLK_CTRL_WB2, ++ .xin_id = 6, ++ .vbif_idx = VBIF_RT, ++ .maxlinewidth = 4096, ++ .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), ++ }, ++}; ++ + static const struct dpu_intf_cfg sm8450_intf[] = { + { + .name = "intf_0", .id = INTF_0, +@@ -423,6 +439,8 @@ const struct dpu_mdss_cfg dpu_sm8450_cfg = { + .dsc = sm8450_dsc, + .merge_3d_count = ARRAY_SIZE(sm8450_merge_3d), + .merge_3d = sm8450_merge_3d, ++ .wb_count = ARRAY_SIZE(sm8450_wb), ++ .wb = sm8450_wb, + .intf_count = ARRAY_SIZE(sm8450_intf), + .intf = sm8450_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h +index b5b6e7031fb9e9..ba06312cbb163e 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h +@@ -53,7 +53,7 @@ u32 dpu_core_irq_read( + int dpu_core_irq_register_callback( + struct dpu_kms *dpu_kms, + int irq_idx, +- void (*irq_cb)(void *arg, int irq_idx), ++ void (*irq_cb)(void *arg), + void *irq_arg); + + /** +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c +index ef871239adb2a3..68fae048a9a837 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c +@@ -459,15 +459,15 @@ int dpu_core_perf_debugfs_init(struct dpu_kms *dpu_kms, struct dentry *parent) + &perf->core_clk_rate); + debugfs_create_u32("enable_bw_release", 0600, entry, + (u32 *)&perf->enable_bw_release); +- debugfs_create_u32("threshold_low", 0600, entry, ++ debugfs_create_u32("threshold_low", 0400, entry, + (u32 *)&perf->perf_cfg->max_bw_low); +- debugfs_create_u32("threshold_high", 0600, entry, ++ debugfs_create_u32("threshold_high", 0400, entry, + (u32 *)&perf->perf_cfg->max_bw_high); +- debugfs_create_u32("min_core_ib", 0600, entry, ++ debugfs_create_u32("min_core_ib", 0400, entry, + (u32 *)&perf->perf_cfg->min_core_ib); +- debugfs_create_u32("min_llcc_ib", 0600, entry, ++ debugfs_create_u32("min_llcc_ib", 0400, entry, + (u32 *)&perf->perf_cfg->min_llcc_ib); +- debugfs_create_u32("min_dram_ib", 0600, entry, ++ debugfs_create_u32("min_dram_ib", 0400, entry, + (u32 *)&perf->perf_cfg->min_dram_ib); + debugfs_create_file("perf_mode", 0600, entry, + (u32 *)perf, &dpu_core_perf_mode_fops); +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +index 8ce7586e2ddf74..e238e4e8116caf 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.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. + * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark +@@ -125,7 +125,7 @@ static void dpu_crtc_setup_lm_misr(struct dpu_crtc_state *crtc_state) + continue; + + /* Calculate MISR over 1 frame */ +- m->hw_lm->ops.setup_misr(m->hw_lm, true, 1); ++ m->hw_lm->ops.setup_misr(m->hw_lm); + } + } + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +index d34e684a417890..6262ec5e40204c 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +@@ -2,7 +2,7 @@ + /* + * Copyright (C) 2013 Red Hat + * Copyright (c) 2014-2018, 2020-2021 The Linux Foundation. All rights reserved. +- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Author: Rob Clark + */ +@@ -39,6 +39,9 @@ + #define DPU_ERROR_ENC(e, fmt, ...) DPU_ERROR("enc%d " fmt,\ + (e) ? (e)->base.base.id : -1, ##__VA_ARGS__) + ++#define DPU_ERROR_ENC_RATELIMITED(e, fmt, ...) DPU_ERROR_RATELIMITED("enc%d " fmt,\ ++ (e) ? (e)->base.base.id : -1, ##__VA_ARGS__) ++ + /* + * Two to anticipate panels that can do cmd/vid dynamic switching + * plan is to create all possible physical encoder types, and switch between +@@ -121,6 +124,8 @@ enum dpu_enc_rc_states { + * @base: drm_encoder base class for registration with DRM + * @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes + * @enabled: True if the encoder is active, protected by enc_lock ++ * @commit_done_timedout: True if there has been a timeout on commit after ++ * enabling the encoder. + * @num_phys_encs: Actual number of physical encoders contained. + * @phys_encs: Container of physical encoders managed. + * @cur_master: Pointer to the current master in this mode. Optimization +@@ -169,6 +174,7 @@ struct dpu_encoder_virt { + spinlock_t enc_spinlock; + + bool enabled; ++ bool commit_done_timedout; + + unsigned int num_phys_encs; + struct dpu_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL]; +@@ -223,6 +229,13 @@ bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc) + return dpu_enc->wide_bus_en; + } + ++bool dpu_encoder_is_dsc_enabled(const struct drm_encoder *drm_enc) ++{ ++ const struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); ++ ++ return dpu_enc->dsc ? true : false; ++} ++ + int dpu_encoder_get_crc_values_cnt(const struct drm_encoder *drm_enc) + { + struct dpu_encoder_virt *dpu_enc; +@@ -255,7 +268,7 @@ void dpu_encoder_setup_misr(const struct drm_encoder *drm_enc) + if (!phys->hw_intf || !phys->hw_intf->ops.setup_misr) + continue; + +- phys->hw_intf->ops.setup_misr(phys->hw_intf, true, 1); ++ phys->hw_intf->ops.setup_misr(phys->hw_intf); + } + } + +@@ -347,8 +360,8 @@ static int dpu_encoder_helper_wait_event_timeout(int32_t drm_id, + u32 irq_idx, struct dpu_encoder_wait_info *info); + + int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc, +- int irq, +- void (*func)(void *arg, int irq_idx), ++ int irq_idx, ++ void (*func)(void *arg), + struct dpu_encoder_wait_info *wait_info) + { + u32 irq_status; +@@ -362,54 +375,54 @@ int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc, + + /* return EWOULDBLOCK since we know the wait isn't necessary */ + if (phys_enc->enable_state == DPU_ENC_DISABLED) { +- DRM_ERROR("encoder is disabled id=%u, callback=%ps, irq=%d\n", ++ DRM_ERROR("encoder is disabled id=%u, callback=%ps, IRQ=[%d, %d]\n", + DRMID(phys_enc->parent), func, +- irq); ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + return -EWOULDBLOCK; + } + +- if (irq < 0) { ++ if (irq_idx < 0) { + DRM_DEBUG_KMS("skip irq wait id=%u, callback=%ps\n", + DRMID(phys_enc->parent), func); + return 0; + } + +- DRM_DEBUG_KMS("id=%u, callback=%ps, irq=%d, pp=%d, pending_cnt=%d\n", ++ DRM_DEBUG_KMS("id=%u, callback=%ps, IRQ=[%d, %d], pp=%d, pending_cnt=%d\n", + DRMID(phys_enc->parent), func, +- irq, phys_enc->hw_pp->idx - PINGPONG_0, ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt)); + + ret = dpu_encoder_helper_wait_event_timeout( + DRMID(phys_enc->parent), +- irq, ++ irq_idx, + wait_info); + + if (ret <= 0) { +- irq_status = dpu_core_irq_read(phys_enc->dpu_kms, irq); ++ irq_status = dpu_core_irq_read(phys_enc->dpu_kms, irq_idx); + if (irq_status) { + unsigned long flags; + +- DRM_DEBUG_KMS("irq not triggered id=%u, callback=%ps, irq=%d, pp=%d, atomic_cnt=%d\n", ++ DRM_DEBUG_KMS("IRQ=[%d, %d] not triggered id=%u, callback=%ps, pp=%d, atomic_cnt=%d\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), + DRMID(phys_enc->parent), func, +- irq, + phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt)); + local_irq_save(flags); +- func(phys_enc, irq); ++ func(phys_enc); + local_irq_restore(flags); + ret = 0; + } else { + ret = -ETIMEDOUT; +- DRM_DEBUG_KMS("irq timeout id=%u, callback=%ps, irq=%d, pp=%d, atomic_cnt=%d\n", ++ DRM_DEBUG_KMS("IRQ=[%d, %d] timeout id=%u, callback=%ps, pp=%d, atomic_cnt=%d\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), + DRMID(phys_enc->parent), func, +- irq, + phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt)); + } + } else { + ret = 0; + trace_dpu_enc_irq_wait_success(DRMID(phys_enc->parent), +- func, irq, ++ func, irq_idx, + phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt)); + } +@@ -1106,8 +1119,6 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc, + + cstate->num_mixers = num_lm; + +- dpu_enc->connector = conn_state->connector; +- + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + +@@ -1200,6 +1211,11 @@ static void dpu_encoder_virt_atomic_enable(struct drm_encoder *drm_enc, + dpu_enc->dsc = dpu_encoder_get_dsc_config(drm_enc); + + mutex_lock(&dpu_enc->enc_lock); ++ ++ dpu_enc->commit_done_timedout = false; ++ ++ dpu_enc->connector = drm_atomic_get_new_connector_for_encoder(state, drm_enc); ++ + cur_mode = &dpu_enc->base.crtc->state->adjusted_mode; + + trace_dpu_enc_enable(DRMID(drm_enc), cur_mode->hdisplay, +@@ -1255,7 +1271,7 @@ static void dpu_encoder_virt_atomic_disable(struct drm_encoder *drm_enc, + trace_dpu_enc_disable(DRMID(drm_enc)); + + /* wait for idle */ +- dpu_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); ++ dpu_encoder_wait_for_tx_complete(drm_enc); + + dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_PRE_STOP); + +@@ -1662,8 +1678,7 @@ void dpu_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc) + phys = dpu_enc->phys_encs[i]; + + ctl = phys->hw_ctl; +- if (ctl->ops.clear_pending_flush) +- ctl->ops.clear_pending_flush(ctl); ++ ctl->ops.clear_pending_flush(ctl); + + /* update only for command mode primary ctl */ + if ((phys == dpu_enc->cur_master) && +@@ -1845,7 +1860,9 @@ static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc, + dsc_common_mode = 0; + pic_width = dsc->pic_width; + +- dsc_common_mode = DSC_MODE_MULTIPLEX | DSC_MODE_SPLIT_PANEL; ++ dsc_common_mode = DSC_MODE_SPLIT_PANEL; ++ if (dpu_encoder_use_dsc_merge(enc_master->parent)) ++ dsc_common_mode |= DSC_MODE_MULTIPLEX; + if (enc_master->intf_mode == INTF_MODE_VIDEO) + dsc_common_mode |= DSC_MODE_VIDEO; + +@@ -2060,7 +2077,7 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc) + } + + /* reset the merge 3D HW block */ +- if (phys_enc->hw_pp->merge_3d) { ++ if (phys_enc->hw_pp && phys_enc->hw_pp->merge_3d) { + phys_enc->hw_pp->merge_3d->ops.setup_3d_mode(phys_enc->hw_pp->merge_3d, + BLEND_3D_NONE); + if (phys_enc->hw_ctl->ops.update_pending_flush_merge_3d) +@@ -2082,7 +2099,7 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc) + if (phys_enc->hw_wb) + intf_cfg.wb = phys_enc->hw_wb->idx; + +- if (phys_enc->hw_pp->merge_3d) ++ if (phys_enc->hw_pp && phys_enc->hw_pp->merge_3d) + intf_cfg.merge_3d = phys_enc->hw_pp->merge_3d->idx; + + if (ctl->ops.reset_intf_cfg) +@@ -2161,6 +2178,7 @@ static void dpu_encoder_early_unregister(struct drm_encoder *encoder) + } + + static int dpu_encoder_virt_add_phys_encs( ++ struct drm_device *dev, + struct msm_display_info *disp_info, + struct dpu_encoder_virt *dpu_enc, + struct dpu_enc_phys_init_params *params) +@@ -2182,7 +2200,7 @@ static int dpu_encoder_virt_add_phys_encs( + + + if (disp_info->intf_type == INTF_WB) { +- enc = dpu_encoder_phys_wb_init(params); ++ enc = dpu_encoder_phys_wb_init(dev, params); + + if (IS_ERR(enc)) { + DPU_ERROR_ENC(dpu_enc, "failed to init wb enc: %ld\n", +@@ -2193,7 +2211,7 @@ static int dpu_encoder_virt_add_phys_encs( + dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc; + ++dpu_enc->num_phys_encs; + } else if (disp_info->is_cmd_mode) { +- enc = dpu_encoder_phys_cmd_init(params); ++ enc = dpu_encoder_phys_cmd_init(dev, params); + + if (IS_ERR(enc)) { + DPU_ERROR_ENC(dpu_enc, "failed to init cmd enc: %ld\n", +@@ -2204,7 +2222,7 @@ static int dpu_encoder_virt_add_phys_encs( + dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc; + ++dpu_enc->num_phys_encs; + } else { +- enc = dpu_encoder_phys_vid_init(params); ++ enc = dpu_encoder_phys_vid_init(dev, params); + + if (IS_ERR(enc)) { + DPU_ERROR_ENC(dpu_enc, "failed to init vid enc: %ld\n", +@@ -2293,7 +2311,7 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc, + break; + } + +- ret = dpu_encoder_virt_add_phys_encs(disp_info, ++ ret = dpu_encoder_virt_add_phys_encs(dpu_kms->dev, disp_info, + dpu_enc, &phys_params); + if (ret) { + DPU_ERROR_ENC(dpu_enc, "failed to add phys encs\n"); +@@ -2327,7 +2345,7 @@ static void dpu_encoder_frame_done_timeout(struct timer_list *t) + return; + } + +- DPU_ERROR_ENC(dpu_enc, "frame done timeout\n"); ++ DPU_ERROR_ENC_RATELIMITED(dpu_enc, "frame done timeout\n"); + + event = DPU_ENCODER_FRAME_EVENT_ERROR; + trace_dpu_enc_frame_done_timeout(DRMID(drm_enc), event); +@@ -2405,10 +2423,18 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev, + return ERR_PTR(ret); + } + +-int dpu_encoder_wait_for_event(struct drm_encoder *drm_enc, +- enum msm_event_wait event) ++/** ++ * dpu_encoder_wait_for_commit_done() - Wait for encoder to flush pending state ++ * @drm_enc: encoder pointer ++ * ++ * Wait for hardware to have flushed the current pending changes to hardware at ++ * a vblank or CTL_START. Physical encoders will map this differently depending ++ * on the type: vid mode -> vsync_irq, cmd mode -> CTL_START. ++ * ++ * Return: 0 on success, -EWOULDBLOCK if already signaled, error otherwise ++ */ ++int dpu_encoder_wait_for_commit_done(struct drm_encoder *drm_enc) + { +- int (*fn_wait)(struct dpu_encoder_phys *phys_enc) = NULL; + struct dpu_encoder_virt *dpu_enc = NULL; + int i, ret = 0; + +@@ -2422,26 +2448,51 @@ int dpu_encoder_wait_for_event(struct drm_encoder *drm_enc, + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + +- switch (event) { +- case MSM_ENC_COMMIT_DONE: +- fn_wait = phys->ops.wait_for_commit_done; +- break; +- case MSM_ENC_TX_COMPLETE: +- fn_wait = phys->ops.wait_for_tx_complete; +- break; +- case MSM_ENC_VBLANK: +- fn_wait = phys->ops.wait_for_vblank; +- break; +- default: +- DPU_ERROR_ENC(dpu_enc, "unknown wait event %d\n", +- event); +- return -EINVAL; ++ if (phys->ops.wait_for_commit_done) { ++ DPU_ATRACE_BEGIN("wait_for_commit_done"); ++ ret = phys->ops.wait_for_commit_done(phys); ++ DPU_ATRACE_END("wait_for_commit_done"); ++ if (ret == -ETIMEDOUT && !dpu_enc->commit_done_timedout) { ++ dpu_enc->commit_done_timedout = true; ++ msm_disp_snapshot_state(drm_enc->dev); ++ } ++ if (ret) ++ return ret; + } ++ } ++ ++ return ret; ++} ++ ++/** ++ * dpu_encoder_wait_for_tx_complete() - Wait for encoder to transfer pixels to panel ++ * @drm_enc: encoder pointer ++ * ++ * Wait for the hardware to transfer all the pixels to the panel. Physical ++ * encoders will map this differently depending on the type: vid mode -> vsync_irq, ++ * cmd mode -> pp_done. ++ * ++ * Return: 0 on success, -EWOULDBLOCK if already signaled, error otherwise ++ */ ++int dpu_encoder_wait_for_tx_complete(struct drm_encoder *drm_enc) ++{ ++ struct dpu_encoder_virt *dpu_enc = NULL; ++ int i, ret = 0; ++ ++ if (!drm_enc) { ++ DPU_ERROR("invalid encoder\n"); ++ return -EINVAL; ++ } ++ dpu_enc = to_dpu_encoder_virt(drm_enc); ++ DPU_DEBUG_ENC(dpu_enc, "\n"); ++ ++ for (i = 0; i < dpu_enc->num_phys_encs; i++) { ++ struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + +- if (fn_wait) { +- DPU_ATRACE_BEGIN("wait_for_completion_event"); +- ret = fn_wait(phys); +- DPU_ATRACE_END("wait_for_completion_event"); ++ if (phys->ops.wait_for_tx_complete) { ++ DPU_ATRACE_BEGIN("wait_for_tx_complete"); ++ ret = phys->ops.wait_for_tx_complete(phys); ++ DPU_ATRACE_END("wait_for_tx_complete"); + if (ret) + return ret; + } +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +index 4c05fd5e9ed18d..0c928d1876e4ae 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +@@ -93,25 +93,9 @@ void dpu_encoder_kickoff(struct drm_encoder *encoder); + */ + int dpu_encoder_vsync_time(struct drm_encoder *drm_enc, ktime_t *wakeup_time); + +-/** +- * dpu_encoder_wait_for_event - Waits for encoder events +- * @encoder: encoder pointer +- * @event: event to wait for +- * MSM_ENC_COMMIT_DONE - Wait for hardware to have flushed the current pending +- * frames to hardware at a vblank or ctl_start +- * Encoders will map this differently depending on the +- * panel type. +- * vid mode -> vsync_irq +- * cmd mode -> ctl_start +- * MSM_ENC_TX_COMPLETE - Wait for the hardware to transfer all the pixels to +- * the panel. Encoders will map this differently +- * depending on the panel type. +- * vid mode -> vsync_irq +- * cmd mode -> pp_done +- * Returns: 0 on success, -EWOULDBLOCK if already signaled, error otherwise +- */ +-int dpu_encoder_wait_for_event(struct drm_encoder *drm_encoder, +- enum msm_event_wait event); ++int dpu_encoder_wait_for_commit_done(struct drm_encoder *drm_encoder); ++ ++int dpu_encoder_wait_for_tx_complete(struct drm_encoder *drm_encoder); + + /* + * dpu_encoder_get_intf_mode - get interface mode of the given encoder +@@ -158,6 +142,13 @@ int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc); + + bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc); + ++/** ++ * dpu_encoder_is_dsc_enabled - indicate whether dsc is enabled ++ * for the encoder. ++ * @drm_enc: Pointer to previously created drm encoder structure ++ */ ++bool dpu_encoder_is_dsc_enabled(const struct drm_encoder *drm_enc); ++ + /** + * dpu_encoder_get_crc_values_cnt - get number of physical encoders contained + * in virtual encoder that can collect CRC values +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +index d48558ede488d5..57a3598f2a303c 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +@@ -106,7 +106,6 @@ struct dpu_encoder_phys_ops { + int (*control_vblank_irq)(struct dpu_encoder_phys *enc, bool enable); + int (*wait_for_commit_done)(struct dpu_encoder_phys *phys_enc); + int (*wait_for_tx_complete)(struct dpu_encoder_phys *phys_enc); +- int (*wait_for_vblank)(struct dpu_encoder_phys *phys_enc); + void (*prepare_for_kickoff)(struct dpu_encoder_phys *phys_enc); + void (*handle_post_kickoff)(struct dpu_encoder_phys *phys_enc); + void (*trigger_start)(struct dpu_encoder_phys *phys_enc); +@@ -281,22 +280,24 @@ struct dpu_encoder_wait_info { + * @p: Pointer to init params structure + * Return: Error code or newly allocated encoder + */ +-struct dpu_encoder_phys *dpu_encoder_phys_vid_init( ++struct dpu_encoder_phys *dpu_encoder_phys_vid_init(struct drm_device *dev, + struct dpu_enc_phys_init_params *p); + + /** + * dpu_encoder_phys_cmd_init - Construct a new command mode physical encoder ++ * @dev: Corresponding device for devres management + * @p: Pointer to init params structure + * Return: Error code or newly allocated encoder + */ +-struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( ++struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(struct drm_device *dev, + struct dpu_enc_phys_init_params *p); + + /** + * dpu_encoder_phys_wb_init - initialize writeback encoder ++ * @dev: Corresponding device for devres management + * @init: Pointer to init info structure with initialization params + */ +-struct dpu_encoder_phys *dpu_encoder_phys_wb_init( ++struct dpu_encoder_phys *dpu_encoder_phys_wb_init(struct drm_device *dev, + struct dpu_enc_phys_init_params *p); + + /** +@@ -365,7 +366,7 @@ void dpu_encoder_helper_report_irq_timeout(struct dpu_encoder_phys *phys_enc, + */ + int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc, + int irq, +- void (*func)(void *arg, int irq_idx), ++ void (*func)(void *arg), + struct dpu_encoder_wait_info *wait_info); + + /** +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +index df88358e7037bf..83a804ebf8d7ef 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +@@ -13,6 +13,8 @@ + #include "dpu_trace.h" + #include "disp/msm_disp_snapshot.h" + ++#include ++ + #define DPU_DEBUG_CMDENC(e, fmt, ...) DPU_DEBUG("enc%d intf%d " fmt, \ + (e) && (e)->base.parent ? \ + (e)->base.parent->base.id : -1, \ +@@ -76,7 +78,7 @@ static void _dpu_encoder_phys_cmd_update_intf_cfg( + phys_enc->hw_intf->ops.program_intf_cmd_cfg(phys_enc->hw_intf, &cmd_mode_cfg); + } + +-static void dpu_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) ++static void dpu_encoder_phys_cmd_pp_tx_done_irq(void *arg) + { + struct dpu_encoder_phys *phys_enc = arg; + unsigned long lock_flags; +@@ -103,7 +105,7 @@ static void dpu_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) + DPU_ATRACE_END("pp_done_irq"); + } + +-static void dpu_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx) ++static void dpu_encoder_phys_cmd_te_rd_ptr_irq(void *arg) + { + struct dpu_encoder_phys *phys_enc = arg; + struct dpu_encoder_phys_cmd *cmd_enc; +@@ -126,7 +128,7 @@ static void dpu_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx) + DPU_ATRACE_END("rd_ptr_irq"); + } + +-static void dpu_encoder_phys_cmd_ctl_start_irq(void *arg, int irq_idx) ++static void dpu_encoder_phys_cmd_ctl_start_irq(void *arg) + { + struct dpu_encoder_phys *phys_enc = arg; + +@@ -139,7 +141,7 @@ static void dpu_encoder_phys_cmd_ctl_start_irq(void *arg, int irq_idx) + DPU_ATRACE_END("ctl_start_irq"); + } + +-static void dpu_encoder_phys_cmd_underrun_irq(void *arg, int irq_idx) ++static void dpu_encoder_phys_cmd_underrun_irq(void *arg) + { + struct dpu_encoder_phys *phys_enc = arg; + +@@ -449,9 +451,6 @@ static void dpu_encoder_phys_cmd_enable_helper( + + _dpu_encoder_phys_cmd_pingpong_config(phys_enc); + +- if (!dpu_encoder_phys_cmd_is_master(phys_enc)) +- return; +- + ctl = phys_enc->hw_ctl; + ctl->ops.update_pending_flush_intf(ctl, phys_enc->hw_intf->idx); + } +@@ -567,14 +566,6 @@ static void dpu_encoder_phys_cmd_disable(struct dpu_encoder_phys *phys_enc) + phys_enc->enable_state = DPU_ENC_DISABLED; + } + +-static void dpu_encoder_phys_cmd_destroy(struct dpu_encoder_phys *phys_enc) +-{ +- struct dpu_encoder_phys_cmd *cmd_enc = +- to_dpu_encoder_phys_cmd(phys_enc); +- +- kfree(cmd_enc); +-} +- + static void dpu_encoder_phys_cmd_prepare_for_kickoff( + struct dpu_encoder_phys *phys_enc) + { +@@ -690,33 +681,6 @@ static int dpu_encoder_phys_cmd_wait_for_commit_done( + return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc); + } + +-static int dpu_encoder_phys_cmd_wait_for_vblank( +- struct dpu_encoder_phys *phys_enc) +-{ +- int rc = 0; +- struct dpu_encoder_phys_cmd *cmd_enc; +- struct dpu_encoder_wait_info wait_info; +- +- cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); +- +- /* only required for master controller */ +- if (!dpu_encoder_phys_cmd_is_master(phys_enc)) +- return rc; +- +- wait_info.wq = &cmd_enc->pending_vblank_wq; +- wait_info.atomic_cnt = &cmd_enc->pending_vblank_cnt; +- wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; +- +- atomic_inc(&cmd_enc->pending_vblank_cnt); +- +- rc = dpu_encoder_helper_wait_for_irq(phys_enc, +- phys_enc->irq[INTR_IDX_RDPTR], +- dpu_encoder_phys_cmd_te_rd_ptr_irq, +- &wait_info); +- +- return rc; +-} +- + static void dpu_encoder_phys_cmd_handle_post_kickoff( + struct dpu_encoder_phys *phys_enc) + { +@@ -740,12 +704,10 @@ static void dpu_encoder_phys_cmd_init_ops( + ops->atomic_mode_set = dpu_encoder_phys_cmd_atomic_mode_set; + ops->enable = dpu_encoder_phys_cmd_enable; + ops->disable = dpu_encoder_phys_cmd_disable; +- ops->destroy = dpu_encoder_phys_cmd_destroy; + ops->control_vblank_irq = dpu_encoder_phys_cmd_control_vblank_irq; + ops->wait_for_commit_done = dpu_encoder_phys_cmd_wait_for_commit_done; + ops->prepare_for_kickoff = dpu_encoder_phys_cmd_prepare_for_kickoff; + ops->wait_for_tx_complete = dpu_encoder_phys_cmd_wait_for_tx_complete; +- ops->wait_for_vblank = dpu_encoder_phys_cmd_wait_for_vblank; + ops->trigger_start = dpu_encoder_phys_cmd_trigger_start; + ops->needs_single_flush = dpu_encoder_phys_cmd_needs_single_flush; + ops->irq_control = dpu_encoder_phys_cmd_irq_control; +@@ -755,7 +717,7 @@ static void dpu_encoder_phys_cmd_init_ops( + ops->get_line_count = dpu_encoder_phys_cmd_get_line_count; + } + +-struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( ++struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(struct drm_device *dev, + struct dpu_enc_phys_init_params *p) + { + struct dpu_encoder_phys *phys_enc = NULL; +@@ -763,7 +725,7 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( + + DPU_DEBUG("intf\n"); + +- cmd_enc = kzalloc(sizeof(*cmd_enc), GFP_KERNEL); ++ cmd_enc = drmm_kzalloc(dev, sizeof(*cmd_enc), GFP_KERNEL); + if (!cmd_enc) { + DPU_ERROR("failed to allocate\n"); + return ERR_PTR(-ENOMEM); +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +index c2189e58de6af2..daaf0e60475380 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +@@ -11,6 +11,8 @@ + #include "dpu_trace.h" + #include "disp/msm_disp_snapshot.h" + ++#include ++ + #define DPU_DEBUG_VIDENC(e, fmt, ...) DPU_DEBUG("enc%d intf%d " fmt, \ + (e) && (e)->parent ? \ + (e)->parent->base.id : -1, \ +@@ -100,6 +102,7 @@ static void drm_mode_to_intf_timing_params( + } + + timing->wide_bus_en = dpu_encoder_is_widebus_enabled(phys_enc->parent); ++ timing->compression_en = dpu_encoder_is_dsc_enabled(phys_enc->parent); + + /* + * for DP, divide the horizonal parameters by 2 when +@@ -257,12 +260,14 @@ static void dpu_encoder_phys_vid_setup_timing_engine( + mode.htotal >>= 1; + mode.hsync_start >>= 1; + mode.hsync_end >>= 1; ++ mode.hskew >>= 1; + + DPU_DEBUG_VIDENC(phys_enc, +- "split_role %d, halve horizontal %d %d %d %d\n", ++ "split_role %d, halve horizontal %d %d %d %d %d\n", + phys_enc->split_role, + mode.hdisplay, mode.htotal, +- mode.hsync_start, mode.hsync_end); ++ mode.hsync_start, mode.hsync_end, ++ mode.hskew); + } + + drm_mode_to_intf_timing_params(phys_enc, &mode, &timing_params); +@@ -297,7 +302,7 @@ static void dpu_encoder_phys_vid_setup_timing_engine( + programmable_fetch_config(phys_enc, &timing_params); + } + +-static void dpu_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) ++static void dpu_encoder_phys_vid_vblank_irq(void *arg) + { + struct dpu_encoder_phys *phys_enc = arg; + struct dpu_hw_ctl *hw_ctl; +@@ -334,7 +339,7 @@ static void dpu_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) + DPU_ATRACE_END("vblank_irq"); + } + +-static void dpu_encoder_phys_vid_underrun_irq(void *arg, int irq_idx) ++static void dpu_encoder_phys_vid_underrun_irq(void *arg) + { + struct dpu_encoder_phys *phys_enc = arg; + +@@ -438,13 +443,7 @@ static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc) + phys_enc->enable_state = DPU_ENC_ENABLING; + } + +-static void dpu_encoder_phys_vid_destroy(struct dpu_encoder_phys *phys_enc) +-{ +- DPU_DEBUG_VIDENC(phys_enc, "\n"); +- kfree(phys_enc); +-} +- +-static int dpu_encoder_phys_vid_wait_for_vblank( ++static int dpu_encoder_phys_vid_wait_for_tx_complete( + struct dpu_encoder_phys *phys_enc) + { + struct dpu_encoder_wait_info wait_info; +@@ -558,7 +557,7 @@ static void dpu_encoder_phys_vid_disable(struct dpu_encoder_phys *phys_enc) + * scanout buffer) don't latch properly.. + */ + if (dpu_encoder_phys_vid_is_master(phys_enc)) { +- ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc); ++ ret = dpu_encoder_phys_vid_wait_for_tx_complete(phys_enc); + if (ret) { + atomic_set(&phys_enc->pending_kickoff_cnt, 0); + DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n", +@@ -578,7 +577,7 @@ static void dpu_encoder_phys_vid_disable(struct dpu_encoder_phys *phys_enc) + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + dpu_encoder_phys_inc_pending(phys_enc); + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); +- ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc); ++ ret = dpu_encoder_phys_vid_wait_for_tx_complete(phys_enc); + if (ret) { + atomic_set(&phys_enc->pending_kickoff_cnt, 0); + DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n", +@@ -681,11 +680,9 @@ static void dpu_encoder_phys_vid_init_ops(struct dpu_encoder_phys_ops *ops) + ops->atomic_mode_set = dpu_encoder_phys_vid_atomic_mode_set; + ops->enable = dpu_encoder_phys_vid_enable; + ops->disable = dpu_encoder_phys_vid_disable; +- ops->destroy = dpu_encoder_phys_vid_destroy; + ops->control_vblank_irq = dpu_encoder_phys_vid_control_vblank_irq; + ops->wait_for_commit_done = dpu_encoder_phys_vid_wait_for_commit_done; +- ops->wait_for_vblank = dpu_encoder_phys_vid_wait_for_vblank; +- ops->wait_for_tx_complete = dpu_encoder_phys_vid_wait_for_vblank; ++ ops->wait_for_tx_complete = dpu_encoder_phys_vid_wait_for_tx_complete; + ops->irq_control = dpu_encoder_phys_vid_irq_control; + ops->prepare_for_kickoff = dpu_encoder_phys_vid_prepare_for_kickoff; + ops->handle_post_kickoff = dpu_encoder_phys_vid_handle_post_kickoff; +@@ -694,7 +691,7 @@ static void dpu_encoder_phys_vid_init_ops(struct dpu_encoder_phys_ops *ops) + ops->get_frame_count = dpu_encoder_phys_vid_get_frame_count; + } + +-struct dpu_encoder_phys *dpu_encoder_phys_vid_init( ++struct dpu_encoder_phys *dpu_encoder_phys_vid_init(struct drm_device *dev, + struct dpu_enc_phys_init_params *p) + { + struct dpu_encoder_phys *phys_enc = NULL; +@@ -704,7 +701,7 @@ struct dpu_encoder_phys *dpu_encoder_phys_vid_init( + return ERR_PTR(-EINVAL); + } + +- phys_enc = kzalloc(sizeof(*phys_enc), GFP_KERNEL); ++ phys_enc = drmm_kzalloc(dev, sizeof(*phys_enc), GFP_KERNEL); + if (!phys_enc) { + DPU_ERROR("failed to create encoder due to memory allocation error\n"); + return ERR_PTR(-ENOMEM); +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 78037a697633b6..0a45c546b03f2b 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 +@@ -8,6 +8,7 @@ + #include + + #include ++#include + + #include "dpu_encoder_phys.h" + #include "dpu_formats.h" +@@ -345,7 +346,11 @@ static void dpu_encoder_phys_wb_setup( + + } + +-static void _dpu_encoder_phys_wb_frame_done_helper(void *arg) ++/** ++ * dpu_encoder_phys_wb_done_irq - writeback interrupt handler ++ * @arg: Pointer to writeback encoder ++ */ ++static void dpu_encoder_phys_wb_done_irq(void *arg) + { + struct dpu_encoder_phys *phys_enc = arg; + struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc); +@@ -371,16 +376,6 @@ static void _dpu_encoder_phys_wb_frame_done_helper(void *arg) + wake_up_all(&phys_enc->pending_kickoff_wq); + } + +-/** +- * dpu_encoder_phys_wb_done_irq - writeback interrupt handler +- * @arg: Pointer to writeback encoder +- * @irq_idx: interrupt index +- */ +-static void dpu_encoder_phys_wb_done_irq(void *arg, int irq_idx) +-{ +- _dpu_encoder_phys_wb_frame_done_helper(arg); +-} +- + /** + * dpu_encoder_phys_wb_irq_ctrl - irq control of WB + * @phys: Pointer to physical encoder +@@ -534,8 +529,7 @@ static void dpu_encoder_phys_wb_disable(struct dpu_encoder_phys *phys_enc) + } + + /* reset h/w before final flush */ +- if (phys_enc->hw_ctl->ops.clear_pending_flush) +- phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl); ++ phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl); + + /* + * New CTL reset sequence from 5.0 MDP onwards. +@@ -553,20 +547,6 @@ static void dpu_encoder_phys_wb_disable(struct dpu_encoder_phys *phys_enc) + phys_enc->enable_state = DPU_ENC_DISABLED; + } + +-/** +- * dpu_encoder_phys_wb_destroy - destroy writeback encoder +- * @phys_enc: Pointer to physical encoder +- */ +-static void dpu_encoder_phys_wb_destroy(struct dpu_encoder_phys *phys_enc) +-{ +- if (!phys_enc) +- return; +- +- DPU_DEBUG("[wb:%d]\n", phys_enc->hw_wb->idx - WB_0); +- +- kfree(phys_enc); +-} +- + static void dpu_encoder_phys_wb_prepare_wb_job(struct dpu_encoder_phys *phys_enc, + struct drm_writeback_job *job) + { +@@ -662,7 +642,6 @@ static void dpu_encoder_phys_wb_init_ops(struct dpu_encoder_phys_ops *ops) + ops->atomic_mode_set = dpu_encoder_phys_wb_atomic_mode_set; + ops->enable = dpu_encoder_phys_wb_enable; + ops->disable = dpu_encoder_phys_wb_disable; +- ops->destroy = dpu_encoder_phys_wb_destroy; + ops->atomic_check = dpu_encoder_phys_wb_atomic_check; + ops->wait_for_commit_done = dpu_encoder_phys_wb_wait_for_commit_done; + ops->prepare_for_kickoff = dpu_encoder_phys_wb_prepare_for_kickoff; +@@ -678,9 +657,10 @@ static void dpu_encoder_phys_wb_init_ops(struct dpu_encoder_phys_ops *ops) + + /** + * dpu_encoder_phys_wb_init - initialize writeback encoder ++ * @dev: Corresponding device for devres management + * @p: Pointer to init info structure with initialization params + */ +-struct dpu_encoder_phys *dpu_encoder_phys_wb_init( ++struct dpu_encoder_phys *dpu_encoder_phys_wb_init(struct drm_device *dev, + struct dpu_enc_phys_init_params *p) + { + struct dpu_encoder_phys *phys_enc = NULL; +@@ -693,7 +673,7 @@ struct dpu_encoder_phys *dpu_encoder_phys_wb_init( + return ERR_PTR(-EINVAL); + } + +- wb_enc = kzalloc(sizeof(*wb_enc), GFP_KERNEL); ++ wb_enc = drmm_kzalloc(dev, sizeof(*wb_enc), GFP_KERNEL); + if (!wb_enc) { + DPU_ERROR("failed to allocate wb phys_enc enc\n"); + return ERR_PTR(-ENOMEM); +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 713dfc0797181d..77d09f961d8669 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +@@ -250,14 +250,17 @@ static const uint32_t wb2_formats[] = { + * SSPP sub blocks config + *************************************************************/ + ++#define SSPP_SCALER_VER(maj, min) (((maj) << 16) | (min)) ++ + /* SSPP common configuration */ +-#define _VIG_SBLK(sdma_pri, qseed_ver) \ ++#define _VIG_SBLK(sdma_pri, qseed_ver, scaler_ver) \ + { \ + .maxdwnscale = MAX_DOWNSCALE_RATIO, \ + .maxupscale = MAX_UPSCALE_RATIO, \ + .smart_dma_priority = sdma_pri, \ + .scaler_blk = {.name = "scaler", \ + .id = qseed_ver, \ ++ .version = scaler_ver, \ + .base = 0xa00, .len = 0xa0,}, \ + .csc_blk = {.name = "csc", \ + .id = DPU_SSPP_CSC_10BIT, \ +@@ -269,13 +272,14 @@ static const uint32_t wb2_formats[] = { + .rotation_cfg = NULL, \ + } + +-#define _VIG_SBLK_ROT(sdma_pri, qseed_ver, rot_cfg) \ ++#define _VIG_SBLK_ROT(sdma_pri, qseed_ver, scaler_ver, rot_cfg) \ + { \ + .maxdwnscale = MAX_DOWNSCALE_RATIO, \ + .maxupscale = MAX_UPSCALE_RATIO, \ + .smart_dma_priority = sdma_pri, \ + .scaler_blk = {.name = "scaler", \ + .id = qseed_ver, \ ++ .version = scaler_ver, \ + .base = 0xa00, .len = 0xa0,}, \ + .csc_blk = {.name = "csc", \ + .id = DPU_SSPP_CSC_10BIT, \ +@@ -299,13 +303,17 @@ static const uint32_t wb2_formats[] = { + } + + static const struct dpu_sspp_sub_blks msm8998_vig_sblk_0 = +- _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3); ++ _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3, ++ SSPP_SCALER_VER(1, 2)); + static const struct dpu_sspp_sub_blks msm8998_vig_sblk_1 = +- _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3); ++ _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3, ++ SSPP_SCALER_VER(1, 2)); + static const struct dpu_sspp_sub_blks msm8998_vig_sblk_2 = +- _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3); ++ _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3, ++ SSPP_SCALER_VER(1, 2)); + static const struct dpu_sspp_sub_blks msm8998_vig_sblk_3 = +- _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3); ++ _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3, ++ SSPP_SCALER_VER(1, 2)); + + static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = { + .rot_maxheight = 1088, +@@ -314,13 +322,30 @@ static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = { + }; + + static const struct dpu_sspp_sub_blks sdm845_vig_sblk_0 = +- _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED3); ++ _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED3, ++ SSPP_SCALER_VER(1, 3)); + static const struct dpu_sspp_sub_blks sdm845_vig_sblk_1 = +- _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED3); ++ _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED3, ++ SSPP_SCALER_VER(1, 3)); + static const struct dpu_sspp_sub_blks sdm845_vig_sblk_2 = +- _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED3); ++ _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED3, ++ SSPP_SCALER_VER(1, 3)); + static const struct dpu_sspp_sub_blks sdm845_vig_sblk_3 = +- _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED3); ++ _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED3, ++ SSPP_SCALER_VER(1, 3)); ++ ++static const struct dpu_sspp_sub_blks sm8150_vig_sblk_0 = ++ _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED3, ++ SSPP_SCALER_VER(1, 4)); ++static const struct dpu_sspp_sub_blks sm8150_vig_sblk_1 = ++ _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED3, ++ SSPP_SCALER_VER(1, 4)); ++static const struct dpu_sspp_sub_blks sm8150_vig_sblk_2 = ++ _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED3, ++ SSPP_SCALER_VER(1, 4)); ++static const struct dpu_sspp_sub_blks sm8150_vig_sblk_3 = ++ _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED3, ++ SSPP_SCALER_VER(1, 4)); + + static const struct dpu_sspp_sub_blks sdm845_dma_sblk_0 = _DMA_SBLK(1); + static const struct dpu_sspp_sub_blks sdm845_dma_sblk_1 = _DMA_SBLK(2); +@@ -328,34 +353,60 @@ static const struct dpu_sspp_sub_blks sdm845_dma_sblk_2 = _DMA_SBLK(3); + static const struct dpu_sspp_sub_blks sdm845_dma_sblk_3 = _DMA_SBLK(4); + + static const struct dpu_sspp_sub_blks sc7180_vig_sblk_0 = +- _VIG_SBLK(4, DPU_SSPP_SCALER_QSEED4); ++ _VIG_SBLK(4, DPU_SSPP_SCALER_QSEED4, ++ SSPP_SCALER_VER(3, 0)); + + static const struct dpu_sspp_sub_blks sc7280_vig_sblk_0 = +- _VIG_SBLK_ROT(4, DPU_SSPP_SCALER_QSEED4, &dpu_rot_sc7280_cfg_v2); ++ _VIG_SBLK_ROT(4, DPU_SSPP_SCALER_QSEED4, ++ SSPP_SCALER_VER(3, 0), ++ &dpu_rot_sc7280_cfg_v2); + + static const struct dpu_sspp_sub_blks sm6115_vig_sblk_0 = +- _VIG_SBLK(2, DPU_SSPP_SCALER_QSEED4); ++ _VIG_SBLK(2, DPU_SSPP_SCALER_QSEED4, ++ SSPP_SCALER_VER(3, 0)); + + static const struct dpu_sspp_sub_blks sm6125_vig_sblk_0 = +- _VIG_SBLK(3, DPU_SSPP_SCALER_QSEED3LITE); ++ _VIG_SBLK(3, DPU_SSPP_SCALER_QSEED3LITE, ++ SSPP_SCALER_VER(2, 4)); + + static const struct dpu_sspp_sub_blks sm8250_vig_sblk_0 = +- _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED4); ++ _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED4, ++ SSPP_SCALER_VER(3, 0)); + static const struct dpu_sspp_sub_blks sm8250_vig_sblk_1 = +- _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED4); ++ _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED4, ++ SSPP_SCALER_VER(3, 0)); + static const struct dpu_sspp_sub_blks sm8250_vig_sblk_2 = +- _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED4); ++ _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED4, ++ SSPP_SCALER_VER(3, 0)); + static const struct dpu_sspp_sub_blks sm8250_vig_sblk_3 = +- _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED4); ++ _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED4, ++ SSPP_SCALER_VER(3, 0)); ++ ++static const struct dpu_sspp_sub_blks sm8450_vig_sblk_0 = ++ _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED4, ++ SSPP_SCALER_VER(3, 1)); ++static const struct dpu_sspp_sub_blks sm8450_vig_sblk_1 = ++ _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED4, ++ SSPP_SCALER_VER(3, 1)); ++static const struct dpu_sspp_sub_blks sm8450_vig_sblk_2 = ++ _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED4, ++ SSPP_SCALER_VER(3, 1)); ++static const struct dpu_sspp_sub_blks sm8450_vig_sblk_3 = ++ _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED4, ++ SSPP_SCALER_VER(3, 1)); + + static const struct dpu_sspp_sub_blks sm8550_vig_sblk_0 = +- _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED4); ++ _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED4, ++ SSPP_SCALER_VER(3, 2)); + static const struct dpu_sspp_sub_blks sm8550_vig_sblk_1 = +- _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED4); ++ _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED4, ++ SSPP_SCALER_VER(3, 2)); + static const struct dpu_sspp_sub_blks sm8550_vig_sblk_2 = +- _VIG_SBLK(9, DPU_SSPP_SCALER_QSEED4); ++ _VIG_SBLK(9, DPU_SSPP_SCALER_QSEED4, ++ SSPP_SCALER_VER(3, 2)); + static const struct dpu_sspp_sub_blks sm8550_vig_sblk_3 = +- _VIG_SBLK(10, DPU_SSPP_SCALER_QSEED4); ++ _VIG_SBLK(10, DPU_SSPP_SCALER_QSEED4, ++ SSPP_SCALER_VER(3, 2)); + static const struct dpu_sspp_sub_blks sm8550_dma_sblk_4 = _DMA_SBLK(5); + static const struct dpu_sspp_sub_blks sm8550_dma_sblk_5 = _DMA_SBLK(6); + +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 6c9634209e9fc7..3f82d84bd1c907 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +@@ -269,7 +269,8 @@ enum { + /** + * struct dpu_scaler_blk: Scaler information + * @info: HW register and features supported by this sub-blk +- * @version: qseed block revision ++ * @version: qseed block revision, on QSEED3+ platforms this is the value of ++ * scaler_blk.base + QSEED3_HW_VERSION registers. + */ + struct dpu_scaler_blk { + DPU_HW_SUBBLK_INFO; +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h +index 1c242298ff2ee0..dca87ea78e251c 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h +@@ -81,7 +81,8 @@ struct dpu_hw_ctl_ops { + + /** + * Clear the value of the cached pending_flush_mask +- * No effect on hardware ++ * No effect on hardware. ++ * Required to be implemented. + * @ctx : ctl path ctx pointer + */ + void (*clear_pending_flush)(struct dpu_hw_ctl *ctx); +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c +index e3c50439f80a13..c8d7929ce52323 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c +@@ -197,8 +197,18 @@ static const struct dpu_intr_reg dpu_intr_set_7xxx[] = { + }, + }; + +-#define DPU_IRQ_REG(irq_idx) (irq_idx / 32) +-#define DPU_IRQ_MASK(irq_idx) (BIT(irq_idx % 32)) ++#define DPU_IRQ_MASK(irq_idx) (BIT(DPU_IRQ_BIT(irq_idx))) ++ ++static inline bool dpu_core_irq_is_valid(int irq_idx) ++{ ++ return irq_idx >= 0 && irq_idx < DPU_NUM_IRQS; ++} ++ ++static inline struct dpu_hw_intr_entry *dpu_core_irq_get_entry(struct dpu_hw_intr *intr, ++ int irq_idx) ++{ ++ return &intr->irq_tbl[irq_idx]; ++} + + /** + * dpu_core_irq_callback_handler - dispatch core interrupts +@@ -207,17 +217,22 @@ static const struct dpu_intr_reg dpu_intr_set_7xxx[] = { + */ + static void dpu_core_irq_callback_handler(struct dpu_kms *dpu_kms, int irq_idx) + { +- VERB("irq_idx=%d\n", irq_idx); ++ struct dpu_hw_intr_entry *irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, irq_idx); + +- if (!dpu_kms->hw_intr->irq_tbl[irq_idx].cb) +- DRM_ERROR("no registered cb, idx:%d\n", irq_idx); ++ VERB("IRQ=[%d, %d]\n", DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + +- atomic_inc(&dpu_kms->hw_intr->irq_tbl[irq_idx].count); ++ if (!irq_entry->cb) { ++ DRM_ERROR("no registered cb, IRQ=[%d, %d]\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); ++ return; ++ } ++ ++ atomic_inc(&irq_entry->count); + + /* + * Perform registered function callback + */ +- dpu_kms->hw_intr->irq_tbl[irq_idx].cb(dpu_kms->hw_intr->irq_tbl[irq_idx].arg, irq_idx); ++ irq_entry->cb(irq_entry->arg); + } + + irqreturn_t dpu_core_irq(struct msm_kms *kms) +@@ -291,8 +306,9 @@ static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) + if (!intr) + return -EINVAL; + +- if (irq_idx < 0 || irq_idx >= intr->total_irqs) { +- pr_err("invalid IRQ index: [%d]\n", irq_idx); ++ if (!dpu_core_irq_is_valid(irq_idx)) { ++ pr_err("invalid IRQ=[%d, %d]\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + return -EINVAL; + } + +@@ -328,7 +344,8 @@ static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) + intr->cache_irq_mask[reg_idx] = cache_irq_mask; + } + +- pr_debug("DPU IRQ %d %senabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", irq_idx, dbgstr, ++ pr_debug("DPU IRQ=[%d, %d] %senabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), dbgstr, + DPU_IRQ_MASK(irq_idx), cache_irq_mask); + + return 0; +@@ -344,8 +361,9 @@ static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) + if (!intr) + return -EINVAL; + +- if (irq_idx < 0 || irq_idx >= intr->total_irqs) { +- pr_err("invalid IRQ index: [%d]\n", irq_idx); ++ if (!dpu_core_irq_is_valid(irq_idx)) { ++ pr_err("invalid IRQ=[%d, %d]\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + return -EINVAL; + } + +@@ -377,7 +395,8 @@ static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) + intr->cache_irq_mask[reg_idx] = cache_irq_mask; + } + +- pr_debug("DPU IRQ %d %sdisabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", irq_idx, dbgstr, ++ pr_debug("DPU IRQ=[%d, %d] %sdisabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), dbgstr, + DPU_IRQ_MASK(irq_idx), cache_irq_mask); + + return 0; +@@ -429,14 +448,8 @@ u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, int irq_idx) + if (!intr) + return 0; + +- if (irq_idx < 0) { +- DPU_ERROR("[%pS] invalid irq_idx=%d\n", +- __builtin_return_address(0), irq_idx); +- return 0; +- } +- +- if (irq_idx < 0 || irq_idx >= intr->total_irqs) { +- pr_err("invalid IRQ index: [%d]\n", irq_idx); ++ if (!dpu_core_irq_is_valid(irq_idx)) { ++ pr_err("invalid IRQ=[%d, %d]\n", DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + return 0; + } + +@@ -462,13 +475,12 @@ struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, + const struct dpu_mdss_cfg *m) + { + struct dpu_hw_intr *intr; +- int nirq = MDP_INTR_MAX * 32; + unsigned int i; + + if (!addr || !m) + return ERR_PTR(-EINVAL); + +- intr = kzalloc(struct_size(intr, irq_tbl, nirq), GFP_KERNEL); ++ intr = kzalloc(sizeof(*intr), GFP_KERNEL); + if (!intr) + return ERR_PTR(-ENOMEM); + +@@ -479,8 +491,6 @@ struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, + + intr->hw.blk_addr = addr + m->mdp[0].base; + +- intr->total_irqs = nirq; +- + intr->irq_mask = BIT(MDP_SSPP_TOP0_INTR) | + BIT(MDP_SSPP_TOP0_INTR2) | + BIT(MDP_SSPP_TOP0_HIST_INTR); +@@ -507,42 +517,47 @@ void dpu_hw_intr_destroy(struct dpu_hw_intr *intr) + } + + int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, int irq_idx, +- void (*irq_cb)(void *arg, int irq_idx), ++ void (*irq_cb)(void *arg), + void *irq_arg) + { ++ struct dpu_hw_intr_entry *irq_entry; + unsigned long irq_flags; + int ret; + + if (!irq_cb) { +- DPU_ERROR("invalid ird_idx:%d irq_cb:%ps\n", irq_idx, irq_cb); ++ DPU_ERROR("IRQ=[%d, %d] NULL callback\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + return -EINVAL; + } + +- if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->total_irqs) { +- DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx); ++ if (!dpu_core_irq_is_valid(irq_idx)) { ++ DPU_ERROR("invalid IRQ=[%d, %d] irq_cb:%ps\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), irq_cb); + return -EINVAL; + } + +- VERB("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx); ++ VERB("[%pS] IRQ=[%d, %d]\n", __builtin_return_address(0), ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + + spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags); + +- if (unlikely(WARN_ON(dpu_kms->hw_intr->irq_tbl[irq_idx].cb))) { ++ irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, irq_idx); ++ if (unlikely(WARN_ON(irq_entry->cb))) { + spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); + + return -EBUSY; + } + + trace_dpu_core_irq_register_callback(irq_idx, irq_cb); +- dpu_kms->hw_intr->irq_tbl[irq_idx].arg = irq_arg; +- dpu_kms->hw_intr->irq_tbl[irq_idx].cb = irq_cb; ++ irq_entry->arg = irq_arg; ++ irq_entry->cb = irq_cb; + + ret = dpu_hw_intr_enable_irq_locked( + dpu_kms->hw_intr, + irq_idx); + if (ret) +- DPU_ERROR("Fail to enable IRQ for irq_idx:%d\n", +- irq_idx); ++ DPU_ERROR("Failed/ to enable IRQ=[%d, %d]\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); + + trace_dpu_irq_register_success(irq_idx); +@@ -552,26 +567,30 @@ int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, int irq_idx, + + int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx) + { ++ struct dpu_hw_intr_entry *irq_entry; + unsigned long irq_flags; + int ret; + +- if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->total_irqs) { +- DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx); ++ if (!dpu_core_irq_is_valid(irq_idx)) { ++ DPU_ERROR("invalid IRQ=[%d, %d]\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + return -EINVAL; + } + +- VERB("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx); ++ VERB("[%pS] IRQ=[%d, %d]\n", __builtin_return_address(0), ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx)); + + spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags); + trace_dpu_core_irq_unregister_callback(irq_idx); + + ret = dpu_hw_intr_disable_irq_locked(dpu_kms->hw_intr, irq_idx); + if (ret) +- DPU_ERROR("Fail to disable IRQ for irq_idx:%d: %d\n", +- irq_idx, ret); ++ DPU_ERROR("Failed to disable IRQ=[%d, %d]: %d\n", ++ DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), ret); + +- dpu_kms->hw_intr->irq_tbl[irq_idx].cb = NULL; +- dpu_kms->hw_intr->irq_tbl[irq_idx].arg = NULL; ++ irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, irq_idx); ++ irq_entry->cb = NULL; ++ irq_entry->arg = NULL; + + spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); + +@@ -584,18 +603,21 @@ int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx) + static int dpu_debugfs_core_irq_show(struct seq_file *s, void *v) + { + struct dpu_kms *dpu_kms = s->private; ++ struct dpu_hw_intr_entry *irq_entry; + unsigned long irq_flags; + int i, irq_count; + void *cb; + +- for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++) { ++ for (i = 0; i < DPU_NUM_IRQS; i++) { + spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags); +- irq_count = atomic_read(&dpu_kms->hw_intr->irq_tbl[i].count); +- cb = dpu_kms->hw_intr->irq_tbl[i].cb; ++ irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, i); ++ irq_count = atomic_read(&irq_entry->count); ++ cb = irq_entry->cb; + spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); + + if (irq_count || cb) +- seq_printf(s, "idx:%d irq:%d cb:%ps\n", i, irq_count, cb); ++ seq_printf(s, "IRQ=[%d, %d] count:%d cb:%ps\n", ++ DPU_IRQ_REG(i), DPU_IRQ_BIT(i), irq_count, cb); + } + + return 0; +@@ -614,6 +636,7 @@ void dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms, + void dpu_core_irq_preinstall(struct msm_kms *kms) + { + struct dpu_kms *dpu_kms = to_dpu_kms(kms); ++ struct dpu_hw_intr_entry *irq_entry; + int i; + + pm_runtime_get_sync(&dpu_kms->pdev->dev); +@@ -621,22 +644,28 @@ void dpu_core_irq_preinstall(struct msm_kms *kms) + dpu_disable_all_irqs(dpu_kms); + pm_runtime_put_sync(&dpu_kms->pdev->dev); + +- for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++) +- atomic_set(&dpu_kms->hw_intr->irq_tbl[i].count, 0); ++ for (i = 0; i < DPU_NUM_IRQS; i++) { ++ irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, i); ++ atomic_set(&irq_entry->count, 0); ++ } + } + + void dpu_core_irq_uninstall(struct msm_kms *kms) + { + struct dpu_kms *dpu_kms = to_dpu_kms(kms); ++ struct dpu_hw_intr_entry *irq_entry; + int i; + + if (!dpu_kms->hw_intr) + return; + + pm_runtime_get_sync(&dpu_kms->pdev->dev); +- for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++) +- if (dpu_kms->hw_intr->irq_tbl[i].cb) +- DPU_ERROR("irq_idx=%d still enabled/registered\n", i); ++ for (i = 0; i < DPU_NUM_IRQS; i++) { ++ irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, i); ++ if (irq_entry->cb) ++ DPU_ERROR("IRQ=[%d, %d] still enabled/registered\n", ++ DPU_IRQ_REG(i), DPU_IRQ_BIT(i)); ++ } + + dpu_clear_irqs(dpu_kms); + dpu_disable_all_irqs(dpu_kms); +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h +index dab761e548636f..9df5d6e737a116 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h +@@ -37,6 +37,16 @@ enum dpu_hw_intr_reg { + #define MDP_INTFn_INTR(intf) (MDP_INTF0_INTR + (intf - INTF_0)) + + #define DPU_IRQ_IDX(reg_idx, offset) (reg_idx * 32 + offset) ++#define DPU_IRQ_REG(irq_idx) (irq_idx / 32) ++#define DPU_IRQ_BIT(irq_idx) (irq_idx % 32) ++ ++#define DPU_NUM_IRQS (MDP_INTR_MAX * 32) ++ ++struct dpu_hw_intr_entry { ++ void (*cb)(void *arg); ++ void *arg; ++ atomic_t count; ++}; + + /** + * struct dpu_hw_intr: hw interrupts handling data structure +@@ -44,7 +54,6 @@ enum dpu_hw_intr_reg { + * @ops: function pointer mapping for IRQ handling + * @cache_irq_mask: array of IRQ enable masks reg storage created during init + * @save_irq_status: array of IRQ status reg storage created during init +- * @total_irqs: total number of irq_idx mapped in the hw_interrupts + * @irq_lock: spinlock for accessing IRQ resources + * @irq_cb_tbl: array of IRQ callbacks + */ +@@ -52,16 +61,11 @@ struct dpu_hw_intr { + struct dpu_hw_blk_reg_map hw; + u32 cache_irq_mask[MDP_INTR_MAX]; + u32 *save_irq_status; +- u32 total_irqs; + spinlock_t irq_lock; + unsigned long irq_mask; + const struct dpu_intr_reg *intr_set; + +- struct { +- void (*cb)(void *arg, int irq_idx); +- void *arg; +- atomic_t count; +- } irq_tbl[]; ++ struct dpu_hw_intr_entry irq_tbl[DPU_NUM_IRQS]; + }; + + /** +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +index 8ec6505d9e7860..9cdd2d8bf79ba1 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.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. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + */ + +@@ -161,13 +161,8 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx, + hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width; + display_hctl = (hsync_end_x << 16) | hsync_start_x; + +- /* +- * DATA_HCTL_EN controls data timing which can be different from +- * video timing. It is recommended to enable it for all cases, except +- * if compression is enabled in 1 pixel per clock mode +- */ + if (p->wide_bus_en) +- intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN | INTF_CFG2_DATA_HCTL_EN; ++ intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN; + + data_width = p->width; + +@@ -227,6 +222,14 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx, + DPU_REG_WRITE(c, INTF_CONFIG, intf_cfg); + DPU_REG_WRITE(c, INTF_PANEL_FORMAT, panel_format); + if (ctx->cap->features & BIT(DPU_DATA_HCTL_EN)) { ++ /* ++ * DATA_HCTL_EN controls data timing which can be different from ++ * video timing. It is recommended to enable it for all cases, except ++ * if compression is enabled in 1 pixel per clock mode ++ */ ++ if (!(p->compression_en && !p->wide_bus_en)) ++ intf_cfg2 |= INTF_CFG2_DATA_HCTL_EN; ++ + DPU_REG_WRITE(c, INTF_CONFIG2, intf_cfg2); + DPU_REG_WRITE(c, INTF_DISPLAY_DATA_HCTL, display_data_hctl); + DPU_REG_WRITE(c, INTF_ACTIVE_DATA_HCTL, active_data_hctl); +@@ -318,9 +321,9 @@ static u32 dpu_hw_intf_get_line_count(struct dpu_hw_intf *intf) + return DPU_REG_READ(c, INTF_LINE_COUNT); + } + +-static void dpu_hw_intf_setup_misr(struct dpu_hw_intf *intf, bool enable, u32 frame_count) ++static void dpu_hw_intf_setup_misr(struct dpu_hw_intf *intf) + { +- dpu_hw_setup_misr(&intf->hw, INTF_MISR_CTRL, enable, frame_count); ++ dpu_hw_setup_misr(&intf->hw, INTF_MISR_CTRL, 0x1); + } + + static int dpu_hw_intf_collect_misr(struct dpu_hw_intf *intf, u32 *misr_value) +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +index 77f80531782b59..192f4e67b1732f 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +@@ -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. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + */ + +@@ -33,6 +33,7 @@ struct dpu_hw_intf_timing_params { + u32 hsync_skew; + + bool wide_bus_en; ++ bool compression_en; + }; + + struct dpu_hw_intf_prog_fetch { +@@ -94,7 +95,7 @@ struct dpu_hw_intf_ops { + + void (*bind_pingpong_blk)(struct dpu_hw_intf *intf, + const enum dpu_pingpong pp); +- void (*setup_misr)(struct dpu_hw_intf *intf, bool enable, u32 frame_count); ++ void (*setup_misr)(struct dpu_hw_intf *intf); + int (*collect_misr)(struct dpu_hw_intf *intf, u32 *misr_value); + + // Tearcheck on INTF since DPU 5.0.0 +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c +index d1c3bd8379ea94..a590c1f7465fbd 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.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. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + */ + +@@ -81,9 +81,9 @@ static void dpu_hw_lm_setup_border_color(struct dpu_hw_mixer *ctx, + } + } + +-static void dpu_hw_lm_setup_misr(struct dpu_hw_mixer *ctx, bool enable, u32 frame_count) ++static void dpu_hw_lm_setup_misr(struct dpu_hw_mixer *ctx) + { +- dpu_hw_setup_misr(&ctx->hw, LM_MISR_CTRL, enable, frame_count); ++ dpu_hw_setup_misr(&ctx->hw, LM_MISR_CTRL, 0x0); + } + + static int dpu_hw_lm_collect_misr(struct dpu_hw_mixer *ctx, u32 *misr_value) +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h +index 36992d046a533b..98b77cda65472d 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h +@@ -1,5 +1,6 @@ + /* SPDX-License-Identifier: GPL-2.0-only */ + /* ++ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + */ + +@@ -57,7 +58,7 @@ struct dpu_hw_lm_ops { + /** + * setup_misr: Enable/disable MISR + */ +- void (*setup_misr)(struct dpu_hw_mixer *ctx, bool enable, u32 frame_count); ++ void (*setup_misr)(struct dpu_hw_mixer *ctx); + + /** + * collect_misr: Read MISR signature +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c +index 9d2273fd2fed58..6eee9f68ab4c7d 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.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. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + */ + #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +@@ -481,9 +481,11 @@ void _dpu_hw_setup_qos_lut(struct dpu_hw_blk_reg_map *c, u32 offset, + cfg->danger_safe_en ? QOS_QOS_CTRL_DANGER_SAFE_EN : 0); + } + ++/* ++ * note: Aside from encoders, input_sel should be set to 0x0 by default ++ */ + void dpu_hw_setup_misr(struct dpu_hw_blk_reg_map *c, +- u32 misr_ctrl_offset, +- bool enable, u32 frame_count) ++ u32 misr_ctrl_offset, u8 input_sel) + { + u32 config = 0; + +@@ -492,15 +494,9 @@ void dpu_hw_setup_misr(struct dpu_hw_blk_reg_map *c, + /* Clear old MISR value (in case it's read before a new value is calculated)*/ + wmb(); + +- if (enable) { +- config = (frame_count & MISR_FRAME_COUNT_MASK) | +- MISR_CTRL_ENABLE | MISR_CTRL_FREE_RUN_MASK; +- +- DPU_REG_WRITE(c, misr_ctrl_offset, config); +- } else { +- DPU_REG_WRITE(c, misr_ctrl_offset, 0); +- } +- ++ config = MISR_FRAME_COUNT | MISR_CTRL_ENABLE | MISR_CTRL_FREE_RUN_MASK | ++ ((input_sel & 0xF) << 24); ++ DPU_REG_WRITE(c, misr_ctrl_offset, config); + } + + int dpu_hw_collect_misr(struct dpu_hw_blk_reg_map *c, +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h +index 1f6079f4707109..0aed54d7f6c942 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h +@@ -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. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. + */ + +@@ -13,7 +13,7 @@ + #include "dpu_hw_catalog.h" + + #define REG_MASK(n) ((BIT(n)) - 1) +-#define MISR_FRAME_COUNT_MASK 0xFF ++#define MISR_FRAME_COUNT 0x1 + #define MISR_CTRL_ENABLE BIT(8) + #define MISR_CTRL_STATUS BIT(9) + #define MISR_CTRL_STATUS_CLEAR BIT(10) +@@ -358,9 +358,7 @@ void _dpu_hw_setup_qos_lut(struct dpu_hw_blk_reg_map *c, u32 offset, + const struct dpu_hw_qos_cfg *cfg); + + void dpu_hw_setup_misr(struct dpu_hw_blk_reg_map *c, +- u32 misr_ctrl_offset, +- bool enable, +- u32 frame_count); ++ u32 misr_ctrl_offset, u8 input_sel); + + int dpu_hw_collect_misr(struct dpu_hw_blk_reg_map *c, + u32 misr_ctrl_offset, +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c +index ebc41640038220..0aa598b355e9ec 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c +@@ -86,6 +86,9 @@ static void dpu_hw_wb_setup_format(struct dpu_hw_wb *ctx, + dst_format |= BIT(14); /* DST_ALPHA_X */ + } + ++ if (DPU_FORMAT_IS_YUV(fmt)) ++ dst_format |= BIT(15); ++ + pattern = (fmt->element[3] << 24) | + (fmt->element[2] << 16) | + (fmt->element[1] << 8) | +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +index aa6ba2cf4b8406..6ba289e04b3b22 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +@@ -490,7 +490,7 @@ static void dpu_kms_wait_for_commit_done(struct msm_kms *kms, + * mode panels. This may be a no-op for command mode panels. + */ + trace_dpu_kms_wait_for_commit_done(DRMID(crtc)); +- ret = dpu_encoder_wait_for_event(encoder, MSM_ENC_COMMIT_DONE); ++ ret = dpu_encoder_wait_for_commit_done(encoder); + if (ret && ret != -EWOULDBLOCK) { + DPU_ERROR("wait for commit done returned %d\n", ret); + break; +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +index b6f53ca6e96285..8cb3cf842c52c0 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +@@ -31,26 +31,17 @@ + * @fmt: Pointer to format string + */ + #define DPU_DEBUG(fmt, ...) \ +- do { \ +- if (drm_debug_enabled(DRM_UT_KMS)) \ +- DRM_DEBUG(fmt, ##__VA_ARGS__); \ +- else \ +- pr_debug(fmt, ##__VA_ARGS__); \ +- } while (0) ++ DRM_DEBUG_DRIVER(fmt, ##__VA_ARGS__) + + /** + * DPU_DEBUG_DRIVER - macro for hardware driver logging + * @fmt: Pointer to format string + */ + #define DPU_DEBUG_DRIVER(fmt, ...) \ +- do { \ +- if (drm_debug_enabled(DRM_UT_DRIVER)) \ +- DRM_ERROR(fmt, ##__VA_ARGS__); \ +- else \ +- pr_debug(fmt, ##__VA_ARGS__); \ +- } while (0) ++ DRM_DEBUG_DRIVER(fmt, ##__VA_ARGS__) + + #define DPU_ERROR(fmt, ...) pr_err("[dpu error]" fmt, ##__VA_ARGS__) ++#define DPU_ERROR_RATELIMITED(fmt, ...) pr_err_ratelimited("[dpu error]" fmt, ##__VA_ARGS__) + + /** + * ktime_compare_safe - compare two ktime structures +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +index 0be195f9149c56..637f50a8d42e62 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +@@ -679,6 +679,9 @@ static int dpu_plane_prepare_fb(struct drm_plane *plane, + new_state->fb, &layout); + if (ret) { + DPU_ERROR_PLANE(pdpu, "failed to get format layout, %d\n", ret); ++ if (pstate->aspace) ++ msm_framebuffer_cleanup(new_state->fb, pstate->aspace, ++ pstate->needs_dirtyfb); + return ret; + } + +@@ -792,6 +795,8 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, + plane); + int ret = 0, min_scale; + struct dpu_plane *pdpu = to_dpu_plane(plane); ++ struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base); ++ u64 max_mdp_clk_rate = kms->perf.max_core_clk_rate; + struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); + struct dpu_sw_pipe *pipe = &pstate->pipe; + struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; +@@ -860,14 +865,20 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, + + max_linewidth = pdpu->catalog->caps->max_linewidth; + +- if (drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) { ++ drm_rect_rotate(&pipe_cfg->src_rect, ++ new_plane_state->fb->width, new_plane_state->fb->height, ++ new_plane_state->rotation); ++ ++ if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || ++ _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) { + /* + * In parallel multirect case only the half of the usual width + * is supported for tiled formats. If we are here, we know that + * full width is more than max_linewidth, thus each rect is + * wider than allowed. + */ +- if (DPU_FORMAT_IS_UBWC(fmt)) { ++ if (DPU_FORMAT_IS_UBWC(fmt) && ++ drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) { + DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u, tiled format\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); + return -E2BIG; +@@ -907,6 +918,14 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, + r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2; + } + ++ drm_rect_rotate_inv(&pipe_cfg->src_rect, ++ new_plane_state->fb->width, new_plane_state->fb->height, ++ new_plane_state->rotation); ++ if (r_pipe->sspp) ++ drm_rect_rotate_inv(&r_pipe_cfg->src_rect, ++ new_plane_state->fb->width, new_plane_state->fb->height, ++ new_plane_state->rotation); ++ + ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt, &crtc_state->adjusted_mode); + if (ret) + return ret; +diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c +index 169f9de4a12a73..3100957225a70f 100644 +--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c ++++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c +@@ -269,6 +269,7 @@ static void mdp4_crtc_atomic_disable(struct drm_crtc *crtc, + { + struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + struct mdp4_kms *mdp4_kms = get_kms(crtc); ++ unsigned long flags; + + DBG("%s", mdp4_crtc->name); + +@@ -281,6 +282,14 @@ static void mdp4_crtc_atomic_disable(struct drm_crtc *crtc, + mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err); + mdp4_disable(mdp4_kms); + ++ if (crtc->state->event && !crtc->state->active) { ++ WARN_ON(mdp4_crtc->event); ++ spin_lock_irqsave(&mdp4_kms->dev->event_lock, flags); ++ drm_crtc_send_vblank_event(crtc, crtc->state->event); ++ crtc->state->event = NULL; ++ spin_unlock_irqrestore(&mdp4_kms->dev->event_lock, flags); ++ } ++ + mdp4_crtc->enabled = false; + } + +diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c +index 56a3063545ec46..12d07e93a4c47e 100644 +--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c ++++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c +@@ -356,7 +356,7 @@ void mdp5_smp_dump(struct mdp5_smp *smp, struct drm_printer *p) + + drm_printf(p, "%s:%d\t%d\t%s\n", + pipe2name(pipe), j, inuse, +- plane ? plane->name : NULL); ++ plane ? plane->name : "(null)"); + + total += inuse; + } +diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c +index 8e3b677f35e64f..559809a5cbcfb1 100644 +--- a/drivers/gpu/drm/msm/dp/dp_aux.c ++++ b/drivers/gpu/drm/msm/dp/dp_aux.c +@@ -35,6 +35,7 @@ struct dp_aux_private { + bool no_send_stop; + bool initted; + bool is_edp; ++ bool enable_xfers; + u32 offset; + u32 segment; + +@@ -297,6 +298,17 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, + goto exit; + } + ++ /* ++ * If we're using DP and an external display isn't connected then the ++ * transfer won't succeed. Return right away. If we don't do this we ++ * can end up with long timeouts if someone tries to access the DP AUX ++ * character device when no DP device is connected. ++ */ ++ if (!aux->is_edp && !aux->enable_xfers) { ++ ret = -ENXIO; ++ goto exit; ++ } ++ + /* + * For eDP it's important to give a reasonably long wait here for HPD + * to be asserted. This is because the panel driver may have _just_ +@@ -428,6 +440,14 @@ irqreturn_t dp_aux_isr(struct drm_dp_aux *dp_aux) + return IRQ_HANDLED; + } + ++void dp_aux_enable_xfers(struct drm_dp_aux *dp_aux, bool enabled) ++{ ++ struct dp_aux_private *aux; ++ ++ aux = container_of(dp_aux, struct dp_aux_private, dp_aux); ++ aux->enable_xfers = enabled; ++} ++ + void dp_aux_reconfig(struct drm_dp_aux *dp_aux) + { + struct dp_aux_private *aux; +diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h +index 511305da4f66df..f3052cb43306bc 100644 +--- a/drivers/gpu/drm/msm/dp/dp_aux.h ++++ b/drivers/gpu/drm/msm/dp/dp_aux.h +@@ -12,6 +12,7 @@ + int dp_aux_register(struct drm_dp_aux *dp_aux); + void dp_aux_unregister(struct drm_dp_aux *dp_aux); + irqreturn_t dp_aux_isr(struct drm_dp_aux *dp_aux); ++void dp_aux_enable_xfers(struct drm_dp_aux *dp_aux, bool enabled); + void dp_aux_init(struct drm_dp_aux *dp_aux); + void dp_aux_deinit(struct drm_dp_aux *dp_aux); + void dp_aux_reconfig(struct drm_dp_aux *dp_aux); +diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c +index 77a8d9366ed7b0..7472dfd631b837 100644 +--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c ++++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c +@@ -135,11 +135,6 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl) + tbd = dp_link_get_test_bits_depth(ctrl->link, + ctrl->panel->dp_mode.bpp); + +- if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN) { +- pr_debug("BIT_DEPTH not set. Configure default\n"); +- tbd = DP_TEST_BIT_DEPTH_8; +- } +- + config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT; + + /* Num of Lanes */ +@@ -1024,14 +1019,14 @@ static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl) + if (ret) + return ret; + +- if (voltage_swing_level >= DP_TRAIN_VOLTAGE_SWING_MAX) { ++ if (voltage_swing_level >= DP_TRAIN_LEVEL_MAX) { + drm_dbg_dp(ctrl->drm_dev, + "max. voltage swing level reached %d\n", + voltage_swing_level); + max_level_reached |= DP_TRAIN_MAX_SWING_REACHED; + } + +- if (pre_emphasis_level >= DP_TRAIN_PRE_EMPHASIS_MAX) { ++ if (pre_emphasis_level >= DP_TRAIN_LEVEL_MAX) { + drm_dbg_dp(ctrl->drm_dev, + "max. pre-emphasis level reached %d\n", + pre_emphasis_level); +@@ -1122,7 +1117,7 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl, + } + + if (ctrl->link->phy_params.v_level >= +- DP_TRAIN_VOLTAGE_SWING_MAX) { ++ DP_TRAIN_LEVEL_MAX) { + DRM_ERROR_RATELIMITED("max v_level reached\n"); + return -EAGAIN; + } +@@ -1258,6 +1253,8 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl, + link_info.rate = ctrl->link->link_params.rate; + link_info.capabilities = DP_LINK_CAP_ENHANCED_FRAMING; + ++ dp_link_reset_phy_params_vx_px(ctrl->link); ++ + dp_aux_link_configure(ctrl->aux, &link_info); + + if (drm_dp_max_downspread(dpcd)) +diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c +index 76f13954015b18..ed77c957eceba3 100644 +--- a/drivers/gpu/drm/msm/dp/dp_display.c ++++ b/drivers/gpu/drm/msm/dp/dp_display.c +@@ -171,6 +171,11 @@ static const struct msm_dp_desc sm8350_dp_descs[] = { + {} + }; + ++static const struct msm_dp_desc sm8650_dp_descs[] = { ++ { .io_start = 0x0af54000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort }, ++ {} ++}; ++ + static const struct of_device_id dp_dt_match[] = { + { .compatible = "qcom,sc7180-dp", .data = &sc7180_dp_descs }, + { .compatible = "qcom,sc7280-dp", .data = &sc7280_dp_descs }, +@@ -181,6 +186,7 @@ static const struct of_device_id dp_dt_match[] = { + { .compatible = "qcom,sc8280xp-edp", .data = &sc8280xp_edp_descs }, + { .compatible = "qcom,sdm845-dp", .data = &sc7180_dp_descs }, + { .compatible = "qcom,sm8350-dp", .data = &sm8350_dp_descs }, ++ { .compatible = "qcom,sm8650-dp", .data = &sm8650_dp_descs }, + {} + }; + +@@ -580,6 +586,8 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) + u32 state; + int ret; + ++ dp_aux_enable_xfers(dp->aux, true); ++ + mutex_lock(&dp->event_mutex); + + state = dp->hpd_state; +@@ -636,6 +644,8 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) + { + u32 state; + ++ dp_aux_enable_xfers(dp->aux, false); ++ + mutex_lock(&dp->event_mutex); + + state = dp->hpd_state; +diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c +index 6375daaeb98e1c..a198af7b2d4499 100644 +--- a/drivers/gpu/drm/msm/dp/dp_link.c ++++ b/drivers/gpu/drm/msm/dp/dp_link.c +@@ -7,6 +7,7 @@ + + #include + ++#include "dp_reg.h" + #include "dp_link.h" + #include "dp_panel.h" + +@@ -1114,7 +1115,7 @@ int dp_link_process_request(struct dp_link *dp_link) + + int dp_link_get_colorimetry_config(struct dp_link *dp_link) + { +- u32 cc; ++ u32 cc = DP_MISC0_COLORIMERY_CFG_LEGACY_RGB; + struct dp_link_private *link; + + if (!dp_link) { +@@ -1128,10 +1129,11 @@ int dp_link_get_colorimetry_config(struct dp_link *dp_link) + * Unless a video pattern CTS test is ongoing, use RGB_VESA + * Only RGB_VESA and RGB_CEA supported for now + */ +- if (dp_link_is_video_pattern_requested(link)) +- cc = link->dp_link.test_video.test_dyn_range; +- else +- cc = DP_TEST_DYNAMIC_RANGE_VESA; ++ if (dp_link_is_video_pattern_requested(link)) { ++ if (link->dp_link.test_video.test_dyn_range & ++ DP_TEST_DYNAMIC_RANGE_CEA) ++ cc = DP_MISC0_COLORIMERY_CFG_CEA_RGB; ++ } + + return cc; + } +@@ -1139,6 +1141,7 @@ int dp_link_get_colorimetry_config(struct dp_link *dp_link) + int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status) + { + int i; ++ u8 max_p_level; + int v_max = 0, p_max = 0; + struct dp_link_private *link; + +@@ -1170,30 +1173,29 @@ int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status) + * Adjust the voltage swing and pre-emphasis level combination to within + * the allowable range. + */ +- if (dp_link->phy_params.v_level > DP_TRAIN_VOLTAGE_SWING_MAX) { ++ if (dp_link->phy_params.v_level > DP_TRAIN_LEVEL_MAX) { + drm_dbg_dp(link->drm_dev, + "Requested vSwingLevel=%d, change to %d\n", + dp_link->phy_params.v_level, +- DP_TRAIN_VOLTAGE_SWING_MAX); +- dp_link->phy_params.v_level = DP_TRAIN_VOLTAGE_SWING_MAX; ++ DP_TRAIN_LEVEL_MAX); ++ dp_link->phy_params.v_level = DP_TRAIN_LEVEL_MAX; + } + +- if (dp_link->phy_params.p_level > DP_TRAIN_PRE_EMPHASIS_MAX) { ++ if (dp_link->phy_params.p_level > DP_TRAIN_LEVEL_MAX) { + drm_dbg_dp(link->drm_dev, + "Requested preEmphasisLevel=%d, change to %d\n", + dp_link->phy_params.p_level, +- DP_TRAIN_PRE_EMPHASIS_MAX); +- dp_link->phy_params.p_level = DP_TRAIN_PRE_EMPHASIS_MAX; ++ DP_TRAIN_LEVEL_MAX); ++ dp_link->phy_params.p_level = DP_TRAIN_LEVEL_MAX; + } + +- if ((dp_link->phy_params.p_level > DP_TRAIN_PRE_EMPHASIS_LVL_1) +- && (dp_link->phy_params.v_level == +- DP_TRAIN_VOLTAGE_SWING_LVL_2)) { ++ max_p_level = DP_TRAIN_LEVEL_MAX - dp_link->phy_params.v_level; ++ if (dp_link->phy_params.p_level > max_p_level) { + drm_dbg_dp(link->drm_dev, + "Requested preEmphasisLevel=%d, change to %d\n", + dp_link->phy_params.p_level, +- DP_TRAIN_PRE_EMPHASIS_LVL_1); +- dp_link->phy_params.p_level = DP_TRAIN_PRE_EMPHASIS_LVL_1; ++ max_p_level); ++ dp_link->phy_params.p_level = max_p_level; + } + + drm_dbg_dp(link->drm_dev, "adjusted: v_level=%d, p_level=%d\n", +@@ -1211,6 +1213,9 @@ void dp_link_reset_phy_params_vx_px(struct dp_link *dp_link) + u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp) + { + u32 tbd; ++ struct dp_link_private *link; ++ ++ link = container_of(dp_link, struct dp_link_private, dp_link); + + /* + * Few simplistic rules and assumptions made here: +@@ -1228,12 +1233,13 @@ u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp) + tbd = DP_TEST_BIT_DEPTH_10; + break; + default: +- tbd = DP_TEST_BIT_DEPTH_UNKNOWN; ++ drm_dbg_dp(link->drm_dev, "bpp=%d not supported, use bpc=8\n", ++ bpp); ++ tbd = DP_TEST_BIT_DEPTH_8; + break; + } + +- if (tbd != DP_TEST_BIT_DEPTH_UNKNOWN) +- tbd = (tbd >> DP_TEST_BIT_DEPTH_SHIFT); ++ tbd = (tbd >> DP_TEST_BIT_DEPTH_SHIFT); + + return tbd; + } +diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h +index 9dd4dd92653046..79c3a02b8dacd7 100644 +--- a/drivers/gpu/drm/msm/dp/dp_link.h ++++ b/drivers/gpu/drm/msm/dp/dp_link.h +@@ -19,19 +19,7 @@ struct dp_link_info { + unsigned long capabilities; + }; + +-enum dp_link_voltage_level { +- DP_TRAIN_VOLTAGE_SWING_LVL_0 = 0, +- DP_TRAIN_VOLTAGE_SWING_LVL_1 = 1, +- DP_TRAIN_VOLTAGE_SWING_LVL_2 = 2, +- DP_TRAIN_VOLTAGE_SWING_MAX = DP_TRAIN_VOLTAGE_SWING_LVL_2, +-}; +- +-enum dp_link_preemaphasis_level { +- DP_TRAIN_PRE_EMPHASIS_LVL_0 = 0, +- DP_TRAIN_PRE_EMPHASIS_LVL_1 = 1, +- DP_TRAIN_PRE_EMPHASIS_LVL_2 = 2, +- DP_TRAIN_PRE_EMPHASIS_MAX = DP_TRAIN_PRE_EMPHASIS_LVL_2, +-}; ++#define DP_TRAIN_LEVEL_MAX 3 + + struct dp_link_test_video { + u32 test_video_pattern; +diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c +index 42d52510ffd4ab..d26589eb8b218b 100644 +--- a/drivers/gpu/drm/msm/dp/dp_panel.c ++++ b/drivers/gpu/drm/msm/dp/dp_panel.c +@@ -136,22 +136,22 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel) + static u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel, + u32 mode_edid_bpp, u32 mode_pclk_khz) + { +- struct dp_link_info *link_info; ++ const struct dp_link_info *link_info; + const u32 max_supported_bpp = 30, min_supported_bpp = 18; +- u32 bpp = 0, data_rate_khz = 0; ++ u32 bpp, data_rate_khz; + +- bpp = min_t(u32, mode_edid_bpp, max_supported_bpp); ++ bpp = min(mode_edid_bpp, max_supported_bpp); + + link_info = &dp_panel->link_info; + data_rate_khz = link_info->num_lanes * link_info->rate * 8; + +- while (bpp > min_supported_bpp) { ++ do { + if (mode_pclk_khz * bpp <= data_rate_khz) +- break; ++ return bpp; + bpp -= 6; +- } ++ } while (bpp > min_supported_bpp); + +- return bpp; ++ return min_supported_bpp; + } + + static int dp_panel_update_modes(struct drm_connector *connector, +@@ -289,26 +289,9 @@ int dp_panel_get_modes(struct dp_panel *dp_panel, + + static u8 dp_panel_get_edid_checksum(struct edid *edid) + { +- struct edid *last_block; +- u8 *raw_edid; +- bool is_edid_corrupt = false; +- +- if (!edid) { +- DRM_ERROR("invalid edid input\n"); +- return 0; +- } +- +- raw_edid = (u8 *)edid; +- raw_edid += (edid->extensions * EDID_LENGTH); +- last_block = (struct edid *)raw_edid; +- +- /* block type extension */ +- drm_edid_block_valid(raw_edid, 1, false, &is_edid_corrupt); +- if (!is_edid_corrupt) +- return last_block->checksum; ++ edid += edid->extensions; + +- DRM_ERROR("Invalid block, no checksum\n"); +- return 0; ++ return edid->checksum; + } + + void dp_panel_handle_sink_request(struct dp_panel *dp_panel) +@@ -461,8 +444,9 @@ int dp_panel_init_panel_info(struct dp_panel *dp_panel) + drm_mode->clock); + drm_dbg_dp(panel->drm_dev, "bpp = %d\n", dp_panel->dp_mode.bpp); + +- dp_panel->dp_mode.bpp = max_t(u32, 18, +- min_t(u32, dp_panel->dp_mode.bpp, 30)); ++ dp_panel->dp_mode.bpp = dp_panel_get_mode_bpp(dp_panel, dp_panel->dp_mode.bpp, ++ dp_panel->dp_mode.drm_mode.clock); ++ + drm_dbg_dp(panel->drm_dev, "updated bpp = %d\n", + dp_panel->dp_mode.bpp); + +diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h +index ea85a691e72b5c..78785ed4b40c49 100644 +--- a/drivers/gpu/drm/msm/dp/dp_reg.h ++++ b/drivers/gpu/drm/msm/dp/dp_reg.h +@@ -143,6 +143,9 @@ + #define DP_MISC0_COLORIMETRY_CFG_SHIFT (0x00000001) + #define DP_MISC0_TEST_BITS_DEPTH_SHIFT (0x00000005) + ++#define DP_MISC0_COLORIMERY_CFG_LEGACY_RGB (0) ++#define DP_MISC0_COLORIMERY_CFG_CEA_RGB (0x04) ++ + #define REG_DP_VALID_BOUNDARY (0x00000030) + #define REG_DP_VALID_BOUNDARY_2 (0x00000034) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c +index baab79ab6e745e..32f965bacdc309 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi.c ++++ b/drivers/gpu/drm/msm/dsi/dsi.c +@@ -126,6 +126,7 @@ static void dsi_unbind(struct device *dev, struct device *master, + struct msm_drm_private *priv = dev_get_drvdata(master); + struct msm_dsi *msm_dsi = dev_get_drvdata(dev); + ++ msm_dsi_tx_buf_free(msm_dsi->host); + priv->dsi[msm_dsi->id] = NULL; + } + +diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h +index bd3763a5d72340..3b46617a59f202 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi.h ++++ b/drivers/gpu/drm/msm/dsi/dsi.h +@@ -125,6 +125,7 @@ int dsi_tx_buf_alloc_v2(struct msm_dsi_host *msm_host, int size); + void *dsi_tx_buf_get_6g(struct msm_dsi_host *msm_host); + void *dsi_tx_buf_get_v2(struct msm_dsi_host *msm_host); + void dsi_tx_buf_put_6g(struct msm_dsi_host *msm_host); ++void msm_dsi_tx_buf_free(struct mipi_dsi_host *mipi_host); + int dsi_dma_base_get_6g(struct msm_dsi_host *msm_host, uint64_t *iova); + int dsi_dma_base_get_v2(struct msm_dsi_host *msm_host, uint64_t *iova); + int dsi_clk_init_v2(struct msm_dsi_host *msm_host); +diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c +index 3d6fb708dc223e..77b805eacb1b18 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_host.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_host.c +@@ -147,6 +147,7 @@ struct msm_dsi_host { + + /* DSI 6G TX buffer*/ + struct drm_gem_object *tx_gem_obj; ++ struct msm_gem_address_space *aspace; + + /* DSI v2 TX buffer */ + void *tx_buf; +@@ -365,8 +366,8 @@ int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host) + { + int ret; + +- DBG("Set clk rates: pclk=%d, byteclk=%lu", +- msm_host->mode->clock, msm_host->byte_clk_rate); ++ DBG("Set clk rates: pclk=%lu, byteclk=%lu", ++ msm_host->pixel_clk_rate, msm_host->byte_clk_rate); + + ret = dev_pm_opp_set_rate(&msm_host->pdev->dev, + msm_host->byte_clk_rate); +@@ -439,9 +440,9 @@ int dsi_link_clk_set_rate_v2(struct msm_dsi_host *msm_host) + { + int ret; + +- DBG("Set clk rates: pclk=%d, byteclk=%lu, esc_clk=%lu, dsi_src_clk=%lu", +- msm_host->mode->clock, msm_host->byte_clk_rate, +- msm_host->esc_clk_rate, msm_host->src_clk_rate); ++ DBG("Set clk rates: pclk=%lu, byteclk=%lu, esc_clk=%lu, dsi_src_clk=%lu", ++ msm_host->pixel_clk_rate, msm_host->byte_clk_rate, ++ msm_host->esc_clk_rate, msm_host->src_clk_rate); + + ret = clk_set_rate(msm_host->byte_clk, msm_host->byte_clk_rate); + if (ret) { +@@ -831,6 +832,7 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod + u32 slice_per_intf, total_bytes_per_intf; + u32 pkt_per_line; + u32 eol_byte_num; ++ u32 bytes_per_pkt; + + /* first calculate dsc parameters and then program + * compress mode registers +@@ -838,6 +840,7 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod + slice_per_intf = msm_dsc_get_slices_per_intf(dsc, hdisplay); + + total_bytes_per_intf = dsc->slice_chunk_size * slice_per_intf; ++ bytes_per_pkt = dsc->slice_chunk_size; /* * slice_per_pkt; */ + + eol_byte_num = total_bytes_per_intf % 3; + +@@ -875,6 +878,7 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod + dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL, reg_ctrl); + dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2); + } else { ++ reg |= DSI_VIDEO_COMPRESSION_MODE_CTRL_WC(bytes_per_pkt); + dsi_write(msm_host, REG_DSI_VIDEO_COMPRESSION_MODE_CTRL, reg); + } + } +@@ -1111,8 +1115,10 @@ int dsi_tx_buf_alloc_6g(struct msm_dsi_host *msm_host, int size) + uint64_t iova; + u8 *data; + ++ msm_host->aspace = msm_gem_address_space_get(priv->kms->aspace); ++ + data = msm_gem_kernel_new(dev, size, MSM_BO_WC, +- priv->kms->aspace, ++ msm_host->aspace, + &msm_host->tx_gem_obj, &iova); + + if (IS_ERR(data)) { +@@ -1141,10 +1147,10 @@ int dsi_tx_buf_alloc_v2(struct msm_dsi_host *msm_host, int size) + return 0; + } + +-static void dsi_tx_buf_free(struct msm_dsi_host *msm_host) ++void msm_dsi_tx_buf_free(struct mipi_dsi_host *host) + { ++ struct msm_dsi_host *msm_host = to_msm_dsi_host(host); + struct drm_device *dev = msm_host->dev; +- struct msm_drm_private *priv; + + /* + * This is possible if we're tearing down before we've had a chance to +@@ -1155,11 +1161,11 @@ static void dsi_tx_buf_free(struct msm_dsi_host *msm_host) + if (!dev) + return; + +- priv = dev->dev_private; + if (msm_host->tx_gem_obj) { +- msm_gem_unpin_iova(msm_host->tx_gem_obj, priv->kms->aspace); +- drm_gem_object_put(msm_host->tx_gem_obj); ++ msm_gem_kernel_put(msm_host->tx_gem_obj, msm_host->aspace); ++ msm_gem_address_space_put(msm_host->aspace); + msm_host->tx_gem_obj = NULL; ++ msm_host->aspace = NULL; + } + + if (msm_host->tx_buf) +@@ -1945,7 +1951,6 @@ void msm_dsi_host_destroy(struct mipi_dsi_host *host) + struct msm_dsi_host *msm_host = to_msm_dsi_host(host); + + DBG(""); +- dsi_tx_buf_free(msm_host); + if (msm_host->workqueue) { + destroy_workqueue(msm_host->workqueue); + msm_host->workqueue = NULL; +diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +index 05621e5e7d6343..e49ebd9f6326f3 100644 +--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c ++++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +@@ -516,7 +516,9 @@ static int dsi_phy_enable_resource(struct msm_dsi_phy *phy) + struct device *dev = &phy->pdev->dev; + int ret; + +- pm_runtime_get_sync(dev); ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret) ++ return ret; + + ret = clk_prepare_enable(phy->ahb_clk); + if (ret) { +@@ -689,6 +691,10 @@ static int dsi_phy_driver_probe(struct platform_device *pdev) + return dev_err_probe(dev, PTR_ERR(phy->ahb_clk), + "Unable to get ahb clk\n"); + ++ ret = devm_pm_runtime_enable(&pdev->dev); ++ if (ret) ++ return ret; ++ + /* PLL init will call into clk_register which requires + * register access, so we need to enable power and ahb clock. + */ +diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c +index 3b1ed02f644d28..f72ce6a3c456d5 100644 +--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c ++++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c +@@ -135,7 +135,7 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_7nm *pll, struct dsi_pll_config + config->pll_clock_inverters = 0x00; + else + config->pll_clock_inverters = 0x40; +- } else { ++ } else if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) { + if (pll_freq <= 1000000000ULL) + config->pll_clock_inverters = 0xa0; + else if (pll_freq <= 2500000000ULL) +@@ -144,6 +144,16 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_7nm *pll, struct dsi_pll_config + config->pll_clock_inverters = 0x00; + else + config->pll_clock_inverters = 0x40; ++ } else { ++ /* 4.2, 4.3 */ ++ if (pll_freq <= 1000000000ULL) ++ config->pll_clock_inverters = 0xa0; ++ else if (pll_freq <= 2500000000ULL) ++ config->pll_clock_inverters = 0x20; ++ else if (pll_freq <= 3500000000ULL) ++ config->pll_clock_inverters = 0x00; ++ else ++ config->pll_clock_inverters = 0x40; + } + + config->decimal_div_start = dec; +@@ -918,7 +928,7 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, + if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) { + if (phy->cphy_mode) { + vreg_ctrl_0 = 0x45; +- vreg_ctrl_1 = 0x45; ++ vreg_ctrl_1 = 0x41; + glbl_rescode_top_ctrl = 0x00; + glbl_rescode_bot_ctrl = 0x00; + } else { +diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h +index 02fd6c7d0bb7b9..48e1a8c6942c9f 100644 +--- a/drivers/gpu/drm/msm/msm_drv.h ++++ b/drivers/gpu/drm/msm/msm_drv.h +@@ -74,18 +74,6 @@ enum msm_dsi_controller { + #define MSM_GPU_MAX_RINGS 4 + #define MAX_H_TILES_PER_DISPLAY 2 + +-/** +- * enum msm_event_wait - type of HW events to wait for +- * @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW +- * @MSM_ENC_TX_COMPLETE - wait for the HW to transfer the frame to panel +- * @MSM_ENC_VBLANK - wait for the HW VBLANK event (for driver-internal waiters) +- */ +-enum msm_event_wait { +- MSM_ENC_COMMIT_DONE = 0, +- MSM_ENC_TX_COMPLETE, +- MSM_ENC_VBLANK, +-}; +- + /** + * struct msm_display_topology - defines a display topology pipeline + * @num_lm: number of layer mixers used +diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c +index 5f68e31a3e4e1c..0915f3b68752e3 100644 +--- a/drivers/gpu/drm/msm/msm_gem_prime.c ++++ b/drivers/gpu/drm/msm/msm_gem_prime.c +@@ -26,7 +26,7 @@ int msm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) + { + void *vaddr; + +- vaddr = msm_gem_get_vaddr(obj); ++ vaddr = msm_gem_get_vaddr_locked(obj); + if (IS_ERR(vaddr)) + return PTR_ERR(vaddr); + iosys_map_set_vaddr(map, vaddr); +@@ -36,7 +36,7 @@ int msm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) + + void msm_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map) + { +- msm_gem_put_vaddr(obj); ++ msm_gem_put_vaddr_locked(obj); + } + + struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev, +diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c +index f38296ad87434e..0641f5bb8649ac 100644 +--- a/drivers/gpu/drm/msm/msm_gem_shrinker.c ++++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c +@@ -76,7 +76,7 @@ static bool + wait_for_idle(struct drm_gem_object *obj) + { + enum dma_resv_usage usage = dma_resv_usage_rw(true); +- return dma_resv_wait_timeout(obj->resv, usage, false, 1000) > 0; ++ return dma_resv_wait_timeout(obj->resv, usage, false, 10) > 0; + } + + static bool +diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c +index 7f64c66673002f..5a7541597d0ce8 100644 +--- a/drivers/gpu/drm/msm/msm_gpu.c ++++ b/drivers/gpu/drm/msm/msm_gpu.c +@@ -749,12 +749,14 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) + struct msm_ringbuffer *ring = submit->ring; + unsigned long flags; + +- pm_runtime_get_sync(&gpu->pdev->dev); ++ WARN_ON(!mutex_is_locked(&gpu->lock)); + +- mutex_lock(&gpu->lock); ++ pm_runtime_get_sync(&gpu->pdev->dev); + + msm_gpu_hw_init(gpu); + ++ submit->seqno = submit->hw_fence->seqno; ++ + update_sw_cntrs(gpu); + + /* +@@ -779,11 +781,8 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) + gpu->funcs->submit(gpu, submit); + gpu->cur_ctx_seqno = submit->queue->ctx->seqno; + +- hangcheck_timer_reset(gpu); +- +- mutex_unlock(&gpu->lock); +- + pm_runtime_put(&gpu->pdev->dev); ++ hangcheck_timer_reset(gpu); + } + + /* +@@ -928,7 +927,6 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, + if (IS_ERR(gpu->gpu_cx)) + gpu->gpu_cx = NULL; + +- gpu->pdev = pdev; + platform_set_drvdata(pdev, &gpu->adreno_smmu); + + msm_devfreq_init(gpu); +diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c +index 5cc8d358cc9759..d5512037c38bcd 100644 +--- a/drivers/gpu/drm/msm/msm_iommu.c ++++ b/drivers/gpu/drm/msm/msm_iommu.c +@@ -21,6 +21,8 @@ struct msm_iommu_pagetable { + struct msm_mmu base; + struct msm_mmu *parent; + struct io_pgtable_ops *pgtbl_ops; ++ const struct iommu_flush_ops *tlb; ++ struct device *iommu_dev; + unsigned long pgsize_bitmap; /* Bitmap of page sizes in use */ + phys_addr_t ttbr; + u32 asid; +@@ -201,11 +203,33 @@ static const struct msm_mmu_funcs pagetable_funcs = { + + static void msm_iommu_tlb_flush_all(void *cookie) + { ++ struct msm_iommu_pagetable *pagetable = cookie; ++ struct adreno_smmu_priv *adreno_smmu; ++ ++ if (!pm_runtime_get_if_in_use(pagetable->iommu_dev)) ++ return; ++ ++ adreno_smmu = dev_get_drvdata(pagetable->parent->dev); ++ ++ pagetable->tlb->tlb_flush_all((void *)adreno_smmu->cookie); ++ ++ pm_runtime_put_autosuspend(pagetable->iommu_dev); + } + + static void msm_iommu_tlb_flush_walk(unsigned long iova, size_t size, + size_t granule, void *cookie) + { ++ struct msm_iommu_pagetable *pagetable = cookie; ++ struct adreno_smmu_priv *adreno_smmu; ++ ++ if (!pm_runtime_get_if_in_use(pagetable->iommu_dev)) ++ return; ++ ++ adreno_smmu = dev_get_drvdata(pagetable->parent->dev); ++ ++ pagetable->tlb->tlb_flush_walk(iova, size, granule, (void *)adreno_smmu->cookie); ++ ++ pm_runtime_put_autosuspend(pagetable->iommu_dev); + } + + static void msm_iommu_tlb_add_page(struct iommu_iotlb_gather *gather, +@@ -213,7 +237,7 @@ static void msm_iommu_tlb_add_page(struct iommu_iotlb_gather *gather, + { + } + +-static const struct iommu_flush_ops null_tlb_ops = { ++static const struct iommu_flush_ops tlb_ops = { + .tlb_flush_all = msm_iommu_tlb_flush_all, + .tlb_flush_walk = msm_iommu_tlb_flush_walk, + .tlb_add_page = msm_iommu_tlb_add_page, +@@ -254,10 +278,10 @@ struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent) + + /* The incoming cfg will have the TTBR1 quirk enabled */ + ttbr0_cfg.quirks &= ~IO_PGTABLE_QUIRK_ARM_TTBR1; +- ttbr0_cfg.tlb = &null_tlb_ops; ++ ttbr0_cfg.tlb = &tlb_ops; + + pagetable->pgtbl_ops = alloc_io_pgtable_ops(ARM_64_LPAE_S1, +- &ttbr0_cfg, iommu->domain); ++ &ttbr0_cfg, pagetable); + + if (!pagetable->pgtbl_ops) { + kfree(pagetable); +@@ -279,6 +303,8 @@ struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent) + + /* Needed later for TLB flush */ + pagetable->parent = parent; ++ pagetable->tlb = ttbr1_cfg->tlb; ++ pagetable->iommu_dev = ttbr1_cfg->iommu_dev; + pagetable->pgsize_bitmap = ttbr0_cfg.pgsize_bitmap; + pagetable->ttbr = ttbr0_cfg.arm_lpae_s1_cfg.ttbr; + +diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c +index 348c66b1468341..83b49d489cb1c5 100644 +--- a/drivers/gpu/drm/msm/msm_mdss.c ++++ b/drivers/gpu/drm/msm/msm_mdss.c +@@ -28,6 +28,8 @@ + + #define MIN_IB_BW 400000000UL /* Min ib vote 400MB */ + ++#define DEFAULT_REG_BW 153600 /* Used in mdss fbdev driver */ ++ + struct msm_mdss { + struct device *dev; + +@@ -40,8 +42,9 @@ struct msm_mdss { + struct irq_domain *domain; + } irq_controller; + const struct msm_mdss_data *mdss_data; +- struct icc_path *path[2]; +- u32 num_paths; ++ struct icc_path *mdp_path[2]; ++ u32 num_mdp_paths; ++ struct icc_path *reg_bus_path; + }; + + static int msm_mdss_parse_data_bus_icc_path(struct device *dev, +@@ -49,38 +52,34 @@ static int msm_mdss_parse_data_bus_icc_path(struct device *dev, + { + struct icc_path *path0; + struct icc_path *path1; ++ struct icc_path *reg_bus_path; + +- path0 = of_icc_get(dev, "mdp0-mem"); ++ path0 = devm_of_icc_get(dev, "mdp0-mem"); + if (IS_ERR_OR_NULL(path0)) + return PTR_ERR_OR_ZERO(path0); + +- msm_mdss->path[0] = path0; +- msm_mdss->num_paths = 1; ++ msm_mdss->mdp_path[0] = path0; ++ msm_mdss->num_mdp_paths = 1; + +- path1 = of_icc_get(dev, "mdp1-mem"); ++ path1 = devm_of_icc_get(dev, "mdp1-mem"); + if (!IS_ERR_OR_NULL(path1)) { +- msm_mdss->path[1] = path1; +- msm_mdss->num_paths++; ++ msm_mdss->mdp_path[1] = path1; ++ msm_mdss->num_mdp_paths++; + } + +- return 0; +-} +- +-static void msm_mdss_put_icc_path(void *data) +-{ +- struct msm_mdss *msm_mdss = data; +- int i; ++ reg_bus_path = of_icc_get(dev, "cpu-cfg"); ++ if (!IS_ERR_OR_NULL(reg_bus_path)) ++ msm_mdss->reg_bus_path = reg_bus_path; + +- for (i = 0; i < msm_mdss->num_paths; i++) +- icc_put(msm_mdss->path[i]); ++ return 0; + } + + static void msm_mdss_icc_request_bw(struct msm_mdss *msm_mdss, unsigned long bw) + { + int i; + +- for (i = 0; i < msm_mdss->num_paths; i++) +- icc_set_bw(msm_mdss->path[i], 0, Bps_to_icc(bw)); ++ for (i = 0; i < msm_mdss->num_mdp_paths; i++) ++ icc_set_bw(msm_mdss->mdp_path[i], 0, Bps_to_icc(bw)); + } + + static void msm_mdss_irq(struct irq_desc *desc) +@@ -245,6 +244,13 @@ static int msm_mdss_enable(struct msm_mdss *msm_mdss) + */ + msm_mdss_icc_request_bw(msm_mdss, MIN_IB_BW); + ++ if (msm_mdss->mdss_data && msm_mdss->mdss_data->reg_bus_bw) ++ icc_set_bw(msm_mdss->reg_bus_path, 0, ++ msm_mdss->mdss_data->reg_bus_bw); ++ else ++ icc_set_bw(msm_mdss->reg_bus_path, 0, ++ DEFAULT_REG_BW); ++ + ret = clk_bulk_prepare_enable(msm_mdss->num_clocks, msm_mdss->clocks); + if (ret) { + dev_err(msm_mdss->dev, "clock enable failed, ret:%d\n", ret); +@@ -298,6 +304,9 @@ static int msm_mdss_disable(struct msm_mdss *msm_mdss) + clk_bulk_disable_unprepare(msm_mdss->num_clocks, msm_mdss->clocks); + msm_mdss_icc_request_bw(msm_mdss, 0); + ++ if (msm_mdss->reg_bus_path) ++ icc_set_bw(msm_mdss->reg_bus_path, 0, 0); ++ + return 0; + } + +@@ -384,6 +393,8 @@ static struct msm_mdss *msm_mdss_init(struct platform_device *pdev, bool is_mdp5 + if (!msm_mdss) + return ERR_PTR(-ENOMEM); + ++ msm_mdss->mdss_data = of_device_get_match_data(&pdev->dev); ++ + msm_mdss->mmio = devm_platform_ioremap_resource_byname(pdev, is_mdp5 ? "mdss_phys" : "mdss"); + if (IS_ERR(msm_mdss->mmio)) + return ERR_CAST(msm_mdss->mmio); +@@ -391,9 +402,6 @@ static struct msm_mdss *msm_mdss_init(struct platform_device *pdev, bool is_mdp5 + dev_dbg(&pdev->dev, "mapped mdss address space @%pK\n", msm_mdss->mmio); + + ret = msm_mdss_parse_data_bus_icc_path(&pdev->dev, msm_mdss); +- if (ret) +- return ERR_PTR(ret); +- ret = devm_add_action_or_reset(&pdev->dev, msm_mdss_put_icc_path, msm_mdss); + if (ret) + return ERR_PTR(ret); + +@@ -477,8 +485,6 @@ static int mdss_probe(struct platform_device *pdev) + if (IS_ERR(mdss)) + return PTR_ERR(mdss); + +- mdss->mdss_data = of_device_get_match_data(&pdev->dev); +- + platform_set_drvdata(pdev, mdss); + + /* +@@ -512,18 +518,21 @@ static const struct msm_mdss_data msm8998_data = { + .ubwc_enc_version = UBWC_1_0, + .ubwc_dec_version = UBWC_1_0, + .highest_bank_bit = 2, ++ .reg_bus_bw = 76800, + }; + + static const struct msm_mdss_data qcm2290_data = { + /* no UBWC */ + .highest_bank_bit = 0x2, ++ .reg_bus_bw = 76800, + }; + + static const struct msm_mdss_data sc7180_data = { + .ubwc_enc_version = UBWC_2_0, + .ubwc_dec_version = UBWC_2_0, + .ubwc_static = 0x1e, +- .highest_bank_bit = 0x3, ++ .highest_bank_bit = 0x1, ++ .reg_bus_bw = 76800, + }; + + static const struct msm_mdss_data sc7280_data = { +@@ -533,6 +542,7 @@ static const struct msm_mdss_data sc7280_data = { + .ubwc_static = 1, + .highest_bank_bit = 1, + .macrotile_mode = 1, ++ .reg_bus_bw = 74000, + }; + + static const struct msm_mdss_data sc8180x_data = { +@@ -540,6 +550,7 @@ static const struct msm_mdss_data sc8180x_data = { + .ubwc_dec_version = UBWC_3_0, + .highest_bank_bit = 3, + .macrotile_mode = 1, ++ .reg_bus_bw = 76800, + }; + + static const struct msm_mdss_data sc8280xp_data = { +@@ -549,12 +560,14 @@ static const struct msm_mdss_data sc8280xp_data = { + .ubwc_static = 1, + .highest_bank_bit = 2, + .macrotile_mode = 1, ++ .reg_bus_bw = 76800, + }; + + static const struct msm_mdss_data sdm845_data = { + .ubwc_enc_version = UBWC_2_0, + .ubwc_dec_version = UBWC_2_0, + .highest_bank_bit = 2, ++ .reg_bus_bw = 76800, + }; + + static const struct msm_mdss_data sm6350_data = { +@@ -563,12 +576,14 @@ static const struct msm_mdss_data sm6350_data = { + .ubwc_swizzle = 6, + .ubwc_static = 0x1e, + .highest_bank_bit = 1, ++ .reg_bus_bw = 76800, + }; + + static const struct msm_mdss_data sm8150_data = { + .ubwc_enc_version = UBWC_3_0, + .ubwc_dec_version = UBWC_3_0, + .highest_bank_bit = 2, ++ .reg_bus_bw = 76800, + }; + + static const struct msm_mdss_data sm6115_data = { +@@ -577,6 +592,7 @@ static const struct msm_mdss_data sm6115_data = { + .ubwc_swizzle = 7, + .ubwc_static = 0x11f, + .highest_bank_bit = 0x1, ++ .reg_bus_bw = 76800, + }; + + static const struct msm_mdss_data sm6125_data = { +@@ -584,6 +600,7 @@ static const struct msm_mdss_data sm6125_data = { + .ubwc_dec_version = UBWC_3_0, + .ubwc_swizzle = 1, + .highest_bank_bit = 1, ++ .reg_bus_bw = 76800, + }; + + static const struct msm_mdss_data sm8250_data = { +@@ -594,6 +611,18 @@ static const struct msm_mdss_data sm8250_data = { + /* TODO: highest_bank_bit = 2 for LP_DDR4 */ + .highest_bank_bit = 3, + .macrotile_mode = 1, ++ .reg_bus_bw = 76800, ++}; ++ ++static const struct msm_mdss_data sm8350_data = { ++ .ubwc_enc_version = UBWC_4_0, ++ .ubwc_dec_version = UBWC_4_0, ++ .ubwc_swizzle = 6, ++ .ubwc_static = 1, ++ /* TODO: highest_bank_bit = 2 for LP_DDR4 */ ++ .highest_bank_bit = 3, ++ .macrotile_mode = 1, ++ .reg_bus_bw = 74000, + }; + + static const struct msm_mdss_data sm8550_data = { +@@ -604,6 +633,7 @@ static const struct msm_mdss_data sm8550_data = { + /* TODO: highest_bank_bit = 2 for LP_DDR4 */ + .highest_bank_bit = 3, + .macrotile_mode = 1, ++ .reg_bus_bw = 57000, + }; + static const struct of_device_id mdss_dt_match[] = { + { .compatible = "qcom,mdss" }, +@@ -620,8 +650,8 @@ static const struct of_device_id mdss_dt_match[] = { + { .compatible = "qcom,sm6375-mdss", .data = &sm6350_data }, + { .compatible = "qcom,sm8150-mdss", .data = &sm8150_data }, + { .compatible = "qcom,sm8250-mdss", .data = &sm8250_data }, +- { .compatible = "qcom,sm8350-mdss", .data = &sm8250_data }, +- { .compatible = "qcom,sm8450-mdss", .data = &sm8250_data }, ++ { .compatible = "qcom,sm8350-mdss", .data = &sm8350_data }, ++ { .compatible = "qcom,sm8450-mdss", .data = &sm8350_data }, + { .compatible = "qcom,sm8550-mdss", .data = &sm8550_data }, + {} + }; +diff --git a/drivers/gpu/drm/msm/msm_mdss.h b/drivers/gpu/drm/msm/msm_mdss.h +index 02bbab42adbc0e..3afef4b1786d28 100644 +--- a/drivers/gpu/drm/msm/msm_mdss.h ++++ b/drivers/gpu/drm/msm/msm_mdss.h +@@ -14,6 +14,7 @@ struct msm_mdss_data { + u32 ubwc_static; + u32 highest_bank_bit; + u32 macrotile_mode; ++ u32 reg_bus_bw; + }; + + #define UBWC_1_0 0x10000000 +diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c +index 40c0bc35a44cee..7f5e0a961bba72 100644 +--- a/drivers/gpu/drm/msm/msm_ringbuffer.c ++++ b/drivers/gpu/drm/msm/msm_ringbuffer.c +@@ -21,8 +21,6 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job) + + msm_fence_init(submit->hw_fence, fctx); + +- submit->seqno = submit->hw_fence->seqno; +- + mutex_lock(&priv->lru.lock); + + for (i = 0; i < submit->nr_bos; i++) { +@@ -34,8 +32,13 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job) + + mutex_unlock(&priv->lru.lock); + ++ /* TODO move submit path over to using a per-ring lock.. */ ++ mutex_lock(&gpu->lock); ++ + msm_gpu_submit(gpu, submit); + ++ mutex_unlock(&gpu->lock); ++ + return dma_fence_get(submit->hw_fence); + } + +diff --git a/drivers/gpu/drm/mxsfb/lcdif_drv.c b/drivers/gpu/drm/mxsfb/lcdif_drv.c +index 18de2f17e2491c..6494e827075690 100644 +--- a/drivers/gpu/drm/mxsfb/lcdif_drv.c ++++ b/drivers/gpu/drm/mxsfb/lcdif_drv.c +@@ -340,6 +340,9 @@ static int __maybe_unused lcdif_suspend(struct device *dev) + if (ret) + return ret; + ++ if (pm_runtime_suspended(dev)) ++ return 0; ++ + return lcdif_rpm_suspend(dev); + } + +@@ -347,7 +350,8 @@ static int __maybe_unused lcdif_resume(struct device *dev) + { + struct drm_device *drm = dev_get_drvdata(dev); + +- lcdif_rpm_resume(dev); ++ if (!pm_runtime_suspended(dev)) ++ lcdif_rpm_resume(dev); + + return drm_mode_config_helper_resume(drm); + } +diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c +index a34917b048f96f..8c7fff19c97bb0 100644 +--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c ++++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c +@@ -1157,7 +1157,7 @@ nv04_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, + chan = drm->channel; + if (!chan) + return -ENODEV; +- cli = (void *)chan->user.client; ++ cli = chan->cli; + push = chan->chan.push; + + s = kzalloc(sizeof(*s), GFP_KERNEL); +diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c +index 670c9739e5e18c..2033214c4b7848 100644 +--- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c ++++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c +@@ -209,6 +209,8 @@ static int nv17_tv_get_ld_modes(struct drm_encoder *encoder, + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(encoder->dev, tv_mode); ++ if (!mode) ++ continue; + + mode->clock = tv_norm->tv_enc_mode.vrefresh * + mode->htotal / 1000 * +@@ -258,6 +260,8 @@ static int nv17_tv_get_hd_modes(struct drm_encoder *encoder, + if (modes[i].hdisplay == output_mode->hdisplay && + modes[i].vdisplay == output_mode->vdisplay) { + mode = drm_mode_duplicate(encoder->dev, output_mode); ++ if (!mode) ++ continue; + mode->type |= DRM_MODE_TYPE_PREFERRED; + + } else { +@@ -265,6 +269,8 @@ static int nv17_tv_get_hd_modes(struct drm_encoder *encoder, + modes[i].vdisplay, 60, false, + (output_mode->flags & + DRM_MODE_FLAG_INTERLACE), false); ++ if (!mode) ++ continue; + } + + /* CVT modes are sometimes unsuitable... */ +diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c +index 4e7c9c353c5112..de8041c94de5d8 100644 +--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c ++++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c +@@ -966,8 +966,7 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, + const int clock = crtc_state->adjusted_mode.clock; + + asyh->or.bpc = connector->display_info.bpc; +- asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3, +- false); ++ asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3 << 4); + } + + mst_state = drm_atomic_get_mst_topology_state(state, &mstm->mgr); +@@ -2310,7 +2309,7 @@ nv50_disp_atomic_commit(struct drm_device *dev, + + err_cleanup: + if (ret) +- drm_atomic_helper_cleanup_planes(dev, state); ++ drm_atomic_helper_unprepare_planes(dev, state); + done: + pm_runtime_put_autosuspend(dev->dev); + return ret; +diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +index 0d9fc741a71932..932c9fd0b2d89c 100644 +--- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h ++++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +@@ -11,6 +11,7 @@ struct nvkm_client { + u32 debug; + + struct rb_root objroot; ++ spinlock_t obj_lock; + + void *data; + int (*event)(u64 token, void *argv, u32 argc); +diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/event.h b/drivers/gpu/drm/nouveau/include/nvkm/core/event.h +index 82b267c111470a..460459af272d6f 100644 +--- a/drivers/gpu/drm/nouveau/include/nvkm/core/event.h ++++ b/drivers/gpu/drm/nouveau/include/nvkm/core/event.h +@@ -14,7 +14,7 @@ struct nvkm_event { + int index_nr; + + spinlock_t refs_lock; +- spinlock_t list_lock; ++ rwlock_t list_lock; + int *refs; + + struct list_head ntfy; +@@ -38,7 +38,7 @@ nvkm_event_init(const struct nvkm_event_func *func, struct nvkm_subdev *subdev, + int types_nr, int index_nr, struct nvkm_event *event) + { + spin_lock_init(&event->refs_lock); +- spin_lock_init(&event->list_lock); ++ rwlock_init(&event->list_lock); + return __nvkm_event_init(func, subdev, types_nr, index_nr, event); + } + +diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c +index 2edd7bb13faea5..2e177ebab30398 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c ++++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c +@@ -204,6 +204,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) + struct nouveau_cli *cli = nouveau_cli(file_priv); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nvif_device *device = &drm->client.device; ++ struct nvkm_device *nvkm_device = nvxx_device(&drm->client.device); + struct nvkm_gr *gr = nvxx_gr(device); + struct drm_nouveau_getparam *getparam = data; + struct pci_dev *pdev = to_pci_dev(dev->dev); +@@ -268,6 +269,17 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) + getparam->value = nouveau_exec_push_max_from_ib_max(ib_max); + break; + } ++ case NOUVEAU_GETPARAM_VRAM_BAR_SIZE: ++ getparam->value = nvkm_device->func->resource_size(nvkm_device, 1); ++ break; ++ case NOUVEAU_GETPARAM_VRAM_USED: { ++ struct ttm_resource_manager *vram_mgr = ttm_manager_type(&drm->ttm.bdev, TTM_PL_VRAM); ++ getparam->value = (u64)ttm_resource_manager_usage(vram_mgr); ++ break; ++ } ++ case NOUVEAU_GETPARAM_HAS_VMA_TILEMODE: ++ getparam->value = 1; ++ break; + default: + NV_PRINTK(dbg, cli, "unknown parameter %lld\n", getparam->param); + return -EINVAL; +@@ -339,7 +351,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) + list_add(&chan->head, &abi16->channels); + + /* create channel object and initialise dma and fence management */ +- ret = nouveau_channel_new(drm, device, false, runm, init->fb_ctxdma_handle, ++ ret = nouveau_channel_new(cli, false, runm, init->fb_ctxdma_handle, + init->tt_ctxdma_handle, &chan->chan); + if (ret) + goto done; +diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c +index 189903b65edc99..48cf593383b341 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_bios.c ++++ b/drivers/gpu/drm/nouveau/nouveau_bios.c +@@ -23,6 +23,7 @@ + */ + + #include "nouveau_drv.h" ++#include "nouveau_bios.h" + #include "nouveau_reg.h" + #include "dispnv04/hw.h" + #include "nouveau_encoder.h" +@@ -1675,7 +1676,7 @@ apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf) + */ + if (nv_match_device(dev, 0x0201, 0x1462, 0x8851)) { + if (*conn == 0xf2005014 && *conf == 0xffffffff) { +- fabricate_dcb_output(dcb, DCB_OUTPUT_TMDS, 1, 1, 1); ++ fabricate_dcb_output(dcb, DCB_OUTPUT_TMDS, 1, 1, DCB_OUTPUT_B); + return false; + } + } +@@ -1761,26 +1762,26 @@ fabricate_dcb_encoder_table(struct drm_device *dev, struct nvbios *bios) + #ifdef __powerpc__ + /* Apple iMac G4 NV17 */ + if (of_machine_is_compatible("PowerMac4,5")) { +- fabricate_dcb_output(dcb, DCB_OUTPUT_TMDS, 0, all_heads, 1); +- fabricate_dcb_output(dcb, DCB_OUTPUT_ANALOG, 1, all_heads, 2); ++ fabricate_dcb_output(dcb, DCB_OUTPUT_TMDS, 0, all_heads, DCB_OUTPUT_B); ++ fabricate_dcb_output(dcb, DCB_OUTPUT_ANALOG, 1, all_heads, DCB_OUTPUT_C); + return; + } + #endif + + /* Make up some sane defaults */ + fabricate_dcb_output(dcb, DCB_OUTPUT_ANALOG, +- bios->legacy.i2c_indices.crt, 1, 1); ++ bios->legacy.i2c_indices.crt, 1, DCB_OUTPUT_B); + + if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0) + fabricate_dcb_output(dcb, DCB_OUTPUT_TV, + bios->legacy.i2c_indices.tv, +- all_heads, 0); ++ all_heads, DCB_OUTPUT_A); + + else if (bios->tmds.output0_script_ptr || + bios->tmds.output1_script_ptr) + fabricate_dcb_output(dcb, DCB_OUTPUT_TMDS, + bios->legacy.i2c_indices.panel, +- all_heads, 1); ++ all_heads, DCB_OUTPUT_B); + } + + static int +diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c +index 0f3bd187ede67d..5d398a422459e1 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_bo.c ++++ b/drivers/gpu/drm/nouveau/nouveau_bo.c +@@ -234,28 +234,28 @@ nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 domain, + } + + nvbo->contig = !(tile_flags & NOUVEAU_GEM_TILE_NONCONTIG); +- if (!nouveau_cli_uvmm(cli) || internal) { +- /* for BO noVM allocs, don't assign kinds */ +- if (cli->device.info.family >= NV_DEVICE_INFO_V0_FERMI) { +- nvbo->kind = (tile_flags & 0x0000ff00) >> 8; +- if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) { +- kfree(nvbo); +- return ERR_PTR(-EINVAL); +- } + +- nvbo->comp = mmu->kind[nvbo->kind] != nvbo->kind; +- } else if (cli->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { +- nvbo->kind = (tile_flags & 0x00007f00) >> 8; +- nvbo->comp = (tile_flags & 0x00030000) >> 16; +- if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) { +- kfree(nvbo); +- return ERR_PTR(-EINVAL); +- } +- } else { +- nvbo->zeta = (tile_flags & 0x00000007); ++ if (cli->device.info.family >= NV_DEVICE_INFO_V0_FERMI) { ++ nvbo->kind = (tile_flags & 0x0000ff00) >> 8; ++ if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) { ++ kfree(nvbo); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ nvbo->comp = mmu->kind[nvbo->kind] != nvbo->kind; ++ } else if (cli->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { ++ nvbo->kind = (tile_flags & 0x00007f00) >> 8; ++ nvbo->comp = (tile_flags & 0x00030000) >> 16; ++ if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) { ++ kfree(nvbo); ++ return ERR_PTR(-EINVAL); + } +- nvbo->mode = tile_mode; ++ } else { ++ nvbo->zeta = (tile_flags & 0x00000007); ++ } ++ nvbo->mode = tile_mode; + ++ if (!nouveau_cli_uvmm(cli) || internal) { + /* Determine the desirable target GPU page size for the buffer. */ + for (i = 0; i < vmm->page_nr; i++) { + /* Because we cannot currently allow VMM maps to fail +@@ -297,12 +297,6 @@ nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 domain, + } + nvbo->page = vmm->page[pi].shift; + } else { +- /* reject other tile flags when in VM mode. */ +- if (tile_mode) +- return ERR_PTR(-EINVAL); +- if (tile_flags & ~NOUVEAU_GEM_TILE_NONCONTIG) +- return ERR_PTR(-EINVAL); +- + /* Determine the desirable target GPU page size for the buffer. */ + for (i = 0; i < vmm->page_nr; i++) { + /* Because we cannot currently allow VMM maps to fail +@@ -318,8 +312,9 @@ nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 domain, + (!vmm->page[i].host || vmm->page[i].shift > PAGE_SHIFT)) + continue; + +- if (pi < 0) +- pi = i; ++ /* pick the last one as it will be smallest. */ ++ pi = i; ++ + /* Stop once the buffer is larger than the current page size. */ + if (*size >= 1ULL << vmm->page[i].shift) + break; +@@ -848,7 +843,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, + { + struct nouveau_drm *drm = nouveau_bdev(bo->bdev); + struct nouveau_channel *chan = drm->ttm.chan; +- struct nouveau_cli *cli = (void *)chan->user.client; ++ struct nouveau_cli *cli = chan->cli; + struct nouveau_fence *fence; + int ret; + +@@ -1254,6 +1249,8 @@ nouveau_ttm_io_mem_reserve(struct ttm_device *bdev, struct ttm_resource *reg) + drm_vma_node_unmap(&nvbo->bo.base.vma_node, + bdev->dev_mapping); + nouveau_ttm_io_mem_free_locked(drm, nvbo->bo.resource); ++ nvbo->bo.resource->bus.offset = 0; ++ nvbo->bo.resource->bus.addr = NULL; + goto retry; + } + +diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c +index 7c97b288680760..cee36b1efd3917 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_chan.c ++++ b/drivers/gpu/drm/nouveau/nouveau_chan.c +@@ -52,7 +52,7 @@ static int + nouveau_channel_killed(struct nvif_event *event, void *repv, u32 repc) + { + struct nouveau_channel *chan = container_of(event, typeof(*chan), kill); +- struct nouveau_cli *cli = (void *)chan->user.client; ++ struct nouveau_cli *cli = chan->cli; + + NV_PRINTK(warn, cli, "channel %d killed!\n", chan->chid); + +@@ -66,7 +66,7 @@ int + nouveau_channel_idle(struct nouveau_channel *chan) + { + if (likely(chan && chan->fence && !atomic_read(&chan->killed))) { +- struct nouveau_cli *cli = (void *)chan->user.client; ++ struct nouveau_cli *cli = chan->cli; + struct nouveau_fence *fence = NULL; + int ret; + +@@ -142,10 +142,11 @@ nouveau_channel_wait(struct nvif_push *push, u32 size) + } + + static int +-nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, ++nouveau_channel_prep(struct nouveau_cli *cli, + u32 size, struct nouveau_channel **pchan) + { +- struct nouveau_cli *cli = (void *)device->object.client; ++ struct nouveau_drm *drm = cli->drm; ++ struct nvif_device *device = &cli->device; + struct nv_dma_v0 args = {}; + struct nouveau_channel *chan; + u32 target; +@@ -155,6 +156,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, + if (!chan) + return -ENOMEM; + ++ chan->cli = cli; + chan->device = device; + chan->drm = drm; + chan->vmm = nouveau_cli_vmm(cli); +@@ -254,7 +256,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, + } + + static int +-nouveau_channel_ctor(struct nouveau_drm *drm, struct nvif_device *device, bool priv, u64 runm, ++nouveau_channel_ctor(struct nouveau_cli *cli, bool priv, u64 runm, + struct nouveau_channel **pchan) + { + const struct nvif_mclass hosts[] = { +@@ -279,7 +281,7 @@ nouveau_channel_ctor(struct nouveau_drm *drm, struct nvif_device *device, bool p + struct nvif_chan_v0 chan; + char name[TASK_COMM_LEN+16]; + } args; +- struct nouveau_cli *cli = (void *)device->object.client; ++ struct nvif_device *device = &cli->device; + struct nouveau_channel *chan; + const u64 plength = 0x10000; + const u64 ioffset = plength; +@@ -298,7 +300,7 @@ nouveau_channel_ctor(struct nouveau_drm *drm, struct nvif_device *device, bool p + size = ioffset + ilength; + + /* allocate dma push buffer */ +- ret = nouveau_channel_prep(drm, device, size, &chan); ++ ret = nouveau_channel_prep(cli, size, &chan); + *pchan = chan; + if (ret) + return ret; +@@ -493,13 +495,12 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) + } + + int +-nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device, ++nouveau_channel_new(struct nouveau_cli *cli, + bool priv, u64 runm, u32 vram, u32 gart, struct nouveau_channel **pchan) + { +- struct nouveau_cli *cli = (void *)device->object.client; + int ret; + +- ret = nouveau_channel_ctor(drm, device, priv, runm, pchan); ++ ret = nouveau_channel_ctor(cli, priv, runm, pchan); + if (ret) { + NV_PRINTK(dbg, cli, "channel create, %d\n", ret); + return ret; +diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.h b/drivers/gpu/drm/nouveau/nouveau_chan.h +index 5de2ef4e98c2bb..260febd634ee21 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_chan.h ++++ b/drivers/gpu/drm/nouveau/nouveau_chan.h +@@ -12,6 +12,7 @@ struct nouveau_channel { + struct nvif_push *push; + } chan; + ++ struct nouveau_cli *cli; + struct nvif_device *device; + struct nouveau_drm *drm; + struct nouveau_vmm *vmm; +@@ -62,7 +63,7 @@ struct nouveau_channel { + int nouveau_channels_init(struct nouveau_drm *); + void nouveau_channels_fini(struct nouveau_drm *); + +-int nouveau_channel_new(struct nouveau_drm *, struct nvif_device *, bool priv, u64 runm, ++int nouveau_channel_new(struct nouveau_cli *, bool priv, u64 runm, + u32 vram, u32 gart, struct nouveau_channel **); + void nouveau_channel_del(struct nouveau_channel **); + int nouveau_channel_idle(struct nouveau_channel *); +diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c +index 79ea30aac31fb8..22a125243d81f7 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_connector.c ++++ b/drivers/gpu/drm/nouveau/nouveau_connector.c +@@ -983,6 +983,9 @@ nouveau_connector_get_modes(struct drm_connector *connector) + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(dev, nv_connector->native_mode); ++ if (!mode) ++ return 0; ++ + drm_mode_probed_add(connector, mode); + ret = 1; + } +diff --git a/drivers/gpu/drm/nouveau/nouveau_dmem.c b/drivers/gpu/drm/nouveau/nouveau_dmem.c +index 12feecf71e752d..097bd3af0719e0 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_dmem.c ++++ b/drivers/gpu/drm/nouveau/nouveau_dmem.c +@@ -193,7 +193,7 @@ static vm_fault_t nouveau_dmem_migrate_to_ram(struct vm_fault *vmf) + if (!spage || !(src & MIGRATE_PFN_MIGRATE)) + goto done; + +- dpage = alloc_page_vma(GFP_HIGHUSER, vmf->vma, vmf->address); ++ dpage = alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vmf->vma, vmf->address); + if (!dpage) + goto done; + +@@ -378,9 +378,9 @@ nouveau_dmem_evict_chunk(struct nouveau_dmem_chunk *chunk) + dma_addr_t *dma_addrs; + struct nouveau_fence *fence; + +- src_pfns = kcalloc(npages, sizeof(*src_pfns), GFP_KERNEL); +- dst_pfns = kcalloc(npages, sizeof(*dst_pfns), GFP_KERNEL); +- dma_addrs = kcalloc(npages, sizeof(*dma_addrs), GFP_KERNEL); ++ src_pfns = kvcalloc(npages, sizeof(*src_pfns), GFP_KERNEL | __GFP_NOFAIL); ++ dst_pfns = kvcalloc(npages, sizeof(*dst_pfns), GFP_KERNEL | __GFP_NOFAIL); ++ dma_addrs = kvcalloc(npages, sizeof(*dma_addrs), GFP_KERNEL | __GFP_NOFAIL); + + migrate_device_range(src_pfns, chunk->pagemap.range.start >> PAGE_SHIFT, + npages); +@@ -406,11 +406,11 @@ nouveau_dmem_evict_chunk(struct nouveau_dmem_chunk *chunk) + migrate_device_pages(src_pfns, dst_pfns, npages); + nouveau_dmem_fence_done(&fence); + migrate_device_finalize(src_pfns, dst_pfns, npages); +- kfree(src_pfns); +- kfree(dst_pfns); ++ kvfree(src_pfns); ++ kvfree(dst_pfns); + for (i = 0; i < npages; i++) + dma_unmap_page(chunk->drm->dev->dev, dma_addrs[i], PAGE_SIZE, DMA_BIDIRECTIONAL); +- kfree(dma_addrs); ++ kvfree(dma_addrs); + } + + void +diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c +index 6a4980b2d4d4e1..bf2ae67b03d944 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_dp.c ++++ b/drivers/gpu/drm/nouveau/nouveau_dp.c +@@ -108,12 +108,15 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector, + u8 *dpcd = nv_encoder->dp.dpcd; + int ret = NOUVEAU_DP_NONE, hpd; + +- /* If we've already read the DPCD on an eDP device, we don't need to +- * reread it as it won't change ++ /* eDP ports don't support hotplugging - so there's no point in probing eDP ports unless we ++ * haven't probed them once before. + */ +- if (connector->connector_type == DRM_MODE_CONNECTOR_eDP && +- dpcd[DP_DPCD_REV] != 0) +- return NOUVEAU_DP_SST; ++ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { ++ if (connector->status == connector_status_connected) ++ return NOUVEAU_DP_SST; ++ else if (connector->status == connector_status_disconnected) ++ return NOUVEAU_DP_NONE; ++ } + + mutex_lock(&nv_encoder->dp.hpd_irq_lock); + if (mstm) { +diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c +index 4396f501b16a3f..ac15a662e06042 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_drm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_drm.c +@@ -343,7 +343,7 @@ nouveau_accel_ce_init(struct nouveau_drm *drm) + return; + } + +- ret = nouveau_channel_new(drm, device, false, runm, NvDmaFB, NvDmaTT, &drm->cechan); ++ ret = nouveau_channel_new(&drm->client, true, runm, NvDmaFB, NvDmaTT, &drm->cechan); + if (ret) + NV_ERROR(drm, "failed to create ce channel, %d\n", ret); + } +@@ -371,7 +371,7 @@ nouveau_accel_gr_init(struct nouveau_drm *drm) + return; + } + +- ret = nouveau_channel_new(drm, device, false, runm, NvDmaFB, NvDmaTT, &drm->channel); ++ ret = nouveau_channel_new(&drm->client, false, runm, NvDmaFB, NvDmaTT, &drm->channel); + if (ret) { + NV_ERROR(drm, "failed to create kernel channel, %d\n", ret); + nouveau_accel_gr_fini(drm); +@@ -708,10 +708,11 @@ nouveau_drm_device_fini(struct drm_device *dev) + } + mutex_unlock(&drm->clients_lock); + +- nouveau_sched_fini(drm); +- + nouveau_cli_fini(&drm->client); + nouveau_cli_fini(&drm->master); ++ ++ nouveau_sched_fini(drm); ++ + nvif_parent_dtor(&drm->parent); + mutex_destroy(&drm->clients_lock); + kfree(drm); +@@ -1133,7 +1134,10 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) + } + + get_task_comm(tmpname, current); +- snprintf(name, sizeof(name), "%s[%d]", tmpname, pid_nr(fpriv->pid)); ++ rcu_read_lock(); ++ snprintf(name, sizeof(name), "%s[%d]", ++ tmpname, pid_nr(rcu_dereference(fpriv->pid))); ++ rcu_read_unlock(); + + if (!(cli = kzalloc(sizeof(*cli), GFP_KERNEL))) { + ret = -ENOMEM; +diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c +index ca762ea5541361..93f08f9479d89b 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_fence.c ++++ b/drivers/gpu/drm/nouveau/nouveau_fence.c +@@ -103,6 +103,7 @@ nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error) + void + nouveau_fence_context_del(struct nouveau_fence_chan *fctx) + { ++ cancel_work_sync(&fctx->uevent_work); + nouveau_fence_context_kill(fctx, 0); + nvif_event_dtor(&fctx->event); + fctx->dead = 1; +@@ -145,12 +146,13 @@ nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fc + return drop; + } + +-static int +-nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc) ++static void ++nouveau_fence_uevent_work(struct work_struct *work) + { +- struct nouveau_fence_chan *fctx = container_of(event, typeof(*fctx), event); ++ struct nouveau_fence_chan *fctx = container_of(work, struct nouveau_fence_chan, ++ uevent_work); + unsigned long flags; +- int ret = NVIF_EVENT_KEEP; ++ int drop = 0; + + spin_lock_irqsave(&fctx->lock, flags); + if (!list_empty(&fctx->pending)) { +@@ -160,11 +162,20 @@ nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc + fence = list_entry(fctx->pending.next, typeof(*fence), head); + chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock)); + if (nouveau_fence_update(chan, fctx)) +- ret = NVIF_EVENT_DROP; ++ drop = 1; + } ++ if (drop) ++ nvif_event_block(&fctx->event); ++ + spin_unlock_irqrestore(&fctx->lock, flags); ++} + +- return ret; ++static int ++nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc) ++{ ++ struct nouveau_fence_chan *fctx = container_of(event, typeof(*fctx), event); ++ schedule_work(&fctx->uevent_work); ++ return NVIF_EVENT_KEEP; + } + + void +@@ -178,6 +189,7 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha + } args; + int ret; + ++ INIT_WORK(&fctx->uevent_work, nouveau_fence_uevent_work); + INIT_LIST_HEAD(&fctx->flip); + INIT_LIST_HEAD(&fctx->pending); + spin_lock_init(&fctx->lock); +diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h +index 64d33ae7f35610..8bc065acfe3587 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_fence.h ++++ b/drivers/gpu/drm/nouveau/nouveau_fence.h +@@ -44,6 +44,7 @@ struct nouveau_fence_chan { + u32 context; + char name[32]; + ++ struct work_struct uevent_work; + struct nvif_event event; + int notify_ref, dead, killed; + }; +diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c +index a0d303e5ce3d8d..7b69e6df57486a 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_gem.c ++++ b/drivers/gpu/drm/nouveau/nouveau_gem.c +@@ -758,7 +758,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, + return -ENOMEM; + + if (unlikely(nouveau_cli_uvmm(cli))) +- return -ENOSYS; ++ return nouveau_abi16_put(abi16, -ENOSYS); + + list_for_each_entry(temp, &abi16->channels, head) { + if (temp->chan->chid == req->channel) { +diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c +index 1b2ff0c40fc1c9..6c599a9f49ee40 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_prime.c ++++ b/drivers/gpu/drm/nouveau/nouveau_prime.c +@@ -64,7 +64,8 @@ struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev, + * to the caller, instead of a normal nouveau_bo ttm reference. */ + ret = drm_gem_object_init(dev, &nvbo->bo.base, size); + if (ret) { +- nouveau_bo_ref(NULL, &nvbo); ++ drm_gem_object_release(&nvbo->bo.base); ++ kfree(nvbo); + obj = ERR_PTR(-ENOMEM); + goto unlock; + } +diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c +index 186351ecf72fd7..ec9f307370fa8a 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_svm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_svm.c +@@ -1011,7 +1011,7 @@ nouveau_svm_fault_buffer_ctor(struct nouveau_svm *svm, s32 oclass, int id) + if (ret) + return ret; + +- buffer->fault = kvcalloc(sizeof(*buffer->fault), buffer->entries, GFP_KERNEL); ++ buffer->fault = kvcalloc(buffer->entries, sizeof(*buffer->fault), GFP_KERNEL); + if (!buffer->fault) + return -ENOMEM; + +diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c +index aae780e4a4aa37..3d41e590d4712d 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c +@@ -804,15 +804,15 @@ op_remap(struct drm_gpuva_op_remap *r, + struct drm_gpuva_op_unmap *u = r->unmap; + struct nouveau_uvma *uvma = uvma_from_va(u->va); + u64 addr = uvma->va.va.addr; +- u64 range = uvma->va.va.range; ++ u64 end = uvma->va.va.addr + uvma->va.va.range; + + if (r->prev) + addr = r->prev->va.addr + r->prev->va.range; + + if (r->next) +- range = r->next->va.addr - addr; ++ end = r->next->va.addr; + +- op_unmap_range(u, addr, range); ++ op_unmap_range(u, addr, end - addr); + } + + static int +@@ -1320,6 +1320,7 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) + + drm_gpuva_for_each_op(va_op, op->ops) { + struct drm_gem_object *obj = op_gem_obj(va_op); ++ struct nouveau_bo *nvbo; + + if (unlikely(!obj)) + continue; +@@ -1330,8 +1331,9 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) + if (unlikely(va_op->op == DRM_GPUVA_OP_UNMAP)) + continue; + +- ret = nouveau_bo_validate(nouveau_gem_object(obj), +- true, false); ++ nvbo = nouveau_gem_object(obj); ++ nouveau_bo_placement_set(nvbo, nvbo->valid_domains, 0); ++ ret = nouveau_bo_validate(nvbo, true, false); + if (ret) { + op = list_last_op(&bind_job->ops); + goto unwind; +diff --git a/drivers/gpu/drm/nouveau/nouveau_vmm.c b/drivers/gpu/drm/nouveau/nouveau_vmm.c +index a6602c01267156..3dda885df5b223 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_vmm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_vmm.c +@@ -108,6 +108,9 @@ nouveau_vma_new(struct nouveau_bo *nvbo, struct nouveau_vmm *vmm, + } else { + ret = nvif_vmm_get(&vmm->vmm, PTES, false, mem->mem.page, 0, + mem->mem.size, &tmp); ++ if (ret) ++ goto done; ++ + vma->addr = tmp.addr; + } + +diff --git a/drivers/gpu/drm/nouveau/nv04_fence.c b/drivers/gpu/drm/nouveau/nv04_fence.c +index 5b71a5a5cd85ce..cdbc75e3d1f669 100644 +--- a/drivers/gpu/drm/nouveau/nv04_fence.c ++++ b/drivers/gpu/drm/nouveau/nv04_fence.c +@@ -39,7 +39,7 @@ struct nv04_fence_priv { + static int + nv04_fence_emit(struct nouveau_fence *fence) + { +- struct nvif_push *push = fence->channel->chan.push; ++ struct nvif_push *push = unrcu_pointer(fence->channel)->chan.push; + int ret = PUSH_WAIT(push, 2); + if (ret == 0) { + PUSH_NVSQ(push, NV_SW, 0x0150, fence->base.seqno); +diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c +index ebdeb8eb9e7741..c55662937ab22c 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/core/client.c ++++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c +@@ -180,6 +180,7 @@ nvkm_client_new(const char *name, u64 device, const char *cfg, const char *dbg, + client->device = device; + client->debug = nvkm_dbgopt(dbg, "CLIENT"); + client->objroot = RB_ROOT; ++ spin_lock_init(&client->obj_lock); + client->event = event; + INIT_LIST_HEAD(&client->umem); + spin_lock_init(&client->lock); +diff --git a/drivers/gpu/drm/nouveau/nvkm/core/event.c b/drivers/gpu/drm/nouveau/nvkm/core/event.c +index a6c877135598f7..61fed7792e415c 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/core/event.c ++++ b/drivers/gpu/drm/nouveau/nvkm/core/event.c +@@ -81,17 +81,17 @@ nvkm_event_ntfy_state(struct nvkm_event_ntfy *ntfy) + static void + nvkm_event_ntfy_remove(struct nvkm_event_ntfy *ntfy) + { +- spin_lock_irq(&ntfy->event->list_lock); ++ write_lock_irq(&ntfy->event->list_lock); + list_del_init(&ntfy->head); +- spin_unlock_irq(&ntfy->event->list_lock); ++ write_unlock_irq(&ntfy->event->list_lock); + } + + static void + nvkm_event_ntfy_insert(struct nvkm_event_ntfy *ntfy) + { +- spin_lock_irq(&ntfy->event->list_lock); ++ write_lock_irq(&ntfy->event->list_lock); + list_add_tail(&ntfy->head, &ntfy->event->ntfy); +- spin_unlock_irq(&ntfy->event->list_lock); ++ write_unlock_irq(&ntfy->event->list_lock); + } + + static void +@@ -176,7 +176,7 @@ nvkm_event_ntfy(struct nvkm_event *event, int id, u32 bits) + return; + + nvkm_trace(event->subdev, "event: ntfy %08x on %d\n", bits, id); +- spin_lock_irqsave(&event->list_lock, flags); ++ read_lock_irqsave(&event->list_lock, flags); + + list_for_each_entry_safe(ntfy, ntmp, &event->ntfy, head) { + if (ntfy->id == id && ntfy->bits & bits) { +@@ -185,7 +185,7 @@ nvkm_event_ntfy(struct nvkm_event *event, int id, u32 bits) + } + } + +- spin_unlock_irqrestore(&event->list_lock, flags); ++ read_unlock_irqrestore(&event->list_lock, flags); + } + + void +diff --git a/drivers/gpu/drm/nouveau/nvkm/core/firmware.c b/drivers/gpu/drm/nouveau/nvkm/core/firmware.c +index 91fb494d400935..afc8d4e3e16f47 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/core/firmware.c ++++ b/drivers/gpu/drm/nouveau/nvkm/core/firmware.c +@@ -187,7 +187,8 @@ nvkm_firmware_dtor(struct nvkm_firmware *fw) + break; + case NVKM_FIRMWARE_IMG_DMA: + nvkm_memory_unref(&memory); +- dma_free_coherent(fw->device->dev, sg_dma_len(&fw->mem.sgl), fw->img, fw->phys); ++ dma_free_noncoherent(fw->device->dev, sg_dma_len(&fw->mem.sgl), ++ fw->img, fw->phys, DMA_TO_DEVICE); + break; + default: + WARN_ON(1); +@@ -212,10 +213,12 @@ nvkm_firmware_ctor(const struct nvkm_firmware_func *func, const char *name, + break; + case NVKM_FIRMWARE_IMG_DMA: { + dma_addr_t addr; +- + len = ALIGN(fw->len, PAGE_SIZE); + +- fw->img = dma_alloc_coherent(fw->device->dev, len, &addr, GFP_KERNEL); ++ fw->img = dma_alloc_noncoherent(fw->device->dev, ++ len, &addr, ++ DMA_TO_DEVICE, ++ GFP_KERNEL); + if (fw->img) { + memcpy(fw->img, src, fw->len); + fw->phys = addr; +diff --git a/drivers/gpu/drm/nouveau/nvkm/core/object.c b/drivers/gpu/drm/nouveau/nvkm/core/object.c +index 7c554c14e8841d..aea3ba72027abf 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/core/object.c ++++ b/drivers/gpu/drm/nouveau/nvkm/core/object.c +@@ -30,8 +30,10 @@ nvkm_object_search(struct nvkm_client *client, u64 handle, + const struct nvkm_object_func *func) + { + struct nvkm_object *object; ++ unsigned long flags; + + if (handle) { ++ spin_lock_irqsave(&client->obj_lock, flags); + struct rb_node *node = client->objroot.rb_node; + while (node) { + object = rb_entry(node, typeof(*object), node); +@@ -40,9 +42,12 @@ nvkm_object_search(struct nvkm_client *client, u64 handle, + else + if (handle > object->object) + node = node->rb_right; +- else ++ else { ++ spin_unlock_irqrestore(&client->obj_lock, flags); + goto done; ++ } + } ++ spin_unlock_irqrestore(&client->obj_lock, flags); + return ERR_PTR(-ENOENT); + } else { + object = &client->object; +@@ -57,30 +62,39 @@ nvkm_object_search(struct nvkm_client *client, u64 handle, + void + nvkm_object_remove(struct nvkm_object *object) + { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&object->client->obj_lock, flags); + if (!RB_EMPTY_NODE(&object->node)) + rb_erase(&object->node, &object->client->objroot); ++ spin_unlock_irqrestore(&object->client->obj_lock, flags); + } + + bool + nvkm_object_insert(struct nvkm_object *object) + { +- struct rb_node **ptr = &object->client->objroot.rb_node; ++ struct rb_node **ptr; + struct rb_node *parent = NULL; ++ unsigned long flags; + ++ spin_lock_irqsave(&object->client->obj_lock, flags); ++ ptr = &object->client->objroot.rb_node; + while (*ptr) { + struct nvkm_object *this = rb_entry(*ptr, typeof(*this), node); + parent = *ptr; +- if (object->object < this->object) ++ if (object->object < this->object) { + ptr = &parent->rb_left; +- else +- if (object->object > this->object) ++ } else if (object->object > this->object) { + ptr = &parent->rb_right; +- else ++ } else { ++ spin_unlock_irqrestore(&object->client->obj_lock, flags); + return false; ++ } + } + + rb_link_node(&object->node, parent, ptr); + rb_insert_color(&object->node, &object->client->objroot); ++ spin_unlock_irqrestore(&object->client->obj_lock, flags); + return true; + } + +diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/fw.c b/drivers/gpu/drm/nouveau/nvkm/falcon/fw.c +index 80a480b1217468..a1c8545f1249a1 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/falcon/fw.c ++++ b/drivers/gpu/drm/nouveau/nvkm/falcon/fw.c +@@ -89,6 +89,12 @@ nvkm_falcon_fw_boot(struct nvkm_falcon_fw *fw, struct nvkm_subdev *user, + nvkm_falcon_fw_dtor_sigs(fw); + } + ++ /* after last write to the img, sync dma mappings */ ++ dma_sync_single_for_device(fw->fw.device->dev, ++ fw->fw.phys, ++ sg_dma_len(&fw->fw.mem.sgl), ++ DMA_TO_DEVICE); ++ + FLCNFW_DBG(fw, "resetting"); + fw->func->reset(fw); + +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c +index 19188683c8fca9..8c2bf1c16f2a95 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c +@@ -154,11 +154,17 @@ shadow_fw_init(struct nvkm_bios *bios, const char *name) + return (void *)fw; + } + ++static void ++shadow_fw_release(void *fw) ++{ ++ release_firmware(fw); ++} ++ + static const struct nvbios_source + shadow_fw = { + .name = "firmware", + .init = shadow_fw_init, +- .fini = (void(*)(void *))release_firmware, ++ .fini = shadow_fw_release, + .read = shadow_fw_read, + .rw = false, + }; +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c +index 4bf486b5710136..cb05f7f48a98bb 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c +@@ -66,11 +66,16 @@ of_init(struct nvkm_bios *bios, const char *name) + return ERR_PTR(-EINVAL); + } + ++static void of_fini(void *p) ++{ ++ kfree(p); ++} ++ + const struct nvbios_source + nvbios_of = { + .name = "OpenFirmware", + .init = of_init, +- .fini = (void(*)(void *))kfree, ++ .fini = of_fini, + .read = of_read, + .size = of_size, + .rw = false, +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h +index 50f0c1914f58e8..4c3f7439657987 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h +@@ -46,6 +46,8 @@ u32 gm107_ram_probe_fbp(const struct nvkm_ram_func *, + u32 gm200_ram_probe_fbp_amount(const struct nvkm_ram_func *, u32, + struct nvkm_device *, int, int *); + ++int gp100_ram_init(struct nvkm_ram *); ++ + /* RAM type-specific MR calculation routines */ + int nvkm_sddr2_calc(struct nvkm_ram *); + int nvkm_sddr3_calc(struct nvkm_ram *); +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c +index 378f6fb7099077..8987a21e81d174 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c +@@ -27,7 +27,7 @@ + #include + #include + +-static int ++int + gp100_ram_init(struct nvkm_ram *ram) + { + struct nvkm_subdev *subdev = &ram->fb->subdev; +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp102.c +index 8550f5e473474b..b6b6ee59019d70 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp102.c ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp102.c +@@ -5,6 +5,7 @@ + + static const struct nvkm_ram_func + gp102_ram = { ++ .init = gp100_ram_init, + }; + + int +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c +index 4b2d7465d22f75..f4989f0526ecb8 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c +@@ -221,8 +221,11 @@ nv50_instobj_acquire(struct nvkm_memory *memory) + void __iomem *map = NULL; + + /* Already mapped? */ +- if (refcount_inc_not_zero(&iobj->maps)) ++ if (refcount_inc_not_zero(&iobj->maps)) { ++ /* read barrier match the wmb on refcount set */ ++ smp_rmb(); + return iobj->map; ++ } + + /* Take the lock, and re-check that another thread hasn't + * already mapped the object in the meantime. +@@ -249,6 +252,8 @@ nv50_instobj_acquire(struct nvkm_memory *memory) + iobj->base.memory.ptrs = &nv50_instobj_fast; + else + iobj->base.memory.ptrs = &nv50_instobj_slow; ++ /* barrier to ensure the ptrs are written before refcount is set */ ++ smp_wmb(); + refcount_set(&iobj->maps, 1); + } + +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c +index 6cb5eefa45e9aa..5a08458fe1b7f5 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmtu102.c +@@ -31,7 +31,7 @@ tu102_vmm_flush(struct nvkm_vmm *vmm, int depth) + + type |= 0x00000001; /* PAGE_ALL */ + if (atomic_read(&vmm->engref[NVKM_SUBDEV_BAR])) +- type |= 0x00000004; /* HUB_ONLY */ ++ type |= 0x00000006; /* HUB_ONLY | ALL PDB (hack) */ + + mutex_lock(&vmm->mmu->mutex); + +diff --git a/drivers/gpu/drm/omapdrm/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig +index b715301ec79f66..6c49270cb290a4 100644 +--- a/drivers/gpu/drm/omapdrm/Kconfig ++++ b/drivers/gpu/drm/omapdrm/Kconfig +@@ -4,7 +4,7 @@ config DRM_OMAP + depends on DRM && OF + depends on ARCH_OMAP2PLUS + select DRM_KMS_HELPER +- select FB_DMAMEM_HELPERS if DRM_FBDEV_EMULATION ++ select FB_DMAMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION + select VIDEOMODE_HELPERS + select HDMI + default n +diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c +index afeeb773755252..21996b713d1c3a 100644 +--- a/drivers/gpu/drm/omapdrm/omap_drv.c ++++ b/drivers/gpu/drm/omapdrm/omap_drv.c +@@ -69,7 +69,6 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state) + { + struct drm_device *dev = old_state->dev; + struct omap_drm_private *priv = dev->dev_private; +- bool fence_cookie = dma_fence_begin_signalling(); + + dispc_runtime_get(priv->dispc); + +@@ -92,6 +91,8 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state) + omap_atomic_wait_for_completion(dev, old_state); + + drm_atomic_helper_commit_planes(dev, old_state, 0); ++ ++ drm_atomic_helper_commit_hw_done(old_state); + } else { + /* + * OMAP3 DSS seems to have issues with the work-around above, +@@ -101,11 +102,9 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state) + drm_atomic_helper_commit_planes(dev, old_state, 0); + + drm_atomic_helper_commit_modeset_enables(dev, old_state); +- } +- +- drm_atomic_helper_commit_hw_done(old_state); + +- dma_fence_end_signalling(fence_cookie); ++ drm_atomic_helper_commit_hw_done(old_state); ++ } + + /* + * Wait for completion of the page flips to ensure that old buffers +@@ -696,6 +695,10 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) + soc = soc_device_match(omapdrm_soc_devices); + priv->omaprev = soc ? (uintptr_t)soc->data : 0; + priv->wq = alloc_ordered_workqueue("omapdrm", 0); ++ if (!priv->wq) { ++ ret = -ENOMEM; ++ goto err_alloc_workqueue; ++ } + + mutex_init(&priv->list_lock); + INIT_LIST_HEAD(&priv->obj_list); +@@ -754,6 +757,7 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) + drm_mode_config_cleanup(ddev); + omap_gem_deinit(ddev); + destroy_workqueue(priv->wq); ++err_alloc_workqueue: + omap_disconnect_pipelines(ddev); + drm_dev_put(ddev); + return ret; +diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c +index 6b08b137af1ad8..523be34682caf1 100644 +--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c ++++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c +@@ -51,6 +51,10 @@ static void pan_worker(struct work_struct *work) + omap_gem_roll(bo, fbi->var.yoffset * npages); + } + ++FB_GEN_DEFAULT_DEFERRED_DMAMEM_OPS(omap_fbdev, ++ drm_fb_helper_damage_range, ++ drm_fb_helper_damage_area) ++ + static int omap_fbdev_pan_display(struct fb_var_screeninfo *var, + struct fb_info *fbi) + { +@@ -78,11 +82,9 @@ static int omap_fbdev_pan_display(struct fb_var_screeninfo *var, + + static int omap_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) + { +- struct drm_fb_helper *helper = info->par; +- struct drm_framebuffer *fb = helper->fb; +- struct drm_gem_object *bo = drm_gem_fb_get_obj(fb, 0); ++ vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + +- return drm_gem_mmap_obj(bo, omap_gem_mmap_size(bo), vma); ++ return fb_deferred_io_mmap(info, vma); + } + + static void omap_fbdev_fb_destroy(struct fb_info *info) +@@ -94,6 +96,7 @@ static void omap_fbdev_fb_destroy(struct fb_info *info) + + DBG(); + ++ fb_deferred_io_cleanup(info); + drm_fb_helper_fini(helper); + + omap_gem_unpin(bo); +@@ -104,15 +107,19 @@ static void omap_fbdev_fb_destroy(struct fb_info *info) + kfree(fbdev); + } + ++/* ++ * For now, we cannot use FB_DEFAULT_DEFERRED_OPS and fb_deferred_io_mmap() ++ * because we use write-combine. ++ */ + static const struct fb_ops omap_fb_ops = { + .owner = THIS_MODULE, +- __FB_DEFAULT_DMAMEM_OPS_RDWR, ++ __FB_DEFAULT_DEFERRED_OPS_RDWR(omap_fbdev), + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_setcmap = drm_fb_helper_setcmap, + .fb_blank = drm_fb_helper_blank, + .fb_pan_display = omap_fbdev_pan_display, +- __FB_DEFAULT_DMAMEM_OPS_DRAW, ++ __FB_DEFAULT_DEFERRED_OPS_DRAW(omap_fbdev), + .fb_ioctl = drm_fb_helper_ioctl, + .fb_mmap = omap_fbdev_fb_mmap, + .fb_destroy = omap_fbdev_fb_destroy, +@@ -213,6 +220,15 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, + fbi->fix.smem_start = dma_addr; + fbi->fix.smem_len = bo->size; + ++ /* deferred I/O */ ++ helper->fbdefio.delay = HZ / 20; ++ helper->fbdefio.deferred_io = drm_fb_helper_deferred_io; ++ ++ fbi->fbdefio = &helper->fbdefio; ++ ret = fb_deferred_io_init(fbi); ++ if (ret) ++ goto fail; ++ + /* if we have DMM, then we can use it for scrolling by just + * shuffling pages around in DMM rather than doing sw blit. + */ +@@ -238,8 +254,20 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, + return ret; + } + ++static int omap_fbdev_dirty(struct drm_fb_helper *helper, struct drm_clip_rect *clip) ++{ ++ if (!(clip->x1 < clip->x2 && clip->y1 < clip->y2)) ++ return 0; ++ ++ if (helper->fb->funcs->dirty) ++ return helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, clip, 1); ++ ++ return 0; ++} ++ + static const struct drm_fb_helper_funcs omap_fb_helper_funcs = { + .fb_probe = omap_fbdev_create, ++ .fb_dirty = omap_fbdev_dirty, + }; + + static struct drm_fb_helper *get_fb(struct fb_info *fbi) +diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig +index 869e535faefa38..3a2f4a9f1d4665 100644 +--- a/drivers/gpu/drm/panel/Kconfig ++++ b/drivers/gpu/drm/panel/Kconfig +@@ -184,7 +184,7 @@ config DRM_PANEL_ILITEK_IL9322 + + config DRM_PANEL_ILITEK_ILI9341 + tristate "Ilitek ILI9341 240x320 QVGA panels" +- depends on OF && SPI ++ depends on SPI + select DRM_KMS_HELPER + select DRM_GEM_DMA_HELPER + depends on BACKLIGHT_CLASS_DEVICE +diff --git a/drivers/gpu/drm/panel/panel-arm-versatile.c b/drivers/gpu/drm/panel/panel-arm-versatile.c +index abb0788843c60c..503ecea72c5eac 100644 +--- a/drivers/gpu/drm/panel/panel-arm-versatile.c ++++ b/drivers/gpu/drm/panel/panel-arm-versatile.c +@@ -267,6 +267,8 @@ static int versatile_panel_get_modes(struct drm_panel *panel, + connector->display_info.bus_flags = vpanel->panel_type->bus_flags; + + mode = drm_mode_duplicate(connector->dev, &vpanel->panel_type->mode); ++ if (!mode) ++ return -ENOMEM; + drm_mode_set_name(mode); + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + +diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c +index c9087f474cbc5a..e6328991c87e93 100644 +--- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c ++++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c +@@ -1847,7 +1847,11 @@ static int boe_panel_prepare(struct drm_panel *panel) + usleep_range(10000, 11000); + + if (boe->desc->lp11_before_reset) { +- mipi_dsi_dcs_nop(boe->dsi); ++ ret = mipi_dsi_dcs_nop(boe->dsi); ++ if (ret < 0) { ++ dev_err(&boe->dsi->dev, "Failed to send NOP: %d\n", ret); ++ goto poweroff; ++ } + usleep_range(1000, 2000); + } + gpiod_set_value(boe->enable_gpio, 1); +@@ -1868,13 +1872,13 @@ static int boe_panel_prepare(struct drm_panel *panel) + return 0; + + poweroff: ++ gpiod_set_value(boe->enable_gpio, 0); + regulator_disable(boe->avee); + poweroffavdd: + regulator_disable(boe->avdd); + poweroff1v8: + usleep_range(5000, 7000); + regulator_disable(boe->pp1800); +- gpiod_set_value(boe->enable_gpio, 0); + + return ret; + } +@@ -2049,6 +2053,7 @@ static const struct panel_desc auo_b101uan08_3_desc = { + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_MODE_LPM, + .init_cmds = auo_b101uan08_3_init_cmd, ++ .lp11_before_reset = true, + }; + + static const struct drm_display_mode boe_tv105wum_nw0_default_mode = { +@@ -2103,14 +2108,15 @@ static const struct panel_desc starry_qfh032011_53g_desc = { + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_MODE_LPM, + .init_cmds = starry_qfh032011_53g_init_cmd, ++ .lp11_before_reset = true, + }; + + static const struct drm_display_mode starry_himax83102_j02_default_mode = { +- .clock = 161600, ++ .clock = 162680, + .hdisplay = 1200, +- .hsync_start = 1200 + 40, +- .hsync_end = 1200 + 40 + 20, +- .htotal = 1200 + 40 + 20 + 40, ++ .hsync_start = 1200 + 60, ++ .hsync_end = 1200 + 60 + 20, ++ .htotal = 1200 + 60 + 20 + 40, + .vdisplay = 1920, + .vsync_start = 1920 + 116, + .vsync_end = 1920 + 116 + 8, +@@ -2237,6 +2243,8 @@ static int boe_panel_add(struct boe_panel *boe) + + gpiod_set_value(boe->enable_gpio, 0); + ++ boe->base.prepare_prev_first = true; ++ + drm_panel_init(&boe->base, dev, &boe_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + err = of_drm_get_panel_orientation(dev->of_node, &boe->orientation); +diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c +index 95c8472d878a99..94fe2f3836a9a3 100644 +--- a/drivers/gpu/drm/panel/panel-edp.c ++++ b/drivers/gpu/drm/panel/panel-edp.c +@@ -203,6 +203,9 @@ struct edp_panel_entry { + + /** @name: Name of this panel (for printing to logs). */ + const char *name; ++ ++ /** @override_edid_mode: Override the mode obtained by edid. */ ++ const struct drm_display_mode *override_edid_mode; + }; + + struct panel_edp { +@@ -301,6 +304,24 @@ static unsigned int panel_edp_get_display_modes(struct panel_edp *panel, + return num; + } + ++static int panel_edp_override_edid_mode(struct panel_edp *panel, ++ struct drm_connector *connector, ++ const struct drm_display_mode *override_mode) ++{ ++ struct drm_display_mode *mode; ++ ++ mode = drm_mode_duplicate(connector->dev, override_mode); ++ if (!mode) { ++ dev_err(panel->base.dev, "failed to add additional mode\n"); ++ return 0; ++ } ++ ++ mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; ++ drm_mode_set_name(mode); ++ drm_mode_probed_add(connector, mode); ++ return 1; ++} ++ + static int panel_edp_get_non_edid_modes(struct panel_edp *panel, + struct drm_connector *connector) + { +@@ -376,6 +397,7 @@ static int panel_edp_suspend(struct device *dev) + { + struct panel_edp *p = dev_get_drvdata(dev); + ++ drm_dp_dpcd_set_powered(p->aux, false); + gpiod_set_value_cansleep(p->enable_gpio, 0); + regulator_disable(p->supply); + p->unprepared_time = ktime_get_boottime(); +@@ -392,8 +414,7 @@ static int panel_edp_unprepare(struct drm_panel *panel) + if (!p->prepared) + return 0; + +- pm_runtime_mark_last_busy(panel->dev); +- ret = pm_runtime_put_autosuspend(panel->dev); ++ ret = pm_runtime_put_sync_suspend(panel->dev); + if (ret < 0) + return ret; + p->prepared = false; +@@ -433,6 +454,7 @@ static int panel_edp_prepare_once(struct panel_edp *p) + } + + gpiod_set_value_cansleep(p->enable_gpio, 1); ++ drm_dp_dpcd_set_powered(p->aux, true); + + delay = p->desc->delay.hpd_reliable; + if (p->no_hpd) +@@ -469,6 +491,7 @@ static int panel_edp_prepare_once(struct panel_edp *p) + return 0; + + error: ++ drm_dp_dpcd_set_powered(p->aux, false); + gpiod_set_value_cansleep(p->enable_gpio, 0); + regulator_disable(p->supply); + p->unprepared_time = ktime_get_boottime(); +@@ -568,6 +591,9 @@ static int panel_edp_get_modes(struct drm_panel *panel, + { + struct panel_edp *p = to_panel_edp(panel); + int num = 0; ++ bool has_override_edid_mode = p->detected_panel && ++ p->detected_panel != ERR_PTR(-EINVAL) && ++ p->detected_panel->override_edid_mode; + + /* probe EDID if a DDC bus is available */ + if (p->ddc) { +@@ -575,9 +601,18 @@ static int panel_edp_get_modes(struct drm_panel *panel, + + if (!p->edid) + p->edid = drm_get_edid(connector, p->ddc); +- +- if (p->edid) +- num += drm_add_edid_modes(connector, p->edid); ++ if (p->edid) { ++ if (has_override_edid_mode) { ++ /* ++ * override_edid_mode is specified. Use ++ * override_edid_mode instead of from edid. ++ */ ++ num += panel_edp_override_edid_mode(p, connector, ++ p->detected_panel->override_edid_mode); ++ } else { ++ num += drm_add_edid_modes(connector, p->edid); ++ } ++ } + + pm_runtime_mark_last_busy(panel->dev); + pm_runtime_put_autosuspend(panel->dev); +@@ -973,6 +1008,8 @@ static const struct panel_desc auo_b116xak01 = { + }, + .delay = { + .hpd_absent = 200, ++ .unprepare = 500, ++ .enable = 50, + }, + }; + +@@ -1828,6 +1865,15 @@ static const struct panel_delay delay_200_500_e200 = { + .delay = _delay \ + } + ++#define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name, _mode) \ ++{ \ ++ .name = _name, \ ++ .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, vend_chr_2, \ ++ product_id), \ ++ .delay = _delay, \ ++ .override_edid_mode = _mode \ ++} ++ + /* + * This table is used to figure out power sequencing delays for panels that + * are detected by EDID. Entries here may point to entries in the +@@ -1840,7 +1886,8 @@ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, "B116XAB01.4"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, "B116XAK01.6"), +- EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01"), ++ EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, &delay_200_500_e50, "B116XTN02.3"), ++ EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), +@@ -1848,8 +1895,10 @@ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"), ++ EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, "NT116WHM-N21,836X2"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, "NT116WHM-N21"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x095f, &delay_200_500_e50, "NE135FBM-N41 v8.1"), ++ EDP_PANEL_ENTRY('B', 'O', 'E', 0x0979, &delay_200_500_e50, "NV116WHM-N49 V8.0"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), +diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c +index e7be15b681021e..6de11723234644 100644 +--- a/drivers/gpu/drm/panel/panel-elida-kd35t133.c ++++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c +@@ -104,6 +104,8 @@ static int kd35t133_unprepare(struct drm_panel *panel) + return ret; + } + ++ gpiod_set_value_cansleep(ctx->reset_gpio, 1); ++ + regulator_disable(ctx->iovcc); + regulator_disable(ctx->vdd); + +diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c +index c73243d85de718..631420d28be4c9 100644 +--- a/drivers/gpu/drm/panel/panel-himax-hx8394.c ++++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c +@@ -234,8 +234,7 @@ static int hx8394_enable(struct drm_panel *panel) + + sleep_in: + /* This will probably fail, but let's try orderly power off anyway. */ +- ret = mipi_dsi_dcs_enter_sleep_mode(dsi); +- if (!ret) ++ if (!mipi_dsi_dcs_enter_sleep_mode(dsi)) + msleep(50); + + return ret; +diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c +index 3574681891e816..b933380b7eb783 100644 +--- a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c ++++ b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c +@@ -22,8 +22,9 @@ + #include + #include + #include ++#include + #include +-#include ++#include + #include + #include + +@@ -421,7 +422,7 @@ static int ili9341_dpi_prepare(struct drm_panel *panel) + + ili9341_dpi_init(ili); + +- return ret; ++ return 0; + } + + static int ili9341_dpi_enable(struct drm_panel *panel) +@@ -691,7 +692,7 @@ static int ili9341_dpi_probe(struct spi_device *spi, struct gpio_desc *dc, + * Every new incarnation of this display must have a unique + * data entry for the system in this driver. + */ +- ili->conf = of_device_get_match_data(dev); ++ ili->conf = device_get_match_data(dev); + if (!ili->conf) { + dev_err(dev, "missing device configuration\n"); + return -ENODEV; +@@ -714,18 +715,18 @@ static int ili9341_probe(struct spi_device *spi) + + reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(reset)) +- dev_err(dev, "Failed to get gpio 'reset'\n"); ++ return dev_err_probe(dev, PTR_ERR(reset), "Failed to get gpio 'reset'\n"); + + dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW); + if (IS_ERR(dc)) +- dev_err(dev, "Failed to get gpio 'dc'\n"); ++ return dev_err_probe(dev, PTR_ERR(dc), "Failed to get gpio 'dc'\n"); + + if (!strcmp(id->name, "sf-tc240t-9370-t")) + return ili9341_dpi_probe(spi, dc, reset); + else if (!strcmp(id->name, "yx240qv29")) + return ili9341_dbi_probe(spi, dc, reset); + +- return -1; ++ return -ENODEV; + } + + static void ili9341_remove(struct spi_device *spi) +diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +index 7838947a1bf3c9..bb201f848ae97a 100644 +--- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c ++++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +@@ -883,10 +883,10 @@ static int ili9881c_prepare(struct drm_panel *panel) + msleep(5); + + /* And reset it */ +- gpiod_set_value(ctx->reset, 1); ++ gpiod_set_value_cansleep(ctx->reset, 1); + msleep(20); + +- gpiod_set_value(ctx->reset, 0); ++ gpiod_set_value_cansleep(ctx->reset, 0); + msleep(20); + + for (i = 0; i < ctx->desc->init_length; i++) { +@@ -941,7 +941,7 @@ static int ili9881c_unprepare(struct drm_panel *panel) + + mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); + regulator_disable(ctx->power); +- gpiod_set_value(ctx->reset, 1); ++ gpiod_set_value_cansleep(ctx->reset, 1); + + return 0; + } +diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c +index ad98dd9322b4a3..227937afe2572e 100644 +--- a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c ++++ b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c +@@ -261,6 +261,8 @@ static int panel_nv3051d_unprepare(struct drm_panel *panel) + + usleep_range(10000, 15000); + ++ gpiod_set_value_cansleep(ctx->reset_gpio, 1); ++ + regulator_disable(ctx->vdd); + + return 0; +diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35950.c b/drivers/gpu/drm/panel/panel-novatek-nt35950.c +index 412ca84d058110..4be5013330ec27 100644 +--- a/drivers/gpu/drm/panel/panel-novatek-nt35950.c ++++ b/drivers/gpu/drm/panel/panel-novatek-nt35950.c +@@ -565,10 +565,8 @@ static int nt35950_probe(struct mipi_dsi_device *dsi) + } + dsi_r_host = of_find_mipi_dsi_host_by_node(dsi_r); + of_node_put(dsi_r); +- if (!dsi_r_host) { +- dev_err(dev, "Cannot get secondary DSI host\n"); +- return -EPROBE_DEFER; +- } ++ if (!dsi_r_host) ++ return dev_err_probe(dev, -EPROBE_DEFER, "Cannot get secondary DSI host\n"); + + nt->dsi[1] = mipi_dsi_device_register_full(dsi_r_host, info); + if (!nt->dsi[1]) { +diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36523.c b/drivers/gpu/drm/panel/panel-novatek-nt36523.c +index 9632b9e95b7159..aab8937595a2a0 100644 +--- a/drivers/gpu/drm/panel/panel-novatek-nt36523.c ++++ b/drivers/gpu/drm/panel/panel-novatek-nt36523.c +@@ -935,8 +935,7 @@ static int j606f_boe_init_sequence(struct panel_info *pinfo) + + static const struct drm_display_mode elish_boe_modes[] = { + { +- /* There is only one 120 Hz timing, but it doesn't work perfectly, 104 Hz preferred */ +- .clock = (1600 + 60 + 8 + 60) * (2560 + 26 + 4 + 168) * 104 / 1000, ++ .clock = (1600 + 60 + 8 + 60) * (2560 + 26 + 4 + 168) * 120 / 1000, + .hdisplay = 1600, + .hsync_start = 1600 + 60, + .hsync_end = 1600 + 60 + 8, +@@ -950,8 +949,7 @@ static const struct drm_display_mode elish_boe_modes[] = { + + static const struct drm_display_mode elish_csot_modes[] = { + { +- /* There is only one 120 Hz timing, but it doesn't work perfectly, 104 Hz preferred */ +- .clock = (1600 + 200 + 40 + 52) * (2560 + 26 + 4 + 168) * 104 / 1000, ++ .clock = (1600 + 200 + 40 + 52) * (2560 + 26 + 4 + 168) * 120 / 1000, + .hdisplay = 1600, + .hsync_start = 1600 + 200, + .hsync_end = 1600 + 200 + 40, +@@ -1266,9 +1264,9 @@ static int nt36523_probe(struct mipi_dsi_device *dsi) + return dev_err_probe(dev, -EPROBE_DEFER, "cannot get secondary DSI host\n"); + + pinfo->dsi[1] = mipi_dsi_device_register_full(dsi1_host, info); +- if (!pinfo->dsi[1]) { ++ if (IS_ERR(pinfo->dsi[1])) { + dev_err(dev, "cannot get secondary DSI device\n"); +- return -ENODEV; ++ return PTR_ERR(pinfo->dsi[1]); + } + } + +diff --git a/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c b/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c +index 5703f4712d96e5..9c336c71562b93 100644 +--- a/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c ++++ b/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c +@@ -72,6 +72,7 @@ static int atana33xc20_suspend(struct device *dev) + if (p->el3_was_on) + atana33xc20_wait(p->el_on3_off_time, 150); + ++ drm_dp_dpcd_set_powered(p->aux, false); + ret = regulator_disable(p->supply); + if (ret) + return ret; +@@ -93,6 +94,7 @@ static int atana33xc20_resume(struct device *dev) + ret = regulator_enable(p->supply); + if (ret) + return ret; ++ drm_dp_dpcd_set_powered(p->aux, true); + p->powered_on_time = ktime_get_boottime(); + + if (p->no_hpd) { +@@ -107,19 +109,17 @@ static int atana33xc20_resume(struct device *dev) + if (hpd_asserted < 0) + ret = hpd_asserted; + +- if (ret) ++ if (ret) { + dev_warn(dev, "Error waiting for HPD GPIO: %d\n", ret); +- +- return ret; +- } +- +- if (p->aux->wait_hpd_asserted) { ++ goto error; ++ } ++ } else if (p->aux->wait_hpd_asserted) { + ret = p->aux->wait_hpd_asserted(p->aux, HPD_MAX_US); + +- if (ret) ++ if (ret) { + dev_warn(dev, "Controller error waiting for HPD: %d\n", ret); +- +- return ret; ++ goto error; ++ } + } + + /* +@@ -131,6 +131,12 @@ static int atana33xc20_resume(struct device *dev) + * right times. + */ + return 0; ++ ++error: ++ drm_dp_dpcd_set_powered(p->aux, false); ++ regulator_disable(p->supply); ++ ++ return ret; + } + + static int atana33xc20_disable(struct drm_panel *panel) +diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c +index ea5a857793827a..f23d8832a1ad05 100644 +--- a/drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c ++++ b/drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c +@@ -309,7 +309,7 @@ static const struct s6d7aa0_panel_desc s6d7aa0_lsl080al02_desc = { + .off_func = s6d7aa0_lsl080al02_off, + .drm_mode = &s6d7aa0_lsl080al02_mode, + .mode_flags = MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_NO_HFP, +- .bus_flags = DRM_BUS_FLAG_DE_HIGH, ++ .bus_flags = 0, + + .has_backlight = false, + .use_passwd3 = false, +diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c +index dd7928d9570f72..11ade6bac592f7 100644 +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -2326,13 +2326,13 @@ static const struct panel_desc innolux_g070y2_t02 = { + static const struct display_timing innolux_g101ice_l01_timing = { + .pixelclock = { 60400000, 71100000, 74700000 }, + .hactive = { 1280, 1280, 1280 }, +- .hfront_porch = { 41, 80, 100 }, +- .hback_porch = { 40, 79, 99 }, +- .hsync_len = { 1, 1, 1 }, ++ .hfront_porch = { 30, 60, 70 }, ++ .hback_porch = { 30, 60, 70 }, ++ .hsync_len = { 22, 40, 60 }, + .vactive = { 800, 800, 800 }, +- .vfront_porch = { 5, 11, 14 }, +- .vback_porch = { 4, 11, 14 }, +- .vsync_len = { 1, 1, 1 }, ++ .vfront_porch = { 3, 8, 14 }, ++ .vback_porch = { 3, 8, 14 }, ++ .vsync_len = { 4, 7, 12 }, + .flags = DISPLAY_FLAGS_DE_HIGH, + }; + +@@ -2349,6 +2349,7 @@ static const struct panel_desc innolux_g101ice_l01 = { + .disable = 200, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, ++ .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .connector_type = DRM_MODE_CONNECTOR_LVDS, + }; + +@@ -2406,6 +2407,9 @@ static const struct panel_desc innolux_g121x1_l03 = { + .unprepare = 200, + .disable = 400, + }, ++ .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, ++ .bus_flags = DRM_BUS_FLAG_DE_HIGH, ++ .connector_type = DRM_MODE_CONNECTOR_LVDS, + }; + + static const struct display_timing innolux_g156hce_l01_timings = { +@@ -2519,6 +2523,7 @@ static const struct display_timing koe_tx26d202vm0bwa_timing = { + .vfront_porch = { 3, 5, 10 }, + .vback_porch = { 2, 5, 10 }, + .vsync_len = { 5, 5, 5 }, ++ .flags = DISPLAY_FLAGS_DE_HIGH, + }; + + static const struct panel_desc koe_tx26d202vm0bwa = { +@@ -3781,6 +3786,7 @@ static const struct panel_desc tianma_tm070jdhg30 = { + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, ++ .bus_flags = DRM_BUS_FLAG_DE_HIGH, + }; + + static const struct panel_desc tianma_tm070jvhg33 = { +@@ -3793,6 +3799,7 @@ static const struct panel_desc tianma_tm070jvhg33 = { + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, ++ .bus_flags = DRM_BUS_FLAG_DE_HIGH, + }; + + static const struct display_timing tianma_tm070rvhg71_timing = { +diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7701.c b/drivers/gpu/drm/panel/panel-sitronix-st7701.c +index 0459965e1b4f7b..036ac403ed2138 100644 +--- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c ++++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c +@@ -288,7 +288,7 @@ static void st7701_init_sequence(struct st7701 *st7701) + FIELD_PREP(DSI_CMD2_BK1_PWRCTRL2_AVDD_MASK, + DIV_ROUND_CLOSEST(desc->avdd_mv - 6200, 200)) | + FIELD_PREP(DSI_CMD2_BK1_PWRCTRL2_AVCL_MASK, +- DIV_ROUND_CLOSEST(-4400 + desc->avcl_mv, 200))); ++ DIV_ROUND_CLOSEST(-4400 - desc->avcl_mv, 200))); + + /* T2D = 0.2us * T2D[3:0] */ + ST7701_DSI(st7701, DSI_CMD2_BK1_SPD1, +diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c +index 6a394563953501..7bb723d445ade4 100644 +--- a/drivers/gpu/drm/panel/panel-sitronix-st7703.c ++++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c +@@ -506,29 +506,30 @@ static int st7703_prepare(struct drm_panel *panel) + return 0; + + dev_dbg(ctx->dev, "Resetting the panel\n"); +- ret = regulator_enable(ctx->vcc); ++ gpiod_set_value_cansleep(ctx->reset_gpio, 1); ++ ++ ret = regulator_enable(ctx->iovcc); + if (ret < 0) { +- dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret); ++ dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); + return ret; + } +- ret = regulator_enable(ctx->iovcc); ++ ++ ret = regulator_enable(ctx->vcc); + if (ret < 0) { +- dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); +- goto disable_vcc; ++ dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret); ++ regulator_disable(ctx->iovcc); ++ return ret; + } + +- gpiod_set_value_cansleep(ctx->reset_gpio, 1); +- usleep_range(20, 40); ++ /* Give power supplies time to stabilize before deasserting reset. */ ++ usleep_range(10000, 20000); ++ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); +- msleep(20); ++ usleep_range(15000, 20000); + + ctx->prepared = true; + + return 0; +- +-disable_vcc: +- regulator_disable(ctx->vcc); +- return ret; + } + + static const u32 mantix_bus_formats[] = { +diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c +index 88e80fe98112da..28bfc48a912729 100644 +--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c ++++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c +@@ -282,15 +282,15 @@ static const struct drm_display_mode et028013dma_mode = { + static const struct drm_display_mode jt240mhqs_hwt_ek_e3_mode = { + .clock = 6000, + .hdisplay = 240, +- .hsync_start = 240 + 28, +- .hsync_end = 240 + 28 + 10, +- .htotal = 240 + 28 + 10 + 10, ++ .hsync_start = 240 + 38, ++ .hsync_end = 240 + 38 + 10, ++ .htotal = 240 + 38 + 10 + 10, + .vdisplay = 280, +- .vsync_start = 280 + 8, +- .vsync_end = 280 + 8 + 4, +- .vtotal = 280 + 8 + 4 + 4, +- .width_mm = 43, +- .height_mm = 37, ++ .vsync_start = 280 + 48, ++ .vsync_end = 280 + 48 + 4, ++ .vtotal = 280 + 48 + 4 + 4, ++ .width_mm = 37, ++ .height_mm = 43, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, + }; + +@@ -643,7 +643,9 @@ static int st7789v_probe(struct spi_device *spi) + if (ret) + return dev_err_probe(dev, ret, "Failed to get backlight\n"); + +- of_drm_get_panel_orientation(spi->dev.of_node, &ctx->orientation); ++ ret = of_drm_get_panel_orientation(spi->dev.of_node, &ctx->orientation); ++ if (ret) ++ return dev_err_probe(&spi->dev, ret, "Failed to get orientation\n"); + + drm_panel_add(&ctx->panel); + +diff --git a/drivers/gpu/drm/panel/panel-tpo-tpg110.c b/drivers/gpu/drm/panel/panel-tpo-tpg110.c +index 845304435e2356..f6a212e542cb93 100644 +--- a/drivers/gpu/drm/panel/panel-tpo-tpg110.c ++++ b/drivers/gpu/drm/panel/panel-tpo-tpg110.c +@@ -379,6 +379,8 @@ static int tpg110_get_modes(struct drm_panel *panel, + connector->display_info.bus_flags = tpg->panel_mode->bus_flags; + + mode = drm_mode_duplicate(connector->dev, &tpg->panel_mode->mode); ++ if (!mode) ++ return -ENOMEM; + drm_mode_set_name(mode); + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + +diff --git a/drivers/gpu/drm/panel/panel-visionox-rm69299.c b/drivers/gpu/drm/panel/panel-visionox-rm69299.c +index c2806e4fd553b1..6e946e5a036eeb 100644 +--- a/drivers/gpu/drm/panel/panel-visionox-rm69299.c ++++ b/drivers/gpu/drm/panel/panel-visionox-rm69299.c +@@ -261,8 +261,6 @@ static void visionox_rm69299_remove(struct mipi_dsi_device *dsi) + struct visionox_rm69299 *ctx = mipi_dsi_get_drvdata(dsi); + + mipi_dsi_detach(ctx->dsi); +- mipi_dsi_device_unregister(ctx->dsi); +- + drm_panel_remove(&ctx->panel); + } + +diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c +index a2ab99698ca80a..ddcc8259061bbd 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_drv.c ++++ b/drivers/gpu/drm/panfrost/panfrost_drv.c +@@ -731,3 +731,4 @@ module_platform_driver(panfrost_driver); + MODULE_AUTHOR("Panfrost Project Developers"); + MODULE_DESCRIPTION("Panfrost DRM Driver"); + MODULE_LICENSE("GPL v2"); ++MODULE_SOFTDEP("pre: governor_simpleondemand"); +diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c +index d28b99732ddeb6..c067ff550692ad 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_gpu.c ++++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c +@@ -71,7 +71,12 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev) + } + + gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_MASK_ALL); +- gpu_write(pfdev, GPU_INT_MASK, GPU_IRQ_MASK_ALL); ++ ++ /* Only enable the interrupts we care about */ ++ gpu_write(pfdev, GPU_INT_MASK, ++ GPU_IRQ_MASK_ERROR | ++ GPU_IRQ_PERFCNT_SAMPLE_COMPLETED | ++ GPU_IRQ_CLEAN_CACHES_COMPLETED); + + return 0; + } +@@ -321,28 +326,38 @@ static void panfrost_gpu_init_features(struct panfrost_device *pfdev) + pfdev->features.shader_present, pfdev->features.l2_present); + } + ++static u64 panfrost_get_core_mask(struct panfrost_device *pfdev) ++{ ++ u64 core_mask; ++ ++ if (pfdev->features.l2_present == 1) ++ return U64_MAX; ++ ++ /* ++ * Only support one core group now. ++ * ~(l2_present - 1) unsets all bits in l2_present except ++ * the bottom bit. (l2_present - 2) has all the bits in ++ * the first core group set. AND them together to generate ++ * a mask of cores in the first core group. ++ */ ++ core_mask = ~(pfdev->features.l2_present - 1) & ++ (pfdev->features.l2_present - 2); ++ dev_info_once(pfdev->dev, "using only 1st core group (%lu cores from %lu)\n", ++ hweight64(core_mask), ++ hweight64(pfdev->features.shader_present)); ++ ++ return core_mask; ++} ++ + void panfrost_gpu_power_on(struct panfrost_device *pfdev) + { + int ret; + u32 val; +- u64 core_mask = U64_MAX; ++ u64 core_mask; + + panfrost_gpu_init_quirks(pfdev); ++ core_mask = panfrost_get_core_mask(pfdev); + +- if (pfdev->features.l2_present != 1) { +- /* +- * Only support one core group now. +- * ~(l2_present - 1) unsets all bits in l2_present except +- * the bottom bit. (l2_present - 2) has all the bits in +- * the first core group set. AND them together to generate +- * a mask of cores in the first core group. +- */ +- core_mask = ~(pfdev->features.l2_present - 1) & +- (pfdev->features.l2_present - 2); +- dev_info_once(pfdev->dev, "using only 1st core group (%lu cores from %lu)\n", +- hweight64(core_mask), +- hweight64(pfdev->features.shader_present)); +- } + gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present & core_mask); + ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO, + val, val == (pfdev->features.l2_present & core_mask), +@@ -367,9 +382,26 @@ void panfrost_gpu_power_on(struct panfrost_device *pfdev) + + void panfrost_gpu_power_off(struct panfrost_device *pfdev) + { +- gpu_write(pfdev, TILER_PWROFF_LO, 0); +- gpu_write(pfdev, SHADER_PWROFF_LO, 0); +- gpu_write(pfdev, L2_PWROFF_LO, 0); ++ int ret; ++ u32 val; ++ ++ gpu_write(pfdev, SHADER_PWROFF_LO, pfdev->features.shader_present); ++ ret = readl_relaxed_poll_timeout(pfdev->iomem + SHADER_PWRTRANS_LO, ++ val, !val, 1, 2000); ++ if (ret) ++ dev_err(pfdev->dev, "shader power transition timeout"); ++ ++ gpu_write(pfdev, TILER_PWROFF_LO, pfdev->features.tiler_present); ++ ret = readl_relaxed_poll_timeout(pfdev->iomem + TILER_PWRTRANS_LO, ++ val, !val, 1, 2000); ++ if (ret) ++ dev_err(pfdev->dev, "tiler power transition timeout"); ++ ++ gpu_write(pfdev, L2_PWROFF_LO, pfdev->features.l2_present); ++ ret = readl_poll_timeout(pfdev->iomem + L2_PWRTRANS_LO, ++ val, !val, 0, 2000); ++ if (ret) ++ dev_err(pfdev->dev, "l2 power transition timeout"); + } + + int panfrost_gpu_init(struct panfrost_device *pfdev) +diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c +index c0123d09f699c7..83fa384f6a24ce 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_mmu.c ++++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c +@@ -500,11 +500,18 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as, + mapping_set_unevictable(mapping); + + for (i = page_offset; i < page_offset + NUM_FAULT_PAGES; i++) { ++ /* Can happen if the last fault only partially filled this ++ * section of the pages array before failing. In that case ++ * we skip already filled pages. ++ */ ++ if (pages[i]) ++ continue; ++ + pages[i] = shmem_read_mapping_page(mapping, i); + if (IS_ERR(pages[i])) { + ret = PTR_ERR(pages[i]); + pages[i] = NULL; +- goto err_pages; ++ goto err_unlock; + } + } + +@@ -512,7 +519,7 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as, + ret = sg_alloc_table_from_pages(sgt, pages + page_offset, + NUM_FAULT_PAGES, 0, SZ_2M, GFP_KERNEL); + if (ret) +- goto err_pages; ++ goto err_unlock; + + ret = dma_map_sgtable(pfdev->dev, sgt, DMA_BIDIRECTIONAL, 0); + if (ret) +@@ -534,8 +541,6 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as, + + err_map: + sg_free_table(sgt); +-err_pages: +- drm_gem_shmem_put_pages(&bo->base); + err_unlock: + dma_resv_unlock(obj->resv); + err_bo: +diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c +index ba3b5b5f0cdfe4..02e6b74d501669 100644 +--- a/drivers/gpu/drm/pl111/pl111_drv.c ++++ b/drivers/gpu/drm/pl111/pl111_drv.c +@@ -323,12 +323,18 @@ static void pl111_amba_remove(struct amba_device *amba_dev) + struct pl111_drm_dev_private *priv = drm->dev_private; + + drm_dev_unregister(drm); ++ drm_atomic_helper_shutdown(drm); + if (priv->panel) + drm_panel_bridge_remove(priv->bridge); + drm_dev_put(drm); + of_reserved_mem_device_release(dev); + } + ++static void pl111_amba_shutdown(struct amba_device *amba_dev) ++{ ++ drm_atomic_helper_shutdown(amba_get_drvdata(amba_dev)); ++} ++ + /* + * This early variant lacks the 565 and 444 pixel formats. + */ +@@ -431,6 +437,7 @@ static struct amba_driver pl111_amba_driver __maybe_unused = { + }, + .probe = pl111_amba_probe, + .remove = pl111_amba_remove, ++ .shutdown = pl111_amba_shutdown, + .id_table = pl111_id_table, + }; + +diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c +index 6492a70e3c396a..8ee614be9adf36 100644 +--- a/drivers/gpu/drm/qxl/qxl_display.c ++++ b/drivers/gpu/drm/qxl/qxl_display.c +@@ -236,6 +236,9 @@ static int qxl_add_mode(struct drm_connector *connector, + return 0; + + mode = drm_cvt_mode(dev, width, height, 60, false, false, false); ++ if (!mode) ++ return 0; ++ + if (preferred) + mode->type |= DRM_MODE_TYPE_PREFERRED; + mode->hdisplay = width; +@@ -1229,6 +1232,9 @@ int qxl_destroy_monitors_object(struct qxl_device *qdev) + if (!qdev->monitors_config_bo) + return 0; + ++ kfree(qdev->dumb_heads); ++ qdev->dumb_heads = NULL; ++ + qdev->monitors_config = NULL; + qdev->ram_header->monitors_config = 0; + +diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c +index b30ede1cf62d32..91930e84a9cd26 100644 +--- a/drivers/gpu/drm/qxl/qxl_drv.c ++++ b/drivers/gpu/drm/qxl/qxl_drv.c +@@ -283,7 +283,7 @@ static const struct drm_ioctl_desc qxl_ioctls[] = { + }; + + static struct drm_driver qxl_driver = { +- .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, ++ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_CURSOR_HOTSPOT, + + .dumb_create = qxl_mode_dumb_create, + .dumb_map_offset = drm_gem_ttm_dumb_map_offset, +diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c +index 4f06356d9ce2e1..f0ae087be914ee 100644 +--- a/drivers/gpu/drm/radeon/evergreen.c ++++ b/drivers/gpu/drm/radeon/evergreen.c +@@ -4821,14 +4821,15 @@ int evergreen_irq_process(struct radeon_device *rdev) + break; + case 44: /* hdmi */ + afmt_idx = src_data; +- if (!(afmt_status[afmt_idx] & AFMT_AZ_FORMAT_WTRIG)) +- DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); +- + if (afmt_idx > 5) { + DRM_ERROR("Unhandled interrupt: %d %d\n", + src_id, src_data); + break; + } ++ ++ if (!(afmt_status[afmt_idx] & AFMT_AZ_FORMAT_WTRIG)) ++ DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); ++ + afmt_status[afmt_idx] &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI%d\n", afmt_idx + 1); +diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c +index 0de79f3a7e3ffc..820c2c3641d388 100644 +--- a/drivers/gpu/drm/radeon/evergreen_cs.c ++++ b/drivers/gpu/drm/radeon/evergreen_cs.c +@@ -395,7 +395,7 @@ static int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned i + struct evergreen_cs_track *track = p->track; + struct eg_surface surf; + unsigned pitch, slice, mslice; +- unsigned long offset; ++ u64 offset; + int r; + + mslice = G_028C6C_SLICE_MAX(track->cb_color_view[id]) + 1; +@@ -433,14 +433,14 @@ static int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned i + return r; + } + +- offset = track->cb_color_bo_offset[id] << 8; ++ offset = (u64)track->cb_color_bo_offset[id] << 8; + if (offset & (surf.base_align - 1)) { +- dev_warn(p->dev, "%s:%d cb[%d] bo base %ld not aligned with %ld\n", ++ dev_warn(p->dev, "%s:%d cb[%d] bo base %llu not aligned with %ld\n", + __func__, __LINE__, id, offset, surf.base_align); + return -EINVAL; + } + +- offset += surf.layer_size * mslice; ++ offset += (u64)surf.layer_size * mslice; + if (offset > radeon_bo_size(track->cb_color_bo[id])) { + /* old ddx are broken they allocate bo with w*h*bpp but + * program slice with ALIGN(h, 8), catch this and patch +@@ -448,14 +448,14 @@ static int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned i + */ + if (!surf.mode) { + uint32_t *ib = p->ib.ptr; +- unsigned long tmp, nby, bsize, size, min = 0; ++ u64 tmp, nby, bsize, size, min = 0; + + /* find the height the ddx wants */ + if (surf.nby > 8) { + min = surf.nby - 8; + } + bsize = radeon_bo_size(track->cb_color_bo[id]); +- tmp = track->cb_color_bo_offset[id] << 8; ++ tmp = (u64)track->cb_color_bo_offset[id] << 8; + for (nby = surf.nby; nby > min; nby--) { + size = nby * surf.nbx * surf.bpe * surf.nsamples; + if ((tmp + size * mslice) <= bsize) { +@@ -467,7 +467,7 @@ static int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned i + slice = ((nby * surf.nbx) / 64) - 1; + if (!evergreen_surface_check(p, &surf, "cb")) { + /* check if this one works */ +- tmp += surf.layer_size * mslice; ++ tmp += (u64)surf.layer_size * mslice; + if (tmp <= bsize) { + ib[track->cb_color_slice_idx[id]] = slice; + goto old_ddx_ok; +@@ -476,9 +476,9 @@ static int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned i + } + } + dev_warn(p->dev, "%s:%d cb[%d] bo too small (layer size %d, " +- "offset %d, max layer %d, bo size %ld, slice %d)\n", ++ "offset %llu, max layer %d, bo size %ld, slice %d)\n", + __func__, __LINE__, id, surf.layer_size, +- track->cb_color_bo_offset[id] << 8, mslice, ++ (u64)track->cb_color_bo_offset[id] << 8, mslice, + radeon_bo_size(track->cb_color_bo[id]), slice); + dev_warn(p->dev, "%s:%d problematic surf: (%d %d) (%d %d %d %d %d %d %d)\n", + __func__, __LINE__, surf.nbx, surf.nby, +@@ -562,7 +562,7 @@ static int evergreen_cs_track_validate_stencil(struct radeon_cs_parser *p) + struct evergreen_cs_track *track = p->track; + struct eg_surface surf; + unsigned pitch, slice, mslice; +- unsigned long offset; ++ u64 offset; + int r; + + mslice = G_028008_SLICE_MAX(track->db_depth_view) + 1; +@@ -608,18 +608,18 @@ static int evergreen_cs_track_validate_stencil(struct radeon_cs_parser *p) + return r; + } + +- offset = track->db_s_read_offset << 8; ++ offset = (u64)track->db_s_read_offset << 8; + if (offset & (surf.base_align - 1)) { +- dev_warn(p->dev, "%s:%d stencil read bo base %ld not aligned with %ld\n", ++ dev_warn(p->dev, "%s:%d stencil read bo base %llu not aligned with %ld\n", + __func__, __LINE__, offset, surf.base_align); + return -EINVAL; + } +- offset += surf.layer_size * mslice; ++ offset += (u64)surf.layer_size * mslice; + if (offset > radeon_bo_size(track->db_s_read_bo)) { + dev_warn(p->dev, "%s:%d stencil read bo too small (layer size %d, " +- "offset %ld, max layer %d, bo size %ld)\n", ++ "offset %llu, max layer %d, bo size %ld)\n", + __func__, __LINE__, surf.layer_size, +- (unsigned long)track->db_s_read_offset << 8, mslice, ++ (u64)track->db_s_read_offset << 8, mslice, + radeon_bo_size(track->db_s_read_bo)); + dev_warn(p->dev, "%s:%d stencil invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n", + __func__, __LINE__, track->db_depth_size, +@@ -627,18 +627,18 @@ static int evergreen_cs_track_validate_stencil(struct radeon_cs_parser *p) + return -EINVAL; + } + +- offset = track->db_s_write_offset << 8; ++ offset = (u64)track->db_s_write_offset << 8; + if (offset & (surf.base_align - 1)) { +- dev_warn(p->dev, "%s:%d stencil write bo base %ld not aligned with %ld\n", ++ dev_warn(p->dev, "%s:%d stencil write bo base %llu not aligned with %ld\n", + __func__, __LINE__, offset, surf.base_align); + return -EINVAL; + } +- offset += surf.layer_size * mslice; ++ offset += (u64)surf.layer_size * mslice; + if (offset > radeon_bo_size(track->db_s_write_bo)) { + dev_warn(p->dev, "%s:%d stencil write bo too small (layer size %d, " +- "offset %ld, max layer %d, bo size %ld)\n", ++ "offset %llu, max layer %d, bo size %ld)\n", + __func__, __LINE__, surf.layer_size, +- (unsigned long)track->db_s_write_offset << 8, mslice, ++ (u64)track->db_s_write_offset << 8, mslice, + radeon_bo_size(track->db_s_write_bo)); + return -EINVAL; + } +@@ -659,7 +659,7 @@ static int evergreen_cs_track_validate_depth(struct radeon_cs_parser *p) + struct evergreen_cs_track *track = p->track; + struct eg_surface surf; + unsigned pitch, slice, mslice; +- unsigned long offset; ++ u64 offset; + int r; + + mslice = G_028008_SLICE_MAX(track->db_depth_view) + 1; +@@ -706,34 +706,34 @@ static int evergreen_cs_track_validate_depth(struct radeon_cs_parser *p) + return r; + } + +- offset = track->db_z_read_offset << 8; ++ offset = (u64)track->db_z_read_offset << 8; + if (offset & (surf.base_align - 1)) { +- dev_warn(p->dev, "%s:%d stencil read bo base %ld not aligned with %ld\n", ++ dev_warn(p->dev, "%s:%d stencil read bo base %llu not aligned with %ld\n", + __func__, __LINE__, offset, surf.base_align); + return -EINVAL; + } +- offset += surf.layer_size * mslice; ++ offset += (u64)surf.layer_size * mslice; + if (offset > radeon_bo_size(track->db_z_read_bo)) { + dev_warn(p->dev, "%s:%d depth read bo too small (layer size %d, " +- "offset %ld, max layer %d, bo size %ld)\n", ++ "offset %llu, max layer %d, bo size %ld)\n", + __func__, __LINE__, surf.layer_size, +- (unsigned long)track->db_z_read_offset << 8, mslice, ++ (u64)track->db_z_read_offset << 8, mslice, + radeon_bo_size(track->db_z_read_bo)); + return -EINVAL; + } + +- offset = track->db_z_write_offset << 8; ++ offset = (u64)track->db_z_write_offset << 8; + if (offset & (surf.base_align - 1)) { +- dev_warn(p->dev, "%s:%d stencil write bo base %ld not aligned with %ld\n", ++ dev_warn(p->dev, "%s:%d stencil write bo base %llu not aligned with %ld\n", + __func__, __LINE__, offset, surf.base_align); + return -EINVAL; + } +- offset += surf.layer_size * mslice; ++ offset += (u64)surf.layer_size * mslice; + if (offset > radeon_bo_size(track->db_z_write_bo)) { + dev_warn(p->dev, "%s:%d depth write bo too small (layer size %d, " +- "offset %ld, max layer %d, bo size %ld)\n", ++ "offset %llu, max layer %d, bo size %ld)\n", + __func__, __LINE__, surf.layer_size, +- (unsigned long)track->db_z_write_offset << 8, mslice, ++ (u64)track->db_z_write_offset << 8, mslice, + radeon_bo_size(track->db_z_write_bo)); + return -EINVAL; + } +diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c +index 927e5f42e97d01..3e48cbb522a1ca 100644 +--- a/drivers/gpu/drm/radeon/ni.c ++++ b/drivers/gpu/drm/radeon/ni.c +@@ -813,7 +813,7 @@ int ni_init_microcode(struct radeon_device *rdev) + err = 0; + } else if (rdev->smc_fw->size != smc_req_size) { + pr_err("ni_mc: Bogus length %zu in firmware \"%s\"\n", +- rdev->mc_fw->size, fw_name); ++ rdev->smc_fw->size, fw_name); + err = -EINVAL; + } + } +diff --git a/drivers/gpu/drm/radeon/pptable.h b/drivers/gpu/drm/radeon/pptable.h +index 4c2eec49dadc93..ce8832916704f9 100644 +--- a/drivers/gpu/drm/radeon/pptable.h ++++ b/drivers/gpu/drm/radeon/pptable.h +@@ -424,7 +424,7 @@ typedef struct _ATOM_PPLIB_SUMO_CLOCK_INFO{ + typedef struct _ATOM_PPLIB_STATE_V2 + { + //number of valid dpm levels in this state; Driver uses it to calculate the whole +- //size of the state: sizeof(ATOM_PPLIB_STATE_V2) + (ucNumDPMLevels - 1) * sizeof(UCHAR) ++ //size of the state: struct_size(ATOM_PPLIB_STATE_V2, clockInfoIndex, ucNumDPMLevels) + UCHAR ucNumDPMLevels; + + //a index to the array of nonClockInfos +@@ -432,14 +432,14 @@ typedef struct _ATOM_PPLIB_STATE_V2 + /** + * Driver will read the first ucNumDPMLevels in this array + */ +- UCHAR clockInfoIndex[1]; ++ UCHAR clockInfoIndex[] __counted_by(ucNumDPMLevels); + } ATOM_PPLIB_STATE_V2; + + typedef struct _StateArray{ + //how many states we have + UCHAR ucNumEntries; + +- ATOM_PPLIB_STATE_V2 states[1]; ++ ATOM_PPLIB_STATE_V2 states[] /* __counted_by(ucNumEntries) */; + }StateArray; + + +@@ -450,7 +450,7 @@ typedef struct _ClockInfoArray{ + //sizeof(ATOM_PPLIB_CLOCK_INFO) + UCHAR ucEntrySize; + +- UCHAR clockInfo[1]; ++ UCHAR clockInfo[] __counted_by(ucNumEntries); + }ClockInfoArray; + + typedef struct _NonClockInfoArray{ +@@ -460,7 +460,7 @@ typedef struct _NonClockInfoArray{ + //sizeof(ATOM_PPLIB_NONCLOCK_INFO) + UCHAR ucEntrySize; + +- ATOM_PPLIB_NONCLOCK_INFO nonClockInfo[1]; ++ ATOM_PPLIB_NONCLOCK_INFO nonClockInfo[] __counted_by(ucNumEntries); + }NonClockInfoArray; + + typedef struct _ATOM_PPLIB_Clock_Voltage_Dependency_Record +diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c +index affa9e0309b274..b63b6b4e9b2818 100644 +--- a/drivers/gpu/drm/radeon/r100.c ++++ b/drivers/gpu/drm/radeon/r100.c +@@ -1015,45 +1015,65 @@ static int r100_cp_init_microcode(struct radeon_device *rdev) + + DRM_DEBUG_KMS("\n"); + +- if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) || +- (rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) || +- (rdev->family == CHIP_RS200)) { ++ switch (rdev->family) { ++ case CHIP_R100: ++ case CHIP_RV100: ++ case CHIP_RV200: ++ case CHIP_RS100: ++ case CHIP_RS200: + DRM_INFO("Loading R100 Microcode\n"); + fw_name = FIRMWARE_R100; +- } else if ((rdev->family == CHIP_R200) || +- (rdev->family == CHIP_RV250) || +- (rdev->family == CHIP_RV280) || +- (rdev->family == CHIP_RS300)) { ++ break; ++ ++ case CHIP_R200: ++ case CHIP_RV250: ++ case CHIP_RV280: ++ case CHIP_RS300: + DRM_INFO("Loading R200 Microcode\n"); + fw_name = FIRMWARE_R200; +- } else if ((rdev->family == CHIP_R300) || +- (rdev->family == CHIP_R350) || +- (rdev->family == CHIP_RV350) || +- (rdev->family == CHIP_RV380) || +- (rdev->family == CHIP_RS400) || +- (rdev->family == CHIP_RS480)) { ++ break; ++ ++ case CHIP_R300: ++ case CHIP_R350: ++ case CHIP_RV350: ++ case CHIP_RV380: ++ case CHIP_RS400: ++ case CHIP_RS480: + DRM_INFO("Loading R300 Microcode\n"); + fw_name = FIRMWARE_R300; +- } else if ((rdev->family == CHIP_R420) || +- (rdev->family == CHIP_R423) || +- (rdev->family == CHIP_RV410)) { ++ break; ++ ++ case CHIP_R420: ++ case CHIP_R423: ++ case CHIP_RV410: + DRM_INFO("Loading R400 Microcode\n"); + fw_name = FIRMWARE_R420; +- } else if ((rdev->family == CHIP_RS690) || +- (rdev->family == CHIP_RS740)) { ++ break; ++ ++ case CHIP_RS690: ++ case CHIP_RS740: + DRM_INFO("Loading RS690/RS740 Microcode\n"); + fw_name = FIRMWARE_RS690; +- } else if (rdev->family == CHIP_RS600) { ++ break; ++ ++ case CHIP_RS600: + DRM_INFO("Loading RS600 Microcode\n"); + fw_name = FIRMWARE_RS600; +- } else if ((rdev->family == CHIP_RV515) || +- (rdev->family == CHIP_R520) || +- (rdev->family == CHIP_RV530) || +- (rdev->family == CHIP_R580) || +- (rdev->family == CHIP_RV560) || +- (rdev->family == CHIP_RV570)) { ++ break; ++ ++ case CHIP_RV515: ++ case CHIP_R520: ++ case CHIP_RV530: ++ case CHIP_R580: ++ case CHIP_RV560: ++ case CHIP_RV570: + DRM_INFO("Loading R500 Microcode\n"); + fw_name = FIRMWARE_R520; ++ break; ++ ++ default: ++ DRM_ERROR("Unsupported Radeon family %u\n", rdev->family); ++ return -EINVAL; + } + + err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); +@@ -2321,7 +2341,7 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track) + switch (prim_walk) { + case 1: + for (i = 0; i < track->num_arrays; i++) { +- size = track->arrays[i].esize * track->max_indx * 4; ++ size = track->arrays[i].esize * track->max_indx * 4UL; + if (track->arrays[i].robj == NULL) { + DRM_ERROR("(PW %u) Vertex array %u no buffer " + "bound\n", prim_walk, i); +@@ -2340,7 +2360,7 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track) + break; + case 2: + for (i = 0; i < track->num_arrays; i++) { +- size = track->arrays[i].esize * (nverts - 1) * 4; ++ size = track->arrays[i].esize * (nverts - 1) * 4UL; + if (track->arrays[i].robj == NULL) { + DRM_ERROR("(PW %u) Vertex array %u no buffer " + "bound\n", prim_walk, i); +diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c +index 638f861af80fa1..6cf54a747749d3 100644 +--- a/drivers/gpu/drm/radeon/r600_cs.c ++++ b/drivers/gpu/drm/radeon/r600_cs.c +@@ -1275,7 +1275,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) + return -EINVAL; + } + tmp = (reg - CB_COLOR0_BASE) / 4; +- track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8; ++ track->cb_color_bo_offset[tmp] = (u64)radeon_get_ib_value(p, idx) << 8; + ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); + track->cb_color_base_last[tmp] = ib[idx]; + track->cb_color_bo[tmp] = reloc->robj; +@@ -1302,7 +1302,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) + "0x%04X\n", reg); + return -EINVAL; + } +- track->htile_offset = radeon_get_ib_value(p, idx) << 8; ++ track->htile_offset = (u64)radeon_get_ib_value(p, idx) << 8; + ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); + track->htile_bo = reloc->robj; + track->db_dirty = true; +diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h +index 8afb03bbce2984..426a49851e3497 100644 +--- a/drivers/gpu/drm/radeon/radeon.h ++++ b/drivers/gpu/drm/radeon/radeon.h +@@ -132,7 +132,6 @@ extern int radeon_cik_support; + /* RADEON_IB_POOL_SIZE must be a power of 2 */ + #define RADEON_IB_POOL_SIZE 16 + #define RADEON_DEBUGFS_MAX_COMPONENTS 32 +-#define RADEONFB_CONN_LIMIT 4 + #define RADEON_BIOS_NUM_SCRATCH 8 + + /* internal ring indices */ +@@ -2215,10 +2214,6 @@ int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +-int radeon_gem_pwrite_ioctl(struct drm_device *dev, void *data, +- struct drm_file *file_priv); +-int radeon_gem_pread_ioctl(struct drm_device *dev, void *data, +- struct drm_file *file_priv); + int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp); + int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, +diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c +index 85c4bb186203c3..53c7273eb6a5cf 100644 +--- a/drivers/gpu/drm/radeon/radeon_atombios.c ++++ b/drivers/gpu/drm/radeon/radeon_atombios.c +@@ -922,8 +922,12 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct + max_device = ATOM_MAX_SUPPORTED_DEVICE_INFO; + + for (i = 0; i < max_device; i++) { +- ATOM_CONNECTOR_INFO_I2C ci = +- supported_devices->info.asConnInfo[i]; ++ ATOM_CONNECTOR_INFO_I2C ci; ++ ++ if (frev > 1) ++ ci = supported_devices->info_2d1.asConnInfo[i]; ++ else ++ ci = supported_devices->info.asConnInfo[i]; + + bios_connectors[i].valid = false; + +@@ -1712,26 +1716,29 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct + fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; + if (fake_edid_record->ucFakeEDIDLength) { + struct edid *edid; +- int edid_size = +- max((int)EDID_LENGTH, (int)fake_edid_record->ucFakeEDIDLength); +- edid = kmalloc(edid_size, GFP_KERNEL); ++ int edid_size; ++ ++ if (fake_edid_record->ucFakeEDIDLength == 128) ++ edid_size = fake_edid_record->ucFakeEDIDLength; ++ else ++ edid_size = fake_edid_record->ucFakeEDIDLength * 128; ++ edid = kmemdup(&fake_edid_record->ucFakeEDIDString[0], ++ edid_size, GFP_KERNEL); + if (edid) { +- memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0], +- fake_edid_record->ucFakeEDIDLength); +- + if (drm_edid_is_valid(edid)) { + rdev->mode_info.bios_hardcoded_edid = edid; + rdev->mode_info.bios_hardcoded_edid_size = edid_size; +- } else ++ } else { + kfree(edid); ++ } + } ++ record += struct_size(fake_edid_record, ++ ucFakeEDIDString, ++ edid_size); ++ } else { ++ /* empty fake edid record must be 3 bytes long */ ++ record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1; + } +- record += fake_edid_record->ucFakeEDIDLength ? +- struct_size(fake_edid_record, +- ucFakeEDIDString, +- fake_edid_record->ucFakeEDIDLength) : +- /* empty fake edid record must be 3 bytes long */ +- sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1; + break; + case LCD_PANEL_RESOLUTION_RECORD_TYPE: + panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; +diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c +index d2f02c3dfce297..b84b58926106a4 100644 +--- a/drivers/gpu/drm/radeon/radeon_connectors.c ++++ b/drivers/gpu/drm/radeon/radeon_connectors.c +@@ -1119,6 +1119,8 @@ static int radeon_tv_get_modes(struct drm_connector *connector) + else { + /* only 800x600 is supported right now on pre-avivo chips */ + tv_mode = drm_cvt_mode(dev, 800, 600, 60, false, false, false); ++ if (!tv_mode) ++ return 0; + tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + drm_mode_probed_add(connector, tv_mode); + } +diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c +index 901e75ec70ff41..5f1d24d3120c4a 100644 +--- a/drivers/gpu/drm/radeon/radeon_display.c ++++ b/drivers/gpu/drm/radeon/radeon_display.c +@@ -683,15 +683,20 @@ static void radeon_crtc_init(struct drm_device *dev, int index) + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc; + +- radeon_crtc = kzalloc(sizeof(struct radeon_crtc) + (RADEONFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); ++ radeon_crtc = kzalloc(sizeof(*radeon_crtc), GFP_KERNEL); + if (radeon_crtc == NULL) + return; + ++ radeon_crtc->flip_queue = alloc_workqueue("radeon-crtc", WQ_HIGHPRI, 0); ++ if (!radeon_crtc->flip_queue) { ++ kfree(radeon_crtc); ++ return; ++ } ++ + drm_crtc_init(dev, &radeon_crtc->base, &radeon_crtc_funcs); + + drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256); + radeon_crtc->crtc_id = index; +- radeon_crtc->flip_queue = alloc_workqueue("radeon-crtc", WQ_HIGHPRI, 0); + rdev->mode_info.crtcs[index] = radeon_crtc; + + if (rdev->family >= CHIP_BONAIRE) { +@@ -704,12 +709,6 @@ static void radeon_crtc_init(struct drm_device *dev, int index) + dev->mode_config.cursor_width = radeon_crtc->max_cursor_width; + dev->mode_config.cursor_height = radeon_crtc->max_cursor_height; + +-#if 0 +- radeon_crtc->mode_set.crtc = &radeon_crtc->base; +- radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1); +- radeon_crtc->mode_set.num_connectors = 0; +-#endif +- + if (rdev->is_atom_bios && (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom)) + radeon_atombios_init_crtc(dev, radeon_crtc); + else +diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c +index fa531493b11134..7bf08164140ef7 100644 +--- a/drivers/gpu/drm/radeon/radeon_drv.c ++++ b/drivers/gpu/drm/radeon/radeon_drv.c +@@ -555,8 +555,6 @@ static const struct drm_ioctl_desc radeon_ioctls_kms[] = { + DRM_IOCTL_DEF_DRV(RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), +- DRM_IOCTL_DEF_DRV(RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH), +- DRM_IOCTL_DEF_DRV(RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_CS, radeon_cs_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_INFO, radeon_info_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), +diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c +index 9cb6401fe97ed3..bb908f125269dc 100644 +--- a/drivers/gpu/drm/radeon/radeon_encoders.c ++++ b/drivers/gpu/drm/radeon/radeon_encoders.c +@@ -42,7 +42,7 @@ static uint32_t radeon_encoder_clones(struct drm_encoder *encoder) + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *clone_encoder; +- uint32_t index_mask = 0; ++ uint32_t index_mask = drm_encoder_mask(encoder); + int count; + + /* DIG routing gets problematic */ +diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c +index 358d19242f4ba2..27225d1fe8d2e7 100644 +--- a/drivers/gpu/drm/radeon/radeon_gem.c ++++ b/drivers/gpu/drm/radeon/radeon_gem.c +@@ -311,22 +311,6 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data, + return 0; + } + +-int radeon_gem_pread_ioctl(struct drm_device *dev, void *data, +- struct drm_file *filp) +-{ +- /* TODO: implement */ +- DRM_ERROR("unimplemented %s\n", __func__); +- return -EOPNOTSUPP; +-} +- +-int radeon_gem_pwrite_ioctl(struct drm_device *dev, void *data, +- struct drm_file *filp) +-{ +- /* TODO: implement */ +- DRM_ERROR("unimplemented %s\n", __func__); +- return -EOPNOTSUPP; +-} +- + int radeon_gem_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) + { +@@ -657,7 +641,7 @@ static void radeon_gem_va_update_vm(struct radeon_device *rdev, + if (r) + goto error_unlock; + +- if (bo_va->it.start) ++ if (bo_va->it.start && bo_va->bo) + r = radeon_vm_bo_update(rdev, bo_va, bo_va->bo->tbo.resource); + + error_unlock: +diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c +index 987cabbf1318e9..c38b4d5d6a14f5 100644 +--- a/drivers/gpu/drm/radeon/radeon_vm.c ++++ b/drivers/gpu/drm/radeon/radeon_vm.c +@@ -1204,13 +1204,17 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) + r = radeon_bo_create(rdev, pd_size, align, true, + RADEON_GEM_DOMAIN_VRAM, 0, NULL, + NULL, &vm->page_directory); +- if (r) ++ if (r) { ++ kfree(vm->page_tables); ++ vm->page_tables = NULL; + return r; +- ++ } + r = radeon_vm_clear_bo(rdev, vm->page_directory); + if (r) { + radeon_bo_unref(&vm->page_directory); + vm->page_directory = NULL; ++ kfree(vm->page_tables); ++ vm->page_tables = NULL; + return r; + } + +diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c +index a91012447b56ed..85e9cba49cecb2 100644 +--- a/drivers/gpu/drm/radeon/si.c ++++ b/drivers/gpu/drm/radeon/si.c +@@ -3611,6 +3611,10 @@ static int si_cp_start(struct radeon_device *rdev) + for (i = RADEON_RING_TYPE_GFX_INDEX; i <= CAYMAN_RING_TYPE_CP2_INDEX; ++i) { + ring = &rdev->ring[i]; + r = radeon_ring_lock(rdev, ring, 2); ++ if (r) { ++ DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r); ++ return r; ++ } + + /* clear the compute context state */ + radeon_ring_write(ring, PACKET3_COMPUTE(PACKET3_CLEAR_STATE, 0)); +diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c +index f74f381af05fdf..f7f1ddc6cdd810 100644 +--- a/drivers/gpu/drm/radeon/sumo_dpm.c ++++ b/drivers/gpu/drm/radeon/sumo_dpm.c +@@ -1493,8 +1493,10 @@ static int sumo_parse_power_table(struct radeon_device *rdev) + non_clock_array_index = power_state->v2.nonClockInfoIndex; + non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) + &non_clock_info_array->nonClockInfo[non_clock_array_index]; +- if (!rdev->pm.power_state[i].clock_info) ++ if (!rdev->pm.power_state[i].clock_info) { ++ kfree(rdev->pm.dpm.ps); + return -EINVAL; ++ } + ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL); + if (ps == NULL) { + kfree(rdev->pm.dpm.ps); +@@ -1619,6 +1621,8 @@ void sumo_construct_vid_mapping_table(struct radeon_device *rdev, + + for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) { + if (table[i].ulSupportedSCLK != 0) { ++ if (table[i].usVoltageIndex >= SUMO_MAX_NUMBER_VOLTAGES) ++ continue; + vid_mapping_table->entries[table[i].usVoltageIndex].vid_7bit = + table[i].usVoltageID; + vid_mapping_table->entries[table[i].usVoltageIndex].vid_2bit = +diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c +index 08ea1c864cb238..ef1cc7bad20a76 100644 +--- a/drivers/gpu/drm/radeon/trinity_dpm.c ++++ b/drivers/gpu/drm/radeon/trinity_dpm.c +@@ -1726,8 +1726,10 @@ static int trinity_parse_power_table(struct radeon_device *rdev) + non_clock_array_index = power_state->v2.nonClockInfoIndex; + non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) + &non_clock_info_array->nonClockInfo[non_clock_array_index]; +- if (!rdev->pm.power_state[i].clock_info) ++ if (!rdev->pm.power_state[i].clock_info) { ++ kfree(rdev->pm.dpm.ps); + return -EINVAL; ++ } + ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL); + if (ps == NULL) { + kfree(rdev->pm.dpm.ps); +diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c +index a29fbafce39366..3793863c210ebd 100644 +--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c ++++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c +@@ -1177,6 +1177,7 @@ static int cdn_dp_probe(struct platform_device *pdev) + struct cdn_dp_device *dp; + struct extcon_dev *extcon; + struct phy *phy; ++ int ret; + int i; + + dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); +@@ -1217,9 +1218,19 @@ static int cdn_dp_probe(struct platform_device *pdev) + mutex_init(&dp->lock); + dev_set_drvdata(dev, dp); + +- cdn_dp_audio_codec_init(dp, dev); ++ ret = cdn_dp_audio_codec_init(dp, dev); ++ if (ret) ++ return ret; ++ ++ ret = component_add(dev, &cdn_dp_component_ops); ++ if (ret) ++ goto err_audio_deinit; + +- return component_add(dev, &cdn_dp_component_ops); ++ return 0; ++ ++err_audio_deinit: ++ platform_device_unregister(dp->audio_pdev); ++ return ret; + } + + static void cdn_dp_remove(struct platform_device *pdev) +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 341550199111f9..89bc86d620146c 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -435,6 +435,8 @@ static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi *dw_hdmi, void *data) + HIWORD_UPDATE(RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK, + RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK | + RK3328_HDMI_HPD_IOE)); ++ ++ dw_hdmi_rk3328_read_hpd(dw_hdmi, data); + } + + static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops = { +diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c +index 6e5b922a121e24..345253e033c538 100644 +--- a/drivers/gpu/drm/rockchip/inno_hdmi.c ++++ b/drivers/gpu/drm/rockchip/inno_hdmi.c +@@ -412,7 +412,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF); + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF); + +- value = mode->hsync_start - mode->hdisplay; ++ value = mode->htotal - mode->hsync_start; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF); + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF); + +@@ -427,7 +427,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, + value = mode->vtotal - mode->vdisplay; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF); + +- value = mode->vsync_start - mode->vdisplay; ++ value = mode->vtotal - mode->vsync_start; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF); + + value = mode->vsync_end - mode->vsync_start; +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +index b8f8b45ebf5940..93ed841f5dceae 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +@@ -40,7 +40,7 @@ static int rockchip_gem_iommu_map(struct rockchip_gem_object *rk_obj) + + ret = iommu_map_sgtable(private->domain, rk_obj->dma_addr, rk_obj->sgt, + prot); +- if (ret < rk_obj->base.size) { ++ if (ret < (ssize_t)rk_obj->base.size) { + DRM_ERROR("failed to map buffer: size=%zd request_size=%zd\n", + ret, rk_obj->base.size); + ret = -ENOMEM; +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 14320bc73e5bfc..ee72e8c6ad69bd 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -247,14 +247,22 @@ static inline void vop_cfg_done(struct vop *vop) + VOP_REG_SET(vop, common, cfg_done, 1); + } + +-static bool has_rb_swapped(uint32_t format) ++static bool has_rb_swapped(uint32_t version, uint32_t format) + { + switch (format) { + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: +- case DRM_FORMAT_BGR888: + case DRM_FORMAT_BGR565: + return true; ++ /* ++ * full framework (IP version 3.x) only need rb swapped for RGB888 and ++ * little framework (IP version 2.x) only need rb swapped for BGR888, ++ * check for 3.x to also only rb swap BGR888 for unknown vop version ++ */ ++ case DRM_FORMAT_RGB888: ++ return VOP_MAJOR(version) == 3; ++ case DRM_FORMAT_BGR888: ++ return VOP_MAJOR(version) != 3; + default: + return false; + } +@@ -373,8 +381,8 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win, + if (info->is_yuv) + is_yuv = true; + +- if (dst_w > 3840) { +- DRM_DEV_ERROR(vop->dev, "Maximum dst width (3840) exceeded\n"); ++ if (dst_w > 4096) { ++ DRM_DEV_ERROR(vop->dev, "Maximum dst width (4096) exceeded\n"); + return; + } + +@@ -1013,7 +1021,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + VOP_WIN_SET(vop, win, dsp_info, dsp_info); + VOP_WIN_SET(vop, win, dsp_st, dsp_st); + +- rb_swap = has_rb_swapped(fb->format->format); ++ rb_swap = has_rb_swapped(vop->data->version, fb->format->format); + VOP_WIN_SET(vop, win, rb_swap, rb_swap); + + /* +@@ -1558,6 +1566,10 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, + VOP_AFBC_SET(vop, enable, s->enable_afbc); + vop_cfg_done(vop); + ++ /* Ack the DMA transfer of the previous frame (RK3066). */ ++ if (VOP_HAS_REG(vop, common, dma_stop)) ++ VOP_REG_SET(vop, common, dma_stop, 0); ++ + spin_unlock(&vop->reg_lock); + + /* +@@ -1614,7 +1626,8 @@ static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) + if (WARN_ON(!crtc->state)) + return NULL; + +- rockchip_state = kzalloc(sizeof(*rockchip_state), GFP_KERNEL); ++ rockchip_state = kmemdup(to_rockchip_crtc_state(crtc->state), ++ sizeof(*rockchip_state), GFP_KERNEL); + if (!rockchip_state) + return NULL; + +@@ -1639,7 +1652,10 @@ static void vop_crtc_reset(struct drm_crtc *crtc) + if (crtc->state) + vop_crtc_destroy_state(crtc, crtc->state); + +- __drm_atomic_helper_crtc_reset(crtc, &crtc_state->base); ++ if (crtc_state) ++ __drm_atomic_helper_crtc_reset(crtc, &crtc_state->base); ++ else ++ __drm_atomic_helper_crtc_reset(crtc, NULL); + } + + #ifdef CONFIG_DRM_ANALOGIX_DP +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +index 5f56e0597df84a..c5c716a69171a8 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +@@ -122,6 +122,7 @@ struct vop_common { + struct vop_reg lut_buffer_index; + struct vop_reg gate_en; + struct vop_reg mmu_en; ++ struct vop_reg dma_stop; + struct vop_reg out_mode; + struct vop_reg standby; + }; +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +index 583df4d22f7e90..d1de12e850e746 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +@@ -609,6 +609,8 @@ static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win, + const struct drm_format_info *info; + u16 hor_scl_mode, ver_scl_mode; + u16 hscl_filter_mode, vscl_filter_mode; ++ uint16_t cbcr_src_w = src_w; ++ uint16_t cbcr_src_h = src_h; + u8 gt2 = 0; + u8 gt4 = 0; + u32 val; +@@ -666,27 +668,27 @@ static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win, + vop2_win_write(win, VOP2_WIN_YRGB_VSCL_FILTER_MODE, vscl_filter_mode); + + if (info->is_yuv) { +- src_w /= info->hsub; +- src_h /= info->vsub; ++ cbcr_src_w /= info->hsub; ++ cbcr_src_h /= info->vsub; + + gt4 = 0; + gt2 = 0; + +- if (src_h >= (4 * dst_h)) { ++ if (cbcr_src_h >= (4 * dst_h)) { + gt4 = 1; +- src_h >>= 2; +- } else if (src_h >= (2 * dst_h)) { ++ cbcr_src_h >>= 2; ++ } else if (cbcr_src_h >= (2 * dst_h)) { + gt2 = 1; +- src_h >>= 1; ++ cbcr_src_h >>= 1; + } + +- hor_scl_mode = scl_get_scl_mode(src_w, dst_w); +- ver_scl_mode = scl_get_scl_mode(src_h, dst_h); ++ hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w); ++ ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h); + +- val = vop2_scale_factor(src_w, dst_w); ++ val = vop2_scale_factor(cbcr_src_w, dst_w); + vop2_win_write(win, VOP2_WIN_SCALE_CBCR_X, val); + +- val = vop2_scale_factor(src_h, dst_h); ++ val = vop2_scale_factor(cbcr_src_h, dst_h); + vop2_win_write(win, VOP2_WIN_SCALE_CBCR_Y, val); + + vop2_win_write(win, VOP2_WIN_VSD_CBCR_GT4, gt4); +@@ -1258,6 +1260,11 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, + vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_270, rotate_270); + vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_90, rotate_90); + } else { ++ if (vop2_cluster_window(win)) { ++ vop2_win_write(win, VOP2_WIN_AFBC_ENABLE, 0); ++ vop2_win_write(win, VOP2_WIN_AFBC_TRANSFORM_OFFSET, 0); ++ } ++ + vop2_win_write(win, VOP2_WIN_YRGB_VIR, DIV_ROUND_UP(fb->pitches[0], 4)); + } + +@@ -1925,7 +1932,7 @@ static void vop2_setup_layer_mixer(struct vop2_video_port *vp) + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX, + (vp2->nlayers + vp1->nlayers + vp0->nlayers - 1)); + else +- port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8); ++ port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX, 8); + + layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL); + +@@ -2079,30 +2086,15 @@ static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs = { + .atomic_disable = vop2_crtc_atomic_disable, + }; + +-static void vop2_crtc_reset(struct drm_crtc *crtc) +-{ +- struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); +- +- if (crtc->state) { +- __drm_atomic_helper_crtc_destroy_state(crtc->state); +- kfree(vcstate); +- } +- +- vcstate = kzalloc(sizeof(*vcstate), GFP_KERNEL); +- if (!vcstate) +- return; +- +- crtc->state = &vcstate->base; +- crtc->state->crtc = crtc; +-} +- + static struct drm_crtc_state *vop2_crtc_duplicate_state(struct drm_crtc *crtc) + { +- struct rockchip_crtc_state *vcstate, *old_vcstate; ++ struct rockchip_crtc_state *vcstate; + +- old_vcstate = to_rockchip_crtc_state(crtc->state); ++ if (WARN_ON(!crtc->state)) ++ return NULL; + +- vcstate = kmemdup(old_vcstate, sizeof(*old_vcstate), GFP_KERNEL); ++ vcstate = kmemdup(to_rockchip_crtc_state(crtc->state), ++ sizeof(*vcstate), GFP_KERNEL); + if (!vcstate) + return NULL; + +@@ -2120,6 +2112,20 @@ static void vop2_crtc_destroy_state(struct drm_crtc *crtc, + kfree(vcstate); + } + ++static void vop2_crtc_reset(struct drm_crtc *crtc) ++{ ++ struct rockchip_crtc_state *vcstate = ++ kzalloc(sizeof(*vcstate), GFP_KERNEL); ++ ++ if (crtc->state) ++ vop2_crtc_destroy_state(crtc, crtc->state); ++ ++ if (vcstate) ++ __drm_atomic_helper_crtc_reset(crtc, &vcstate->base); ++ else ++ __drm_atomic_helper_crtc_reset(crtc, NULL); ++} ++ + static const struct drm_crtc_funcs vop2_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, +diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c +index 5828593877923f..1b6e0b210aa530 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c ++++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c +@@ -577,8 +577,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, + ret = -EINVAL; + goto err_put_port; + } else if (ret) { +- DRM_DEV_ERROR(dev, "failed to find panel and bridge node\n"); +- ret = -EPROBE_DEFER; ++ dev_err_probe(dev, ret, "failed to find panel and bridge node\n"); + goto err_put_port; + } + if (lvds->panel) +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 7b28050067769d..f7d0edd762b36c 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -435,6 +435,7 @@ static const struct vop_output rk3066_output = { + }; + + static const struct vop_common rk3066_common = { ++ .dma_stop = VOP_REG(RK3066_SYS_CTRL0, 0x1, 0), + .standby = VOP_REG(RK3066_SYS_CTRL0, 0x1, 1), + .out_mode = VOP_REG(RK3066_DSP_CTRL0, 0xf, 0), + .cfg_done = VOP_REG(RK3066_REG_CFG_DONE, 0x1, 0), +@@ -483,6 +484,7 @@ static const struct vop_data rk3066_vop = { + .output = &rk3066_output, + .win = rk3066_vop_win_data, + .win_size = ARRAY_SIZE(rk3066_vop_win_data), ++ .feature = VOP_FEATURE_INTERNAL_RGB, + .max_output = { 1920, 1080 }, + }; + +diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c +index a42763e1429dc1..d3462be7493037 100644 +--- a/drivers/gpu/drm/scheduler/sched_entity.c ++++ b/drivers/gpu/drm/scheduler/sched_entity.c +@@ -111,8 +111,10 @@ void drm_sched_entity_modify_sched(struct drm_sched_entity *entity, + { + WARN_ON(!num_sched_list || !sched_list); + ++ spin_lock(&entity->rq_lock); + entity->sched_list = sched_list; + entity->num_sched_list = num_sched_list; ++ spin_unlock(&entity->rq_lock); + } + EXPORT_SYMBOL(drm_sched_entity_modify_sched); + +diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c +index 5a80b228d18cae..deec6acdcf6462 100644 +--- a/drivers/gpu/drm/solomon/ssd130x.c ++++ b/drivers/gpu/drm/solomon/ssd130x.c +@@ -267,7 +267,7 @@ static int ssd130x_pwm_enable(struct ssd130x_device *ssd130x) + + pwm_init_state(ssd130x->pwm, &pwmstate); + pwm_set_relative_duty_cycle(&pwmstate, 50, 100); +- pwm_apply_state(ssd130x->pwm, &pwmstate); ++ pwm_apply_might_sleep(ssd130x->pwm, &pwmstate); + + /* Enable the PWM */ + pwm_enable(ssd130x->pwm); +@@ -553,14 +553,45 @@ static int ssd130x_update_rect(struct ssd130x_device *ssd130x, + static void ssd130x_clear_screen(struct ssd130x_device *ssd130x, + struct ssd130x_plane_state *ssd130x_state) + { +- struct drm_rect fullscreen = { +- .x1 = 0, +- .x2 = ssd130x->width, +- .y1 = 0, +- .y2 = ssd130x->height, +- }; +- +- ssd130x_update_rect(ssd130x, ssd130x_state, &fullscreen); ++ unsigned int page_height = ssd130x->device_info->page_height; ++ unsigned int pages = DIV_ROUND_UP(ssd130x->height, page_height); ++ u8 *data_array = ssd130x_state->data_array; ++ unsigned int width = ssd130x->width; ++ int ret, i; ++ ++ if (!ssd130x->page_address_mode) { ++ memset(data_array, 0, width * pages); ++ ++ /* Set address range for horizontal addressing mode */ ++ ret = ssd130x_set_col_range(ssd130x, ssd130x->col_offset, width); ++ if (ret < 0) ++ return; ++ ++ ret = ssd130x_set_page_range(ssd130x, ssd130x->page_offset, pages); ++ if (ret < 0) ++ return; ++ ++ /* Write out update in one go if we aren't using page addressing mode */ ++ ssd130x_write_data(ssd130x, data_array, width * pages); ++ } else { ++ /* ++ * In page addressing mode, the start address needs to be reset, ++ * and each page then needs to be written out separately. ++ */ ++ memset(data_array, 0, width); ++ ++ for (i = 0; i < pages; i++) { ++ ret = ssd130x_set_page_pos(ssd130x, ++ ssd130x->page_offset + i, ++ ssd130x->col_offset); ++ if (ret < 0) ++ return; ++ ++ ret = ssd130x_write_data(ssd130x, data_array, width); ++ if (ret < 0) ++ return; ++ } ++ } + } + + static int ssd130x_fb_blit_rect(struct drm_plane_state *state, +diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c +index c68c831136c9b0..e1232f74dfa537 100644 +--- a/drivers/gpu/drm/stm/drv.c ++++ b/drivers/gpu/drm/stm/drv.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #include "ltdc.h" + +@@ -75,7 +76,7 @@ static int drv_load(struct drm_device *ddev) + + DRM_DEBUG("%s\n", __func__); + +- ldev = devm_kzalloc(ddev->dev, sizeof(*ldev), GFP_KERNEL); ++ ldev = drmm_kzalloc(ddev, sizeof(*ldev), GFP_KERNEL); + if (!ldev) + return -ENOMEM; + +@@ -114,6 +115,7 @@ static void drv_unload(struct drm_device *ddev) + DRM_DEBUG("%s\n", __func__); + + drm_kms_helper_poll_fini(ddev); ++ drm_atomic_helper_shutdown(ddev); + ltdc_unload(ddev); + } + +@@ -202,12 +204,14 @@ static int stm_drm_platform_probe(struct platform_device *pdev) + + ret = drm_dev_register(ddev, 0); + if (ret) +- goto err_put; ++ goto err_unload; + + drm_fbdev_dma_setup(ddev, 16); + + return 0; + ++err_unload: ++ drv_unload(ddev); + err_put: + drm_dev_put(ddev); + +@@ -225,6 +229,11 @@ static void stm_drm_platform_remove(struct platform_device *pdev) + drm_dev_put(ddev); + } + ++static void stm_drm_platform_shutdown(struct platform_device *pdev) ++{ ++ drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); ++} ++ + static const struct of_device_id drv_dt_ids[] = { + { .compatible = "st,stm32-ltdc"}, + { /* end node */ }, +@@ -234,6 +243,7 @@ MODULE_DEVICE_TABLE(of, drv_dt_ids); + static struct platform_driver stm_drm_platform_driver = { + .probe = stm_drm_platform_probe, + .remove_new = stm_drm_platform_remove, ++ .shutdown = stm_drm_platform_shutdown, + .driver = { + .name = "stm32-display", + .of_match_table = drv_dt_ids, +diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c +index 5576fdae496233..0832b749b66e7f 100644 +--- a/drivers/gpu/drm/stm/ltdc.c ++++ b/drivers/gpu/drm/stm/ltdc.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + #include