diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 0000000..bef2d00 --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,9 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "ab4fef131ee828e96ba67d31a7d690bd5f2f42040c6766b1b12fe856f87e0ff7" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 0000000..9425a54 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,22 @@ + +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" + diff --git a/diffs/diff1.diff b/diffs/diff1.diff new file mode 100644 index 0000000..e4aa2ab --- /dev/null +++ b/diffs/diff1.diff @@ -0,0 +1,53801 @@ +diff --git a/.gitignore b/.gitignore +index 705e099..1be78fd 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -127,3 +127,7 @@ all.config + + # Kdevelop4 + *.kdev4 ++ ++#Automatically generated by ASN.1 compiler ++net/ipv4/netfilter/nf_nat_snmp_basic-asn1.c ++net/ipv4/netfilter/nf_nat_snmp_basic-asn1.h +diff --git a/Documentation/ABI/testing/sysfs-devices-platform-dock b/Documentation/ABI/testing/sysfs-devices-platform-dock +new file mode 100644 +index 0000000..1d8c18f +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-devices-platform-dock +@@ -0,0 +1,39 @@ ++What: /sys/devices/platform/dock.N/docked ++Date: Dec, 2006 ++KernelVersion: 2.6.19 ++Contact: linux-acpi@vger.kernel.org ++Description: ++ (RO) Value 1 or 0 indicates whether the software believes the ++ laptop is docked in a docking station. ++ ++What: /sys/devices/platform/dock.N/undock ++Date: Dec, 2006 ++KernelVersion: 2.6.19 ++Contact: linux-acpi@vger.kernel.org ++Description: ++ (WO) Writing to this file causes the software to initiate an ++ undock request to the firmware. ++ ++What: /sys/devices/platform/dock.N/uid ++Date: Feb, 2007 ++KernelVersion: v2.6.21 ++Contact: linux-acpi@vger.kernel.org ++Description: ++ (RO) Displays the docking station the laptop is docked to. ++ ++What: /sys/devices/platform/dock.N/flags ++Date: May, 2007 ++KernelVersion: v2.6.21 ++Contact: linux-acpi@vger.kernel.org ++Description: ++ (RO) Show dock station flags, useful for checking if undock ++ request has been made by the user (from the immediate_undock ++ option). ++ ++What: /sys/devices/platform/dock.N/type ++Date: Aug, 2008 ++KernelVersion: v2.6.27 ++Contact: linux-acpi@vger.kernel.org ++Description: ++ (RO) Display the dock station type- dock_station, ata_bay or ++ battery_bay. +diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu +index bfd29bc..4ed63b6 100644 +--- a/Documentation/ABI/testing/sysfs-devices-system-cpu ++++ b/Documentation/ABI/testing/sysfs-devices-system-cpu +@@ -108,6 +108,8 @@ Description: CPU topology files that describe a logical CPU's relationship + + What: /sys/devices/system/cpu/cpuidle/current_driver + /sys/devices/system/cpu/cpuidle/current_governer_ro ++ /sys/devices/system/cpu/cpuidle/available_governors ++ /sys/devices/system/cpu/cpuidle/current_governor + Date: September 2007 + Contact: Linux kernel mailing list + Description: Discover cpuidle policy and mechanism +@@ -119,13 +121,84 @@ Description: Discover cpuidle policy and mechanism + Idle policy (governor) is differentiated from idle mechanism + (driver) + +- current_driver: displays current idle mechanism ++ current_driver: (RO) displays current idle mechanism + +- current_governor_ro: displays current idle policy ++ current_governor_ro: (RO) displays current idle policy ++ ++ With the cpuidle_sysfs_switch boot option enabled (meant for ++ developer testing), the following three attributes are visible ++ instead: ++ ++ current_driver: same as described above ++ ++ available_governors: (RO) displays a space separated list of ++ available governors ++ ++ current_governor: (RW) displays current idle policy. Users can ++ switch the governor at runtime by writing to this file. + + See files in Documentation/cpuidle/ for more information. + + ++What: /sys/devices/system/cpu/cpuX/cpuidle/stateN/name ++ /sys/devices/system/cpu/cpuX/cpuidle/stateN/latency ++ /sys/devices/system/cpu/cpuX/cpuidle/stateN/power ++ /sys/devices/system/cpu/cpuX/cpuidle/stateN/time ++ /sys/devices/system/cpu/cpuX/cpuidle/stateN/usage ++Date: September 2007 ++KernelVersion: v2.6.24 ++Contact: Linux power management list ++Description: ++ The directory /sys/devices/system/cpu/cpuX/cpuidle contains per ++ logical CPU specific cpuidle information for each online cpu X. ++ The processor idle states which are available for use have the ++ following attributes: ++ ++ name: (RO) Name of the idle state (string). ++ ++ latency: (RO) The latency to exit out of this idle state (in ++ microseconds). ++ ++ power: (RO) The power consumed while in this idle state (in ++ milliwatts). ++ ++ time: (RO) The total time spent in this idle state (in microseconds). ++ ++ usage: (RO) Number of times this state was entered (a count). ++ ++ ++What: /sys/devices/system/cpu/cpuX/cpuidle/stateN/desc ++Date: February 2008 ++KernelVersion: v2.6.25 ++Contact: Linux power management list ++Description: ++ (RO) A small description about the idle state (string). ++ ++ ++What: /sys/devices/system/cpu/cpuX/cpuidle/stateN/disable ++Date: March 2012 ++KernelVersion: v3.10 ++Contact: Linux power management list ++Description: ++ (RW) Option to disable this idle state (bool). The behavior and ++ the effect of the disable variable depends on the implementation ++ of a particular governor. In the ladder governor, for example, ++ it is not coherent, i.e. if one is disabling a light state, then ++ all deeper states are disabled as well, but the disable variable ++ does not reflect it. Likewise, if one enables a deep state but a ++ lighter state still is disabled, then this has no effect. ++ ++ ++What: /sys/devices/system/cpu/cpuX/cpuidle/stateN/residency ++Date: March 2014 ++KernelVersion: v3.15 ++Contact: Linux power management list ++Description: ++ (RO) Display the target residency i.e. the minimum amount of ++ time (in microseconds) this cpu should spend in this idle state ++ to make the transition worth the effort. ++ ++ + What: /sys/devices/system/cpu/cpu#/cpufreq/* + Date: pre-git history + Contact: linux-pm@vger.kernel.org +diff --git a/Documentation/ABI/testing/sysfs-platform-dptf b/Documentation/ABI/testing/sysfs-platform-dptf +new file mode 100644 +index 0000000..325dc06 +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-platform-dptf +@@ -0,0 +1,40 @@ ++What: /sys/bus/platform/devices/INT3407:00/dptf_power/charger_type ++Date: Jul, 2016 ++KernelVersion: v4.10 ++Contact: linux-acpi@vger.kernel.org ++Description: ++ (RO) The charger type - Traditional, Hybrid or NVDC. ++ ++What: /sys/bus/platform/devices/INT3407:00/dptf_power/adapter_rating_mw ++Date: Jul, 2016 ++KernelVersion: v4.10 ++Contact: linux-acpi@vger.kernel.org ++Description: ++ (RO) Adapter rating in milliwatts (the maximum Adapter power). ++ Must be 0 if no AC Adaptor is plugged in. ++ ++What: /sys/bus/platform/devices/INT3407:00/dptf_power/max_platform_power_mw ++Date: Jul, 2016 ++KernelVersion: v4.10 ++Contact: linux-acpi@vger.kernel.org ++Description: ++ (RO) Maximum platform power that can be supported by the battery ++ in milliwatts. ++ ++What: /sys/bus/platform/devices/INT3407:00/dptf_power/platform_power_source ++Date: Jul, 2016 ++KernelVersion: v4.10 ++Contact: linux-acpi@vger.kernel.org ++Description: ++ (RO) Display the platform power source ++ 0x00 = DC ++ 0x01 = AC ++ 0x02 = USB ++ 0x03 = Wireless Charger ++ ++What: /sys/bus/platform/devices/INT3407:00/dptf_power/battery_steady_power ++Date: Jul, 2016 ++KernelVersion: v4.10 ++Contact: linux-acpi@vger.kernel.org ++Description: ++ (RO) The maximum sustained power for battery in milliwatts. +diff --git a/Documentation/PCI/pci.txt b/Documentation/PCI/pci.txt +index 611a75e4..badb26a 100644 +--- a/Documentation/PCI/pci.txt ++++ b/Documentation/PCI/pci.txt +@@ -570,7 +570,9 @@ your driver if they're helpful, or just use plain hex constants. + The device IDs are arbitrary hex numbers (vendor controlled) and normally used + only in a single location, the pci_device_id table. + +-Please DO submit new vendor/device IDs to http://pciids.sourceforge.net/. ++Please DO submit new vendor/device IDs to http://pci-ids.ucw.cz/. ++There are mirrors of the pci.ids file at http://pciids.sourceforge.net/ ++and https://github.com/pciutils/pciids. + + + +diff --git a/Documentation/accelerators/ocxl.rst b/Documentation/accelerators/ocxl.rst +index 4f7af84..ddcc58d 100644 +--- a/Documentation/accelerators/ocxl.rst ++++ b/Documentation/accelerators/ocxl.rst +@@ -152,6 +152,11 @@ OCXL_IOCTL_IRQ_SET_FD: + Associate an event fd to an AFU interrupt so that the user process + can be notified when the AFU sends an interrupt. + ++OCXL_IOCTL_GET_METADATA: ++ ++ Obtains configuration information from the card, such at the size of ++ MMIO areas, the AFU version, and the PASID for the current context. ++ + + mmap + ---- +diff --git a/Documentation/atomic_bitops.txt b/Documentation/atomic_bitops.txt +index 5550bfdc..be70b32 100644 +--- a/Documentation/atomic_bitops.txt ++++ b/Documentation/atomic_bitops.txt +@@ -58,7 +58,12 @@ Like with atomic_t, the rule of thumb is: + + - RMW operations that have a return value are fully ordered. + +-Except for test_and_set_bit_lock() which has ACQUIRE semantics and ++ - RMW operations that are conditional are unordered on FAILURE, ++ otherwise the above rules apply. In the case of test_and_{}_bit() operations, ++ if the bit in memory is unchanged by the operation then it is deemed to have ++ failed. ++ ++Except for a successful test_and_set_bit_lock() which has ACQUIRE semantics and + clear_bit_unlock() which has RELEASE semantics. + + Since a platform only has a single means of achieving atomic operations +diff --git a/Documentation/devicetree/bindings/auxdisplay/arm-charlcd.txt b/Documentation/devicetree/bindings/auxdisplay/arm-charlcd.txt +new file mode 100644 +index 0000000..e28e2aa +--- /dev/null ++++ b/Documentation/devicetree/bindings/auxdisplay/arm-charlcd.txt +@@ -0,0 +1,18 @@ ++ARM Versatile Character LCD ++----------------------------------------------------- ++This binding defines the character LCD interface found on ARM Versatile AB ++and PB reference platforms. ++ ++Required properties: ++- compatible : "arm,versatile-clcd" ++- reg : Location and size of character LCD registers ++ ++Optional properties: ++- interrupts - single interrupt for character LCD. The character LCD can ++ operate in polled mode without an interrupt. ++ ++Example: ++ lcd@10008000 { ++ compatible = "arm,versatile-lcd"; ++ reg = <0x10008000 0x1000>; ++ }; +diff --git a/Documentation/devicetree/bindings/eeprom/at24.txt b/Documentation/devicetree/bindings/eeprom/at24.txt +index 1812c84..abfae1b 100644 +--- a/Documentation/devicetree/bindings/eeprom/at24.txt ++++ b/Documentation/devicetree/bindings/eeprom/at24.txt +@@ -38,9 +38,9 @@ Required properties: + + "catalyst", + "microchip", ++ "nxp", + "ramtron", + "renesas", +- "nxp", + "st", + + Some vendors use different model names for chips which are just +diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt +index 33c9a10..20f121d 100644 +--- a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt ++++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt +@@ -14,6 +14,7 @@ Required properties: + - "renesas,irqc-r8a7794" (R-Car E2) + - "renesas,intc-ex-r8a7795" (R-Car H3) + - "renesas,intc-ex-r8a7796" (R-Car M3-W) ++ - "renesas,intc-ex-r8a77965" (R-Car M3-N) + - "renesas,intc-ex-r8a77970" (R-Car V3M) + - "renesas,intc-ex-r8a77995" (R-Car D3) + - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in +diff --git a/Documentation/devicetree/bindings/misc/arm-charlcd.txt b/Documentation/devicetree/bindings/misc/arm-charlcd.txt +deleted file mode 100644 +index e28e2aa..0000000 +--- a/Documentation/devicetree/bindings/misc/arm-charlcd.txt ++++ /dev/null +@@ -1,18 +0,0 @@ +-ARM Versatile Character LCD +------------------------------------------------------ +-This binding defines the character LCD interface found on ARM Versatile AB +-and PB reference platforms. +- +-Required properties: +-- compatible : "arm,versatile-clcd" +-- reg : Location and size of character LCD registers +- +-Optional properties: +-- interrupts - single interrupt for character LCD. The character LCD can +- operate in polled mode without an interrupt. +- +-Example: +- lcd@10008000 { +- compatible = "arm,versatile-lcd"; +- reg = <0x10008000 0x1000>; +- }; +diff --git a/Documentation/devicetree/bindings/net/renesas,ravb.txt b/Documentation/devicetree/bindings/net/renesas,ravb.txt +index c902261..92fd4b2 100644 +--- a/Documentation/devicetree/bindings/net/renesas,ravb.txt ++++ b/Documentation/devicetree/bindings/net/renesas,ravb.txt +@@ -18,6 +18,7 @@ Required properties: + - "renesas,etheravb-r8a7795" for the R8A7795 SoC. + - "renesas,etheravb-r8a7796" for the R8A7796 SoC. + - "renesas,etheravb-r8a77970" for the R8A77970 SoC. ++ - "renesas,etheravb-r8a77980" for the R8A77980 SoC. + - "renesas,etheravb-r8a77995" for the R8A77995 SoC. + - "renesas,etheravb-rcar-gen3" as a fallback for the above + R-Car Gen3 devices. +diff --git a/Documentation/devicetree/bindings/power/mti,mips-cpc.txt b/Documentation/devicetree/bindings/power/mti,mips-cpc.txt +new file mode 100644 +index 0000000..c6b8251 +--- /dev/null ++++ b/Documentation/devicetree/bindings/power/mti,mips-cpc.txt +@@ -0,0 +1,8 @@ ++Binding for MIPS Cluster Power Controller (CPC). ++ ++This binding allows a system to specify where the CPC registers are ++located. ++ ++Required properties: ++compatible : Should be "mti,mips-cpc". ++regs: Should describe the address & size of the CPC register region. +diff --git a/Documentation/devicetree/bindings/power/wakeup-source.txt b/Documentation/devicetree/bindings/power/wakeup-source.txt +index 3c81f78..5d254ab 100644 +--- a/Documentation/devicetree/bindings/power/wakeup-source.txt ++++ b/Documentation/devicetree/bindings/power/wakeup-source.txt +@@ -60,7 +60,7 @@ Examples + #size-cells = <0>; + + button@1 { +- debounce_interval = <50>; ++ debounce-interval = <50>; + wakeup-source; + linux,code = <116>; + label = "POWER"; +diff --git a/Documentation/devicetree/bindings/thermal/imx-thermal.txt b/Documentation/devicetree/bindings/thermal/imx-thermal.txt +index 28be51a..379eb76 100644 +--- a/Documentation/devicetree/bindings/thermal/imx-thermal.txt ++++ b/Documentation/devicetree/bindings/thermal/imx-thermal.txt +@@ -22,7 +22,32 @@ Optional properties: + - clocks : thermal sensor's clock source. + + Example: ++ocotp: ocotp@21bc000 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "fsl,imx6sx-ocotp", "syscon"; ++ reg = <0x021bc000 0x4000>; ++ clocks = <&clks IMX6SX_CLK_OCOTP>; + ++ tempmon_calib: calib@38 { ++ reg = <0x38 4>; ++ }; ++ ++ tempmon_temp_grade: temp-grade@20 { ++ reg = <0x20 4>; ++ }; ++}; ++ ++tempmon: tempmon { ++ compatible = "fsl,imx6sx-tempmon", "fsl,imx6q-tempmon"; ++ interrupts = ; ++ fsl,tempmon = <&anatop>; ++ nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>; ++ nvmem-cell-names = "calib", "temp_grade"; ++ clocks = <&clks IMX6SX_CLK_PLL3_USB_OTG>; ++}; ++ ++Legacy method (Deprecated): + tempmon { + compatible = "fsl,imx6q-tempmon"; + fsl,tempmon = <&anatop>; +diff --git a/Documentation/features/sched/membarrier-sync-core/arch-support.txt b/Documentation/features/sched/membarrier-sync-core/arch-support.txt +new file mode 100644 +index 0000000..2c815a7 +--- /dev/null ++++ b/Documentation/features/sched/membarrier-sync-core/arch-support.txt +@@ -0,0 +1,62 @@ ++# ++# Feature name: membarrier-sync-core ++# Kconfig: ARCH_HAS_MEMBARRIER_SYNC_CORE ++# description: arch supports core serializing membarrier ++# ++# Architecture requirements ++# ++# * arm64 ++# ++# Rely on eret context synchronization when returning from IPI handler, and ++# when returning to user-space. ++# ++# * x86 ++# ++# x86-32 uses IRET as return from interrupt, which takes care of the IPI. ++# However, it uses both IRET and SYSEXIT to go back to user-space. The IRET ++# instruction is core serializing, but not SYSEXIT. ++# ++# x86-64 uses IRET as return from interrupt, which takes care of the IPI. ++# However, it can return to user-space through either SYSRETL (compat code), ++# SYSRETQ, or IRET. ++# ++# Given that neither SYSRET{L,Q}, nor SYSEXIT, are core serializing, we rely ++# instead on write_cr3() performed by switch_mm() to provide core serialization ++# after changing the current mm, and deal with the special case of kthread -> ++# uthread (temporarily keeping current mm into active_mm) by issuing a ++# sync_core_before_usermode() in that specific case. ++# ++ ----------------------- ++ | arch |status| ++ ----------------------- ++ | alpha: | TODO | ++ | arc: | TODO | ++ | arm: | TODO | ++ | arm64: | ok | ++ | blackfin: | TODO | ++ | c6x: | TODO | ++ | cris: | TODO | ++ | frv: | TODO | ++ | h8300: | TODO | ++ | hexagon: | TODO | ++ | ia64: | TODO | ++ | m32r: | TODO | ++ | m68k: | TODO | ++ | metag: | TODO | ++ | microblaze: | TODO | ++ | mips: | TODO | ++ | mn10300: | TODO | ++ | nios2: | TODO | ++ | openrisc: | TODO | ++ | parisc: | TODO | ++ | powerpc: | TODO | ++ | s390: | TODO | ++ | score: | TODO | ++ | sh: | TODO | ++ | sparc: | TODO | ++ | tile: | TODO | ++ | um: | TODO | ++ | unicore32: | TODO | ++ | x86: | ok | ++ | xtensa: | TODO | ++ ----------------------- +diff --git a/Documentation/gpu/tve200.rst b/Documentation/gpu/tve200.rst +index 69b17b3..152ea93 100644 +--- a/Documentation/gpu/tve200.rst ++++ b/Documentation/gpu/tve200.rst +@@ -3,4 +3,4 @@ + ================================== + + .. kernel-doc:: drivers/gpu/drm/tve200/tve200_drv.c +- :doc: Faraday TV Encoder 200 ++ :doc: Faraday TV Encoder TVE200 DRM Driver +diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 +index d477024..65514c2 100644 +--- a/Documentation/i2c/busses/i2c-i801 ++++ b/Documentation/i2c/busses/i2c-i801 +@@ -28,8 +28,10 @@ Supported adapters: + * Intel Wildcat Point (PCH) + * Intel Wildcat Point-LP (PCH) + * Intel BayTrail (SOC) ++ * Intel Braswell (SOC) + * Intel Sunrise Point-H (PCH) + * Intel Sunrise Point-LP (PCH) ++ * Intel Kaby Lake-H (PCH) + * Intel DNV (SOC) + * Intel Broxton (SOC) + * Intel Lewisburg (PCH) +diff --git a/Documentation/ia64/serial.txt b/Documentation/ia64/serial.txt +index 6869c73..a63d2c5 100644 +--- a/Documentation/ia64/serial.txt ++++ b/Documentation/ia64/serial.txt +@@ -111,7 +111,7 @@ TROUBLESHOOTING SERIAL CONSOLE PROBLEMS + + - If you don't have an HCDP, the kernel doesn't know where + your console lives until the driver discovers serial +- devices. Use "console=uart, io,0x3f8" (or appropriate ++ devices. Use "console=uart,io,0x3f8" (or appropriate + address for your machine). + + Kernel and init script output works fine, but no "login:" prompt: +diff --git a/Documentation/locking/mutex-design.txt b/Documentation/locking/mutex-design.txt +index 60c482d..818aca1 100644 +--- a/Documentation/locking/mutex-design.txt ++++ b/Documentation/locking/mutex-design.txt +@@ -21,37 +21,23 @@ Implementation + -------------- + + Mutexes are represented by 'struct mutex', defined in include/linux/mutex.h +-and implemented in kernel/locking/mutex.c. These locks use a three +-state atomic counter (->count) to represent the different possible +-transitions that can occur during the lifetime of a lock: +- +- 1: unlocked +- 0: locked, no waiters +- negative: locked, with potential waiters +- +-In its most basic form it also includes a wait-queue and a spinlock +-that serializes access to it. CONFIG_SMP systems can also include +-a pointer to the lock task owner (->owner) as well as a spinner MCS +-lock (->osq), both described below in (ii). ++and implemented in kernel/locking/mutex.c. These locks use an atomic variable ++(->owner) to keep track of the lock state during its lifetime. Field owner ++actually contains 'struct task_struct *' to the current lock owner and it is ++therefore NULL if not currently owned. Since task_struct pointers are aligned ++at at least L1_CACHE_BYTES, low bits (3) are used to store extra state (e.g., ++if waiter list is non-empty). In its most basic form it also includes a ++wait-queue and a spinlock that serializes access to it. Furthermore, ++CONFIG_MUTEX_SPIN_ON_OWNER=y systems use a spinner MCS lock (->osq), described ++below in (ii). + + When acquiring a mutex, there are three possible paths that can be + taken, depending on the state of the lock: + +-(i) fastpath: tries to atomically acquire the lock by decrementing the +- counter. If it was already taken by another task it goes to the next +- possible path. This logic is architecture specific. On x86-64, the +- locking fastpath is 2 instructions: +- +- 0000000000000e10 : +- e21: f0 ff 0b lock decl (%rbx) +- e24: 79 08 jns e2e +- +- the unlocking fastpath is equally tight: +- +- 0000000000000bc0 : +- bc8: f0 ff 07 lock incl (%rdi) +- bcb: 7f 0a jg bd7 +- ++(i) fastpath: tries to atomically acquire the lock by cmpxchg()ing the owner with ++ the current task. This only works in the uncontended case (cmpxchg() checks ++ against 0UL, so all 3 state bits above have to be 0). If the lock is ++ contended it goes to the next possible path. + + (ii) midpath: aka optimistic spinning, tries to spin for acquisition + while the lock owner is running and there are no other tasks ready +@@ -143,11 +129,10 @@ Test if the mutex is taken: + Disadvantages + ------------- + +-Unlike its original design and purpose, 'struct mutex' is larger than +-most locks in the kernel. E.g: on x86-64 it is 40 bytes, almost twice +-as large as 'struct semaphore' (24 bytes) and tied, along with rwsems, +-for the largest lock in the kernel. Larger structure sizes mean more +-CPU cache and memory footprint. ++Unlike its original design and purpose, 'struct mutex' is among the largest ++locks in the kernel. E.g: on x86-64 it is 32 bytes, where 'struct semaphore' ++is 24 bytes and rw_semaphore is 40 bytes. Larger structure sizes mean more CPU ++cache and memory footprint. + + When to use mutexes + ------------------- +diff --git a/Documentation/media/dmx.h.rst.exceptions b/Documentation/media/dmx.h.rst.exceptions +index 63f55a9..a8c4239 100644 +--- a/Documentation/media/dmx.h.rst.exceptions ++++ b/Documentation/media/dmx.h.rst.exceptions +@@ -50,9 +50,15 @@ replace typedef dmx_filter_t :c:type:`dmx_filter` + replace typedef dmx_pes_type_t :c:type:`dmx_pes_type` + replace typedef dmx_input_t :c:type:`dmx_input` + +-ignore symbol DMX_OUT_DECODER +-ignore symbol DMX_OUT_TAP +-ignore symbol DMX_OUT_TS_TAP +-ignore symbol DMX_OUT_TSDEMUX_TAP ++replace symbol DMX_BUFFER_FLAG_HAD_CRC32_DISCARD :c:type:`dmx_buffer_flags` ++replace symbol DMX_BUFFER_FLAG_TEI :c:type:`dmx_buffer_flags` ++replace symbol DMX_BUFFER_PKT_COUNTER_MISMATCH :c:type:`dmx_buffer_flags` ++replace symbol DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED :c:type:`dmx_buffer_flags` ++replace symbol DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR :c:type:`dmx_buffer_flags` ++ ++replace symbol DMX_OUT_DECODER :c:type:`dmx_output` ++replace symbol DMX_OUT_TAP :c:type:`dmx_output` ++replace symbol DMX_OUT_TS_TAP :c:type:`dmx_output` ++replace symbol DMX_OUT_TSDEMUX_TAP :c:type:`dmx_output` + + replace ioctl DMX_DQBUF dmx_qbuf +diff --git a/Documentation/media/uapi/dvb/dmx-qbuf.rst b/Documentation/media/uapi/dvb/dmx-qbuf.rst +index b48c493..be5a4c6 100644 +--- a/Documentation/media/uapi/dvb/dmx-qbuf.rst ++++ b/Documentation/media/uapi/dvb/dmx-qbuf.rst +@@ -51,9 +51,10 @@ out to disk. Buffers remain locked until dequeued, until the + the device is closed. + + Applications call the ``DMX_DQBUF`` ioctl to dequeue a filled +-(capturing) buffer from the driver's outgoing queue. They just set the ``reserved`` field array to zero. When ``DMX_DQBUF`` is called with a +-pointer to this structure, the driver fills the remaining fields or +-returns an error code. ++(capturing) buffer from the driver's outgoing queue. ++They just set the ``index`` field withe the buffer ID to be queued. ++When ``DMX_DQBUF`` is called with a pointer to struct :c:type:`dmx_buffer`, ++the driver fills the remaining fields or returns an error code. + + By default ``DMX_DQBUF`` blocks when no buffer is in the outgoing + queue. When the ``O_NONBLOCK`` flag was given to the +diff --git a/Documentation/networking/segmentation-offloads.txt b/Documentation/networking/segmentation-offloads.txt +index 2f09455..d47480b 100644 +--- a/Documentation/networking/segmentation-offloads.txt ++++ b/Documentation/networking/segmentation-offloads.txt +@@ -13,6 +13,7 @@ The following technologies are described: + * Generic Segmentation Offload - GSO + * Generic Receive Offload - GRO + * Partial Generic Segmentation Offload - GSO_PARTIAL ++ * SCTP accelleration with GSO - GSO_BY_FRAGS + + TCP Segmentation Offload + ======================== +@@ -49,6 +50,10 @@ datagram into multiple IPv4 fragments. Many of the requirements for UDP + fragmentation offload are the same as TSO. However the IPv4 ID for + fragments should not increment as a single IPv4 datagram is fragmented. + ++UFO is deprecated: modern kernels will no longer generate UFO skbs, but can ++still receive them from tuntap and similar devices. Offload of UDP-based ++tunnel protocols is still supported. ++ + IPIP, SIT, GRE, UDP Tunnel, and Remote Checksum Offloads + ======================================================== + +@@ -83,10 +88,10 @@ SKB_GSO_UDP_TUNNEL_CSUM. These two additional tunnel types reflect the + fact that the outer header also requests to have a non-zero checksum + included in the outer header. + +-Finally there is SKB_GSO_REMCSUM which indicates that a given tunnel header +-has requested a remote checksum offload. In this case the inner headers +-will be left with a partial checksum and only the outer header checksum +-will be computed. ++Finally there is SKB_GSO_TUNNEL_REMCSUM which indicates that a given tunnel ++header has requested a remote checksum offload. In this case the inner ++headers will be left with a partial checksum and only the outer header ++checksum will be computed. + + Generic Segmentation Offload + ============================ +@@ -128,3 +133,28 @@ values for if the header was simply duplicated. The one exception to this + is the outer IPv4 ID field. It is up to the device drivers to guarantee + that the IPv4 ID field is incremented in the case that a given header does + not have the DF bit set. ++ ++SCTP accelleration with GSO ++=========================== ++ ++SCTP - despite the lack of hardware support - can still take advantage of ++GSO to pass one large packet through the network stack, rather than ++multiple small packets. ++ ++This requires a different approach to other offloads, as SCTP packets ++cannot be just segmented to (P)MTU. Rather, the chunks must be contained in ++IP segments, padding respected. So unlike regular GSO, SCTP can't just ++generate a big skb, set gso_size to the fragmentation point and deliver it ++to IP layer. ++ ++Instead, the SCTP protocol layer builds an skb with the segments correctly ++padded and stored as chained skbs, and skb_segment() splits based on those. ++To signal this, gso_size is set to the special value GSO_BY_FRAGS. ++ ++Therefore, any code in the core networking stack must be aware of the ++possibility that gso_size will be GSO_BY_FRAGS and handle that case ++appropriately. (For size checks, the skb_gso_validate_*_len family of ++helpers do this automatically.) ++ ++This also affects drivers with the NETIF_F_FRAGLIST & NETIF_F_GSO_SCTP bits ++set. Note also that NETIF_F_GSO_SCTP is included in NETIF_F_GSO_SOFTWARE. +diff --git a/Documentation/sphinx/kerneldoc.py b/Documentation/sphinx/kerneldoc.py +index 39aa9e8..fbedcc3 100644 +--- a/Documentation/sphinx/kerneldoc.py ++++ b/Documentation/sphinx/kerneldoc.py +@@ -36,8 +36,7 @@ import glob + + from docutils import nodes, statemachine + from docutils.statemachine import ViewList +-from docutils.parsers.rst import directives +-from sphinx.util.compat import Directive ++from docutils.parsers.rst import directives, Directive + from sphinx.ext.autodoc import AutodocReporter + + __version__ = '1.0' +diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt +index 792fa87..d6b3ff5 100644 +--- a/Documentation/virtual/kvm/api.txt ++++ b/Documentation/virtual/kvm/api.txt +@@ -123,14 +123,15 @@ memory layout to fit in user mode), check KVM_CAP_MIPS_VZ and use the + flag KVM_VM_MIPS_VZ. + + +-4.3 KVM_GET_MSR_INDEX_LIST ++4.3 KVM_GET_MSR_INDEX_LIST, KVM_GET_MSR_FEATURE_INDEX_LIST + +-Capability: basic ++Capability: basic, KVM_CAP_GET_MSR_FEATURES for KVM_GET_MSR_FEATURE_INDEX_LIST + Architectures: x86 +-Type: system ++Type: system ioctl + Parameters: struct kvm_msr_list (in/out) + Returns: 0 on success; -1 on error + Errors: ++ EFAULT: the msr index list cannot be read from or written to + E2BIG: the msr index list is to be to fit in the array specified by + the user. + +@@ -139,16 +140,23 @@ struct kvm_msr_list { + __u32 indices[0]; + }; + +-This ioctl returns the guest msrs that are supported. The list varies +-by kvm version and host processor, but does not change otherwise. The +-user fills in the size of the indices array in nmsrs, and in return +-kvm adjusts nmsrs to reflect the actual number of msrs and fills in +-the indices array with their numbers. ++The user fills in the size of the indices array in nmsrs, and in return ++kvm adjusts nmsrs to reflect the actual number of msrs and fills in the ++indices array with their numbers. ++ ++KVM_GET_MSR_INDEX_LIST returns the guest msrs that are supported. The list ++varies by kvm version and host processor, but does not change otherwise. + + Note: if kvm indicates supports MCE (KVM_CAP_MCE), then the MCE bank MSRs are + not returned in the MSR list, as different vcpus can have a different number + of banks, as set via the KVM_X86_SETUP_MCE ioctl. + ++KVM_GET_MSR_FEATURE_INDEX_LIST returns the list of MSRs that can be passed ++to the KVM_GET_MSRS system ioctl. This lets userspace probe host capabilities ++and processor features that are exposed via MSRs (e.g., VMX capabilities). ++This list also varies by kvm version and host processor, but does not change ++otherwise. ++ + + 4.4 KVM_CHECK_EXTENSION + +@@ -475,14 +483,22 @@ Support for this has been removed. Use KVM_SET_GUEST_DEBUG instead. + + 4.18 KVM_GET_MSRS + +-Capability: basic ++Capability: basic (vcpu), KVM_CAP_GET_MSR_FEATURES (system) + Architectures: x86 +-Type: vcpu ioctl ++Type: system ioctl, vcpu ioctl + Parameters: struct kvm_msrs (in/out) +-Returns: 0 on success, -1 on error ++Returns: number of msrs successfully returned; ++ -1 on error ++ ++When used as a system ioctl: ++Reads the values of MSR-based features that are available for the VM. This ++is similar to KVM_GET_SUPPORTED_CPUID, but it returns MSR indices and values. ++The list of msr-based features can be obtained using KVM_GET_MSR_FEATURE_INDEX_LIST ++in a system ioctl. + ++When used as a vcpu ioctl: + Reads model-specific registers from the vcpu. Supported msr indices can +-be obtained using KVM_GET_MSR_INDEX_LIST. ++be obtained using KVM_GET_MSR_INDEX_LIST in a system ioctl. + + struct kvm_msrs { + __u32 nmsrs; /* number of msrs in entries */ +diff --git a/Documentation/virtual/kvm/cpuid.txt b/Documentation/virtual/kvm/cpuid.txt +index dcab6dc..87a7506 100644 +--- a/Documentation/virtual/kvm/cpuid.txt ++++ b/Documentation/virtual/kvm/cpuid.txt +@@ -58,6 +58,10 @@ KVM_FEATURE_PV_TLB_FLUSH || 9 || guest checks this feature bit + || || before enabling paravirtualized + || || tlb flush. + ------------------------------------------------------------------------------ ++KVM_FEATURE_ASYNC_PF_VMEXIT || 10 || paravirtualized async PF VM exit ++ || || can be enabled by setting bit 2 ++ || || when writing to msr 0x4b564d02 ++------------------------------------------------------------------------------ + KVM_FEATURE_CLOCKSOURCE_STABLE_BIT || 24 || host will warn if no guest-side + || || per-cpu warps are expected in + || || kvmclock. +diff --git a/Documentation/virtual/kvm/msr.txt b/Documentation/virtual/kvm/msr.txt +index 1ebecc1..f3f0d57 100644 +--- a/Documentation/virtual/kvm/msr.txt ++++ b/Documentation/virtual/kvm/msr.txt +@@ -170,7 +170,8 @@ MSR_KVM_ASYNC_PF_EN: 0x4b564d02 + when asynchronous page faults are enabled on the vcpu 0 when + disabled. Bit 1 is 1 if asynchronous page faults can be injected + when vcpu is in cpl == 0. Bit 2 is 1 if asynchronous page faults +- are delivered to L1 as #PF vmexits. ++ are delivered to L1 as #PF vmexits. Bit 2 can be set only if ++ KVM_FEATURE_ASYNC_PF_VMEXIT is present in CPUID. + + First 4 byte of 64 byte memory location will be written to by + the hypervisor at the time of asynchronous page fault (APF) +diff --git a/Documentation/x86/intel_rdt_ui.txt b/Documentation/x86/intel_rdt_ui.txt +index 756fd76..71c3098 100644 +--- a/Documentation/x86/intel_rdt_ui.txt ++++ b/Documentation/x86/intel_rdt_ui.txt +@@ -671,7 +671,7 @@ occupancy of the real time threads on these cores. + # mkdir p1 + + Move the cpus 4-7 over to p1 +-# echo f0 > p0/cpus ++# echo f0 > p1/cpus + + View the llc occupancy snapshot + +diff --git a/Documentation/x86/topology.txt b/Documentation/x86/topology.txt +index f3e9d7e..2953e3e 100644 +--- a/Documentation/x86/topology.txt ++++ b/Documentation/x86/topology.txt +@@ -108,7 +108,7 @@ The topology of a system is described in the units of: + + The number of online threads is also printed in /proc/cpuinfo "siblings." + +- - topology_sibling_mask(): ++ - topology_sibling_cpumask(): + + The cpumask contains all online threads in the core to which a thread + belongs. +diff --git a/MAINTAINERS b/MAINTAINERS +index 3bdc260..4623caf 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1238,7 +1238,7 @@ F: drivers/clk/at91 + + ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT + M: Nicolas Ferre +-M: Alexandre Belloni ++M: Alexandre Belloni + L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) + W: http://www.linux4sam.org + T: git git://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91.git +@@ -1590,7 +1590,7 @@ ARM/Marvell Dove/MV78xx0/Orion SOC support + M: Jason Cooper + M: Andrew Lunn + M: Sebastian Hesselbarth +-M: Gregory Clement ++M: Gregory Clement + L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) + S: Maintained + F: Documentation/devicetree/bindings/soc/dove/ +@@ -1604,7 +1604,7 @@ F: arch/arm/boot/dts/orion5x* + ARM/Marvell Kirkwood and Armada 370, 375, 38x, 39x, XP, 3700, 7K/8K SOC support + M: Jason Cooper + M: Andrew Lunn +-M: Gregory Clement ++M: Gregory Clement + M: Sebastian Hesselbarth + L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) + S: Maintained +@@ -1999,8 +1999,10 @@ M: Maxime Coquelin + M: Alexandre Torgue + L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) + S: Maintained +-T: git git://git.kernel.org/pub/scm/linux/kernel/git/mcoquelin/stm32.git ++T: git git://git.kernel.org/pub/scm/linux/kernel/git/atorgue/stm32.git stm32-next + N: stm32 ++F: arch/arm/boot/dts/stm32* ++F: arch/arm/mach-stm32/ + F: drivers/clocksource/armv7m_systick.c + + ARM/TANGO ARCHITECTURE +@@ -7600,8 +7602,10 @@ F: mm/kasan/ + F: scripts/Makefile.kasan + + KCONFIG ++M: Masahiro Yamada ++T: git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git kconfig + L: linux-kbuild@vger.kernel.org +-S: Orphan ++S: Maintained + F: Documentation/kbuild/kconfig-language.txt + F: scripts/kconfig/ + +@@ -7909,7 +7913,6 @@ S: Maintained + F: scripts/leaking_addresses.pl + + LED SUBSYSTEM +-M: Richard Purdie + M: Jacek Anaszewski + M: Pavel Machek + L: linux-leds@vger.kernel.org +@@ -9206,6 +9209,7 @@ MIPS GENERIC PLATFORM + M: Paul Burton + L: linux-mips@linux-mips.org + S: Supported ++F: Documentation/devicetree/bindings/power/mti,mips-cpc.txt + F: arch/mips/generic/ + F: arch/mips/tools/generic-board-config.sh + +@@ -9945,6 +9949,7 @@ F: drivers/nfc/nxp-nci + + OBJTOOL + M: Josh Poimboeuf ++M: Peter Zijlstra + S: Supported + F: tools/objtool/ + +@@ -10925,6 +10930,17 @@ L: linux-gpio@vger.kernel.org + S: Supported + F: drivers/pinctrl/pinctrl-at91-pio4.* + ++PIN CONTROLLER - FREESCALE ++M: Dong Aisheng ++M: Fabio Estevam ++M: Shawn Guo ++M: Stefan Agner ++R: Pengutronix Kernel Team ++L: linux-gpio@vger.kernel.org ++S: Maintained ++F: drivers/pinctrl/freescale/ ++F: Documentation/devicetree/bindings/pinctrl/fsl,* ++ + PIN CONTROLLER - INTEL + M: Mika Westerberg + M: Heikki Krogerus +diff --git a/Makefile b/Makefile +index 79ad2bf..e02d092 100644 +--- a/Makefile ++++ b/Makefile +@@ -2,7 +2,7 @@ + VERSION = 4 + PATCHLEVEL = 16 + SUBLEVEL = 0 +-EXTRAVERSION = -rc1 ++EXTRAVERSION = -rc5 + NAME = Fearless Coyote + + # *DOCUMENTATION* +@@ -388,7 +388,7 @@ PYTHON = python + CHECK = sparse + + CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ +- -Wbitwise -Wno-return-void $(CF) ++ -Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF) + NOSTDINC_FLAGS = + CFLAGS_MODULE = + AFLAGS_MODULE = +@@ -489,6 +489,11 @@ KBUILD_CFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC) + KBUILD_AFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC) + endif + ++RETPOLINE_CFLAGS_GCC := -mindirect-branch=thunk-extern -mindirect-branch-register ++RETPOLINE_CFLAGS_CLANG := -mretpoline-external-thunk ++RETPOLINE_CFLAGS := $(call cc-option,$(RETPOLINE_CFLAGS_GCC),$(call cc-option,$(RETPOLINE_CFLAGS_CLANG))) ++export RETPOLINE_CFLAGS ++ + ifeq ($(config-targets),1) + # =========================================================================== + # *config targets only - make sure prerequisites are updated, and descend +@@ -579,10 +584,9 @@ ifeq ($(KBUILD_EXTMOD),) + # To avoid any implicit rule to kick in, define an empty command + $(KCONFIG_CONFIG) include/config/auto.conf.cmd: ; + +-# If .config is newer than include/config/auto.conf, someone tinkered +-# with it and forgot to run make oldconfig. +-# if auto.conf.cmd is missing then we are probably in a cleaned tree so +-# we execute the config step to be sure to catch updated Kconfig files ++# The actual configuration files used during the build are stored in ++# include/generated/ and include/config/. Update them if .config is newer than ++# include/config/auto.conf (which mirrors .config). + include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd + $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig + else +@@ -857,8 +861,7 @@ KBUILD_AFLAGS += $(ARCH_AFLAGS) $(KAFLAGS) + KBUILD_CFLAGS += $(ARCH_CFLAGS) $(KCFLAGS) + + # Use --build-id when available. +-LDFLAGS_BUILD_ID := $(patsubst -Wl$(comma)%,%,\ +- $(call cc-ldoption, -Wl$(comma)--build-id,)) ++LDFLAGS_BUILD_ID := $(call ld-option, --build-id) + KBUILD_LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID) + LDFLAGS_vmlinux += $(LDFLAGS_BUILD_ID) + +diff --git a/arch/alpha/include/asm/cmpxchg.h b/arch/alpha/include/asm/cmpxchg.h +index 46ebf14a..8a2b331 100644 +--- a/arch/alpha/include/asm/cmpxchg.h ++++ b/arch/alpha/include/asm/cmpxchg.h +@@ -6,7 +6,6 @@ + * Atomic exchange routines. + */ + +-#define __ASM__MB + #define ____xchg(type, args...) __xchg ## type ## _local(args) + #define ____cmpxchg(type, args...) __cmpxchg ## type ## _local(args) + #include +@@ -33,10 +32,6 @@ + cmpxchg_local((ptr), (o), (n)); \ + }) + +-#ifdef CONFIG_SMP +-#undef __ASM__MB +-#define __ASM__MB "\tmb\n" +-#endif + #undef ____xchg + #undef ____cmpxchg + #define ____xchg(type, args...) __xchg ##type(args) +@@ -64,7 +59,6 @@ + cmpxchg((ptr), (o), (n)); \ + }) + +-#undef __ASM__MB + #undef ____cmpxchg + + #endif /* _ALPHA_CMPXCHG_H */ +diff --git a/arch/alpha/include/asm/xchg.h b/arch/alpha/include/asm/xchg.h +index 68dfb3c..e2b59fa 100644 +--- a/arch/alpha/include/asm/xchg.h ++++ b/arch/alpha/include/asm/xchg.h +@@ -12,6 +12,10 @@ + * Atomic exchange. + * Since it can be used to implement critical sections + * it must clobber "memory" (also for interrupts in UP). ++ * ++ * The leading and the trailing memory barriers guarantee that these ++ * operations are fully ordered. ++ * + */ + + static inline unsigned long +@@ -19,6 +23,7 @@ ____xchg(_u8, volatile char *m, unsigned long val) + { + unsigned long ret, tmp, addr64; + ++ smp_mb(); + __asm__ __volatile__( + " andnot %4,7,%3\n" + " insbl %1,%4,%1\n" +@@ -28,12 +33,12 @@ ____xchg(_u8, volatile char *m, unsigned long val) + " or %1,%2,%2\n" + " stq_c %2,0(%3)\n" + " beq %2,2f\n" +- __ASM__MB + ".subsection 2\n" + "2: br 1b\n" + ".previous" + : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64) + : "r" ((long)m), "1" (val) : "memory"); ++ smp_mb(); + + return ret; + } +@@ -43,6 +48,7 @@ ____xchg(_u16, volatile short *m, unsigned long val) + { + unsigned long ret, tmp, addr64; + ++ smp_mb(); + __asm__ __volatile__( + " andnot %4,7,%3\n" + " inswl %1,%4,%1\n" +@@ -52,12 +58,12 @@ ____xchg(_u16, volatile short *m, unsigned long val) + " or %1,%2,%2\n" + " stq_c %2,0(%3)\n" + " beq %2,2f\n" +- __ASM__MB + ".subsection 2\n" + "2: br 1b\n" + ".previous" + : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64) + : "r" ((long)m), "1" (val) : "memory"); ++ smp_mb(); + + return ret; + } +@@ -67,17 +73,18 @@ ____xchg(_u32, volatile int *m, unsigned long val) + { + unsigned long dummy; + ++ smp_mb(); + __asm__ __volatile__( + "1: ldl_l %0,%4\n" + " bis $31,%3,%1\n" + " stl_c %1,%2\n" + " beq %1,2f\n" +- __ASM__MB + ".subsection 2\n" + "2: br 1b\n" + ".previous" + : "=&r" (val), "=&r" (dummy), "=m" (*m) + : "rI" (val), "m" (*m) : "memory"); ++ smp_mb(); + + return val; + } +@@ -87,17 +94,18 @@ ____xchg(_u64, volatile long *m, unsigned long val) + { + unsigned long dummy; + ++ smp_mb(); + __asm__ __volatile__( + "1: ldq_l %0,%4\n" + " bis $31,%3,%1\n" + " stq_c %1,%2\n" + " beq %1,2f\n" +- __ASM__MB + ".subsection 2\n" + "2: br 1b\n" + ".previous" + : "=&r" (val), "=&r" (dummy), "=m" (*m) + : "rI" (val), "m" (*m) : "memory"); ++ smp_mb(); + + return val; + } +@@ -128,10 +136,12 @@ ____xchg(, volatile void *ptr, unsigned long x, int size) + * store NEW in MEM. Return the initial value in MEM. Success is + * indicated by comparing RETURN with OLD. + * +- * The memory barrier should be placed in SMP only when we actually +- * make the change. If we don't change anything (so if the returned +- * prev is equal to old) then we aren't acquiring anything new and +- * we don't need any memory barrier as far I can tell. ++ * The leading and the trailing memory barriers guarantee that these ++ * operations are fully ordered. ++ * ++ * The trailing memory barrier is placed in SMP unconditionally, in ++ * order to guarantee that dependency ordering is preserved when a ++ * dependency is headed by an unsuccessful operation. + */ + + static inline unsigned long +@@ -139,6 +149,7 @@ ____cmpxchg(_u8, volatile char *m, unsigned char old, unsigned char new) + { + unsigned long prev, tmp, cmp, addr64; + ++ smp_mb(); + __asm__ __volatile__( + " andnot %5,7,%4\n" + " insbl %1,%5,%1\n" +@@ -150,13 +161,13 @@ ____cmpxchg(_u8, volatile char *m, unsigned char old, unsigned char new) + " or %1,%2,%2\n" + " stq_c %2,0(%4)\n" + " beq %2,3f\n" +- __ASM__MB + "2:\n" + ".subsection 2\n" + "3: br 1b\n" + ".previous" + : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64) + : "r" ((long)m), "Ir" (old), "1" (new) : "memory"); ++ smp_mb(); + + return prev; + } +@@ -166,6 +177,7 @@ ____cmpxchg(_u16, volatile short *m, unsigned short old, unsigned short new) + { + unsigned long prev, tmp, cmp, addr64; + ++ smp_mb(); + __asm__ __volatile__( + " andnot %5,7,%4\n" + " inswl %1,%5,%1\n" +@@ -177,13 +189,13 @@ ____cmpxchg(_u16, volatile short *m, unsigned short old, unsigned short new) + " or %1,%2,%2\n" + " stq_c %2,0(%4)\n" + " beq %2,3f\n" +- __ASM__MB + "2:\n" + ".subsection 2\n" + "3: br 1b\n" + ".previous" + : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64) + : "r" ((long)m), "Ir" (old), "1" (new) : "memory"); ++ smp_mb(); + + return prev; + } +@@ -193,6 +205,7 @@ ____cmpxchg(_u32, volatile int *m, int old, int new) + { + unsigned long prev, cmp; + ++ smp_mb(); + __asm__ __volatile__( + "1: ldl_l %0,%5\n" + " cmpeq %0,%3,%1\n" +@@ -200,13 +213,13 @@ ____cmpxchg(_u32, volatile int *m, int old, int new) + " mov %4,%1\n" + " stl_c %1,%2\n" + " beq %1,3f\n" +- __ASM__MB + "2:\n" + ".subsection 2\n" + "3: br 1b\n" + ".previous" + : "=&r"(prev), "=&r"(cmp), "=m"(*m) + : "r"((long) old), "r"(new), "m"(*m) : "memory"); ++ smp_mb(); + + return prev; + } +@@ -216,6 +229,7 @@ ____cmpxchg(_u64, volatile long *m, unsigned long old, unsigned long new) + { + unsigned long prev, cmp; + ++ smp_mb(); + __asm__ __volatile__( + "1: ldq_l %0,%5\n" + " cmpeq %0,%3,%1\n" +@@ -223,13 +237,13 @@ ____cmpxchg(_u64, volatile long *m, unsigned long old, unsigned long new) + " mov %4,%1\n" + " stq_c %1,%2\n" + " beq %1,3f\n" +- __ASM__MB + "2:\n" + ".subsection 2\n" + "3: br 1b\n" + ".previous" + : "=&r"(prev), "=&r"(cmp), "=m"(*m) + : "r"((long) old), "r"(new), "m"(*m) : "memory"); ++ smp_mb(); + + return prev; + } +diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig +index f3a80cf..d76bf4a 100644 +--- a/arch/arc/Kconfig ++++ b/arch/arc/Kconfig +@@ -484,7 +484,6 @@ config ARC_CURR_IN_REG + + config ARC_EMUL_UNALIGNED + bool "Emulate unaligned memory access (userspace only)" +- default N + select SYSCTL_ARCH_UNALIGN_NO_WARN + select SYSCTL_ARCH_UNALIGN_ALLOW + depends on ISA_ARCOMPACT +diff --git a/arch/arc/boot/dts/axs101.dts b/arch/arc/boot/dts/axs101.dts +index 70aec7d..626b694 100644 +--- a/arch/arc/boot/dts/axs101.dts ++++ b/arch/arc/boot/dts/axs101.dts +@@ -17,6 +17,6 @@ + compatible = "snps,axs101", "snps,arc-sdp"; + + chosen { +- bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 consoleblank=0 video=1280x720@60"; ++ bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 consoleblank=0 video=1280x720@60 print-fatal-signals=1"; + }; + }; +diff --git a/arch/arc/boot/dts/axs10x_mb.dtsi b/arch/arc/boot/dts/axs10x_mb.dtsi +index 74d070c..47b74fb 100644 +--- a/arch/arc/boot/dts/axs10x_mb.dtsi ++++ b/arch/arc/boot/dts/axs10x_mb.dtsi +@@ -214,13 +214,13 @@ + }; + + eeprom@0x54{ +- compatible = "24c01"; ++ compatible = "atmel,24c01"; + reg = <0x54>; + pagesize = <0x8>; + }; + + eeprom@0x57{ +- compatible = "24c04"; ++ compatible = "atmel,24c04"; + reg = <0x57>; + pagesize = <0x8>; + }; +diff --git a/arch/arc/boot/dts/haps_hs_idu.dts b/arch/arc/boot/dts/haps_hs_idu.dts +index 215cddd..0c60330 100644 +--- a/arch/arc/boot/dts/haps_hs_idu.dts ++++ b/arch/arc/boot/dts/haps_hs_idu.dts +@@ -22,7 +22,7 @@ + }; + + chosen { +- bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=ttyS0,115200n8 debug"; ++ bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=ttyS0,115200n8 debug print-fatal-signals=1"; + }; + + aliases { +diff --git a/arch/arc/boot/dts/nsim_700.dts b/arch/arc/boot/dts/nsim_700.dts +index 5ee96b0..ff2f2c7 100644 +--- a/arch/arc/boot/dts/nsim_700.dts ++++ b/arch/arc/boot/dts/nsim_700.dts +@@ -17,7 +17,7 @@ + interrupt-parent = <&core_intc>; + + chosen { +- bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8"; ++ bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8 print-fatal-signals=1"; + }; + + aliases { +diff --git a/arch/arc/boot/dts/nsim_hs.dts b/arch/arc/boot/dts/nsim_hs.dts +index 8d787b2..8e2489b 100644 +--- a/arch/arc/boot/dts/nsim_hs.dts ++++ b/arch/arc/boot/dts/nsim_hs.dts +@@ -24,7 +24,7 @@ + }; + + chosen { +- bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8"; ++ bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8 print-fatal-signals=1"; + }; + + aliases { +diff --git a/arch/arc/boot/dts/nsim_hs_idu.dts b/arch/arc/boot/dts/nsim_hs_idu.dts +index 4f98ebf..ed12f4947 100644 +--- a/arch/arc/boot/dts/nsim_hs_idu.dts ++++ b/arch/arc/boot/dts/nsim_hs_idu.dts +@@ -15,7 +15,7 @@ + interrupt-parent = <&core_intc>; + + chosen { +- bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8"; ++ bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8 print-fatal-signals=1"; + }; + + aliases { +diff --git a/arch/arc/boot/dts/nsimosci.dts b/arch/arc/boot/dts/nsimosci.dts +index 3c391ba..7842e5e 100644 +--- a/arch/arc/boot/dts/nsimosci.dts ++++ b/arch/arc/boot/dts/nsimosci.dts +@@ -20,7 +20,7 @@ + /* this is for console on PGU */ + /* bootargs = "console=tty0 consoleblank=0"; */ + /* this is for console on serial */ +- bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug video=640x480-24"; ++ bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug video=640x480-24 print-fatal-signals=1"; + }; + + aliases { +diff --git a/arch/arc/boot/dts/nsimosci_hs.dts b/arch/arc/boot/dts/nsimosci_hs.dts +index 14a727c..b8838cf 100644 +--- a/arch/arc/boot/dts/nsimosci_hs.dts ++++ b/arch/arc/boot/dts/nsimosci_hs.dts +@@ -20,7 +20,7 @@ + /* this is for console on PGU */ + /* bootargs = "console=tty0 consoleblank=0"; */ + /* this is for console on serial */ +- bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug video=640x480-24"; ++ bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug video=640x480-24 print-fatal-signals=1"; + }; + + aliases { +diff --git a/arch/arc/boot/dts/nsimosci_hs_idu.dts b/arch/arc/boot/dts/nsimosci_hs_idu.dts +index 5052917..72a2c72 100644 +--- a/arch/arc/boot/dts/nsimosci_hs_idu.dts ++++ b/arch/arc/boot/dts/nsimosci_hs_idu.dts +@@ -18,7 +18,7 @@ + + chosen { + /* this is for console on serial */ +- bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblan=0 debug video=640x480-24"; ++ bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblan=0 debug video=640x480-24 print-fatal-signals=1"; + }; + + aliases { +diff --git a/arch/arc/include/asm/bug.h b/arch/arc/include/asm/bug.h +index ea022d4..21ec824 100644 +--- a/arch/arc/include/asm/bug.h ++++ b/arch/arc/include/asm/bug.h +@@ -23,7 +23,8 @@ void die(const char *str, struct pt_regs *regs, unsigned long address); + + #define BUG() do { \ + pr_warn("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \ +- dump_stack(); \ ++ barrier_before_unreachable(); \ ++ __builtin_trap(); \ + } while (0) + + #define HAVE_ARCH_BUG +diff --git a/arch/arc/include/asm/entry-arcv2.h b/arch/arc/include/asm/entry-arcv2.h +index 257a68f..309f4e6 100644 +--- a/arch/arc/include/asm/entry-arcv2.h ++++ b/arch/arc/include/asm/entry-arcv2.h +@@ -184,7 +184,7 @@ + .macro FAKE_RET_FROM_EXCPN + lr r9, [status32] + bic r9, r9, (STATUS_U_MASK|STATUS_DE_MASK|STATUS_AE_MASK) +- or r9, r9, (STATUS_L_MASK|STATUS_IE_MASK) ++ or r9, r9, STATUS_IE_MASK + kflag r9 + .endm + +diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c +index f61a52b..5fe84e4 100644 +--- a/arch/arc/kernel/mcip.c ++++ b/arch/arc/kernel/mcip.c +@@ -22,10 +22,79 @@ static DEFINE_RAW_SPINLOCK(mcip_lock); + + static char smp_cpuinfo_buf[128]; + ++/* ++ * Set mask to halt GFRC if any online core in SMP cluster is halted. ++ * Only works for ARC HS v3.0+, on earlier versions has no effect. ++ */ ++static void mcip_update_gfrc_halt_mask(int cpu) ++{ ++ struct bcr_generic gfrc; ++ unsigned long flags; ++ u32 gfrc_halt_mask; ++ ++ READ_BCR(ARC_REG_GFRC_BUILD, gfrc); ++ ++ /* ++ * CMD_GFRC_SET_CORE and CMD_GFRC_READ_CORE commands were added in ++ * GFRC 0x3 version. ++ */ ++ if (gfrc.ver < 0x3) ++ return; ++ ++ raw_spin_lock_irqsave(&mcip_lock, flags); ++ ++ __mcip_cmd(CMD_GFRC_READ_CORE, 0); ++ gfrc_halt_mask = read_aux_reg(ARC_REG_MCIP_READBACK); ++ gfrc_halt_mask |= BIT(cpu); ++ __mcip_cmd_data(CMD_GFRC_SET_CORE, 0, gfrc_halt_mask); ++ ++ raw_spin_unlock_irqrestore(&mcip_lock, flags); ++} ++ ++static void mcip_update_debug_halt_mask(int cpu) ++{ ++ u32 mcip_mask = 0; ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&mcip_lock, flags); ++ ++ /* ++ * mcip_mask is same for CMD_DEBUG_SET_SELECT and CMD_DEBUG_SET_MASK ++ * commands. So read it once instead of reading both CMD_DEBUG_READ_MASK ++ * and CMD_DEBUG_READ_SELECT. ++ */ ++ __mcip_cmd(CMD_DEBUG_READ_SELECT, 0); ++ mcip_mask = read_aux_reg(ARC_REG_MCIP_READBACK); ++ ++ mcip_mask |= BIT(cpu); ++ ++ __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, mcip_mask); ++ /* ++ * Parameter specified halt cause: ++ * STATUS32[H]/actionpoint/breakpoint/self-halt ++ * We choose all of them (0xF). ++ */ ++ __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xF, mcip_mask); ++ ++ raw_spin_unlock_irqrestore(&mcip_lock, flags); ++} ++ + static void mcip_setup_per_cpu(int cpu) + { ++ struct mcip_bcr mp; ++ ++ READ_BCR(ARC_REG_MCIP_BCR, mp); ++ + smp_ipi_irq_setup(cpu, IPI_IRQ); + smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ); ++ ++ /* Update GFRC halt mask as new CPU came online */ ++ if (mp.gfrc) ++ mcip_update_gfrc_halt_mask(cpu); ++ ++ /* Update MCIP debug mask as new CPU came online */ ++ if (mp.dbg) ++ mcip_update_debug_halt_mask(cpu); + } + + static void mcip_ipi_send(int cpu) +@@ -101,11 +170,6 @@ static void mcip_probe_n_setup(void) + IS_AVAIL1(mp.gfrc, "GFRC")); + + cpuinfo_arc700[0].extn.gfrc = mp.gfrc; +- +- if (mp.dbg) { +- __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, 0xf); +- __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xf, 0xf); +- } + } + + struct plat_smp_ops plat_smp_ops = { +diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c +index 9d27331..b2cae79 100644 +--- a/arch/arc/kernel/setup.c ++++ b/arch/arc/kernel/setup.c +@@ -51,7 +51,7 @@ static const struct id_to_str arc_cpu_rel[] = { + { 0x51, "R2.0" }, + { 0x52, "R2.1" }, + { 0x53, "R3.0" }, +- { 0x54, "R4.0" }, ++ { 0x54, "R3.10a" }, + #endif + { 0x00, NULL } + }; +@@ -373,7 +373,7 @@ static void arc_chk_core_config(void) + { + struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()]; + int saved = 0, present = 0; +- char *opt_nm = NULL;; ++ char *opt_nm = NULL; + + if (!cpu->extn.timer0) + panic("Timer0 is not present!\n"); +diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c +index efe8b42..21d86c3 100644 +--- a/arch/arc/kernel/smp.c ++++ b/arch/arc/kernel/smp.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -47,6 +48,42 @@ void __init smp_prepare_boot_cpu(void) + { + } + ++static int __init arc_get_cpu_map(const char *name, struct cpumask *cpumask) ++{ ++ unsigned long dt_root = of_get_flat_dt_root(); ++ const char *buf; ++ ++ buf = of_get_flat_dt_prop(dt_root, name, NULL); ++ if (!buf) ++ return -EINVAL; ++ ++ if (cpulist_parse(buf, cpumask)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++/* ++ * Read from DeviceTree and setup cpu possible mask. If there is no ++ * "possible-cpus" property in DeviceTree pretend all [0..NR_CPUS-1] exist. ++ */ ++static void __init arc_init_cpu_possible(void) ++{ ++ struct cpumask cpumask; ++ ++ if (arc_get_cpu_map("possible-cpus", &cpumask)) { ++ pr_warn("Failed to get possible-cpus from dtb, pretending all %u cpus exist\n", ++ NR_CPUS); ++ ++ cpumask_setall(&cpumask); ++ } ++ ++ if (!cpumask_test_cpu(0, &cpumask)) ++ panic("Master cpu (cpu[0]) is missed in cpu possible mask!"); ++ ++ init_cpu_possible(&cpumask); ++} ++ + /* + * Called from setup_arch() before calling setup_processor() + * +@@ -58,10 +95,7 @@ void __init smp_prepare_boot_cpu(void) + */ + void __init smp_init_cpus(void) + { +- unsigned int i; +- +- for (i = 0; i < NR_CPUS; i++) +- set_cpu_possible(i, true); ++ arc_init_cpu_possible(); + + if (plat_smp_ops.init_early_smp) + plat_smp_ops.init_early_smp(); +@@ -70,16 +104,12 @@ void __init smp_init_cpus(void) + /* called from init ( ) => process 1 */ + void __init smp_prepare_cpus(unsigned int max_cpus) + { +- int i; +- + /* + * if platform didn't set the present map already, do it now + * boot cpu is set to present already by init/main.c + */ +- if (num_present_cpus() <= 1) { +- for (i = 0; i < max_cpus; i++) +- set_cpu_present(i, true); +- } ++ if (num_present_cpus() <= 1) ++ init_cpu_present(cpu_possible_mask); + } + + void __init smp_cpus_done(unsigned int max_cpus) +diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c +index 333daab..183391d 100644 +--- a/arch/arc/kernel/unwind.c ++++ b/arch/arc/kernel/unwind.c +@@ -366,7 +366,7 @@ static void init_unwind_hdr(struct unwind_table *table, + return; + + ret_err: +- panic("Attention !!! Dwarf FDE parsing errors\n");; ++ panic("Attention !!! Dwarf FDE parsing errors\n"); + } + + #ifdef CONFIG_MODULES +diff --git a/arch/arc/mm/cache.c b/arch/arc/mm/cache.c +index eee924d..2072f34 100644 +--- a/arch/arc/mm/cache.c ++++ b/arch/arc/mm/cache.c +@@ -780,7 +780,10 @@ noinline static void slc_entire_op(const int op) + + write_aux_reg(r, ctrl); + +- write_aux_reg(ARC_REG_SLC_INVALIDATE, 1); ++ if (op & OP_INV) /* Inv or flush-n-inv use same cmd reg */ ++ write_aux_reg(ARC_REG_SLC_INVALIDATE, 0x1); ++ else ++ write_aux_reg(ARC_REG_SLC_FLUSH, 0x1); + + /* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */ + read_aux_reg(r); +diff --git a/arch/arm/boot/dts/bcm11351.dtsi b/arch/arm/boot/dts/bcm11351.dtsi +index 18045c3..db7cded 100644 +--- a/arch/arm/boot/dts/bcm11351.dtsi ++++ b/arch/arm/boot/dts/bcm11351.dtsi +@@ -55,7 +55,7 @@ + <0x3ff00100 0x100>; + }; + +- smc@0x3404c000 { ++ smc@3404c000 { + compatible = "brcm,bcm11351-smc", "brcm,kona-smc"; + reg = <0x3404c000 0x400>; /* 1 KiB in SRAM */ + }; +diff --git a/arch/arm/boot/dts/bcm21664.dtsi b/arch/arm/boot/dts/bcm21664.dtsi +index 6dde95f..266f261 100644 +--- a/arch/arm/boot/dts/bcm21664.dtsi ++++ b/arch/arm/boot/dts/bcm21664.dtsi +@@ -55,7 +55,7 @@ + <0x3ff00100 0x100>; + }; + +- smc@0x3404e000 { ++ smc@3404e000 { + compatible = "brcm,bcm21664-smc", "brcm,kona-smc"; + reg = <0x3404e000 0x400>; /* 1 KiB in SRAM */ + }; +diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi +index 0e3d2a5..a5c3824 100644 +--- a/arch/arm/boot/dts/bcm2835.dtsi ++++ b/arch/arm/boot/dts/bcm2835.dtsi +@@ -18,10 +18,10 @@ + soc { + ranges = <0x7e000000 0x20000000 0x02000000>; + dma-ranges = <0x40000000 0x00000000 0x20000000>; ++ }; + +- arm-pmu { +- compatible = "arm,arm1176-pmu"; +- }; ++ arm-pmu { ++ compatible = "arm,arm1176-pmu"; + }; + }; + +diff --git a/arch/arm/boot/dts/bcm2836.dtsi b/arch/arm/boot/dts/bcm2836.dtsi +index 1dfd764..c933e84 100644 +--- a/arch/arm/boot/dts/bcm2836.dtsi ++++ b/arch/arm/boot/dts/bcm2836.dtsi +@@ -9,19 +9,19 @@ + <0x40000000 0x40000000 0x00001000>; + dma-ranges = <0xc0000000 0x00000000 0x3f000000>; + +- local_intc: local_intc { ++ local_intc: local_intc@40000000 { + compatible = "brcm,bcm2836-l1-intc"; + reg = <0x40000000 0x100>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&local_intc>; + }; ++ }; + +- arm-pmu { +- compatible = "arm,cortex-a7-pmu"; +- interrupt-parent = <&local_intc>; +- interrupts = <9 IRQ_TYPE_LEVEL_HIGH>; +- }; ++ arm-pmu { ++ compatible = "arm,cortex-a7-pmu"; ++ interrupt-parent = <&local_intc>; ++ interrupts = <9 IRQ_TYPE_LEVEL_HIGH>; + }; + + timer { +diff --git a/arch/arm/boot/dts/bcm2837.dtsi b/arch/arm/boot/dts/bcm2837.dtsi +index efa7d33..7704bb0 100644 +--- a/arch/arm/boot/dts/bcm2837.dtsi ++++ b/arch/arm/boot/dts/bcm2837.dtsi +@@ -8,7 +8,7 @@ + <0x40000000 0x40000000 0x00001000>; + dma-ranges = <0xc0000000 0x00000000 0x3f000000>; + +- local_intc: local_intc { ++ local_intc: local_intc@40000000 { + compatible = "brcm,bcm2836-l1-intc"; + reg = <0x40000000 0x100>; + interrupt-controller; +diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi +index 18db25a..9d293de 100644 +--- a/arch/arm/boot/dts/bcm283x.dtsi ++++ b/arch/arm/boot/dts/bcm283x.dtsi +@@ -465,7 +465,7 @@ + status = "disabled"; + }; + +- aux: aux@0x7e215000 { ++ aux: aux@7e215000 { + compatible = "brcm,bcm2835-aux"; + #clock-cells = <1>; + reg = <0x7e215000 0x8>; +diff --git a/arch/arm/boot/dts/bcm958625hr.dts b/arch/arm/boot/dts/bcm958625hr.dts +index 6a44b80..f0e2008 100644 +--- a/arch/arm/boot/dts/bcm958625hr.dts ++++ b/arch/arm/boot/dts/bcm958625hr.dts +@@ -49,7 +49,7 @@ + + memory { + device_type = "memory"; +- reg = <0x60000000 0x80000000>; ++ reg = <0x60000000 0x20000000>; + }; + + gpio-restart { +diff --git a/arch/arm/boot/dts/gemini-dlink-dns-313.dts b/arch/arm/boot/dts/gemini-dlink-dns-313.dts +index 08568ce..da8bb9d 100644 +--- a/arch/arm/boot/dts/gemini-dlink-dns-313.dts ++++ b/arch/arm/boot/dts/gemini-dlink-dns-313.dts +@@ -269,7 +269,7 @@ + + sata: sata@46000000 { + /* The ROM uses this muxmode */ +- cortina,gemini-ata-muxmode = <3>; ++ cortina,gemini-ata-muxmode = <0>; + cortina,gemini-enable-sata-bridge; + status = "okay"; + }; +diff --git a/arch/arm/boot/dts/imx6dl-icore-rqs.dts b/arch/arm/boot/dts/imx6dl-icore-rqs.dts +index cf42c2f..1281bc3 100644 +--- a/arch/arm/boot/dts/imx6dl-icore-rqs.dts ++++ b/arch/arm/boot/dts/imx6dl-icore-rqs.dts +@@ -42,7 +42,7 @@ + + /dts-v1/; + +-#include "imx6q.dtsi" ++#include "imx6dl.dtsi" + #include "imx6qdl-icore-rqs.dtsi" + + / { +diff --git a/arch/arm/boot/dts/logicpd-som-lv.dtsi b/arch/arm/boot/dts/logicpd-som-lv.dtsi +index c1aa7a4..a30ee9f 100644 +--- a/arch/arm/boot/dts/logicpd-som-lv.dtsi ++++ b/arch/arm/boot/dts/logicpd-som-lv.dtsi +@@ -71,6 +71,8 @@ + }; + + &i2c1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c1_pins>; + clock-frequency = <2600000>; + + twl: twl@48 { +@@ -189,7 +191,12 @@ + >; + }; + +- ++ i2c1_pins: pinmux_i2c1_pins { ++ pinctrl-single,pins = < ++ OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT | MUX_MODE0) /* i2c1_scl.i2c1_scl */ ++ OMAP3_CORE1_IOPAD(0x21bc, PIN_INPUT | MUX_MODE0) /* i2c1_sda.i2c1_sda */ ++ >; ++ }; + }; + + &omap3_pmx_wkup { +diff --git a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi +index b50b796..4791544 100644 +--- a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi ++++ b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi +@@ -66,6 +66,8 @@ + }; + + &i2c1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c1_pins>; + clock-frequency = <2600000>; + + twl: twl@48 { +@@ -136,6 +138,12 @@ + OMAP3_CORE1_IOPAD(0x21b8, PIN_INPUT | MUX_MODE0) /* hsusb0_data7.hsusb0_data7 */ + >; + }; ++ i2c1_pins: pinmux_i2c1_pins { ++ pinctrl-single,pins = < ++ OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT | MUX_MODE0) /* i2c1_scl.i2c1_scl */ ++ OMAP3_CORE1_IOPAD(0x21bc, PIN_INPUT | MUX_MODE0) /* i2c1_sda.i2c1_sda */ ++ >; ++ }; + }; + + &uart2 { +diff --git a/arch/arm/boot/dts/omap5-uevm.dts b/arch/arm/boot/dts/omap5-uevm.dts +index ec2c8ba..592e17f 100644 +--- a/arch/arm/boot/dts/omap5-uevm.dts ++++ b/arch/arm/boot/dts/omap5-uevm.dts +@@ -47,7 +47,7 @@ + gpios = <&gpio3 19 GPIO_ACTIVE_LOW>; /* gpio3_83 */ + wakeup-source; + autorepeat; +- debounce_interval = <50>; ++ debounce-interval = <50>; + }; + }; + +diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi +index 3b704cf..a974581 100644 +--- a/arch/arm/boot/dts/rk3036.dtsi ++++ b/arch/arm/boot/dts/rk3036.dtsi +@@ -280,7 +280,7 @@ + max-frequency = <37500000>; + clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>, + <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>; +- clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; ++ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + fifo-depth = <0x100>; + interrupts = ; + resets = <&cru SRST_SDIO>; +@@ -298,7 +298,7 @@ + max-frequency = <37500000>; + clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>, + <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; +- clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; ++ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + default-sample-phase = <158>; + disable-wp; + dmas = <&pdma 12>; +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 780ec3a..341deaf 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -621,7 +621,7 @@ + interrupts = ; + clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>, + <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>; +- clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; ++ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + fifo-depth = <0x100>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4>; +@@ -634,7 +634,7 @@ + interrupts = ; + clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>, + <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>; +- clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; ++ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + fifo-depth = <0x100>; + pinctrl-names = "default"; + pinctrl-0 = <&sdio_clk &sdio_cmd &sdio_bus4>; +@@ -649,7 +649,7 @@ + max-frequency = <37500000>; + clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>, + <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; +- clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; ++ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + bus-width = <8>; + default-sample-phase = <158>; + fifo-depth = <0x100>; +diff --git a/arch/arm/boot/dts/rk3288-phycore-som.dtsi b/arch/arm/boot/dts/rk3288-phycore-som.dtsi +index 99cfae8..5eae477 100644 +--- a/arch/arm/boot/dts/rk3288-phycore-som.dtsi ++++ b/arch/arm/boot/dts/rk3288-phycore-som.dtsi +@@ -110,26 +110,6 @@ + }; + }; + +-&cpu0 { +- cpu0-supply = <&vdd_cpu>; +- operating-points = < +- /* KHz uV */ +- 1800000 1400000 +- 1608000 1350000 +- 1512000 1300000 +- 1416000 1200000 +- 1200000 1100000 +- 1008000 1050000 +- 816000 1000000 +- 696000 950000 +- 600000 900000 +- 408000 900000 +- 312000 900000 +- 216000 900000 +- 126000 900000 +- >; +-}; +- + &emmc { + status = "okay"; + bus-width = <8>; +diff --git a/arch/arm/boot/dts/zx296702.dtsi b/arch/arm/boot/dts/zx296702.dtsi +index 8a74efd..240e7a2 100644 +--- a/arch/arm/boot/dts/zx296702.dtsi ++++ b/arch/arm/boot/dts/zx296702.dtsi +@@ -56,7 +56,7 @@ + clocks = <&topclk ZX296702_A9_PERIPHCLK>; + }; + +- l2cc: l2-cache-controller@0x00c00000 { ++ l2cc: l2-cache-controller@c00000 { + compatible = "arm,pl310-cache"; + reg = <0x00c00000 0x1000>; + cache-unified; +@@ -67,30 +67,30 @@ + arm,double-linefill-incr = <0>; + }; + +- pcu: pcu@0xa0008000 { ++ pcu: pcu@a0008000 { + compatible = "zte,zx296702-pcu"; + reg = <0xa0008000 0x1000>; + }; + +- topclk: topclk@0x09800000 { ++ topclk: topclk@9800000 { + compatible = "zte,zx296702-topcrm-clk"; + reg = <0x09800000 0x1000>; + #clock-cells = <1>; + }; + +- lsp1clk: lsp1clk@0x09400000 { ++ lsp1clk: lsp1clk@9400000 { + compatible = "zte,zx296702-lsp1crpm-clk"; + reg = <0x09400000 0x1000>; + #clock-cells = <1>; + }; + +- lsp0clk: lsp0clk@0x0b000000 { ++ lsp0clk: lsp0clk@b000000 { + compatible = "zte,zx296702-lsp0crpm-clk"; + reg = <0x0b000000 0x1000>; + #clock-cells = <1>; + }; + +- uart0: serial@0x09405000 { ++ uart0: serial@9405000 { + compatible = "zte,zx296702-uart"; + reg = <0x09405000 0x1000>; + interrupts = ; +@@ -98,7 +98,7 @@ + status = "disabled"; + }; + +- uart1: serial@0x09406000 { ++ uart1: serial@9406000 { + compatible = "zte,zx296702-uart"; + reg = <0x09406000 0x1000>; + interrupts = ; +@@ -106,7 +106,7 @@ + status = "disabled"; + }; + +- mmc0: mmc@0x09408000 { ++ mmc0: mmc@9408000 { + compatible = "snps,dw-mshc"; + #address-cells = <1>; + #size-cells = <0>; +@@ -119,7 +119,7 @@ + status = "disabled"; + }; + +- mmc1: mmc@0x0b003000 { ++ mmc1: mmc@b003000 { + compatible = "snps,dw-mshc"; + #address-cells = <1>; + #size-cells = <0>; +@@ -132,7 +132,7 @@ + status = "disabled"; + }; + +- sysctrl: sysctrl@0xa0007000 { ++ sysctrl: sysctrl@a0007000 { + compatible = "zte,sysctrl", "syscon"; + reg = <0xa0007000 0x1000>; + }; +diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig +index 2f145c4..92674f2 100644 +--- a/arch/arm/configs/omap2plus_defconfig ++++ b/arch/arm/configs/omap2plus_defconfig +@@ -319,7 +319,7 @@ CONFIG_MEDIA_CAMERA_SUPPORT=y + CONFIG_RC_CORE=m + CONFIG_MEDIA_CONTROLLER=y + CONFIG_VIDEO_V4L2_SUBDEV_API=y +-CONFIG_LIRC=m ++CONFIG_LIRC=y + CONFIG_RC_DEVICES=y + CONFIG_IR_RX51=m + CONFIG_V4L_PLATFORM_DRIVERS=y +diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c +index 629f8e9..cf2701c 100644 +--- a/arch/arm/kernel/time.c ++++ b/arch/arm/kernel/time.c +@@ -83,7 +83,7 @@ static void dummy_clock_access(struct timespec64 *ts) + } + + static clock_access_fn __read_persistent_clock = dummy_clock_access; +-static clock_access_fn __read_boot_clock = dummy_clock_access;; ++static clock_access_fn __read_boot_clock = dummy_clock_access; + + void read_persistent_clock64(struct timespec64 *ts) + { +diff --git a/arch/arm/kvm/hyp/Makefile b/arch/arm/kvm/hyp/Makefile +index 5638ce0..63d6b40 100644 +--- a/arch/arm/kvm/hyp/Makefile ++++ b/arch/arm/kvm/hyp/Makefile +@@ -7,6 +7,8 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING + + KVM=../../../../virt/kvm + ++CFLAGS_ARMV7VE :=$(call cc-option, -march=armv7ve) ++ + obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o + obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o + obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o +@@ -15,7 +17,10 @@ obj-$(CONFIG_KVM_ARM_HOST) += tlb.o + obj-$(CONFIG_KVM_ARM_HOST) += cp15-sr.o + obj-$(CONFIG_KVM_ARM_HOST) += vfp.o + obj-$(CONFIG_KVM_ARM_HOST) += banked-sr.o ++CFLAGS_banked-sr.o += $(CFLAGS_ARMV7VE) ++ + obj-$(CONFIG_KVM_ARM_HOST) += entry.o + obj-$(CONFIG_KVM_ARM_HOST) += hyp-entry.o + obj-$(CONFIG_KVM_ARM_HOST) += switch.o ++CFLAGS_switch.o += $(CFLAGS_ARMV7VE) + obj-$(CONFIG_KVM_ARM_HOST) += s2-setup.o +diff --git a/arch/arm/kvm/hyp/banked-sr.c b/arch/arm/kvm/hyp/banked-sr.c +index 111bda8..be4b8b0 100644 +--- a/arch/arm/kvm/hyp/banked-sr.c ++++ b/arch/arm/kvm/hyp/banked-sr.c +@@ -20,6 +20,10 @@ + + #include + ++/* ++ * gcc before 4.9 doesn't understand -march=armv7ve, so we have to ++ * trick the assembler. ++ */ + __asm__(".arch_extension virt"); + + void __hyp_text __banked_save_state(struct kvm_cpu_context *ctxt) +diff --git a/arch/arm/mach-clps711x/board-dt.c b/arch/arm/mach-clps711x/board-dt.c +index ee1f83b..4c89a8e 100644 +--- a/arch/arm/mach-clps711x/board-dt.c ++++ b/arch/arm/mach-clps711x/board-dt.c +@@ -69,7 +69,7 @@ static void clps711x_restart(enum reboot_mode mode, const char *cmd) + soft_restart(0); + } + +-static const char *clps711x_compat[] __initconst = { ++static const char *const clps711x_compat[] __initconst = { + "cirrus,ep7209", + NULL + }; +diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c +index e457f29..d6b1190 100644 +--- a/arch/arm/mach-davinci/board-dm355-evm.c ++++ b/arch/arm/mach-davinci/board-dm355-evm.c +@@ -368,7 +368,7 @@ static struct spi_eeprom at25640a = { + .flags = EE_ADDR2, + }; + +-static struct spi_board_info dm355_evm_spi_info[] __initconst = { ++static const struct spi_board_info dm355_evm_spi_info[] __initconst = { + { + .modalias = "at25", + .platform_data = &at25640a, +diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c +index be99724..fad9a56 100644 +--- a/arch/arm/mach-davinci/board-dm355-leopard.c ++++ b/arch/arm/mach-davinci/board-dm355-leopard.c +@@ -217,7 +217,7 @@ static struct spi_eeprom at25640a = { + .flags = EE_ADDR2, + }; + +-static struct spi_board_info dm355_leopard_spi_info[] __initconst = { ++static const struct spi_board_info dm355_leopard_spi_info[] __initconst = { + { + .modalias = "at25", + .platform_data = &at25640a, +diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c +index e75741f..e378098 100644 +--- a/arch/arm/mach-davinci/board-dm365-evm.c ++++ b/arch/arm/mach-davinci/board-dm365-evm.c +@@ -726,7 +726,7 @@ static struct spi_eeprom at25640 = { + .flags = EE_ADDR2, + }; + +-static struct spi_board_info dm365_evm_spi_info[] __initconst = { ++static const struct spi_board_info dm365_evm_spi_info[] __initconst = { + { + .modalias = "at25", + .platform_data = &at25640, +diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig +index 6b32dc5..2c20599 100644 +--- a/arch/arm/mach-mvebu/Kconfig ++++ b/arch/arm/mach-mvebu/Kconfig +@@ -41,7 +41,7 @@ config MACH_ARMADA_375 + depends on ARCH_MULTI_V7 + select ARMADA_370_XP_IRQ + select ARM_ERRATA_720789 +- select ARM_ERRATA_753970 ++ select PL310_ERRATA_753970 + select ARM_GIC + select ARMADA_375_CLK + select HAVE_ARM_SCU +@@ -57,7 +57,7 @@ config MACH_ARMADA_38X + bool "Marvell Armada 380/385 boards" + depends on ARCH_MULTI_V7 + select ARM_ERRATA_720789 +- select ARM_ERRATA_753970 ++ select PL310_ERRATA_753970 + select ARM_GIC + select ARM_GLOBAL_TIMER + select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK +diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c +index 43e3e18..fa51241 100644 +--- a/arch/arm/mach-omap1/clock.c ++++ b/arch/arm/mach-omap1/clock.c +@@ -1011,17 +1011,17 @@ static int clk_debugfs_register_one(struct clk *c) + return -ENOMEM; + c->dent = d; + +- d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount); ++ d = debugfs_create_u8("usecount", S_IRUGO, c->dent, &c->usecount); + if (!d) { + err = -ENOMEM; + goto err_out; + } +- d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate); ++ d = debugfs_create_ulong("rate", S_IRUGO, c->dent, &c->rate); + if (!d) { + err = -ENOMEM; + goto err_out; + } +- d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags); ++ d = debugfs_create_x8("flags", S_IRUGO, c->dent, &c->flags); + if (!d) { + err = -ENOMEM; + goto err_out; +diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c +index 4bb6751..fc5fb77 100644 +--- a/arch/arm/mach-omap2/omap-wakeupgen.c ++++ b/arch/arm/mach-omap2/omap-wakeupgen.c +@@ -299,8 +299,6 @@ static void irq_save_context(void) + if (soc_is_dra7xx()) + return; + +- if (!sar_base) +- sar_base = omap4_get_sar_ram_base(); + if (wakeupgen_ops && wakeupgen_ops->save_context) + wakeupgen_ops->save_context(); + } +@@ -598,6 +596,8 @@ static int __init wakeupgen_init(struct device_node *node, + irq_hotplug_init(); + irq_pm_init(); + ++ sar_base = omap4_get_sar_ram_base(); ++ + return 0; + } + IRQCHIP_DECLARE(ti_wakeupgen, "ti,omap4-wugen-mpu", wakeupgen_init); +diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c +index 124f9af..34156ec 100644 +--- a/arch/arm/mach-omap2/omap_hwmod.c ++++ b/arch/arm/mach-omap2/omap_hwmod.c +@@ -977,6 +977,9 @@ static int _enable_clocks(struct omap_hwmod *oh) + + pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name); + ++ if (oh->flags & HWMOD_OPT_CLKS_NEEDED) ++ _enable_optional_clocks(oh); ++ + if (oh->_clk) + clk_enable(oh->_clk); + +@@ -985,9 +988,6 @@ static int _enable_clocks(struct omap_hwmod *oh) + clk_enable(os->_clk); + } + +- if (oh->flags & HWMOD_OPT_CLKS_NEEDED) +- _enable_optional_clocks(oh); +- + /* The opt clocks are controlled by the device driver. */ + + return 0; +diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c +index 366158a..6f68576 100644 +--- a/arch/arm/mach-omap2/pm.c ++++ b/arch/arm/mach-omap2/pm.c +@@ -186,7 +186,7 @@ static void omap_pm_end(void) + cpu_idle_poll_ctrl(false); + } + +-static void omap_pm_finish(void) ++static void omap_pm_wake(void) + { + if (soc_is_omap34xx()) + omap_prcm_irq_complete(); +@@ -196,7 +196,7 @@ static const struct platform_suspend_ops omap_pm_ops = { + .begin = omap_pm_begin, + .end = omap_pm_end, + .enter = omap_pm_enter, +- .finish = omap_pm_finish, ++ .wake = omap_pm_wake, + .valid = suspend_valid_only_mem, + }; + +diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c +index ece09c9..d61fbd7 100644 +--- a/arch/arm/mach-omap2/timer.c ++++ b/arch/arm/mach-omap2/timer.c +@@ -156,12 +156,6 @@ static struct clock_event_device clockevent_gpt = { + .tick_resume = omap2_gp_timer_shutdown, + }; + +-static struct property device_disabled = { +- .name = "status", +- .length = sizeof("disabled"), +- .value = "disabled", +-}; +- + static const struct of_device_id omap_timer_match[] __initconst = { + { .compatible = "ti,omap2420-timer", }, + { .compatible = "ti,omap3430-timer", }, +@@ -203,8 +197,17 @@ static struct device_node * __init omap_get_timer_dt(const struct of_device_id * + of_get_property(np, "ti,timer-secure", NULL))) + continue; + +- if (!of_device_is_compatible(np, "ti,omap-counter32k")) +- of_add_property(np, &device_disabled); ++ if (!of_device_is_compatible(np, "ti,omap-counter32k")) { ++ struct property *prop; ++ ++ prop = kzalloc(sizeof(*prop), GFP_KERNEL); ++ if (!prop) ++ return NULL; ++ prop->name = "status"; ++ prop->value = "disabled"; ++ prop->length = strlen(prop->value); ++ of_add_property(np, prop); ++ } + return np; + } + +diff --git a/arch/arm/mach-orion5x/Kconfig b/arch/arm/mach-orion5x/Kconfig +index 2a7bb6c..a810f4d 100644 +--- a/arch/arm/mach-orion5x/Kconfig ++++ b/arch/arm/mach-orion5x/Kconfig +@@ -58,7 +58,6 @@ config MACH_KUROBOX_PRO + + config MACH_DNS323 + bool "D-Link DNS-323" +- select GENERIC_NET_UTILS + select I2C_BOARDINFO if I2C + help + Say 'Y' here if you want your kernel to support the +@@ -66,7 +65,6 @@ config MACH_DNS323 + + config MACH_TS209 + bool "QNAP TS-109/TS-209" +- select GENERIC_NET_UTILS + help + Say 'Y' here if you want your kernel to support the + QNAP TS-109/TS-209 platform. +@@ -101,7 +99,6 @@ config MACH_LINKSTATION_LS_HGL + + config MACH_TS409 + bool "QNAP TS-409" +- select GENERIC_NET_UTILS + help + Say 'Y' here if you want your kernel to support the + QNAP TS-409 platform. +diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c +index cd483bf..d13344b 100644 +--- a/arch/arm/mach-orion5x/dns323-setup.c ++++ b/arch/arm/mach-orion5x/dns323-setup.c +@@ -173,10 +173,42 @@ static struct mv643xx_eth_platform_data dns323_eth_data = { + .phy_addr = MV643XX_ETH_PHY_ADDR(8), + }; + ++/* dns323_parse_hex_*() taken from tsx09-common.c; should a common copy of these ++ * functions be kept somewhere? ++ */ ++static int __init dns323_parse_hex_nibble(char n) ++{ ++ if (n >= '0' && n <= '9') ++ return n - '0'; ++ ++ if (n >= 'A' && n <= 'F') ++ return n - 'A' + 10; ++ ++ if (n >= 'a' && n <= 'f') ++ return n - 'a' + 10; ++ ++ return -1; ++} ++ ++static int __init dns323_parse_hex_byte(const char *b) ++{ ++ int hi; ++ int lo; ++ ++ hi = dns323_parse_hex_nibble(b[0]); ++ lo = dns323_parse_hex_nibble(b[1]); ++ ++ if (hi < 0 || lo < 0) ++ return -1; ++ ++ return (hi << 4) | lo; ++} ++ + static int __init dns323_read_mac_addr(void) + { + u_int8_t addr[6]; +- void __iomem *mac_page; ++ int i; ++ char *mac_page; + + /* MAC address is stored as a regular ol' string in /dev/mtdblock4 + * (0x007d0000-0x00800000) starting at offset 196480 (0x2ff80). +@@ -185,8 +217,23 @@ static int __init dns323_read_mac_addr(void) + if (!mac_page) + return -ENOMEM; + +- if (!mac_pton((__force const char *) mac_page, addr)) +- goto error_fail; ++ /* Sanity check the string we're looking at */ ++ for (i = 0; i < 5; i++) { ++ if (*(mac_page + (i * 3) + 2) != ':') { ++ goto error_fail; ++ } ++ } ++ ++ for (i = 0; i < 6; i++) { ++ int byte; ++ ++ byte = dns323_parse_hex_byte(mac_page + (i * 3)); ++ if (byte < 0) { ++ goto error_fail; ++ } ++ ++ addr[i] = byte; ++ } + + iounmap(mac_page); + printk("DNS-323: Found ethernet MAC address: %pM\n", addr); +diff --git a/arch/arm/mach-orion5x/tsx09-common.c b/arch/arm/mach-orion5x/tsx09-common.c +index 8977498..905d4f2 100644 +--- a/arch/arm/mach-orion5x/tsx09-common.c ++++ b/arch/arm/mach-orion5x/tsx09-common.c +@@ -53,12 +53,53 @@ struct mv643xx_eth_platform_data qnap_tsx09_eth_data = { + .phy_addr = MV643XX_ETH_PHY_ADDR(8), + }; + ++static int __init qnap_tsx09_parse_hex_nibble(char n) ++{ ++ if (n >= '0' && n <= '9') ++ return n - '0'; ++ ++ if (n >= 'A' && n <= 'F') ++ return n - 'A' + 10; ++ ++ if (n >= 'a' && n <= 'f') ++ return n - 'a' + 10; ++ ++ return -1; ++} ++ ++static int __init qnap_tsx09_parse_hex_byte(const char *b) ++{ ++ int hi; ++ int lo; ++ ++ hi = qnap_tsx09_parse_hex_nibble(b[0]); ++ lo = qnap_tsx09_parse_hex_nibble(b[1]); ++ ++ if (hi < 0 || lo < 0) ++ return -1; ++ ++ return (hi << 4) | lo; ++} ++ + static int __init qnap_tsx09_check_mac_addr(const char *addr_str) + { + u_int8_t addr[6]; ++ int i; + +- if (!mac_pton(addr_str, addr)) +- return -1; ++ for (i = 0; i < 6; i++) { ++ int byte; ++ ++ /* ++ * Enforce "xx:xx:xx:xx:xx:xx\n" format. ++ */ ++ if (addr_str[(i * 3) + 2] != ((i < 5) ? ':' : '\n')) ++ return -1; ++ ++ byte = qnap_tsx09_parse_hex_byte(addr_str + (i * 3)); ++ if (byte < 0) ++ return -1; ++ addr[i] = byte; ++ } + + printk(KERN_INFO "tsx09: found ethernet mac address %pM\n", addr); + +@@ -77,12 +118,12 @@ void __init qnap_tsx09_find_mac_addr(u32 mem_base, u32 size) + unsigned long addr; + + for (addr = mem_base; addr < (mem_base + size); addr += 1024) { +- void __iomem *nor_page; ++ char *nor_page; + int ret = 0; + + nor_page = ioremap(addr, 1024); + if (nor_page != NULL) { +- ret = qnap_tsx09_check_mac_addr((__force const char *)nor_page); ++ ret = qnap_tsx09_check_mac_addr(nor_page); + iounmap(nor_page); + } + +diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c +index 57058ac..7e5d7a0 100644 +--- a/arch/arm/mach-ux500/cpu-db8500.c ++++ b/arch/arm/mach-ux500/cpu-db8500.c +@@ -23,7 +23,6 @@ + #include + #include + #include +-#include + #include + + #include +@@ -112,37 +111,6 @@ static void ux500_restart(enum reboot_mode mode, const char *cmd) + prcmu_system_reset(0); + } + +-/* +- * The PMU IRQ lines of two cores are wired together into a single interrupt. +- * Bounce the interrupt to the other core if it's not ours. +- */ +-static irqreturn_t db8500_pmu_handler(int irq, void *dev, irq_handler_t handler) +-{ +- irqreturn_t ret = handler(irq, dev); +- int other = !smp_processor_id(); +- +- if (ret == IRQ_NONE && cpu_online(other)) +- irq_set_affinity(irq, cpumask_of(other)); +- +- /* +- * We should be able to get away with the amount of IRQ_NONEs we give, +- * while still having the spurious IRQ detection code kick in if the +- * interrupt really starts hitting spuriously. +- */ +- return ret; +-} +- +-static struct arm_pmu_platdata db8500_pmu_platdata = { +- .handle_irq = db8500_pmu_handler, +- .irq_flags = IRQF_NOBALANCING | IRQF_NO_THREAD, +-}; +- +-static struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = { +- /* Requires call-back bindings. */ +- OF_DEV_AUXDATA("arm,cortex-a9-pmu", 0, "arm-pmu", &db8500_pmu_platdata), +- {}, +-}; +- + static struct of_dev_auxdata u8540_auxdata_lookup[] __initdata = { + OF_DEV_AUXDATA("stericsson,db8500-prcmu", 0x80157000, "db8500-prcmu", NULL), + {}, +@@ -165,9 +133,6 @@ static void __init u8500_init_machine(void) + if (of_machine_is_compatible("st-ericsson,u8540")) + of_platform_populate(NULL, u8500_local_bus_nodes, + u8540_auxdata_lookup, NULL); +- else +- of_platform_populate(NULL, u8500_local_bus_nodes, +- u8500_auxdata_lookup, NULL); + } + + static const char * stericsson_dt_platform_compat[] = { +diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c +index aff6994..a2399fd 100644 +--- a/arch/arm/plat-orion/common.c ++++ b/arch/arm/plat-orion/common.c +@@ -472,28 +472,27 @@ void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data, + /***************************************************************************** + * Ethernet switch + ****************************************************************************/ +-static __initconst const char *orion_ge00_mvmdio_bus_name = "orion-mii"; +-static __initdata struct mdio_board_info +- orion_ge00_switch_board_info; ++static __initdata struct mdio_board_info orion_ge00_switch_board_info = { ++ .bus_id = "orion-mii", ++ .modalias = "mv88e6085", ++}; + + void __init orion_ge00_switch_init(struct dsa_chip_data *d) + { +- struct mdio_board_info *bd; + unsigned int i; + + if (!IS_BUILTIN(CONFIG_PHYLIB)) + return; + +- for (i = 0; i < ARRAY_SIZE(d->port_names); i++) +- if (!strcmp(d->port_names[i], "cpu")) ++ for (i = 0; i < ARRAY_SIZE(d->port_names); i++) { ++ if (!strcmp(d->port_names[i], "cpu")) { ++ d->netdev[i] = &orion_ge00.dev; + break; ++ } ++ } + +- bd = &orion_ge00_switch_board_info; +- bd->bus_id = orion_ge00_mvmdio_bus_name; +- bd->mdio_addr = d->sw_addr; +- d->netdev[i] = &orion_ge00.dev; +- strcpy(bd->modalias, "mv88e6085"); +- bd->platform_data = d; ++ orion_ge00_switch_board_info.mdio_addr = d->sw_addr; ++ orion_ge00_switch_board_info.platform_data = d; + + mdiobus_register_board_info(&orion_ge00_switch_board_info, 1); + } +diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +index a806326..70c776e 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +@@ -165,14 +165,14 @@ + + uart_A: serial@24000 { + compatible = "amlogic,meson-gx-uart", "amlogic,meson-uart"; +- reg = <0x0 0x24000 0x0 0x14>; ++ reg = <0x0 0x24000 0x0 0x18>; + interrupts = ; + status = "disabled"; + }; + + uart_B: serial@23000 { + compatible = "amlogic,meson-gx-uart", "amlogic,meson-uart"; +- reg = <0x0 0x23000 0x0 0x14>; ++ reg = <0x0 0x23000 0x0 0x18>; + interrupts = ; + status = "disabled"; + }; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +index 6cb3c2a..4ee2e79 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +@@ -235,14 +235,14 @@ + + uart_A: serial@84c0 { + compatible = "amlogic,meson-gx-uart"; +- reg = <0x0 0x84c0 0x0 0x14>; ++ reg = <0x0 0x84c0 0x0 0x18>; + interrupts = ; + status = "disabled"; + }; + + uart_B: serial@84dc { + compatible = "amlogic,meson-gx-uart"; +- reg = <0x0 0x84dc 0x0 0x14>; ++ reg = <0x0 0x84dc 0x0 0x18>; + interrupts = ; + status = "disabled"; + }; +@@ -287,7 +287,7 @@ + + uart_C: serial@8700 { + compatible = "amlogic,meson-gx-uart"; +- reg = <0x0 0x8700 0x0 0x14>; ++ reg = <0x0 0x8700 0x0 0x18>; + interrupts = ; + status = "disabled"; + }; +@@ -404,14 +404,14 @@ + + uart_AO: serial@4c0 { + compatible = "amlogic,meson-gx-uart", "amlogic,meson-ao-uart"; +- reg = <0x0 0x004c0 0x0 0x14>; ++ reg = <0x0 0x004c0 0x0 0x18>; + interrupts = ; + status = "disabled"; + }; + + uart_AO_B: serial@4e0 { + compatible = "amlogic,meson-gx-uart", "amlogic,meson-ao-uart"; +- reg = <0x0 0x004e0 0x0 0x14>; ++ reg = <0x0 0x004e0 0x0 0x18>; + interrupts = ; + status = "disabled"; + }; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +index 4f355f1..c851411 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +@@ -631,6 +631,7 @@ + + internal_phy: ethernet-phy@8 { + compatible = "ethernet-phy-id0181.4400", "ethernet-phy-ieee802.3-c22"; ++ interrupts = ; + reg = <8>; + max-speed = <100>; + }; +diff --git a/arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi b/arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi +index 4220fbd..ff5c4c4 100644 +--- a/arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi ++++ b/arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi +@@ -98,7 +98,7 @@ + clock-output-names = "clk125mhz"; + }; + +- pci { ++ pcie@30000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + #interrupt-cells = <1>; +@@ -118,6 +118,7 @@ + ranges = + <0x02000000 0 0x40000000 0 0x40000000 0 0x20000000 + 0x43000000 0x40 0x00000000 0x40 0x00000000 0x20 0x00000000>; ++ bus-range = <0 0xff>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = + /* addr pin ic icaddr icintr */ +diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts +index e94fa1a..047641f 100644 +--- a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts ++++ b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts +@@ -51,7 +51,7 @@ + #size-cells = <2>; + ranges; + +- ramoops@0x21f00000 { ++ ramoops@21f00000 { + compatible = "ramoops"; + reg = <0x0 0x21f00000 0x0 0x00100000>; + record-size = <0x00020000>; +diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi +index 9fbe470..94597e3 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi +@@ -341,7 +341,7 @@ + reg = <0 0x10005000 0 0x1000>; + }; + +- pio: pinctrl@0x10005000 { ++ pio: pinctrl@10005000 { + compatible = "mediatek,mt8173-pinctrl"; + reg = <0 0x1000b000 0 0x1000>; + mediatek,pctl-regmap = <&syscfg_pctl_a>; +diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi b/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi +index 492a011..1c8f1b8 100644 +--- a/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi ++++ b/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi +@@ -140,16 +140,16 @@ + }; + + agnoc@0 { +- qcom,pcie@00600000 { ++ qcom,pcie@600000 { + perst-gpio = <&msmgpio 35 GPIO_ACTIVE_LOW>; + }; + +- qcom,pcie@00608000 { ++ qcom,pcie@608000 { + status = "okay"; + perst-gpio = <&msmgpio 130 GPIO_ACTIVE_LOW>; + }; + +- qcom,pcie@00610000 { ++ qcom,pcie@610000 { + status = "okay"; + perst-gpio = <&msmgpio 114 GPIO_ACTIVE_LOW>; + }; +diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi +index 4b2afcc..0a6f795 100644 +--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi +@@ -840,7 +840,7 @@ + #size-cells = <1>; + ranges; + +- pcie0: qcom,pcie@00600000 { ++ pcie0: qcom,pcie@600000 { + compatible = "qcom,pcie-msm8996", "snps,dw-pcie"; + status = "disabled"; + power-domains = <&gcc PCIE0_GDSC>; +@@ -893,7 +893,7 @@ + + }; + +- pcie1: qcom,pcie@00608000 { ++ pcie1: qcom,pcie@608000 { + compatible = "qcom,pcie-msm8996", "snps,dw-pcie"; + power-domains = <&gcc PCIE1_GDSC>; + bus-range = <0x00 0xff>; +@@ -946,7 +946,7 @@ + "bus_slave"; + }; + +- pcie2: qcom,pcie@00610000 { ++ pcie2: qcom,pcie@610000 { + compatible = "qcom,pcie-msm8996", "snps,dw-pcie"; + power-domains = <&gcc PCIE2_GDSC>; + bus-range = <0x00 0xff>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts +index 3890468..2825772 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts +@@ -132,17 +132,16 @@ + assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>; + assigned-clock-parents = <&gmac_clkin>, <&gmac_clkin>; + clock_in_out = "input"; +- /* shows instability at 1GBit right now */ +- max-speed = <100>; + phy-supply = <&vcc_io>; + phy-mode = "rgmii"; + pinctrl-names = "default"; + pinctrl-0 = <&rgmiim1_pins>; ++ snps,force_thresh_dma_mode; + snps,reset-gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 50000>; +- tx_delay = <0x26>; +- rx_delay = <0x11>; ++ tx_delay = <0x24>; ++ rx_delay = <0x18>; + status = "okay"; + }; + +diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +index a037ee5..cae3415 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +@@ -730,7 +730,7 @@ + interrupts = ; + clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>, + <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>; +- clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; ++ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + fifo-depth = <0x100>; + status = "disabled"; + }; +@@ -741,7 +741,7 @@ + interrupts = ; + clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>, + <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>; +- clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; ++ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + fifo-depth = <0x100>; + status = "disabled"; + }; +@@ -752,7 +752,7 @@ + interrupts = ; + clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>, + <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; +- clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; ++ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + fifo-depth = <0x100>; + status = "disabled"; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi +index aa4d070..03458ac 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi +@@ -257,7 +257,7 @@ + max-frequency = <150000000>; + clocks = <&cru HCLK_SDIO0>, <&cru SCLK_SDIO0>, + <&cru SCLK_SDIO0_DRV>, <&cru SCLK_SDIO0_SAMPLE>; +- clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; ++ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + fifo-depth = <0x100>; + interrupts = ; + resets = <&cru SRST_SDIO0>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi +index 0f873c8..ce592a4 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi +@@ -457,7 +457,7 @@ + assigned-clocks = <&cru SCLK_PCIEPHY_REF>; + assigned-clock-parents = <&cru SCLK_PCIEPHY_REF100M>; + assigned-clock-rates = <100000000>; +- ep-gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_HIGH>; ++ ep-gpios = <&gpio2 RK_PA4 GPIO_ACTIVE_HIGH>; + num-lanes = <4>; + pinctrl-names = "default"; + pinctrl-0 = <&pcie_clkreqn_cpm>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +index 7aa2144..2605118 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -1739,8 +1739,8 @@ + compatible = "rockchip,rk3399-edp"; + reg = <0x0 0xff970000 0x0 0x8000>; + interrupts = ; +- clocks = <&cru PCLK_EDP>, <&cru PCLK_EDP_CTRL>; +- clock-names = "dp", "pclk"; ++ clocks = <&cru PCLK_EDP>, <&cru PCLK_EDP_CTRL>, <&cru PCLK_VIO_GRF>; ++ clock-names = "dp", "pclk", "grf"; + pinctrl-names = "default"; + pinctrl-0 = <&edp_hpd>; + power-domains = <&power RK3399_PD_EDP>; +diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h +index be7bd19..350c76a 100644 +--- a/arch/arm64/include/asm/cputype.h ++++ b/arch/arm64/include/asm/cputype.h +@@ -20,7 +20,7 @@ + + #define MPIDR_UP_BITMASK (0x1 << 30) + #define MPIDR_MT_BITMASK (0x1 << 24) +-#define MPIDR_HWID_BITMASK 0xff00ffffff ++#define MPIDR_HWID_BITMASK UL(0xff00ffffff) + + #define MPIDR_LEVEL_BITS_SHIFT 3 + #define MPIDR_LEVEL_BITS (1 << MPIDR_LEVEL_BITS_SHIFT) +diff --git a/arch/arm64/include/asm/hugetlb.h b/arch/arm64/include/asm/hugetlb.h +index 1dca41b..e73f685 100644 +--- a/arch/arm64/include/asm/hugetlb.h ++++ b/arch/arm64/include/asm/hugetlb.h +@@ -22,7 +22,7 @@ + + static inline pte_t huge_ptep_get(pte_t *ptep) + { +- return *ptep; ++ return READ_ONCE(*ptep); + } + + +diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h +index 9679067..7faed6e 100644 +--- a/arch/arm64/include/asm/kvm_mmu.h ++++ b/arch/arm64/include/asm/kvm_mmu.h +@@ -185,42 +185,42 @@ static inline pmd_t kvm_s2pmd_mkexec(pmd_t pmd) + return pmd; + } + +-static inline void kvm_set_s2pte_readonly(pte_t *pte) ++static inline void kvm_set_s2pte_readonly(pte_t *ptep) + { + pteval_t old_pteval, pteval; + +- pteval = READ_ONCE(pte_val(*pte)); ++ pteval = READ_ONCE(pte_val(*ptep)); + do { + old_pteval = pteval; + pteval &= ~PTE_S2_RDWR; + pteval |= PTE_S2_RDONLY; +- pteval = cmpxchg_relaxed(&pte_val(*pte), old_pteval, pteval); ++ pteval = cmpxchg_relaxed(&pte_val(*ptep), old_pteval, pteval); + } while (pteval != old_pteval); + } + +-static inline bool kvm_s2pte_readonly(pte_t *pte) ++static inline bool kvm_s2pte_readonly(pte_t *ptep) + { +- return (pte_val(*pte) & PTE_S2_RDWR) == PTE_S2_RDONLY; ++ return (READ_ONCE(pte_val(*ptep)) & PTE_S2_RDWR) == PTE_S2_RDONLY; + } + +-static inline bool kvm_s2pte_exec(pte_t *pte) ++static inline bool kvm_s2pte_exec(pte_t *ptep) + { +- return !(pte_val(*pte) & PTE_S2_XN); ++ return !(READ_ONCE(pte_val(*ptep)) & PTE_S2_XN); + } + +-static inline void kvm_set_s2pmd_readonly(pmd_t *pmd) ++static inline void kvm_set_s2pmd_readonly(pmd_t *pmdp) + { +- kvm_set_s2pte_readonly((pte_t *)pmd); ++ kvm_set_s2pte_readonly((pte_t *)pmdp); + } + +-static inline bool kvm_s2pmd_readonly(pmd_t *pmd) ++static inline bool kvm_s2pmd_readonly(pmd_t *pmdp) + { +- return kvm_s2pte_readonly((pte_t *)pmd); ++ return kvm_s2pte_readonly((pte_t *)pmdp); + } + +-static inline bool kvm_s2pmd_exec(pmd_t *pmd) ++static inline bool kvm_s2pmd_exec(pmd_t *pmdp) + { +- return !(pmd_val(*pmd) & PMD_S2_XN); ++ return !(READ_ONCE(pmd_val(*pmdp)) & PMD_S2_XN); + } + + static inline bool kvm_page_empty(void *ptr) +diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h +index 8d33319..39ec0b8 100644 +--- a/arch/arm64/include/asm/mmu_context.h ++++ b/arch/arm64/include/asm/mmu_context.h +@@ -141,13 +141,13 @@ static inline void cpu_install_idmap(void) + * Atomically replaces the active TTBR1_EL1 PGD with a new VA-compatible PGD, + * avoiding the possibility of conflicting TLB entries being allocated. + */ +-static inline void cpu_replace_ttbr1(pgd_t *pgd) ++static inline void cpu_replace_ttbr1(pgd_t *pgdp) + { + typedef void (ttbr_replace_func)(phys_addr_t); + extern ttbr_replace_func idmap_cpu_replace_ttbr1; + ttbr_replace_func *replace_phys; + +- phys_addr_t pgd_phys = virt_to_phys(pgd); ++ phys_addr_t pgd_phys = virt_to_phys(pgdp); + + replace_phys = (void *)__pa_symbol(idmap_cpu_replace_ttbr1); + +diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h +index e9d9f1b..2e05bcd 100644 +--- a/arch/arm64/include/asm/pgalloc.h ++++ b/arch/arm64/include/asm/pgalloc.h +@@ -36,23 +36,23 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) + return (pmd_t *)__get_free_page(PGALLOC_GFP); + } + +-static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) ++static inline void pmd_free(struct mm_struct *mm, pmd_t *pmdp) + { +- BUG_ON((unsigned long)pmd & (PAGE_SIZE-1)); +- free_page((unsigned long)pmd); ++ BUG_ON((unsigned long)pmdp & (PAGE_SIZE-1)); ++ free_page((unsigned long)pmdp); + } + +-static inline void __pud_populate(pud_t *pud, phys_addr_t pmd, pudval_t prot) ++static inline void __pud_populate(pud_t *pudp, phys_addr_t pmdp, pudval_t prot) + { +- set_pud(pud, __pud(__phys_to_pud_val(pmd) | prot)); ++ set_pud(pudp, __pud(__phys_to_pud_val(pmdp) | prot)); + } + +-static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) ++static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmdp) + { +- __pud_populate(pud, __pa(pmd), PMD_TYPE_TABLE); ++ __pud_populate(pudp, __pa(pmdp), PMD_TYPE_TABLE); + } + #else +-static inline void __pud_populate(pud_t *pud, phys_addr_t pmd, pudval_t prot) ++static inline void __pud_populate(pud_t *pudp, phys_addr_t pmdp, pudval_t prot) + { + BUILD_BUG(); + } +@@ -65,30 +65,30 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) + return (pud_t *)__get_free_page(PGALLOC_GFP); + } + +-static inline void pud_free(struct mm_struct *mm, pud_t *pud) ++static inline void pud_free(struct mm_struct *mm, pud_t *pudp) + { +- BUG_ON((unsigned long)pud & (PAGE_SIZE-1)); +- free_page((unsigned long)pud); ++ BUG_ON((unsigned long)pudp & (PAGE_SIZE-1)); ++ free_page((unsigned long)pudp); + } + +-static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pud, pgdval_t prot) ++static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pudp, pgdval_t prot) + { +- set_pgd(pgdp, __pgd(__phys_to_pgd_val(pud) | prot)); ++ set_pgd(pgdp, __pgd(__phys_to_pgd_val(pudp) | prot)); + } + +-static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) ++static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgdp, pud_t *pudp) + { +- __pgd_populate(pgd, __pa(pud), PUD_TYPE_TABLE); ++ __pgd_populate(pgdp, __pa(pudp), PUD_TYPE_TABLE); + } + #else +-static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pud, pgdval_t prot) ++static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pudp, pgdval_t prot) + { + BUILD_BUG(); + } + #endif /* CONFIG_PGTABLE_LEVELS > 3 */ + + extern pgd_t *pgd_alloc(struct mm_struct *mm); +-extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); ++extern void pgd_free(struct mm_struct *mm, pgd_t *pgdp); + + static inline pte_t * + pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr) +@@ -114,10 +114,10 @@ pte_alloc_one(struct mm_struct *mm, unsigned long addr) + /* + * Free a PTE table. + */ +-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) ++static inline void pte_free_kernel(struct mm_struct *mm, pte_t *ptep) + { +- if (pte) +- free_page((unsigned long)pte); ++ if (ptep) ++ free_page((unsigned long)ptep); + } + + static inline void pte_free(struct mm_struct *mm, pgtable_t pte) +@@ -126,10 +126,10 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte) + __free_page(pte); + } + +-static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte, ++static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t ptep, + pmdval_t prot) + { +- set_pmd(pmdp, __pmd(__phys_to_pmd_val(pte) | prot)); ++ set_pmd(pmdp, __pmd(__phys_to_pmd_val(ptep) | prot)); + } + + /* +diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h +index 094374c..7e2c27e 100644 +--- a/arch/arm64/include/asm/pgtable.h ++++ b/arch/arm64/include/asm/pgtable.h +@@ -218,7 +218,7 @@ static inline pmd_t pmd_mkcont(pmd_t pmd) + + static inline void set_pte(pte_t *ptep, pte_t pte) + { +- *ptep = pte; ++ WRITE_ONCE(*ptep, pte); + + /* + * Only if the new pte is valid and kernel, otherwise TLB maintenance +@@ -250,6 +250,8 @@ extern void __sync_icache_dcache(pte_t pteval, unsigned long addr); + static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pte) + { ++ pte_t old_pte; ++ + if (pte_present(pte) && pte_user_exec(pte) && !pte_special(pte)) + __sync_icache_dcache(pte, addr); + +@@ -258,14 +260,15 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, + * hardware updates of the pte (ptep_set_access_flags safely changes + * valid ptes without going through an invalid entry). + */ +- if (IS_ENABLED(CONFIG_DEBUG_VM) && pte_valid(*ptep) && pte_valid(pte) && ++ old_pte = READ_ONCE(*ptep); ++ if (IS_ENABLED(CONFIG_DEBUG_VM) && pte_valid(old_pte) && pte_valid(pte) && + (mm == current->active_mm || atomic_read(&mm->mm_users) > 1)) { + VM_WARN_ONCE(!pte_young(pte), + "%s: racy access flag clearing: 0x%016llx -> 0x%016llx", +- __func__, pte_val(*ptep), pte_val(pte)); +- VM_WARN_ONCE(pte_write(*ptep) && !pte_dirty(pte), ++ __func__, pte_val(old_pte), pte_val(pte)); ++ VM_WARN_ONCE(pte_write(old_pte) && !pte_dirty(pte), + "%s: racy dirty state clearing: 0x%016llx -> 0x%016llx", +- __func__, pte_val(*ptep), pte_val(pte)); ++ __func__, pte_val(old_pte), pte_val(pte)); + } + + set_pte(ptep, pte); +@@ -431,7 +434,7 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, + + static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) + { +- *pmdp = pmd; ++ WRITE_ONCE(*pmdp, pmd); + dsb(ishst); + isb(); + } +@@ -482,7 +485,7 @@ static inline phys_addr_t pmd_page_paddr(pmd_t pmd) + + static inline void set_pud(pud_t *pudp, pud_t pud) + { +- *pudp = pud; ++ WRITE_ONCE(*pudp, pud); + dsb(ishst); + isb(); + } +@@ -500,7 +503,7 @@ static inline phys_addr_t pud_page_paddr(pud_t pud) + /* Find an entry in the second-level page table. */ + #define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) + +-#define pmd_offset_phys(dir, addr) (pud_page_paddr(*(dir)) + pmd_index(addr) * sizeof(pmd_t)) ++#define pmd_offset_phys(dir, addr) (pud_page_paddr(READ_ONCE(*(dir))) + pmd_index(addr) * sizeof(pmd_t)) + #define pmd_offset(dir, addr) ((pmd_t *)__va(pmd_offset_phys((dir), (addr)))) + + #define pmd_set_fixmap(addr) ((pmd_t *)set_fixmap_offset(FIX_PMD, addr)) +@@ -535,7 +538,7 @@ static inline phys_addr_t pud_page_paddr(pud_t pud) + + static inline void set_pgd(pgd_t *pgdp, pgd_t pgd) + { +- *pgdp = pgd; ++ WRITE_ONCE(*pgdp, pgd); + dsb(ishst); + } + +@@ -552,7 +555,7 @@ static inline phys_addr_t pgd_page_paddr(pgd_t pgd) + /* Find an entry in the frst-level page table. */ + #define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) + +-#define pud_offset_phys(dir, addr) (pgd_page_paddr(*(dir)) + pud_index(addr) * sizeof(pud_t)) ++#define pud_offset_phys(dir, addr) (pgd_page_paddr(READ_ONCE(*(dir))) + pud_index(addr) * sizeof(pud_t)) + #define pud_offset(dir, addr) ((pud_t *)__va(pud_offset_phys((dir), (addr)))) + + #define pud_set_fixmap(addr) ((pud_t *)set_fixmap_offset(FIX_PUD, addr)) +diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h +index 472ef94..902f9ed 100644 +--- a/arch/arm64/include/asm/stacktrace.h ++++ b/arch/arm64/include/asm/stacktrace.h +@@ -28,7 +28,7 @@ struct stackframe { + unsigned long fp; + unsigned long pc; + #ifdef CONFIG_FUNCTION_GRAPH_TRACER +- unsigned int graph; ++ int graph; + #endif + }; + +diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h +index 543e11f..e66b0fc 100644 +--- a/arch/arm64/include/asm/uaccess.h ++++ b/arch/arm64/include/asm/uaccess.h +@@ -72,15 +72,15 @@ static inline void set_fs(mm_segment_t fs) + * This is equivalent to the following test: + * (u65)addr + (u65)size <= (u65)current->addr_limit + 1 + */ +-static inline unsigned long __range_ok(unsigned long addr, unsigned long size) ++static inline unsigned long __range_ok(const void __user *addr, unsigned long size) + { +- unsigned long limit = current_thread_info()->addr_limit; ++ unsigned long ret, limit = current_thread_info()->addr_limit; + + __chk_user_ptr(addr); + asm volatile( + // A + B <= C + 1 for all A,B,C, in four easy steps: + // 1: X = A + B; X' = X % 2^64 +- " adds %0, %0, %2\n" ++ " adds %0, %3, %2\n" + // 2: Set C = 0 if X > 2^64, to guarantee X' > C in step 4 + " csel %1, xzr, %1, hi\n" + // 3: Set X' = ~0 if X >= 2^64. For X == 2^64, this decrements X' +@@ -92,9 +92,9 @@ static inline unsigned long __range_ok(unsigned long addr, unsigned long size) + // testing X' - C == 0, subject to the previous adjustments. + " sbcs xzr, %0, %1\n" + " cset %0, ls\n" +- : "+r" (addr), "+r" (limit) : "Ir" (size) : "cc"); ++ : "=&r" (ret), "+r" (limit) : "Ir" (size), "0" (addr) : "cc"); + +- return addr; ++ return ret; + } + + /* +@@ -104,7 +104,7 @@ static inline unsigned long __range_ok(unsigned long addr, unsigned long size) + */ + #define untagged_addr(addr) sign_extend64(addr, 55) + +-#define access_ok(type, addr, size) __range_ok((unsigned long)(addr), size) ++#define access_ok(type, addr, size) __range_ok(addr, size) + #define user_addr_max get_fs + + #define _ASM_EXTABLE(from, to) \ +diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c +index c33b5e4..68450e9 100644 +--- a/arch/arm64/kernel/armv8_deprecated.c ++++ b/arch/arm64/kernel/armv8_deprecated.c +@@ -370,6 +370,7 @@ static unsigned int __kprobes aarch32_check_condition(u32 opcode, u32 psr) + static int swp_handler(struct pt_regs *regs, u32 instr) + { + u32 destreg, data, type, address = 0; ++ const void __user *user_ptr; + int rn, rt2, res = 0; + + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); +@@ -401,7 +402,8 @@ static int swp_handler(struct pt_regs *regs, u32 instr) + aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET), data); + + /* Check access in reasonable access range for both SWP and SWPB */ +- if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) { ++ user_ptr = (const void __user *)(unsigned long)(address & ~3); ++ if (!access_ok(VERIFY_WRITE, user_ptr, 4)) { + pr_debug("SWP{B} emulation: access to 0x%08x not allowed!\n", + address); + goto fault; +diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c +index 0782359..b5a2833 100644 +--- a/arch/arm64/kernel/cpu_errata.c ++++ b/arch/arm64/kernel/cpu_errata.c +@@ -178,7 +178,7 @@ static int enable_smccc_arch_workaround_1(void *data) + case PSCI_CONDUIT_HVC: + arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_ARCH_WORKAROUND_1, &res); +- if (res.a0) ++ if ((int)res.a0 < 0) + return 0; + cb = call_hvc_arch_workaround_1; + smccc_start = __smccc_workaround_1_hvc_start; +@@ -188,7 +188,7 @@ static int enable_smccc_arch_workaround_1(void *data) + case PSCI_CONDUIT_SMC: + arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_ARCH_WORKAROUND_1, &res); +- if (res.a0) ++ if ((int)res.a0 < 0) + return 0; + cb = call_smc_arch_workaround_1; + smccc_start = __smccc_workaround_1_smc_start; +@@ -408,6 +408,15 @@ const struct arm64_cpu_capabilities arm64_errata[] = { + }, + { + .capability = ARM64_HARDEN_BRANCH_PREDICTOR, ++ MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR), ++ .enable = qcom_enable_link_stack_sanitization, ++ }, ++ { ++ .capability = ARM64_HARDEN_BP_POST_GUEST_EXIT, ++ MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR), ++ }, ++ { ++ .capability = ARM64_HARDEN_BRANCH_PREDICTOR, + MIDR_ALL_VERSIONS(MIDR_BRCM_VULCAN), + .enable = enable_smccc_arch_workaround_1, + }, +diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c +index 29b1f87..2985a06 100644 +--- a/arch/arm64/kernel/cpufeature.c ++++ b/arch/arm64/kernel/cpufeature.c +@@ -199,9 +199,11 @@ static const struct arm64_ftr_bits ftr_id_aa64mmfr2[] = { + }; + + static const struct arm64_ftr_bits ftr_ctr[] = { +- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RAO */ ++ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RES1 */ ++ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 29, 1, 1), /* DIC */ ++ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 28, 1, 1), /* IDC */ + ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0), /* CWG */ +- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0), /* ERG */ ++ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, 20, 4, 0), /* ERG */ + ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1), /* DminLine */ + /* + * Linux can handle differing I-cache policies. Userspace JITs will +diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c +index f85ac58..a8bf1c8 100644 +--- a/arch/arm64/kernel/efi.c ++++ b/arch/arm64/kernel/efi.c +@@ -90,7 +90,7 @@ static int __init set_permissions(pte_t *ptep, pgtable_t token, + unsigned long addr, void *data) + { + efi_memory_desc_t *md = data; +- pte_t pte = *ptep; ++ pte_t pte = READ_ONCE(*ptep); + + if (md->attribute & EFI_MEMORY_RO) + pte = set_pte_bit(pte, __pgprot(PTE_RDONLY)); +diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c +index f20cf7e..1ec5f28 100644 +--- a/arch/arm64/kernel/hibernate.c ++++ b/arch/arm64/kernel/hibernate.c +@@ -202,10 +202,10 @@ static int create_safe_exec_page(void *src_start, size_t length, + gfp_t mask) + { + int rc = 0; +- pgd_t *pgd; +- pud_t *pud; +- pmd_t *pmd; +- pte_t *pte; ++ pgd_t *pgdp; ++ pud_t *pudp; ++ pmd_t *pmdp; ++ pte_t *ptep; + unsigned long dst = (unsigned long)allocator(mask); + + if (!dst) { +@@ -216,38 +216,38 @@ static int create_safe_exec_page(void *src_start, size_t length, + memcpy((void *)dst, src_start, length); + flush_icache_range(dst, dst + length); + +- pgd = pgd_offset_raw(allocator(mask), dst_addr); +- if (pgd_none(*pgd)) { +- pud = allocator(mask); +- if (!pud) { ++ pgdp = pgd_offset_raw(allocator(mask), dst_addr); ++ if (pgd_none(READ_ONCE(*pgdp))) { ++ pudp = allocator(mask); ++ if (!pudp) { + rc = -ENOMEM; + goto out; + } +- pgd_populate(&init_mm, pgd, pud); ++ pgd_populate(&init_mm, pgdp, pudp); + } + +- pud = pud_offset(pgd, dst_addr); +- if (pud_none(*pud)) { +- pmd = allocator(mask); +- if (!pmd) { ++ pudp = pud_offset(pgdp, dst_addr); ++ if (pud_none(READ_ONCE(*pudp))) { ++ pmdp = allocator(mask); ++ if (!pmdp) { + rc = -ENOMEM; + goto out; + } +- pud_populate(&init_mm, pud, pmd); ++ pud_populate(&init_mm, pudp, pmdp); + } + +- pmd = pmd_offset(pud, dst_addr); +- if (pmd_none(*pmd)) { +- pte = allocator(mask); +- if (!pte) { ++ pmdp = pmd_offset(pudp, dst_addr); ++ if (pmd_none(READ_ONCE(*pmdp))) { ++ ptep = allocator(mask); ++ if (!ptep) { + rc = -ENOMEM; + goto out; + } +- pmd_populate_kernel(&init_mm, pmd, pte); ++ pmd_populate_kernel(&init_mm, pmdp, ptep); + } + +- pte = pte_offset_kernel(pmd, dst_addr); +- set_pte(pte, pfn_pte(virt_to_pfn(dst), PAGE_KERNEL_EXEC)); ++ ptep = pte_offset_kernel(pmdp, dst_addr); ++ set_pte(ptep, pfn_pte(virt_to_pfn(dst), PAGE_KERNEL_EXEC)); + + /* + * Load our new page tables. A strict BBM approach requires that we +@@ -263,7 +263,7 @@ static int create_safe_exec_page(void *src_start, size_t length, + */ + cpu_set_reserved_ttbr0(); + local_flush_tlb_all(); +- write_sysreg(phys_to_ttbr(virt_to_phys(pgd)), ttbr0_el1); ++ write_sysreg(phys_to_ttbr(virt_to_phys(pgdp)), ttbr0_el1); + isb(); + + *phys_dst_addr = virt_to_phys((void *)dst); +@@ -320,9 +320,9 @@ int swsusp_arch_suspend(void) + return ret; + } + +-static void _copy_pte(pte_t *dst_pte, pte_t *src_pte, unsigned long addr) ++static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr) + { +- pte_t pte = *src_pte; ++ pte_t pte = READ_ONCE(*src_ptep); + + if (pte_valid(pte)) { + /* +@@ -330,7 +330,7 @@ static void _copy_pte(pte_t *dst_pte, pte_t *src_pte, unsigned long addr) + * read only (code, rodata). Clear the RDONLY bit from + * the temporary mappings we use during restore. + */ +- set_pte(dst_pte, pte_mkwrite(pte)); ++ set_pte(dst_ptep, pte_mkwrite(pte)); + } else if (debug_pagealloc_enabled() && !pte_none(pte)) { + /* + * debug_pagealloc will removed the PTE_VALID bit if +@@ -343,112 +343,116 @@ static void _copy_pte(pte_t *dst_pte, pte_t *src_pte, unsigned long addr) + */ + BUG_ON(!pfn_valid(pte_pfn(pte))); + +- set_pte(dst_pte, pte_mkpresent(pte_mkwrite(pte))); ++ set_pte(dst_ptep, pte_mkpresent(pte_mkwrite(pte))); + } + } + +-static int copy_pte(pmd_t *dst_pmd, pmd_t *src_pmd, unsigned long start, ++static int copy_pte(pmd_t *dst_pmdp, pmd_t *src_pmdp, unsigned long start, + unsigned long end) + { +- pte_t *src_pte; +- pte_t *dst_pte; ++ pte_t *src_ptep; ++ pte_t *dst_ptep; + unsigned long addr = start; + +- dst_pte = (pte_t *)get_safe_page(GFP_ATOMIC); +- if (!dst_pte) ++ dst_ptep = (pte_t *)get_safe_page(GFP_ATOMIC); ++ if (!dst_ptep) + return -ENOMEM; +- pmd_populate_kernel(&init_mm, dst_pmd, dst_pte); +- dst_pte = pte_offset_kernel(dst_pmd, start); ++ pmd_populate_kernel(&init_mm, dst_pmdp, dst_ptep); ++ dst_ptep = pte_offset_kernel(dst_pmdp, start); + +- src_pte = pte_offset_kernel(src_pmd, start); ++ src_ptep = pte_offset_kernel(src_pmdp, start); + do { +- _copy_pte(dst_pte, src_pte, addr); +- } while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end); ++ _copy_pte(dst_ptep, src_ptep, addr); ++ } while (dst_ptep++, src_ptep++, addr += PAGE_SIZE, addr != end); + + return 0; + } + +-static int copy_pmd(pud_t *dst_pud, pud_t *src_pud, unsigned long start, ++static int copy_pmd(pud_t *dst_pudp, pud_t *src_pudp, unsigned long start, + unsigned long end) + { +- pmd_t *src_pmd; +- pmd_t *dst_pmd; ++ pmd_t *src_pmdp; ++ pmd_t *dst_pmdp; + unsigned long next; + unsigned long addr = start; + +- if (pud_none(*dst_pud)) { +- dst_pmd = (pmd_t *)get_safe_page(GFP_ATOMIC); +- if (!dst_pmd) ++ if (pud_none(READ_ONCE(*dst_pudp))) { ++ dst_pmdp = (pmd_t *)get_safe_page(GFP_ATOMIC); ++ if (!dst_pmdp) + return -ENOMEM; +- pud_populate(&init_mm, dst_pud, dst_pmd); ++ pud_populate(&init_mm, dst_pudp, dst_pmdp); + } +- dst_pmd = pmd_offset(dst_pud, start); ++ dst_pmdp = pmd_offset(dst_pudp, start); + +- src_pmd = pmd_offset(src_pud, start); ++ src_pmdp = pmd_offset(src_pudp, start); + do { ++ pmd_t pmd = READ_ONCE(*src_pmdp); ++ + next = pmd_addr_end(addr, end); +- if (pmd_none(*src_pmd)) ++ if (pmd_none(pmd)) + continue; +- if (pmd_table(*src_pmd)) { +- if (copy_pte(dst_pmd, src_pmd, addr, next)) ++ if (pmd_table(pmd)) { ++ if (copy_pte(dst_pmdp, src_pmdp, addr, next)) + return -ENOMEM; + } else { +- set_pmd(dst_pmd, +- __pmd(pmd_val(*src_pmd) & ~PMD_SECT_RDONLY)); ++ set_pmd(dst_pmdp, ++ __pmd(pmd_val(pmd) & ~PMD_SECT_RDONLY)); + } +- } while (dst_pmd++, src_pmd++, addr = next, addr != end); ++ } while (dst_pmdp++, src_pmdp++, addr = next, addr != end); + + return 0; + } + +-static int copy_pud(pgd_t *dst_pgd, pgd_t *src_pgd, unsigned long start, ++static int copy_pud(pgd_t *dst_pgdp, pgd_t *src_pgdp, unsigned long start, + unsigned long end) + { +- pud_t *dst_pud; +- pud_t *src_pud; ++ pud_t *dst_pudp; ++ pud_t *src_pudp; + unsigned long next; + unsigned long addr = start; + +- if (pgd_none(*dst_pgd)) { +- dst_pud = (pud_t *)get_safe_page(GFP_ATOMIC); +- if (!dst_pud) ++ if (pgd_none(READ_ONCE(*dst_pgdp))) { ++ dst_pudp = (pud_t *)get_safe_page(GFP_ATOMIC); ++ if (!dst_pudp) + return -ENOMEM; +- pgd_populate(&init_mm, dst_pgd, dst_pud); ++ pgd_populate(&init_mm, dst_pgdp, dst_pudp); + } +- dst_pud = pud_offset(dst_pgd, start); ++ dst_pudp = pud_offset(dst_pgdp, start); + +- src_pud = pud_offset(src_pgd, start); ++ src_pudp = pud_offset(src_pgdp, start); + do { ++ pud_t pud = READ_ONCE(*src_pudp); ++ + next = pud_addr_end(addr, end); +- if (pud_none(*src_pud)) ++ if (pud_none(pud)) + continue; +- if (pud_table(*(src_pud))) { +- if (copy_pmd(dst_pud, src_pud, addr, next)) ++ if (pud_table(pud)) { ++ if (copy_pmd(dst_pudp, src_pudp, addr, next)) + return -ENOMEM; + } else { +- set_pud(dst_pud, +- __pud(pud_val(*src_pud) & ~PMD_SECT_RDONLY)); ++ set_pud(dst_pudp, ++ __pud(pud_val(pud) & ~PMD_SECT_RDONLY)); + } +- } while (dst_pud++, src_pud++, addr = next, addr != end); ++ } while (dst_pudp++, src_pudp++, addr = next, addr != end); + + return 0; + } + +-static int copy_page_tables(pgd_t *dst_pgd, unsigned long start, ++static int copy_page_tables(pgd_t *dst_pgdp, unsigned long start, + unsigned long end) + { + unsigned long next; + unsigned long addr = start; +- pgd_t *src_pgd = pgd_offset_k(start); ++ pgd_t *src_pgdp = pgd_offset_k(start); + +- dst_pgd = pgd_offset_raw(dst_pgd, start); ++ dst_pgdp = pgd_offset_raw(dst_pgdp, start); + do { + next = pgd_addr_end(addr, end); +- if (pgd_none(*src_pgd)) ++ if (pgd_none(READ_ONCE(*src_pgdp))) + continue; +- if (copy_pud(dst_pgd, src_pgd, addr, next)) ++ if (copy_pud(dst_pgdp, src_pgdp, addr, next)) + return -ENOMEM; +- } while (dst_pgd++, src_pgd++, addr = next, addr != end); ++ } while (dst_pgdp++, src_pgdp++, addr = next, addr != end); + + return 0; + } +diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c +index 75b220b..85a251b 100644 +--- a/arch/arm64/kernel/perf_event.c ++++ b/arch/arm64/kernel/perf_event.c +@@ -908,9 +908,9 @@ static void __armv8pmu_probe_pmu(void *info) + int pmuver; + + dfr0 = read_sysreg(id_aa64dfr0_el1); +- pmuver = cpuid_feature_extract_signed_field(dfr0, ++ pmuver = cpuid_feature_extract_unsigned_field(dfr0, + ID_AA64DFR0_PMUVER_SHIFT); +- if (pmuver < 1) ++ if (pmuver == 0xf || pmuver == 0) + return; + + probe->present = true; +diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c +index ad8aeb0..c0da6ef 100644 +--- a/arch/arm64/kernel/process.c ++++ b/arch/arm64/kernel/process.c +@@ -220,8 +220,15 @@ void __show_regs(struct pt_regs *regs) + + show_regs_print_info(KERN_DEFAULT); + print_pstate(regs); +- printk("pc : %pS\n", (void *)regs->pc); +- printk("lr : %pS\n", (void *)lr); ++ ++ if (!user_mode(regs)) { ++ printk("pc : %pS\n", (void *)regs->pc); ++ printk("lr : %pS\n", (void *)lr); ++ } else { ++ printk("pc : %016llx\n", regs->pc); ++ printk("lr : %016llx\n", lr); ++ } ++ + printk("sp : %016llx\n", sp); + + i = top_reg; +diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c +index 6618036..9ae31f7 100644 +--- a/arch/arm64/kernel/ptrace.c ++++ b/arch/arm64/kernel/ptrace.c +@@ -1419,7 +1419,7 @@ static int compat_ptrace_hbp_get(unsigned int note_type, + u64 addr = 0; + u32 ctrl = 0; + +- int err, idx = compat_ptrace_hbp_num_to_idx(num);; ++ int err, idx = compat_ptrace_hbp_num_to_idx(num); + + if (num & 1) { + err = ptrace_hbp_get_addr(note_type, tsk, idx, &addr); +diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c +index 76809cc..d5718a0 100644 +--- a/arch/arm64/kernel/stacktrace.c ++++ b/arch/arm64/kernel/stacktrace.c +@@ -59,6 +59,11 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame) + #ifdef CONFIG_FUNCTION_GRAPH_TRACER + if (tsk->ret_stack && + (frame->pc == (unsigned long)return_to_handler)) { ++ if (WARN_ON_ONCE(frame->graph == -1)) ++ return -EINVAL; ++ if (frame->graph < -1) ++ frame->graph += FTRACE_NOTRACE_DEPTH; ++ + /* + * This is a case where function graph tracer has + * modified a return address (LR) in a stack frame +diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c +index 8b8bbd3..a382b2a 100644 +--- a/arch/arm64/kernel/sys_compat.c ++++ b/arch/arm64/kernel/sys_compat.c +@@ -57,7 +57,7 @@ do_compat_cache_op(unsigned long start, unsigned long end, int flags) + if (end < start || flags) + return -EINVAL; + +- if (!access_ok(VERIFY_READ, start, end - start)) ++ if (!access_ok(VERIFY_READ, (const void __user *)start, end - start)) + return -EFAULT; + + return __do_compat_cache_op(start, end); +diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c +index a439128..f258636 100644 +--- a/arch/arm64/kernel/time.c ++++ b/arch/arm64/kernel/time.c +@@ -52,7 +52,7 @@ unsigned long profile_pc(struct pt_regs *regs) + frame.fp = regs->regs[29]; + frame.pc = regs->pc; + #ifdef CONFIG_FUNCTION_GRAPH_TRACER +- frame.graph = -1; /* no task info */ ++ frame.graph = current->curr_ret_stack; + #endif + do { + int ret = unwind_frame(NULL, &frame); +diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c +index bbb0fde..eb2d151 100644 +--- a/arch/arm64/kernel/traps.c ++++ b/arch/arm64/kernel/traps.c +@@ -57,7 +57,7 @@ static const char *handler[]= { + "Error" + }; + +-int show_unhandled_signals = 1; ++int show_unhandled_signals = 0; + + static void dump_backtrace_entry(unsigned long where) + { +@@ -526,14 +526,6 @@ asmlinkage long do_ni_syscall(struct pt_regs *regs) + } + #endif + +- if (show_unhandled_signals_ratelimited()) { +- pr_info("%s[%d]: syscall %d\n", current->comm, +- task_pid_nr(current), regs->syscallno); +- dump_instr("", regs); +- if (user_mode(regs)) +- __show_regs(regs); +- } +- + return sys_ni_syscall(); + } + +diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c +index 116252a8..870f4b1 100644 +--- a/arch/arm64/kvm/hyp/switch.c ++++ b/arch/arm64/kvm/hyp/switch.c +@@ -407,8 +407,10 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) + u32 midr = read_cpuid_id(); + + /* Apply BTAC predictors mitigation to all Falkor chips */ +- if ((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR_V1) ++ if (((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR) || ++ ((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR_V1)) { + __qcom_hyp_sanitize_btac_predictors(); ++ } + } + + fp_enabled = __fpsimd_enabled(); +diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c +index 7b60d62..65dfc85 100644 +--- a/arch/arm64/mm/dump.c ++++ b/arch/arm64/mm/dump.c +@@ -286,48 +286,52 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level, + + } + +-static void walk_pte(struct pg_state *st, pmd_t *pmd, unsigned long start) ++static void walk_pte(struct pg_state *st, pmd_t *pmdp, unsigned long start) + { +- pte_t *pte = pte_offset_kernel(pmd, 0UL); ++ pte_t *ptep = pte_offset_kernel(pmdp, 0UL); + unsigned long addr; + unsigned i; + +- for (i = 0; i < PTRS_PER_PTE; i++, pte++) { ++ for (i = 0; i < PTRS_PER_PTE; i++, ptep++) { + addr = start + i * PAGE_SIZE; +- note_page(st, addr, 4, pte_val(*pte)); ++ note_page(st, addr, 4, READ_ONCE(pte_val(*ptep))); + } + } + +-static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start) ++static void walk_pmd(struct pg_state *st, pud_t *pudp, unsigned long start) + { +- pmd_t *pmd = pmd_offset(pud, 0UL); ++ pmd_t *pmdp = pmd_offset(pudp, 0UL); + unsigned long addr; + unsigned i; + +- for (i = 0; i < PTRS_PER_PMD; i++, pmd++) { ++ for (i = 0; i < PTRS_PER_PMD; i++, pmdp++) { ++ pmd_t pmd = READ_ONCE(*pmdp); ++ + addr = start + i * PMD_SIZE; +- if (pmd_none(*pmd) || pmd_sect(*pmd)) { +- note_page(st, addr, 3, pmd_val(*pmd)); ++ if (pmd_none(pmd) || pmd_sect(pmd)) { ++ note_page(st, addr, 3, pmd_val(pmd)); + } else { +- BUG_ON(pmd_bad(*pmd)); +- walk_pte(st, pmd, addr); ++ BUG_ON(pmd_bad(pmd)); ++ walk_pte(st, pmdp, addr); + } + } + } + +-static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start) ++static void walk_pud(struct pg_state *st, pgd_t *pgdp, unsigned long start) + { +- pud_t *pud = pud_offset(pgd, 0UL); ++ pud_t *pudp = pud_offset(pgdp, 0UL); + unsigned long addr; + unsigned i; + +- for (i = 0; i < PTRS_PER_PUD; i++, pud++) { ++ for (i = 0; i < PTRS_PER_PUD; i++, pudp++) { ++ pud_t pud = READ_ONCE(*pudp); ++ + addr = start + i * PUD_SIZE; +- if (pud_none(*pud) || pud_sect(*pud)) { +- note_page(st, addr, 2, pud_val(*pud)); ++ if (pud_none(pud) || pud_sect(pud)) { ++ note_page(st, addr, 2, pud_val(pud)); + } else { +- BUG_ON(pud_bad(*pud)); +- walk_pmd(st, pud, addr); ++ BUG_ON(pud_bad(pud)); ++ walk_pmd(st, pudp, addr); + } + } + } +@@ -335,17 +339,19 @@ static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start) + static void walk_pgd(struct pg_state *st, struct mm_struct *mm, + unsigned long start) + { +- pgd_t *pgd = pgd_offset(mm, 0UL); ++ pgd_t *pgdp = pgd_offset(mm, 0UL); + unsigned i; + unsigned long addr; + +- for (i = 0; i < PTRS_PER_PGD; i++, pgd++) { ++ for (i = 0; i < PTRS_PER_PGD; i++, pgdp++) { ++ pgd_t pgd = READ_ONCE(*pgdp); ++ + addr = start + i * PGDIR_SIZE; +- if (pgd_none(*pgd)) { +- note_page(st, addr, 1, pgd_val(*pgd)); ++ if (pgd_none(pgd)) { ++ note_page(st, addr, 1, pgd_val(pgd)); + } else { +- BUG_ON(pgd_bad(*pgd)); +- walk_pud(st, pgd, addr); ++ BUG_ON(pgd_bad(pgd)); ++ walk_pud(st, pgdp, addr); + } + } + } +diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c +index f76bb2c..bff1155 100644 +--- a/arch/arm64/mm/fault.c ++++ b/arch/arm64/mm/fault.c +@@ -130,7 +130,8 @@ static void mem_abort_decode(unsigned int esr) + void show_pte(unsigned long addr) + { + struct mm_struct *mm; +- pgd_t *pgd; ++ pgd_t *pgdp; ++ pgd_t pgd; + + if (addr < TASK_SIZE) { + /* TTBR0 */ +@@ -149,33 +150,37 @@ void show_pte(unsigned long addr) + return; + } + +- pr_alert("%s pgtable: %luk pages, %u-bit VAs, pgd = %p\n", ++ pr_alert("%s pgtable: %luk pages, %u-bit VAs, pgdp = %p\n", + mm == &init_mm ? "swapper" : "user", PAGE_SIZE / SZ_1K, + VA_BITS, mm->pgd); +- pgd = pgd_offset(mm, addr); +- pr_alert("[%016lx] *pgd=%016llx", addr, pgd_val(*pgd)); ++ pgdp = pgd_offset(mm, addr); ++ pgd = READ_ONCE(*pgdp); ++ pr_alert("[%016lx] pgd=%016llx", addr, pgd_val(pgd)); + + do { +- pud_t *pud; +- pmd_t *pmd; +- pte_t *pte; ++ pud_t *pudp, pud; ++ pmd_t *pmdp, pmd; ++ pte_t *ptep, pte; + +- if (pgd_none(*pgd) || pgd_bad(*pgd)) ++ if (pgd_none(pgd) || pgd_bad(pgd)) + break; + +- pud = pud_offset(pgd, addr); +- pr_cont(", *pud=%016llx", pud_val(*pud)); +- if (pud_none(*pud) || pud_bad(*pud)) ++ pudp = pud_offset(pgdp, addr); ++ pud = READ_ONCE(*pudp); ++ pr_cont(", pud=%016llx", pud_val(pud)); ++ if (pud_none(pud) || pud_bad(pud)) + break; + +- pmd = pmd_offset(pud, addr); +- pr_cont(", *pmd=%016llx", pmd_val(*pmd)); +- if (pmd_none(*pmd) || pmd_bad(*pmd)) ++ pmdp = pmd_offset(pudp, addr); ++ pmd = READ_ONCE(*pmdp); ++ pr_cont(", pmd=%016llx", pmd_val(pmd)); ++ if (pmd_none(pmd) || pmd_bad(pmd)) + break; + +- pte = pte_offset_map(pmd, addr); +- pr_cont(", *pte=%016llx", pte_val(*pte)); +- pte_unmap(pte); ++ ptep = pte_offset_map(pmdp, addr); ++ pte = READ_ONCE(*ptep); ++ pr_cont(", pte=%016llx", pte_val(pte)); ++ pte_unmap(ptep); + } while(0); + + pr_cont("\n"); +@@ -196,8 +201,9 @@ int ptep_set_access_flags(struct vm_area_struct *vma, + pte_t entry, int dirty) + { + pteval_t old_pteval, pteval; ++ pte_t pte = READ_ONCE(*ptep); + +- if (pte_same(*ptep, entry)) ++ if (pte_same(pte, entry)) + return 0; + + /* only preserve the access flags and write permission */ +@@ -210,7 +216,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma, + * (calculated as: a & b == ~(~a | ~b)). + */ + pte_val(entry) ^= PTE_RDONLY; +- pteval = READ_ONCE(pte_val(*ptep)); ++ pteval = pte_val(pte); + do { + old_pteval = pteval; + pteval ^= PTE_RDONLY; +diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c +index 6cb0fa9..ecc6818 100644 +--- a/arch/arm64/mm/hugetlbpage.c ++++ b/arch/arm64/mm/hugetlbpage.c +@@ -54,14 +54,14 @@ static inline pgprot_t pte_pgprot(pte_t pte) + static int find_num_contig(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, size_t *pgsize) + { +- pgd_t *pgd = pgd_offset(mm, addr); +- pud_t *pud; +- pmd_t *pmd; ++ pgd_t *pgdp = pgd_offset(mm, addr); ++ pud_t *pudp; ++ pmd_t *pmdp; + + *pgsize = PAGE_SIZE; +- pud = pud_offset(pgd, addr); +- pmd = pmd_offset(pud, addr); +- if ((pte_t *)pmd == ptep) { ++ pudp = pud_offset(pgdp, addr); ++ pmdp = pmd_offset(pudp, addr); ++ if ((pte_t *)pmdp == ptep) { + *pgsize = PMD_SIZE; + return CONT_PMDS; + } +@@ -181,11 +181,8 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, + + clear_flush(mm, addr, ptep, pgsize, ncontig); + +- for (i = 0; i < ncontig; i++, ptep++, addr += pgsize, pfn += dpfn) { +- pr_debug("%s: set pte %p to 0x%llx\n", __func__, ptep, +- pte_val(pfn_pte(pfn, hugeprot))); ++ for (i = 0; i < ncontig; i++, ptep++, addr += pgsize, pfn += dpfn) + set_pte_at(mm, addr, ptep, pfn_pte(pfn, hugeprot)); +- } + } + + void set_huge_swap_pte_at(struct mm_struct *mm, unsigned long addr, +@@ -203,20 +200,20 @@ void set_huge_swap_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *huge_pte_alloc(struct mm_struct *mm, + unsigned long addr, unsigned long sz) + { +- pgd_t *pgd; +- pud_t *pud; +- pte_t *pte = NULL; +- +- pr_debug("%s: addr:0x%lx sz:0x%lx\n", __func__, addr, sz); +- pgd = pgd_offset(mm, addr); +- pud = pud_alloc(mm, pgd, addr); +- if (!pud) ++ pgd_t *pgdp; ++ pud_t *pudp; ++ pmd_t *pmdp; ++ pte_t *ptep = NULL; ++ ++ pgdp = pgd_offset(mm, addr); ++ pudp = pud_alloc(mm, pgdp, addr); ++ if (!pudp) + return NULL; + + if (sz == PUD_SIZE) { +- pte = (pte_t *)pud; ++ ptep = (pte_t *)pudp; + } else if (sz == (PAGE_SIZE * CONT_PTES)) { +- pmd_t *pmd = pmd_alloc(mm, pud, addr); ++ pmdp = pmd_alloc(mm, pudp, addr); + + WARN_ON(addr & (sz - 1)); + /* +@@ -226,60 +223,55 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, + * will be no pte_unmap() to correspond with this + * pte_alloc_map(). + */ +- pte = pte_alloc_map(mm, pmd, addr); ++ ptep = pte_alloc_map(mm, pmdp, addr); + } else if (sz == PMD_SIZE) { + if (IS_ENABLED(CONFIG_ARCH_WANT_HUGE_PMD_SHARE) && +- pud_none(*pud)) +- pte = huge_pmd_share(mm, addr, pud); ++ pud_none(READ_ONCE(*pudp))) ++ ptep = huge_pmd_share(mm, addr, pudp); + else +- pte = (pte_t *)pmd_alloc(mm, pud, addr); ++ ptep = (pte_t *)pmd_alloc(mm, pudp, addr); + } else if (sz == (PMD_SIZE * CONT_PMDS)) { +- pmd_t *pmd; +- +- pmd = pmd_alloc(mm, pud, addr); ++ pmdp = pmd_alloc(mm, pudp, addr); + WARN_ON(addr & (sz - 1)); +- return (pte_t *)pmd; ++ return (pte_t *)pmdp; + } + +- pr_debug("%s: addr:0x%lx sz:0x%lx ret pte=%p/0x%llx\n", __func__, addr, +- sz, pte, pte_val(*pte)); +- return pte; ++ return ptep; + } + + pte_t *huge_pte_offset(struct mm_struct *mm, + unsigned long addr, unsigned long sz) + { +- pgd_t *pgd; +- pud_t *pud; +- pmd_t *pmd; ++ pgd_t *pgdp; ++ pud_t *pudp, pud; ++ pmd_t *pmdp, pmd; + +- pgd = pgd_offset(mm, addr); +- pr_debug("%s: addr:0x%lx pgd:%p\n", __func__, addr, pgd); +- if (!pgd_present(*pgd)) ++ pgdp = pgd_offset(mm, addr); ++ if (!pgd_present(READ_ONCE(*pgdp))) + return NULL; + +- pud = pud_offset(pgd, addr); +- if (sz != PUD_SIZE && pud_none(*pud)) ++ pudp = pud_offset(pgdp, addr); ++ pud = READ_ONCE(*pudp); ++ if (sz != PUD_SIZE && pud_none(pud)) + return NULL; + /* hugepage or swap? */ +- if (pud_huge(*pud) || !pud_present(*pud)) +- return (pte_t *)pud; ++ if (pud_huge(pud) || !pud_present(pud)) ++ return (pte_t *)pudp; + /* table; check the next level */ + + if (sz == CONT_PMD_SIZE) + addr &= CONT_PMD_MASK; + +- pmd = pmd_offset(pud, addr); ++ pmdp = pmd_offset(pudp, addr); ++ pmd = READ_ONCE(*pmdp); + if (!(sz == PMD_SIZE || sz == CONT_PMD_SIZE) && +- pmd_none(*pmd)) ++ pmd_none(pmd)) + return NULL; +- if (pmd_huge(*pmd) || !pmd_present(*pmd)) +- return (pte_t *)pmd; ++ if (pmd_huge(pmd) || !pmd_present(pmd)) ++ return (pte_t *)pmdp; + +- if (sz == CONT_PTE_SIZE) { +- pte_t *pte = pte_offset_kernel(pmd, (addr & CONT_PTE_MASK)); +- return pte; +- } ++ if (sz == CONT_PTE_SIZE) ++ return pte_offset_kernel(pmdp, (addr & CONT_PTE_MASK)); + + return NULL; + } +@@ -367,7 +359,7 @@ void huge_ptep_set_wrprotect(struct mm_struct *mm, + size_t pgsize; + pte_t pte; + +- if (!pte_cont(*ptep)) { ++ if (!pte_cont(READ_ONCE(*ptep))) { + ptep_set_wrprotect(mm, addr, ptep); + return; + } +@@ -391,7 +383,7 @@ void huge_ptep_clear_flush(struct vm_area_struct *vma, + size_t pgsize; + int ncontig; + +- if (!pte_cont(*ptep)) { ++ if (!pte_cont(READ_ONCE(*ptep))) { + ptep_clear_flush(vma, addr, ptep); + return; + } +diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c +index 6e02e6f..dabfc1e 100644 +--- a/arch/arm64/mm/kasan_init.c ++++ b/arch/arm64/mm/kasan_init.c +@@ -44,92 +44,92 @@ static phys_addr_t __init kasan_alloc_zeroed_page(int node) + return __pa(p); + } + +-static pte_t *__init kasan_pte_offset(pmd_t *pmd, unsigned long addr, int node, ++static pte_t *__init kasan_pte_offset(pmd_t *pmdp, unsigned long addr, int node, + bool early) + { +- if (pmd_none(*pmd)) { ++ if (pmd_none(READ_ONCE(*pmdp))) { + phys_addr_t pte_phys = early ? __pa_symbol(kasan_zero_pte) + : kasan_alloc_zeroed_page(node); +- __pmd_populate(pmd, pte_phys, PMD_TYPE_TABLE); ++ __pmd_populate(pmdp, pte_phys, PMD_TYPE_TABLE); + } + +- return early ? pte_offset_kimg(pmd, addr) +- : pte_offset_kernel(pmd, addr); ++ return early ? pte_offset_kimg(pmdp, addr) ++ : pte_offset_kernel(pmdp, addr); + } + +-static pmd_t *__init kasan_pmd_offset(pud_t *pud, unsigned long addr, int node, ++static pmd_t *__init kasan_pmd_offset(pud_t *pudp, unsigned long addr, int node, + bool early) + { +- if (pud_none(*pud)) { ++ if (pud_none(READ_ONCE(*pudp))) { + phys_addr_t pmd_phys = early ? __pa_symbol(kasan_zero_pmd) + : kasan_alloc_zeroed_page(node); +- __pud_populate(pud, pmd_phys, PMD_TYPE_TABLE); ++ __pud_populate(pudp, pmd_phys, PMD_TYPE_TABLE); + } + +- return early ? pmd_offset_kimg(pud, addr) : pmd_offset(pud, addr); ++ return early ? pmd_offset_kimg(pudp, addr) : pmd_offset(pudp, addr); + } + +-static pud_t *__init kasan_pud_offset(pgd_t *pgd, unsigned long addr, int node, ++static pud_t *__init kasan_pud_offset(pgd_t *pgdp, unsigned long addr, int node, + bool early) + { +- if (pgd_none(*pgd)) { ++ if (pgd_none(READ_ONCE(*pgdp))) { + phys_addr_t pud_phys = early ? __pa_symbol(kasan_zero_pud) + : kasan_alloc_zeroed_page(node); +- __pgd_populate(pgd, pud_phys, PMD_TYPE_TABLE); ++ __pgd_populate(pgdp, pud_phys, PMD_TYPE_TABLE); + } + +- return early ? pud_offset_kimg(pgd, addr) : pud_offset(pgd, addr); ++ return early ? pud_offset_kimg(pgdp, addr) : pud_offset(pgdp, addr); + } + +-static void __init kasan_pte_populate(pmd_t *pmd, unsigned long addr, ++static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr, + unsigned long end, int node, bool early) + { + unsigned long next; +- pte_t *pte = kasan_pte_offset(pmd, addr, node, early); ++ pte_t *ptep = kasan_pte_offset(pmdp, addr, node, early); + + do { + phys_addr_t page_phys = early ? __pa_symbol(kasan_zero_page) + : kasan_alloc_zeroed_page(node); + next = addr + PAGE_SIZE; +- set_pte(pte, pfn_pte(__phys_to_pfn(page_phys), PAGE_KERNEL)); +- } while (pte++, addr = next, addr != end && pte_none(*pte)); ++ set_pte(ptep, pfn_pte(__phys_to_pfn(page_phys), PAGE_KERNEL)); ++ } while (ptep++, addr = next, addr != end && pte_none(READ_ONCE(*ptep))); + } + +-static void __init kasan_pmd_populate(pud_t *pud, unsigned long addr, ++static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr, + unsigned long end, int node, bool early) + { + unsigned long next; +- pmd_t *pmd = kasan_pmd_offset(pud, addr, node, early); ++ pmd_t *pmdp = kasan_pmd_offset(pudp, addr, node, early); + + do { + next = pmd_addr_end(addr, end); +- kasan_pte_populate(pmd, addr, next, node, early); +- } while (pmd++, addr = next, addr != end && pmd_none(*pmd)); ++ kasan_pte_populate(pmdp, addr, next, node, early); ++ } while (pmdp++, addr = next, addr != end && pmd_none(READ_ONCE(*pmdp))); + } + +-static void __init kasan_pud_populate(pgd_t *pgd, unsigned long addr, ++static void __init kasan_pud_populate(pgd_t *pgdp, unsigned long addr, + unsigned long end, int node, bool early) + { + unsigned long next; +- pud_t *pud = kasan_pud_offset(pgd, addr, node, early); ++ pud_t *pudp = kasan_pud_offset(pgdp, addr, node, early); + + do { + next = pud_addr_end(addr, end); +- kasan_pmd_populate(pud, addr, next, node, early); +- } while (pud++, addr = next, addr != end && pud_none(*pud)); ++ kasan_pmd_populate(pudp, addr, next, node, early); ++ } while (pudp++, addr = next, addr != end && pud_none(READ_ONCE(*pudp))); + } + + static void __init kasan_pgd_populate(unsigned long addr, unsigned long end, + int node, bool early) + { + unsigned long next; +- pgd_t *pgd; ++ pgd_t *pgdp; + +- pgd = pgd_offset_k(addr); ++ pgdp = pgd_offset_k(addr); + do { + next = pgd_addr_end(addr, end); +- kasan_pud_populate(pgd, addr, next, node, early); +- } while (pgd++, addr = next, addr != end); ++ kasan_pud_populate(pgdp, addr, next, node, early); ++ } while (pgdp++, addr = next, addr != end); + } + + /* The early shadow maps everything to a single page of zeroes */ +@@ -155,14 +155,14 @@ static void __init kasan_map_populate(unsigned long start, unsigned long end, + */ + void __init kasan_copy_shadow(pgd_t *pgdir) + { +- pgd_t *pgd, *pgd_new, *pgd_end; ++ pgd_t *pgdp, *pgdp_new, *pgdp_end; + +- pgd = pgd_offset_k(KASAN_SHADOW_START); +- pgd_end = pgd_offset_k(KASAN_SHADOW_END); +- pgd_new = pgd_offset_raw(pgdir, KASAN_SHADOW_START); ++ pgdp = pgd_offset_k(KASAN_SHADOW_START); ++ pgdp_end = pgd_offset_k(KASAN_SHADOW_END); ++ pgdp_new = pgd_offset_raw(pgdir, KASAN_SHADOW_START); + do { +- set_pgd(pgd_new, *pgd); +- } while (pgd++, pgd_new++, pgd != pgd_end); ++ set_pgd(pgdp_new, READ_ONCE(*pgdp)); ++ } while (pgdp++, pgdp_new++, pgdp != pgdp_end); + } + + static void __init clear_pgds(unsigned long start, +diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c +index 4694cda..8c704f1 100644 +--- a/arch/arm64/mm/mmu.c ++++ b/arch/arm64/mm/mmu.c +@@ -108,7 +108,7 @@ static bool pgattr_change_is_safe(u64 old, u64 new) + * The following mapping attributes may be updated in live + * kernel mappings without the need for break-before-make. + */ +- static const pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE; ++ static const pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE | PTE_NG; + + /* creating or taking down mappings is always safe */ + if (old == 0 || new == 0) +@@ -118,52 +118,55 @@ static bool pgattr_change_is_safe(u64 old, u64 new) + if ((old | new) & PTE_CONT) + return false; + +- /* Transitioning from Global to Non-Global is safe */ +- if (((old ^ new) == PTE_NG) && (new & PTE_NG)) +- return true; ++ /* Transitioning from Non-Global to Global is unsafe */ ++ if (old & ~new & PTE_NG) ++ return false; + + return ((old ^ new) & ~mask) == 0; + } + +-static void init_pte(pmd_t *pmd, unsigned long addr, unsigned long end, ++static void init_pte(pmd_t *pmdp, unsigned long addr, unsigned long end, + phys_addr_t phys, pgprot_t prot) + { +- pte_t *pte; ++ pte_t *ptep; + +- pte = pte_set_fixmap_offset(pmd, addr); ++ ptep = pte_set_fixmap_offset(pmdp, addr); + do { +- pte_t old_pte = *pte; ++ pte_t old_pte = READ_ONCE(*ptep); + +- set_pte(pte, pfn_pte(__phys_to_pfn(phys), prot)); ++ set_pte(ptep, pfn_pte(__phys_to_pfn(phys), prot)); + + /* + * After the PTE entry has been populated once, we + * only allow updates to the permission attributes. + */ +- BUG_ON(!pgattr_change_is_safe(pte_val(old_pte), pte_val(*pte))); ++ BUG_ON(!pgattr_change_is_safe(pte_val(old_pte), ++ READ_ONCE(pte_val(*ptep)))); + + phys += PAGE_SIZE; +- } while (pte++, addr += PAGE_SIZE, addr != end); ++ } while (ptep++, addr += PAGE_SIZE, addr != end); + + pte_clear_fixmap(); + } + +-static void alloc_init_cont_pte(pmd_t *pmd, unsigned long addr, ++static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr, + unsigned long end, phys_addr_t phys, + pgprot_t prot, + phys_addr_t (*pgtable_alloc)(void), + int flags) + { + unsigned long next; ++ pmd_t pmd = READ_ONCE(*pmdp); + +- BUG_ON(pmd_sect(*pmd)); +- if (pmd_none(*pmd)) { ++ BUG_ON(pmd_sect(pmd)); ++ if (pmd_none(pmd)) { + phys_addr_t pte_phys; + BUG_ON(!pgtable_alloc); + pte_phys = pgtable_alloc(); +- __pmd_populate(pmd, pte_phys, PMD_TYPE_TABLE); ++ __pmd_populate(pmdp, pte_phys, PMD_TYPE_TABLE); ++ pmd = READ_ONCE(*pmdp); + } +- BUG_ON(pmd_bad(*pmd)); ++ BUG_ON(pmd_bad(pmd)); + + do { + pgprot_t __prot = prot; +@@ -175,67 +178,69 @@ static void alloc_init_cont_pte(pmd_t *pmd, unsigned long addr, + (flags & NO_CONT_MAPPINGS) == 0) + __prot = __pgprot(pgprot_val(prot) | PTE_CONT); + +- init_pte(pmd, addr, next, phys, __prot); ++ init_pte(pmdp, addr, next, phys, __prot); + + phys += next - addr; + } while (addr = next, addr != end); + } + +-static void init_pmd(pud_t *pud, unsigned long addr, unsigned long end, ++static void init_pmd(pud_t *pudp, unsigned long addr, unsigned long end, + phys_addr_t phys, pgprot_t prot, + phys_addr_t (*pgtable_alloc)(void), int flags) + { + unsigned long next; +- pmd_t *pmd; ++ pmd_t *pmdp; + +- pmd = pmd_set_fixmap_offset(pud, addr); ++ pmdp = pmd_set_fixmap_offset(pudp, addr); + do { +- pmd_t old_pmd = *pmd; ++ pmd_t old_pmd = READ_ONCE(*pmdp); + + next = pmd_addr_end(addr, end); + + /* try section mapping first */ + if (((addr | next | phys) & ~SECTION_MASK) == 0 && + (flags & NO_BLOCK_MAPPINGS) == 0) { +- pmd_set_huge(pmd, phys, prot); ++ pmd_set_huge(pmdp, phys, prot); + + /* + * After the PMD entry has been populated once, we + * only allow updates to the permission attributes. + */ + BUG_ON(!pgattr_change_is_safe(pmd_val(old_pmd), +- pmd_val(*pmd))); ++ READ_ONCE(pmd_val(*pmdp)))); + } else { +- alloc_init_cont_pte(pmd, addr, next, phys, prot, ++ alloc_init_cont_pte(pmdp, addr, next, phys, prot, + pgtable_alloc, flags); + + BUG_ON(pmd_val(old_pmd) != 0 && +- pmd_val(old_pmd) != pmd_val(*pmd)); ++ pmd_val(old_pmd) != READ_ONCE(pmd_val(*pmdp))); + } + phys += next - addr; +- } while (pmd++, addr = next, addr != end); ++ } while (pmdp++, addr = next, addr != end); + + pmd_clear_fixmap(); + } + +-static void alloc_init_cont_pmd(pud_t *pud, unsigned long addr, ++static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr, + unsigned long end, phys_addr_t phys, + pgprot_t prot, + phys_addr_t (*pgtable_alloc)(void), int flags) + { + unsigned long next; ++ pud_t pud = READ_ONCE(*pudp); + + /* + * Check for initial section mappings in the pgd/pud. + */ +- BUG_ON(pud_sect(*pud)); +- if (pud_none(*pud)) { ++ BUG_ON(pud_sect(pud)); ++ if (pud_none(pud)) { + phys_addr_t pmd_phys; + BUG_ON(!pgtable_alloc); + pmd_phys = pgtable_alloc(); +- __pud_populate(pud, pmd_phys, PUD_TYPE_TABLE); ++ __pud_populate(pudp, pmd_phys, PUD_TYPE_TABLE); ++ pud = READ_ONCE(*pudp); + } +- BUG_ON(pud_bad(*pud)); ++ BUG_ON(pud_bad(pud)); + + do { + pgprot_t __prot = prot; +@@ -247,7 +252,7 @@ static void alloc_init_cont_pmd(pud_t *pud, unsigned long addr, + (flags & NO_CONT_MAPPINGS) == 0) + __prot = __pgprot(pgprot_val(prot) | PTE_CONT); + +- init_pmd(pud, addr, next, phys, __prot, pgtable_alloc, flags); ++ init_pmd(pudp, addr, next, phys, __prot, pgtable_alloc, flags); + + phys += next - addr; + } while (addr = next, addr != end); +@@ -265,25 +270,27 @@ static inline bool use_1G_block(unsigned long addr, unsigned long next, + return true; + } + +-static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end, +- phys_addr_t phys, pgprot_t prot, +- phys_addr_t (*pgtable_alloc)(void), +- int flags) ++static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end, ++ phys_addr_t phys, pgprot_t prot, ++ phys_addr_t (*pgtable_alloc)(void), ++ int flags) + { +- pud_t *pud; + unsigned long next; ++ pud_t *pudp; ++ pgd_t pgd = READ_ONCE(*pgdp); + +- if (pgd_none(*pgd)) { ++ if (pgd_none(pgd)) { + phys_addr_t pud_phys; + BUG_ON(!pgtable_alloc); + pud_phys = pgtable_alloc(); +- __pgd_populate(pgd, pud_phys, PUD_TYPE_TABLE); ++ __pgd_populate(pgdp, pud_phys, PUD_TYPE_TABLE); ++ pgd = READ_ONCE(*pgdp); + } +- BUG_ON(pgd_bad(*pgd)); ++ BUG_ON(pgd_bad(pgd)); + +- pud = pud_set_fixmap_offset(pgd, addr); ++ pudp = pud_set_fixmap_offset(pgdp, addr); + do { +- pud_t old_pud = *pud; ++ pud_t old_pud = READ_ONCE(*pudp); + + next = pud_addr_end(addr, end); + +@@ -292,23 +299,23 @@ static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end, + */ + if (use_1G_block(addr, next, phys) && + (flags & NO_BLOCK_MAPPINGS) == 0) { +- pud_set_huge(pud, phys, prot); ++ pud_set_huge(pudp, phys, prot); + + /* + * After the PUD entry has been populated once, we + * only allow updates to the permission attributes. + */ + BUG_ON(!pgattr_change_is_safe(pud_val(old_pud), +- pud_val(*pud))); ++ READ_ONCE(pud_val(*pudp)))); + } else { +- alloc_init_cont_pmd(pud, addr, next, phys, prot, ++ alloc_init_cont_pmd(pudp, addr, next, phys, prot, + pgtable_alloc, flags); + + BUG_ON(pud_val(old_pud) != 0 && +- pud_val(old_pud) != pud_val(*pud)); ++ pud_val(old_pud) != READ_ONCE(pud_val(*pudp))); + } + phys += next - addr; +- } while (pud++, addr = next, addr != end); ++ } while (pudp++, addr = next, addr != end); + + pud_clear_fixmap(); + } +@@ -320,7 +327,7 @@ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys, + int flags) + { + unsigned long addr, length, end, next; +- pgd_t *pgd = pgd_offset_raw(pgdir, virt); ++ pgd_t *pgdp = pgd_offset_raw(pgdir, virt); + + /* + * If the virtual and physical address don't have the same offset +@@ -336,10 +343,10 @@ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys, + end = addr + length; + do { + next = pgd_addr_end(addr, end); +- alloc_init_pud(pgd, addr, next, phys, prot, pgtable_alloc, ++ alloc_init_pud(pgdp, addr, next, phys, prot, pgtable_alloc, + flags); + phys += next - addr; +- } while (pgd++, addr = next, addr != end); ++ } while (pgdp++, addr = next, addr != end); + } + + static phys_addr_t pgd_pgtable_alloc(void) +@@ -401,10 +408,10 @@ static void update_mapping_prot(phys_addr_t phys, unsigned long virt, + flush_tlb_kernel_range(virt, virt + size); + } + +-static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, ++static void __init __map_memblock(pgd_t *pgdp, phys_addr_t start, + phys_addr_t end, pgprot_t prot, int flags) + { +- __create_pgd_mapping(pgd, start, __phys_to_virt(start), end - start, ++ __create_pgd_mapping(pgdp, start, __phys_to_virt(start), end - start, + prot, early_pgtable_alloc, flags); + } + +@@ -418,7 +425,7 @@ void __init mark_linear_text_alias_ro(void) + PAGE_KERNEL_RO); + } + +-static void __init map_mem(pgd_t *pgd) ++static void __init map_mem(pgd_t *pgdp) + { + phys_addr_t kernel_start = __pa_symbol(_text); + phys_addr_t kernel_end = __pa_symbol(__init_begin); +@@ -451,7 +458,7 @@ static void __init map_mem(pgd_t *pgd) + if (memblock_is_nomap(reg)) + continue; + +- __map_memblock(pgd, start, end, PAGE_KERNEL, flags); ++ __map_memblock(pgdp, start, end, PAGE_KERNEL, flags); + } + + /* +@@ -464,7 +471,7 @@ static void __init map_mem(pgd_t *pgd) + * Note that contiguous mappings cannot be remapped in this way, + * so we should avoid them here. + */ +- __map_memblock(pgd, kernel_start, kernel_end, ++ __map_memblock(pgdp, kernel_start, kernel_end, + PAGE_KERNEL, NO_CONT_MAPPINGS); + memblock_clear_nomap(kernel_start, kernel_end - kernel_start); + +@@ -475,7 +482,7 @@ static void __init map_mem(pgd_t *pgd) + * through /sys/kernel/kexec_crash_size interface. + */ + if (crashk_res.end) { +- __map_memblock(pgd, crashk_res.start, crashk_res.end + 1, ++ __map_memblock(pgdp, crashk_res.start, crashk_res.end + 1, + PAGE_KERNEL, + NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS); + memblock_clear_nomap(crashk_res.start, +@@ -499,7 +506,7 @@ void mark_rodata_ro(void) + debug_checkwx(); + } + +-static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end, ++static void __init map_kernel_segment(pgd_t *pgdp, void *va_start, void *va_end, + pgprot_t prot, struct vm_struct *vma, + int flags, unsigned long vm_flags) + { +@@ -509,7 +516,7 @@ static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end, + BUG_ON(!PAGE_ALIGNED(pa_start)); + BUG_ON(!PAGE_ALIGNED(size)); + +- __create_pgd_mapping(pgd, pa_start, (unsigned long)va_start, size, prot, ++ __create_pgd_mapping(pgdp, pa_start, (unsigned long)va_start, size, prot, + early_pgtable_alloc, flags); + + if (!(vm_flags & VM_NO_GUARD)) +@@ -562,7 +569,7 @@ core_initcall(map_entry_trampoline); + /* + * Create fine-grained mappings for the kernel. + */ +-static void __init map_kernel(pgd_t *pgd) ++static void __init map_kernel(pgd_t *pgdp) + { + static struct vm_struct vmlinux_text, vmlinux_rodata, vmlinux_inittext, + vmlinux_initdata, vmlinux_data; +@@ -578,24 +585,24 @@ static void __init map_kernel(pgd_t *pgd) + * Only rodata will be remapped with different permissions later on, + * all other segments are allowed to use contiguous mappings. + */ +- map_kernel_segment(pgd, _text, _etext, text_prot, &vmlinux_text, 0, ++ map_kernel_segment(pgdp, _text, _etext, text_prot, &vmlinux_text, 0, + VM_NO_GUARD); +- map_kernel_segment(pgd, __start_rodata, __inittext_begin, PAGE_KERNEL, ++ map_kernel_segment(pgdp, __start_rodata, __inittext_begin, PAGE_KERNEL, + &vmlinux_rodata, NO_CONT_MAPPINGS, VM_NO_GUARD); +- map_kernel_segment(pgd, __inittext_begin, __inittext_end, text_prot, ++ map_kernel_segment(pgdp, __inittext_begin, __inittext_end, text_prot, + &vmlinux_inittext, 0, VM_NO_GUARD); +- map_kernel_segment(pgd, __initdata_begin, __initdata_end, PAGE_KERNEL, ++ map_kernel_segment(pgdp, __initdata_begin, __initdata_end, PAGE_KERNEL, + &vmlinux_initdata, 0, VM_NO_GUARD); +- map_kernel_segment(pgd, _data, _end, PAGE_KERNEL, &vmlinux_data, 0, 0); ++ map_kernel_segment(pgdp, _data, _end, PAGE_KERNEL, &vmlinux_data, 0, 0); + +- if (!pgd_val(*pgd_offset_raw(pgd, FIXADDR_START))) { ++ if (!READ_ONCE(pgd_val(*pgd_offset_raw(pgdp, FIXADDR_START)))) { + /* + * The fixmap falls in a separate pgd to the kernel, and doesn't + * live in the carveout for the swapper_pg_dir. We can simply + * re-use the existing dir for the fixmap. + */ +- set_pgd(pgd_offset_raw(pgd, FIXADDR_START), +- *pgd_offset_k(FIXADDR_START)); ++ set_pgd(pgd_offset_raw(pgdp, FIXADDR_START), ++ READ_ONCE(*pgd_offset_k(FIXADDR_START))); + } else if (CONFIG_PGTABLE_LEVELS > 3) { + /* + * The fixmap shares its top level pgd entry with the kernel +@@ -604,14 +611,15 @@ static void __init map_kernel(pgd_t *pgd) + * entry instead. + */ + BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES)); +- pud_populate(&init_mm, pud_set_fixmap_offset(pgd, FIXADDR_START), ++ pud_populate(&init_mm, ++ pud_set_fixmap_offset(pgdp, FIXADDR_START), + lm_alias(bm_pmd)); + pud_clear_fixmap(); + } else { + BUG(); + } + +- kasan_copy_shadow(pgd); ++ kasan_copy_shadow(pgdp); + } + + /* +@@ -621,10 +629,10 @@ static void __init map_kernel(pgd_t *pgd) + void __init paging_init(void) + { + phys_addr_t pgd_phys = early_pgtable_alloc(); +- pgd_t *pgd = pgd_set_fixmap(pgd_phys); ++ pgd_t *pgdp = pgd_set_fixmap(pgd_phys); + +- map_kernel(pgd); +- map_mem(pgd); ++ map_kernel(pgdp); ++ map_mem(pgdp); + + /* + * We want to reuse the original swapper_pg_dir so we don't have to +@@ -635,7 +643,7 @@ void __init paging_init(void) + * To do this we need to go via a temporary pgd. + */ + cpu_replace_ttbr1(__va(pgd_phys)); +- memcpy(swapper_pg_dir, pgd, PGD_SIZE); ++ memcpy(swapper_pg_dir, pgdp, PGD_SIZE); + cpu_replace_ttbr1(lm_alias(swapper_pg_dir)); + + pgd_clear_fixmap(); +@@ -655,37 +663,40 @@ void __init paging_init(void) + */ + int kern_addr_valid(unsigned long addr) + { +- pgd_t *pgd; +- pud_t *pud; +- pmd_t *pmd; +- pte_t *pte; ++ pgd_t *pgdp; ++ pud_t *pudp, pud; ++ pmd_t *pmdp, pmd; ++ pte_t *ptep, pte; + + if ((((long)addr) >> VA_BITS) != -1UL) + return 0; + +- pgd = pgd_offset_k(addr); +- if (pgd_none(*pgd)) ++ pgdp = pgd_offset_k(addr); ++ if (pgd_none(READ_ONCE(*pgdp))) + return 0; + +- pud = pud_offset(pgd, addr); +- if (pud_none(*pud)) ++ pudp = pud_offset(pgdp, addr); ++ pud = READ_ONCE(*pudp); ++ if (pud_none(pud)) + return 0; + +- if (pud_sect(*pud)) +- return pfn_valid(pud_pfn(*pud)); ++ if (pud_sect(pud)) ++ return pfn_valid(pud_pfn(pud)); + +- pmd = pmd_offset(pud, addr); +- if (pmd_none(*pmd)) ++ pmdp = pmd_offset(pudp, addr); ++ pmd = READ_ONCE(*pmdp); ++ if (pmd_none(pmd)) + return 0; + +- if (pmd_sect(*pmd)) +- return pfn_valid(pmd_pfn(*pmd)); ++ if (pmd_sect(pmd)) ++ return pfn_valid(pmd_pfn(pmd)); + +- pte = pte_offset_kernel(pmd, addr); +- if (pte_none(*pte)) ++ ptep = pte_offset_kernel(pmdp, addr); ++ pte = READ_ONCE(*ptep); ++ if (pte_none(pte)) + return 0; + +- return pfn_valid(pte_pfn(*pte)); ++ return pfn_valid(pte_pfn(pte)); + } + #ifdef CONFIG_SPARSEMEM_VMEMMAP + #if !ARM64_SWAPPER_USES_SECTION_MAPS +@@ -700,32 +711,32 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node, + { + unsigned long addr = start; + unsigned long next; +- pgd_t *pgd; +- pud_t *pud; +- pmd_t *pmd; ++ pgd_t *pgdp; ++ pud_t *pudp; ++ pmd_t *pmdp; + + do { + next = pmd_addr_end(addr, end); + +- pgd = vmemmap_pgd_populate(addr, node); +- if (!pgd) ++ pgdp = vmemmap_pgd_populate(addr, node); ++ if (!pgdp) + return -ENOMEM; + +- pud = vmemmap_pud_populate(pgd, addr, node); +- if (!pud) ++ pudp = vmemmap_pud_populate(pgdp, addr, node); ++ if (!pudp) + return -ENOMEM; + +- pmd = pmd_offset(pud, addr); +- if (pmd_none(*pmd)) { ++ pmdp = pmd_offset(pudp, addr); ++ if (pmd_none(READ_ONCE(*pmdp))) { + void *p = NULL; + + p = vmemmap_alloc_block_buf(PMD_SIZE, node); + if (!p) + return -ENOMEM; + +- pmd_set_huge(pmd, __pa(p), __pgprot(PROT_SECT_NORMAL)); ++ pmd_set_huge(pmdp, __pa(p), __pgprot(PROT_SECT_NORMAL)); + } else +- vmemmap_verify((pte_t *)pmd, node, addr, next); ++ vmemmap_verify((pte_t *)pmdp, node, addr, next); + } while (addr = next, addr != end); + + return 0; +@@ -739,20 +750,22 @@ void vmemmap_free(unsigned long start, unsigned long end, + + static inline pud_t * fixmap_pud(unsigned long addr) + { +- pgd_t *pgd = pgd_offset_k(addr); ++ pgd_t *pgdp = pgd_offset_k(addr); ++ pgd_t pgd = READ_ONCE(*pgdp); + +- BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd)); ++ BUG_ON(pgd_none(pgd) || pgd_bad(pgd)); + +- return pud_offset_kimg(pgd, addr); ++ return pud_offset_kimg(pgdp, addr); + } + + static inline pmd_t * fixmap_pmd(unsigned long addr) + { +- pud_t *pud = fixmap_pud(addr); ++ pud_t *pudp = fixmap_pud(addr); ++ pud_t pud = READ_ONCE(*pudp); + +- BUG_ON(pud_none(*pud) || pud_bad(*pud)); ++ BUG_ON(pud_none(pud) || pud_bad(pud)); + +- return pmd_offset_kimg(pud, addr); ++ return pmd_offset_kimg(pudp, addr); + } + + static inline pte_t * fixmap_pte(unsigned long addr) +@@ -768,30 +781,31 @@ static inline pte_t * fixmap_pte(unsigned long addr) + */ + void __init early_fixmap_init(void) + { +- pgd_t *pgd; +- pud_t *pud; +- pmd_t *pmd; ++ pgd_t *pgdp, pgd; ++ pud_t *pudp; ++ pmd_t *pmdp; + unsigned long addr = FIXADDR_START; + +- pgd = pgd_offset_k(addr); ++ pgdp = pgd_offset_k(addr); ++ pgd = READ_ONCE(*pgdp); + if (CONFIG_PGTABLE_LEVELS > 3 && +- !(pgd_none(*pgd) || pgd_page_paddr(*pgd) == __pa_symbol(bm_pud))) { ++ !(pgd_none(pgd) || pgd_page_paddr(pgd) == __pa_symbol(bm_pud))) { + /* + * We only end up here if the kernel mapping and the fixmap + * share the top level pgd entry, which should only happen on + * 16k/4 levels configurations. + */ + BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES)); +- pud = pud_offset_kimg(pgd, addr); ++ pudp = pud_offset_kimg(pgdp, addr); + } else { +- if (pgd_none(*pgd)) +- __pgd_populate(pgd, __pa_symbol(bm_pud), PUD_TYPE_TABLE); +- pud = fixmap_pud(addr); ++ if (pgd_none(pgd)) ++ __pgd_populate(pgdp, __pa_symbol(bm_pud), PUD_TYPE_TABLE); ++ pudp = fixmap_pud(addr); + } +- if (pud_none(*pud)) +- __pud_populate(pud, __pa_symbol(bm_pmd), PMD_TYPE_TABLE); +- pmd = fixmap_pmd(addr); +- __pmd_populate(pmd, __pa_symbol(bm_pte), PMD_TYPE_TABLE); ++ if (pud_none(READ_ONCE(*pudp))) ++ __pud_populate(pudp, __pa_symbol(bm_pmd), PMD_TYPE_TABLE); ++ pmdp = fixmap_pmd(addr); ++ __pmd_populate(pmdp, __pa_symbol(bm_pte), PMD_TYPE_TABLE); + + /* + * The boot-ioremap range spans multiple pmds, for which +@@ -800,11 +814,11 @@ void __init early_fixmap_init(void) + BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT) + != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT)); + +- if ((pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN))) +- || pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_END))) { ++ if ((pmdp != fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN))) ++ || pmdp != fixmap_pmd(fix_to_virt(FIX_BTMAP_END))) { + WARN_ON(1); +- pr_warn("pmd %p != %p, %p\n", +- pmd, fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)), ++ pr_warn("pmdp %p != %p, %p\n", ++ pmdp, fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)), + fixmap_pmd(fix_to_virt(FIX_BTMAP_END))); + pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n", + fix_to_virt(FIX_BTMAP_BEGIN)); +@@ -824,16 +838,16 @@ void __set_fixmap(enum fixed_addresses idx, + phys_addr_t phys, pgprot_t flags) + { + unsigned long addr = __fix_to_virt(idx); +- pte_t *pte; ++ pte_t *ptep; + + BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses); + +- pte = fixmap_pte(addr); ++ ptep = fixmap_pte(addr); + + if (pgprot_val(flags)) { +- set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags)); ++ set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, flags)); + } else { +- pte_clear(&init_mm, addr, pte); ++ pte_clear(&init_mm, addr, ptep); + flush_tlb_kernel_range(addr, addr+PAGE_SIZE); + } + } +@@ -915,36 +929,46 @@ int __init arch_ioremap_pmd_supported(void) + return 1; + } + +-int pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot) ++int pud_set_huge(pud_t *pudp, phys_addr_t phys, pgprot_t prot) + { + pgprot_t sect_prot = __pgprot(PUD_TYPE_SECT | + pgprot_val(mk_sect_prot(prot))); ++ ++ /* ioremap_page_range doesn't honour BBM */ ++ if (pud_present(READ_ONCE(*pudp))) ++ return 0; ++ + BUG_ON(phys & ~PUD_MASK); +- set_pud(pud, pfn_pud(__phys_to_pfn(phys), sect_prot)); ++ set_pud(pudp, pfn_pud(__phys_to_pfn(phys), sect_prot)); + return 1; + } + +-int pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot) ++int pmd_set_huge(pmd_t *pmdp, phys_addr_t phys, pgprot_t prot) + { + pgprot_t sect_prot = __pgprot(PMD_TYPE_SECT | + pgprot_val(mk_sect_prot(prot))); ++ ++ /* ioremap_page_range doesn't honour BBM */ ++ if (pmd_present(READ_ONCE(*pmdp))) ++ return 0; ++ + BUG_ON(phys & ~PMD_MASK); +- set_pmd(pmd, pfn_pmd(__phys_to_pfn(phys), sect_prot)); ++ set_pmd(pmdp, pfn_pmd(__phys_to_pfn(phys), sect_prot)); + return 1; + } + +-int pud_clear_huge(pud_t *pud) ++int pud_clear_huge(pud_t *pudp) + { +- if (!pud_sect(*pud)) ++ if (!pud_sect(READ_ONCE(*pudp))) + return 0; +- pud_clear(pud); ++ pud_clear(pudp); + return 1; + } + +-int pmd_clear_huge(pmd_t *pmd) ++int pmd_clear_huge(pmd_t *pmdp) + { +- if (!pmd_sect(*pmd)) ++ if (!pmd_sect(READ_ONCE(*pmdp))) + return 0; +- pmd_clear(pmd); ++ pmd_clear(pmdp); + return 1; + } +diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c +index a682a0a..a563593 100644 +--- a/arch/arm64/mm/pageattr.c ++++ b/arch/arm64/mm/pageattr.c +@@ -29,7 +29,7 @@ static int change_page_range(pte_t *ptep, pgtable_t token, unsigned long addr, + void *data) + { + struct page_change_data *cdata = data; +- pte_t pte = *ptep; ++ pte_t pte = READ_ONCE(*ptep); + + pte = clear_pte_bit(pte, cdata->clear_mask); + pte = set_pte_bit(pte, cdata->set_mask); +@@ -156,30 +156,32 @@ void __kernel_map_pages(struct page *page, int numpages, int enable) + */ + bool kernel_page_present(struct page *page) + { +- pgd_t *pgd; +- pud_t *pud; +- pmd_t *pmd; +- pte_t *pte; ++ pgd_t *pgdp; ++ pud_t *pudp, pud; ++ pmd_t *pmdp, pmd; ++ pte_t *ptep; + unsigned long addr = (unsigned long)page_address(page); + +- pgd = pgd_offset_k(addr); +- if (pgd_none(*pgd)) ++ pgdp = pgd_offset_k(addr); ++ if (pgd_none(READ_ONCE(*pgdp))) + return false; + +- pud = pud_offset(pgd, addr); +- if (pud_none(*pud)) ++ pudp = pud_offset(pgdp, addr); ++ pud = READ_ONCE(*pudp); ++ if (pud_none(pud)) + return false; +- if (pud_sect(*pud)) ++ if (pud_sect(pud)) + return true; + +- pmd = pmd_offset(pud, addr); +- if (pmd_none(*pmd)) ++ pmdp = pmd_offset(pudp, addr); ++ pmd = READ_ONCE(*pmdp); ++ if (pmd_none(pmd)) + return false; +- if (pmd_sect(*pmd)) ++ if (pmd_sect(pmd)) + return true; + +- pte = pte_offset_kernel(pmd, addr); +- return pte_valid(*pte); ++ ptep = pte_offset_kernel(pmdp, addr); ++ return pte_valid(READ_ONCE(*ptep)); + } + #endif /* CONFIG_HIBERNATION */ + #endif /* CONFIG_DEBUG_PAGEALLOC */ +diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S +index 71baed7..c0af476 100644 +--- a/arch/arm64/mm/proc.S ++++ b/arch/arm64/mm/proc.S +@@ -205,7 +205,8 @@ ENDPROC(idmap_cpu_replace_ttbr1) + dc cvac, cur_\()\type\()p // Ensure any existing dirty + dmb sy // lines are written back before + ldr \type, [cur_\()\type\()p] // loading the entry +- tbz \type, #0, next_\()\type // Skip invalid entries ++ tbz \type, #0, skip_\()\type // Skip invalid and ++ tbnz \type, #11, skip_\()\type // non-global entries + .endm + + .macro __idmap_kpti_put_pgtable_ent_ng, type +@@ -265,8 +266,9 @@ ENTRY(idmap_kpti_install_ng_mappings) + add end_pgdp, cur_pgdp, #(PTRS_PER_PGD * 8) + do_pgd: __idmap_kpti_get_pgtable_ent pgd + tbnz pgd, #1, walk_puds +- __idmap_kpti_put_pgtable_ent_ng pgd + next_pgd: ++ __idmap_kpti_put_pgtable_ent_ng pgd ++skip_pgd: + add cur_pgdp, cur_pgdp, #8 + cmp cur_pgdp, end_pgdp + b.ne do_pgd +@@ -294,8 +296,9 @@ walk_puds: + add end_pudp, cur_pudp, #(PTRS_PER_PUD * 8) + do_pud: __idmap_kpti_get_pgtable_ent pud + tbnz pud, #1, walk_pmds +- __idmap_kpti_put_pgtable_ent_ng pud + next_pud: ++ __idmap_kpti_put_pgtable_ent_ng pud ++skip_pud: + add cur_pudp, cur_pudp, 8 + cmp cur_pudp, end_pudp + b.ne do_pud +@@ -314,8 +317,9 @@ walk_pmds: + add end_pmdp, cur_pmdp, #(PTRS_PER_PMD * 8) + do_pmd: __idmap_kpti_get_pgtable_ent pmd + tbnz pmd, #1, walk_ptes +- __idmap_kpti_put_pgtable_ent_ng pmd + next_pmd: ++ __idmap_kpti_put_pgtable_ent_ng pmd ++skip_pmd: + add cur_pmdp, cur_pmdp, #8 + cmp cur_pmdp, end_pmdp + b.ne do_pmd +@@ -333,7 +337,7 @@ walk_ptes: + add end_ptep, cur_ptep, #(PTRS_PER_PTE * 8) + do_pte: __idmap_kpti_get_pgtable_ent pte + __idmap_kpti_put_pgtable_ent_ng pte +-next_pte: ++skip_pte: + add cur_ptep, cur_ptep, #8 + cmp cur_ptep, end_ptep + b.ne do_pte +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index 1d4f1da..a933504 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -250,8 +250,9 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx) + off = offsetof(struct bpf_array, map.max_entries); + emit_a64_mov_i64(tmp, off, ctx); + emit(A64_LDR32(tmp, r2, tmp), ctx); ++ emit(A64_MOV(0, r3, r3), ctx); + emit(A64_CMP(0, r3, tmp), ctx); +- emit(A64_B_(A64_COND_GE, jmp_offset), ctx); ++ emit(A64_B_(A64_COND_CS, jmp_offset), ctx); + + /* if (tail_call_cnt > MAX_TAIL_CALL_CNT) + * goto out; +@@ -259,7 +260,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx) + */ + emit_a64_mov_i64(tmp, MAX_TAIL_CALL_CNT, ctx); + emit(A64_CMP(1, tcc, tmp), ctx); +- emit(A64_B_(A64_COND_GT, jmp_offset), ctx); ++ emit(A64_B_(A64_COND_HI, jmp_offset), ctx); + emit(A64_ADD_I(1, tcc, tcc, 1), ctx); + + /* prog = array->ptrs[index]; +diff --git a/arch/cris/include/arch-v10/arch/bug.h b/arch/cris/include/arch-v10/arch/bug.h +index 905afea..06da9d4 100644 +--- a/arch/cris/include/arch-v10/arch/bug.h ++++ b/arch/cris/include/arch-v10/arch/bug.h +@@ -44,18 +44,25 @@ struct bug_frame { + * not be used like this with newer versions of gcc. + */ + #define BUG() \ ++do { \ + __asm__ __volatile__ ("clear.d [" __stringify(BUG_MAGIC) "]\n\t"\ + "movu.w " __stringify(__LINE__) ",$r0\n\t"\ + "jump 0f\n\t" \ + ".section .rodata\n" \ + "0:\t.string \"" __FILE__ "\"\n\t" \ +- ".previous") ++ ".previous"); \ ++ unreachable(); \ ++} while (0) + #endif + + #else + + /* This just causes an oops. */ +-#define BUG() (*(int *)0 = 0) ++#define BUG() \ ++do { \ ++ barrier_before_unreachable(); \ ++ __builtin_trap(); \ ++} while (0) + + #endif + +diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h +index 762eeb0f..2524fb6 100644 +--- a/arch/ia64/include/asm/atomic.h ++++ b/arch/ia64/include/asm/atomic.h +@@ -66,38 +66,35 @@ ATOMIC_OPS(add, +) + ATOMIC_OPS(sub, -) + + #ifdef __OPTIMIZE__ +-#define __ia64_atomic_const(i) __builtin_constant_p(i) ? \ ++#define __ia64_atomic_const(i) \ ++ static const int __ia64_atomic_p = __builtin_constant_p(i) ? \ + ((i) == 1 || (i) == 4 || (i) == 8 || (i) == 16 || \ +- (i) == -1 || (i) == -4 || (i) == -8 || (i) == -16) : 0 ++ (i) == -1 || (i) == -4 || (i) == -8 || (i) == -16) : 0;\ ++ __ia64_atomic_p ++#else ++#define __ia64_atomic_const(i) 0 ++#endif + +-#define atomic_add_return(i, v) \ ++#define atomic_add_return(i,v) \ + ({ \ +- int __i = (i); \ +- static const int __ia64_atomic_p = __ia64_atomic_const(i); \ +- __ia64_atomic_p ? ia64_fetch_and_add(__i, &(v)->counter) : \ +- ia64_atomic_add(__i, v); \ ++ int __ia64_aar_i = (i); \ ++ __ia64_atomic_const(i) \ ++ ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \ ++ : ia64_atomic_add(__ia64_aar_i, v); \ + }) + +-#define atomic_sub_return(i, v) \ ++#define atomic_sub_return(i,v) \ + ({ \ +- int __i = (i); \ +- static const int __ia64_atomic_p = __ia64_atomic_const(i); \ +- __ia64_atomic_p ? ia64_fetch_and_add(-__i, &(v)->counter) : \ +- ia64_atomic_sub(__i, v); \ ++ int __ia64_asr_i = (i); \ ++ __ia64_atomic_const(i) \ ++ ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter) \ ++ : ia64_atomic_sub(__ia64_asr_i, v); \ + }) +-#else +-#define atomic_add_return(i, v) ia64_atomic_add(i, v) +-#define atomic_sub_return(i, v) ia64_atomic_sub(i, v) +-#endif + + #define atomic_fetch_add(i,v) \ + ({ \ + int __ia64_aar_i = (i); \ +- (__builtin_constant_p(i) \ +- && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ +- || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ +- || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ +- || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ ++ __ia64_atomic_const(i) \ + ? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq) \ + : ia64_atomic_fetch_add(__ia64_aar_i, v); \ + }) +@@ -105,11 +102,7 @@ ATOMIC_OPS(sub, -) + #define atomic_fetch_sub(i,v) \ + ({ \ + int __ia64_asr_i = (i); \ +- (__builtin_constant_p(i) \ +- && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ +- || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ +- || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ +- || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ ++ __ia64_atomic_const(i) \ + ? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq) \ + : ia64_atomic_fetch_sub(__ia64_asr_i, v); \ + }) +@@ -170,11 +163,7 @@ ATOMIC64_OPS(sub, -) + #define atomic64_add_return(i,v) \ + ({ \ + long __ia64_aar_i = (i); \ +- (__builtin_constant_p(i) \ +- && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ +- || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ +- || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ +- || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ ++ __ia64_atomic_const(i) \ + ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \ + : ia64_atomic64_add(__ia64_aar_i, v); \ + }) +@@ -182,11 +171,7 @@ ATOMIC64_OPS(sub, -) + #define atomic64_sub_return(i,v) \ + ({ \ + long __ia64_asr_i = (i); \ +- (__builtin_constant_p(i) \ +- && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ +- || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ +- || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ +- || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ ++ __ia64_atomic_const(i) \ + ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter) \ + : ia64_atomic64_sub(__ia64_asr_i, v); \ + }) +@@ -194,11 +179,7 @@ ATOMIC64_OPS(sub, -) + #define atomic64_fetch_add(i,v) \ + ({ \ + long __ia64_aar_i = (i); \ +- (__builtin_constant_p(i) \ +- && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ +- || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ +- || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ +- || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ ++ __ia64_atomic_const(i) \ + ? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq) \ + : ia64_atomic64_fetch_add(__ia64_aar_i, v); \ + }) +@@ -206,11 +187,7 @@ ATOMIC64_OPS(sub, -) + #define atomic64_fetch_sub(i,v) \ + ({ \ + long __ia64_asr_i = (i); \ +- (__builtin_constant_p(i) \ +- && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ +- || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ +- || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ +- || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ ++ __ia64_atomic_const(i) \ + ? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq) \ + : ia64_atomic64_fetch_sub(__ia64_asr_i, v); \ + }) +diff --git a/arch/ia64/include/asm/bug.h b/arch/ia64/include/asm/bug.h +index bd3eeb8..66b37a5 100644 +--- a/arch/ia64/include/asm/bug.h ++++ b/arch/ia64/include/asm/bug.h +@@ -4,7 +4,11 @@ + + #ifdef CONFIG_BUG + #define ia64_abort() __builtin_trap() +-#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); ia64_abort(); } while (0) ++#define BUG() do { \ ++ printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ ++ barrier_before_unreachable(); \ ++ ia64_abort(); \ ++} while (0) + + /* should this BUG be made generic? */ + #define HAVE_ARCH_BUG +diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile +index 0b4c65a..498f3da 100644 +--- a/arch/ia64/kernel/Makefile ++++ b/arch/ia64/kernel/Makefile +@@ -41,7 +41,6 @@ ifneq ($(CONFIG_IA64_ESI),) + obj-y += esi_stub.o # must be in kernel proper + endif + obj-$(CONFIG_INTEL_IOMMU) += pci-dma.o +-obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o + + obj-$(CONFIG_BINFMT_ELF) += elfcore.o + +diff --git a/arch/ia64/kernel/err_inject.c b/arch/ia64/kernel/err_inject.c +index 85bba43..8b5b8e6b 100644 +--- a/arch/ia64/kernel/err_inject.c ++++ b/arch/ia64/kernel/err_inject.c +@@ -117,7 +117,7 @@ store_call_start(struct device *dev, struct device_attribute *attr, + + #ifdef ERR_INJ_DEBUG + printk(KERN_DEBUG "Returns: status=%d,\n", (int)status[cpu]); +- printk(KERN_DEBUG "capapbilities=%lx,\n", capabilities[cpu]); ++ printk(KERN_DEBUG "capabilities=%lx,\n", capabilities[cpu]); + printk(KERN_DEBUG "resources=%lx\n", resources[cpu]); + #endif + return size; +@@ -142,7 +142,7 @@ store_virtual_to_phys(struct device *dev, struct device_attribute *attr, + u64 virt_addr=simple_strtoull(buf, NULL, 16); + int ret; + +- ret = get_user_pages(virt_addr, 1, FOLL_WRITE, NULL, NULL); ++ ret = get_user_pages_fast(virt_addr, 1, FOLL_WRITE, NULL); + if (ret<=0) { + #ifdef ERR_INJ_DEBUG + printk("Virtual address %lx is not existing.\n",virt_addr); +diff --git a/arch/ia64/scripts/unwcheck.py b/arch/ia64/scripts/unwcheck.py +index 89f3a148..c55276e 100644 +--- a/arch/ia64/scripts/unwcheck.py ++++ b/arch/ia64/scripts/unwcheck.py +@@ -16,7 +16,7 @@ import re + import sys + + if len(sys.argv) != 2: +- print "Usage: %s FILE" % sys.argv[0] ++ print("Usage: %s FILE" % sys.argv[0]) + sys.exit(2) + + readelf = os.getenv("READELF", "readelf") +@@ -29,7 +29,7 @@ def check_func (func, slots, rlen_sum): + global num_errors + num_errors += 1 + if not func: func = "[%#x-%#x]" % (start, end) +- print "ERROR: %s: %lu slots, total region length = %lu" % (func, slots, rlen_sum) ++ print("ERROR: %s: %lu slots, total region length = %lu" % (func, slots, rlen_sum)) + return + + num_funcs = 0 +@@ -43,23 +43,23 @@ for line in os.popen("%s -u %s" % (readelf, sys.argv[1])): + check_func(func, slots, rlen_sum) + + func = m.group(1) +- start = long(m.group(2), 16) +- end = long(m.group(3), 16) ++ start = int(m.group(2), 16) ++ end = int(m.group(3), 16) + slots = 3 * (end - start) / 16 +- rlen_sum = 0L ++ rlen_sum = 0 + num_funcs += 1 + else: + m = rlen_pattern.match(line) + if m: +- rlen_sum += long(m.group(1)) ++ rlen_sum += int(m.group(1)) + check_func(func, slots, rlen_sum) + + if num_errors == 0: +- print "No errors detected in %u functions." % num_funcs ++ print("No errors detected in %u functions." % num_funcs) + else: + if num_errors > 1: + err="errors" + else: + err="error" +- print "%u %s detected in %u functions." % (num_errors, err, num_funcs) ++ print("%u %s detected in %u functions." % (num_errors, err, num_funcs)) + sys.exit(1) +diff --git a/arch/m68k/include/asm/bug.h b/arch/m68k/include/asm/bug.h +index b7e2bf1..275dca1 100644 +--- a/arch/m68k/include/asm/bug.h ++++ b/arch/m68k/include/asm/bug.h +@@ -8,16 +8,19 @@ + #ifndef CONFIG_SUN3 + #define BUG() do { \ + pr_crit("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ ++ barrier_before_unreachable(); \ + __builtin_trap(); \ + } while (0) + #else + #define BUG() do { \ + pr_crit("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ ++ barrier_before_unreachable(); \ + panic("BUG!"); \ + } while (0) + #endif + #else + #define BUG() do { \ ++ barrier_before_unreachable(); \ + __builtin_trap(); \ + } while (0) + #endif +diff --git a/arch/mips/ath25/board.c b/arch/mips/ath25/board.c +index 9ab48ff..6d11ae5 100644 +--- a/arch/mips/ath25/board.c ++++ b/arch/mips/ath25/board.c +@@ -135,6 +135,8 @@ int __init ath25_find_config(phys_addr_t base, unsigned long size) + } + + board_data = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL); ++ if (!board_data) ++ goto error; + ath25_board.config = (struct ath25_boarddata *)board_data; + memcpy_fromio(board_data, bcfg, 0x100); + if (broken_boarddata) { +diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile +index 1bd5c4f..c22da16 100644 +--- a/arch/mips/boot/Makefile ++++ b/arch/mips/boot/Makefile +@@ -126,6 +126,7 @@ $(obj)/vmlinux.its.S: $(addprefix $(srctree)/arch/mips/$(PLATFORM)/,$(ITS_INPUTS + + quiet_cmd_cpp_its_S = ITS $@ + cmd_cpp_its_S = $(CPP) $(cpp_flags) -P -C -o $@ $< \ ++ -D__ASSEMBLY__ \ + -DKERNEL_NAME="\"Linux $(KERNELRELEASE)\"" \ + -DVMLINUX_BINARY="\"$(3)\"" \ + -DVMLINUX_COMPRESSION="\"$(2)\"" \ +diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c +index 5b3a3f6..d99f524 100644 +--- a/arch/mips/cavium-octeon/octeon-irq.c ++++ b/arch/mips/cavium-octeon/octeon-irq.c +@@ -2277,6 +2277,8 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, + } + + host_data = kzalloc(sizeof(*host_data), GFP_KERNEL); ++ if (!host_data) ++ return -ENOMEM; + raw_spin_lock_init(&host_data->lock); + + addr = of_get_address(ciu_node, 0, NULL, NULL); +diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h +index 946681d..9a0fa66 100644 +--- a/arch/mips/include/asm/compat.h ++++ b/arch/mips/include/asm/compat.h +@@ -86,7 +86,6 @@ struct compat_flock { + compat_off_t l_len; + s32 l_sysid; + compat_pid_t l_pid; +- short __unused; + s32 pad[4]; + }; + +diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c +index 19c88d7..fcf9af4 100644 +--- a/arch/mips/kernel/mips-cpc.c ++++ b/arch/mips/kernel/mips-cpc.c +@@ -10,6 +10,8 @@ + + #include + #include ++#include ++#include + #include + + #include +@@ -22,6 +24,17 @@ static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags); + + phys_addr_t __weak mips_cpc_default_phys_base(void) + { ++ struct device_node *cpc_node; ++ struct resource res; ++ int err; ++ ++ cpc_node = of_find_compatible_node(of_root, NULL, "mti,mips-cpc"); ++ if (cpc_node) { ++ err = of_address_to_resource(cpc_node, 0, &res); ++ if (!err) ++ return res.start; ++ } ++ + return 0; + } + +diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c +index 85bc601..5f8b0a9 100644 +--- a/arch/mips/kernel/setup.c ++++ b/arch/mips/kernel/setup.c +@@ -375,6 +375,7 @@ static void __init bootmem_init(void) + unsigned long reserved_end; + unsigned long mapstart = ~0UL; + unsigned long bootmap_size; ++ phys_addr_t ramstart = (phys_addr_t)ULLONG_MAX; + bool bootmap_valid = false; + int i; + +@@ -395,7 +396,8 @@ static void __init bootmem_init(void) + max_low_pfn = 0; + + /* +- * Find the highest page frame number we have available. ++ * Find the highest page frame number we have available ++ * and the lowest used RAM address + */ + for (i = 0; i < boot_mem_map.nr_map; i++) { + unsigned long start, end; +@@ -407,6 +409,8 @@ static void __init bootmem_init(void) + end = PFN_DOWN(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + ++ ramstart = min(ramstart, boot_mem_map.map[i].addr); ++ + #ifndef CONFIG_HIGHMEM + /* + * Skip highmem here so we get an accurate max_low_pfn if low +@@ -436,6 +440,13 @@ static void __init bootmem_init(void) + mapstart = max(reserved_end, start); + } + ++ /* ++ * Reserve any memory between the start of RAM and PHYS_OFFSET ++ */ ++ if (ramstart > PHYS_OFFSET) ++ add_memory_region(PHYS_OFFSET, ramstart - PHYS_OFFSET, ++ BOOT_MEM_RESERVED); ++ + if (min_low_pfn >= max_low_pfn) + panic("Incorrect memory mapping !!!"); + if (min_low_pfn > ARCH_PFN_OFFSET) { +@@ -664,9 +675,6 @@ static int __init early_parse_mem(char *p) + + add_memory_region(start, size, BOOT_MEM_RAM); + +- if (start && start > PHYS_OFFSET) +- add_memory_region(PHYS_OFFSET, start - PHYS_OFFSET, +- BOOT_MEM_RESERVED); + return 0; + } + early_param("mem", early_parse_mem); +diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c +index 87dcac2..159e83a 100644 +--- a/arch/mips/kernel/smp-bmips.c ++++ b/arch/mips/kernel/smp-bmips.c +@@ -168,11 +168,11 @@ static void bmips_prepare_cpus(unsigned int max_cpus) + return; + } + +- if (request_irq(IPI0_IRQ, bmips_ipi_interrupt, IRQF_PERCPU, +- "smp_ipi0", NULL)) ++ if (request_irq(IPI0_IRQ, bmips_ipi_interrupt, ++ IRQF_PERCPU | IRQF_NO_SUSPEND, "smp_ipi0", NULL)) + panic("Can't request IPI0 interrupt"); +- if (request_irq(IPI1_IRQ, bmips_ipi_interrupt, IRQF_PERCPU, +- "smp_ipi1", NULL)) ++ if (request_irq(IPI1_IRQ, bmips_ipi_interrupt, ++ IRQF_PERCPU | IRQF_NO_SUSPEND, "smp_ipi1", NULL)) + panic("Can't request IPI1 interrupt"); + } + +@@ -572,7 +572,7 @@ asmlinkage void __weak plat_wired_tlb_setup(void) + */ + } + +-void __init bmips_cpu_setup(void) ++void bmips_cpu_setup(void) + { + void __iomem __maybe_unused *cbr = BMIPS_GET_CBR(); + u32 __maybe_unused cfg; +diff --git a/arch/mips/loongson64/Kconfig b/arch/mips/loongson64/Kconfig +index bc2fdbf..72af0c1 100644 +--- a/arch/mips/loongson64/Kconfig ++++ b/arch/mips/loongson64/Kconfig +@@ -7,6 +7,8 @@ choice + config LEMOTE_FULOONG2E + bool "Lemote Fuloong(2e) mini-PC" + select ARCH_SPARSEMEM_ENABLE ++ select ARCH_MIGHT_HAVE_PC_PARPORT ++ select ARCH_MIGHT_HAVE_PC_SERIO + select CEVT_R4K + select CSRC_R4K + select SYS_HAS_CPU_LOONGSON2E +@@ -33,6 +35,8 @@ config LEMOTE_FULOONG2E + config LEMOTE_MACH2F + bool "Lemote Loongson 2F family machines" + select ARCH_SPARSEMEM_ENABLE ++ select ARCH_MIGHT_HAVE_PC_PARPORT ++ select ARCH_MIGHT_HAVE_PC_SERIO + select BOARD_SCACHE + select BOOT_ELF32 + select CEVT_R4K if ! MIPS_EXTERNAL_TIMER +@@ -62,6 +66,8 @@ config LEMOTE_MACH2F + config LOONGSON_MACH3X + bool "Generic Loongson 3 family machines" + select ARCH_SPARSEMEM_ENABLE ++ select ARCH_MIGHT_HAVE_PC_PARPORT ++ select ARCH_MIGHT_HAVE_PC_SERIO + select GENERIC_ISA_DMA_SUPPORT_BROKEN + select BOOT_ELF32 + select BOARD_SCACHE +diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h +index 3742508..bd5ce31 100644 +--- a/arch/parisc/include/asm/cacheflush.h ++++ b/arch/parisc/include/asm/cacheflush.h +@@ -26,6 +26,7 @@ void flush_user_icache_range_asm(unsigned long, unsigned long); + void flush_kernel_icache_range_asm(unsigned long, unsigned long); + void flush_user_dcache_range_asm(unsigned long, unsigned long); + void flush_kernel_dcache_range_asm(unsigned long, unsigned long); ++void purge_kernel_dcache_range_asm(unsigned long, unsigned long); + void flush_kernel_dcache_page_asm(void *); + void flush_kernel_icache_page(void *); + +diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h +index 0e6ab6e..2dbe558 100644 +--- a/arch/parisc/include/asm/processor.h ++++ b/arch/parisc/include/asm/processor.h +@@ -316,6 +316,8 @@ extern int _parisc_requires_coherency; + #define parisc_requires_coherency() (0) + #endif + ++extern int running_on_qemu; ++ + #endif /* __ASSEMBLY__ */ + + #endif /* __ASM_PARISC_PROCESSOR_H */ +diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c +index 19c0c14..7908977 100644 +--- a/arch/parisc/kernel/cache.c ++++ b/arch/parisc/kernel/cache.c +@@ -465,10 +465,10 @@ EXPORT_SYMBOL(copy_user_page); + int __flush_tlb_range(unsigned long sid, unsigned long start, + unsigned long end) + { +- unsigned long flags, size; ++ unsigned long flags; + +- size = (end - start); +- if (size >= parisc_tlb_flush_threshold) { ++ if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && ++ end - start >= parisc_tlb_flush_threshold) { + flush_tlb_all(); + return 1; + } +@@ -539,13 +539,11 @@ void flush_cache_mm(struct mm_struct *mm) + struct vm_area_struct *vma; + pgd_t *pgd; + +- /* Flush the TLB to avoid speculation if coherency is required. */ +- if (parisc_requires_coherency()) +- flush_tlb_all(); +- + /* Flushing the whole cache on each cpu takes forever on + rp3440, etc. So, avoid it if the mm isn't too big. */ +- if (mm_total_size(mm) >= parisc_cache_flush_threshold) { ++ if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && ++ mm_total_size(mm) >= parisc_cache_flush_threshold) { ++ flush_tlb_all(); + flush_cache_all(); + return; + } +@@ -553,9 +551,9 @@ void flush_cache_mm(struct mm_struct *mm) + if (mm->context == mfsp(3)) { + for (vma = mm->mmap; vma; vma = vma->vm_next) { + flush_user_dcache_range_asm(vma->vm_start, vma->vm_end); +- if ((vma->vm_flags & VM_EXEC) == 0) +- continue; +- flush_user_icache_range_asm(vma->vm_start, vma->vm_end); ++ if (vma->vm_flags & VM_EXEC) ++ flush_user_icache_range_asm(vma->vm_start, vma->vm_end); ++ flush_tlb_range(vma, vma->vm_start, vma->vm_end); + } + return; + } +@@ -581,14 +579,9 @@ void flush_cache_mm(struct mm_struct *mm) + void flush_cache_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) + { +- BUG_ON(!vma->vm_mm->context); +- +- /* Flush the TLB to avoid speculation if coherency is required. */ +- if (parisc_requires_coherency()) ++ if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && ++ end - start >= parisc_cache_flush_threshold) { + flush_tlb_range(vma, start, end); +- +- if ((end - start) >= parisc_cache_flush_threshold +- || vma->vm_mm->context != mfsp(3)) { + flush_cache_all(); + return; + } +@@ -596,6 +589,7 @@ void flush_cache_range(struct vm_area_struct *vma, + flush_user_dcache_range_asm(start, end); + if (vma->vm_flags & VM_EXEC) + flush_user_icache_range_asm(start, end); ++ flush_tlb_range(vma, start, end); + } + + void +@@ -604,8 +598,7 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long + BUG_ON(!vma->vm_mm->context); + + if (pfn_valid(pfn)) { +- if (parisc_requires_coherency()) +- flush_tlb_page(vma, vmaddr); ++ flush_tlb_page(vma, vmaddr); + __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn)); + } + } +@@ -613,21 +606,33 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long + void flush_kernel_vmap_range(void *vaddr, int size) + { + unsigned long start = (unsigned long)vaddr; ++ unsigned long end = start + size; + +- if ((unsigned long)size > parisc_cache_flush_threshold) ++ if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && ++ (unsigned long)size >= parisc_cache_flush_threshold) { ++ flush_tlb_kernel_range(start, end); + flush_data_cache(); +- else +- flush_kernel_dcache_range_asm(start, start + size); ++ return; ++ } ++ ++ flush_kernel_dcache_range_asm(start, end); ++ flush_tlb_kernel_range(start, end); + } + EXPORT_SYMBOL(flush_kernel_vmap_range); + + void invalidate_kernel_vmap_range(void *vaddr, int size) + { + unsigned long start = (unsigned long)vaddr; ++ unsigned long end = start + size; + +- if ((unsigned long)size > parisc_cache_flush_threshold) ++ if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && ++ (unsigned long)size >= parisc_cache_flush_threshold) { ++ flush_tlb_kernel_range(start, end); + flush_data_cache(); +- else +- flush_kernel_dcache_range_asm(start, start + size); ++ return; ++ } ++ ++ purge_kernel_dcache_range_asm(start, end); ++ flush_tlb_kernel_range(start, end); + } + EXPORT_SYMBOL(invalidate_kernel_vmap_range); +diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S +index bbbe360..fbb4e43 100644 +--- a/arch/parisc/kernel/head.S ++++ b/arch/parisc/kernel/head.S +@@ -138,6 +138,16 @@ $pgt_fill_loop: + std %dp,0x18(%r10) + #endif + ++#ifdef CONFIG_64BIT ++ /* Get PDCE_PROC for monarch CPU. */ ++#define MEM_PDC_LO 0x388 ++#define MEM_PDC_HI 0x35C ++ ldw MEM_PDC_LO(%r0),%r3 ++ ldw MEM_PDC_HI(%r0),%r10 ++ depd %r10, 31, 32, %r3 /* move to upper word */ ++#endif ++ ++ + #ifdef CONFIG_SMP + /* Set the smp rendezvous address into page zero. + ** It would be safer to do this in init_smp_config() but +@@ -196,12 +206,6 @@ common_stext: + ** Someday, palo might not do this for the Monarch either. + */ + 2: +-#define MEM_PDC_LO 0x388 +-#define MEM_PDC_HI 0x35C +- ldw MEM_PDC_LO(%r0),%r3 +- ldw MEM_PDC_HI(%r0),%r6 +- depd %r6, 31, 32, %r3 /* move to upper word */ +- + mfctl %cr30,%r6 /* PCX-W2 firmware bug */ + + ldo PDC_PSW(%r0),%arg0 /* 21 */ +@@ -268,6 +272,8 @@ $install_iva: + aligned_rfi: + pcxt_ssm_bug + ++ copy %r3, %arg0 /* PDCE_PROC for smp_callin() */ ++ + rsm PSW_SM_QUIET,%r0 /* off troublesome PSW bits */ + /* Don't need NOPs, have 8 compliant insn before rfi */ + +diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S +index 2d40c4f..67b0f75 100644 +--- a/arch/parisc/kernel/pacache.S ++++ b/arch/parisc/kernel/pacache.S +@@ -1110,6 +1110,28 @@ ENTRY_CFI(flush_kernel_dcache_range_asm) + .procend + ENDPROC_CFI(flush_kernel_dcache_range_asm) + ++ENTRY_CFI(purge_kernel_dcache_range_asm) ++ .proc ++ .callinfo NO_CALLS ++ .entry ++ ++ ldil L%dcache_stride, %r1 ++ ldw R%dcache_stride(%r1), %r23 ++ ldo -1(%r23), %r21 ++ ANDCM %r26, %r21, %r26 ++ ++1: cmpb,COND(<<),n %r26, %r25,1b ++ pdc,m %r23(%r26) ++ ++ sync ++ syncdma ++ bv %r0(%r2) ++ nop ++ .exit ++ ++ .procend ++ENDPROC_CFI(purge_kernel_dcache_range_asm) ++ + ENTRY_CFI(flush_user_icache_range_asm) + .proc + .callinfo NO_CALLS +diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c +index 30c28ab..4065b5e 100644 +--- a/arch/parisc/kernel/smp.c ++++ b/arch/parisc/kernel/smp.c +@@ -292,10 +292,15 @@ smp_cpu_init(int cpunum) + * Slaves start using C here. Indirectly called from smp_slave_stext. + * Do what start_kernel() and main() do for boot strap processor (aka monarch) + */ +-void __init smp_callin(void) ++void __init smp_callin(unsigned long pdce_proc) + { + int slave_id = cpu_now_booting; + ++#ifdef CONFIG_64BIT ++ WARN_ON(((unsigned long)(PAGE0->mem_pdc_hi) << 32 ++ | PAGE0->mem_pdc) != pdce_proc); ++#endif ++ + smp_cpu_init(slave_id); + preempt_disable(); + +diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c +index 4b8fd6d..f7e6845 100644 +--- a/arch/parisc/kernel/time.c ++++ b/arch/parisc/kernel/time.c +@@ -76,10 +76,10 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id) + next_tick = cpuinfo->it_value; + + /* Calculate how many ticks have elapsed. */ ++ now = mfctl(16); + do { + ++ticks_elapsed; + next_tick += cpt; +- now = mfctl(16); + } while (next_tick - now > cpt); + + /* Store (in CR16 cycles) up to when we are accounting right now. */ +@@ -103,16 +103,17 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id) + * if one or the other wrapped. If "now" is "bigger" we'll end up + * with a very large unsigned number. + */ +- while (next_tick - mfctl(16) > cpt) ++ now = mfctl(16); ++ while (next_tick - now > cpt) + next_tick += cpt; + + /* Program the IT when to deliver the next interrupt. + * Only bottom 32-bits of next_tick are writable in CR16! + * Timer interrupt will be delivered at least a few hundred cycles +- * after the IT fires, so if we are too close (<= 500 cycles) to the ++ * after the IT fires, so if we are too close (<= 8000 cycles) to the + * next cycle, simply skip it. + */ +- if (next_tick - mfctl(16) <= 500) ++ if (next_tick - now <= 8000) + next_tick += cpt; + mtctl(next_tick, 16); + +@@ -248,7 +249,7 @@ static int __init init_cr16_clocksource(void) + * different sockets, so mark them unstable and lower rating on + * multi-socket SMP systems. + */ +- if (num_online_cpus() > 1) { ++ if (num_online_cpus() > 1 && !running_on_qemu) { + int cpu; + unsigned long cpu0_loc; + cpu0_loc = per_cpu(cpu_data, 0).cpu_loc; +diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c +index 48f4139..cab32ee 100644 +--- a/arch/parisc/mm/init.c ++++ b/arch/parisc/mm/init.c +@@ -629,7 +629,12 @@ void __init mem_init(void) + #endif + + mem_init_print_info(NULL); +-#ifdef CONFIG_DEBUG_KERNEL /* double-sanity-check paranoia */ ++ ++#if 0 ++ /* ++ * Do not expose the virtual kernel memory layout to userspace. ++ * But keep code for debugging purposes. ++ */ + printk("virtual kernel memory layout:\n" + " vmalloc : 0x%px - 0x%px (%4ld MB)\n" + " memory : 0x%px - 0x%px (%4ld MB)\n" +diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile +index ef6549e..26d5d2a 100644 +--- a/arch/powerpc/boot/Makefile ++++ b/arch/powerpc/boot/Makefile +@@ -101,7 +101,8 @@ $(addprefix $(obj)/,$(zlib-y)): \ + libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c + libfdtheader := fdt.h libfdt.h libfdt_internal.h + +-$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o): \ ++$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o \ ++ treeboot-akebono.o treeboot-currituck.o treeboot-iss4xx.o): \ + $(addprefix $(obj)/,$(libfdtheader)) + + src-wlib-y := string.S crt0.S stdio.c decompress.c main.c \ +diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h +index 30a155c..c615abd 100644 +--- a/arch/powerpc/include/asm/book3s/32/pgtable.h ++++ b/arch/powerpc/include/asm/book3s/32/pgtable.h +@@ -16,6 +16,7 @@ + #define PGD_INDEX_SIZE (32 - PGDIR_SHIFT) + + #define PMD_CACHE_INDEX PMD_INDEX_SIZE ++#define PUD_CACHE_INDEX PUD_INDEX_SIZE + + #ifndef __ASSEMBLY__ + #define PTE_TABLE_SIZE (sizeof(pte_t) << PTE_INDEX_SIZE) +diff --git a/arch/powerpc/include/asm/book3s/64/hash-4k.h b/arch/powerpc/include/asm/book3s/64/hash-4k.h +index 949d691..67c5475 100644 +--- a/arch/powerpc/include/asm/book3s/64/hash-4k.h ++++ b/arch/powerpc/include/asm/book3s/64/hash-4k.h +@@ -63,7 +63,8 @@ static inline int hash__hugepd_ok(hugepd_t hpd) + * keeping the prototype consistent across the two formats. + */ + static inline unsigned long pte_set_hidx(pte_t *ptep, real_pte_t rpte, +- unsigned int subpg_index, unsigned long hidx) ++ unsigned int subpg_index, unsigned long hidx, ++ int offset) + { + return (hidx << H_PAGE_F_GIX_SHIFT) & + (H_PAGE_F_SECOND | H_PAGE_F_GIX); +diff --git a/arch/powerpc/include/asm/book3s/64/hash-64k.h b/arch/powerpc/include/asm/book3s/64/hash-64k.h +index 338b7da..3bcf269 100644 +--- a/arch/powerpc/include/asm/book3s/64/hash-64k.h ++++ b/arch/powerpc/include/asm/book3s/64/hash-64k.h +@@ -45,7 +45,7 @@ + * generic accessors and iterators here + */ + #define __real_pte __real_pte +-static inline real_pte_t __real_pte(pte_t pte, pte_t *ptep) ++static inline real_pte_t __real_pte(pte_t pte, pte_t *ptep, int offset) + { + real_pte_t rpte; + unsigned long *hidxp; +@@ -59,7 +59,7 @@ static inline real_pte_t __real_pte(pte_t pte, pte_t *ptep) + */ + smp_rmb(); + +- hidxp = (unsigned long *)(ptep + PTRS_PER_PTE); ++ hidxp = (unsigned long *)(ptep + offset); + rpte.hidx = *hidxp; + return rpte; + } +@@ -86,9 +86,10 @@ static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index) + * expected to modify the PTE bits accordingly and commit the PTE to memory. + */ + static inline unsigned long pte_set_hidx(pte_t *ptep, real_pte_t rpte, +- unsigned int subpg_index, unsigned long hidx) ++ unsigned int subpg_index, ++ unsigned long hidx, int offset) + { +- unsigned long *hidxp = (unsigned long *)(ptep + PTRS_PER_PTE); ++ unsigned long *hidxp = (unsigned long *)(ptep + offset); + + rpte.hidx &= ~HIDX_BITS(0xfUL, subpg_index); + *hidxp = rpte.hidx | HIDX_BITS(HIDX_SHIFT_BY_ONE(hidx), subpg_index); +@@ -140,13 +141,18 @@ static inline int hash__remap_4k_pfn(struct vm_area_struct *vma, unsigned long a + } + + #define H_PTE_TABLE_SIZE PTE_FRAG_SIZE +-#ifdef CONFIG_TRANSPARENT_HUGEPAGE ++#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined (CONFIG_HUGETLB_PAGE) + #define H_PMD_TABLE_SIZE ((sizeof(pmd_t) << PMD_INDEX_SIZE) + \ + (sizeof(unsigned long) << PMD_INDEX_SIZE)) + #else + #define H_PMD_TABLE_SIZE (sizeof(pmd_t) << PMD_INDEX_SIZE) + #endif ++#ifdef CONFIG_HUGETLB_PAGE ++#define H_PUD_TABLE_SIZE ((sizeof(pud_t) << PUD_INDEX_SIZE) + \ ++ (sizeof(unsigned long) << PUD_INDEX_SIZE)) ++#else + #define H_PUD_TABLE_SIZE (sizeof(pud_t) << PUD_INDEX_SIZE) ++#endif + #define H_PGD_TABLE_SIZE (sizeof(pgd_t) << PGD_INDEX_SIZE) + + #ifdef CONFIG_TRANSPARENT_HUGEPAGE +diff --git a/arch/powerpc/include/asm/book3s/64/hash.h b/arch/powerpc/include/asm/book3s/64/hash.h +index 0920eff..935adcd 100644 +--- a/arch/powerpc/include/asm/book3s/64/hash.h ++++ b/arch/powerpc/include/asm/book3s/64/hash.h +@@ -23,7 +23,8 @@ + H_PUD_INDEX_SIZE + H_PGD_INDEX_SIZE + PAGE_SHIFT) + #define H_PGTABLE_RANGE (ASM_CONST(1) << H_PGTABLE_EADDR_SIZE) + +-#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && defined(CONFIG_PPC_64K_PAGES) ++#if (defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_HUGETLB_PAGE)) && \ ++ defined(CONFIG_PPC_64K_PAGES) + /* + * only with hash 64k we need to use the second half of pmd page table + * to store pointer to deposited pgtable_t +@@ -33,6 +34,16 @@ + #define H_PMD_CACHE_INDEX H_PMD_INDEX_SIZE + #endif + /* ++ * We store the slot details in the second half of page table. ++ * Increase the pud level table so that hugetlb ptes can be stored ++ * at pud level. ++ */ ++#if defined(CONFIG_HUGETLB_PAGE) && defined(CONFIG_PPC_64K_PAGES) ++#define H_PUD_CACHE_INDEX (H_PUD_INDEX_SIZE + 1) ++#else ++#define H_PUD_CACHE_INDEX (H_PUD_INDEX_SIZE) ++#endif ++/* + * Define the address range of the kernel non-linear virtual area + */ + #define H_KERN_VIRT_START ASM_CONST(0xD000000000000000) +diff --git a/arch/powerpc/include/asm/book3s/64/pgalloc.h b/arch/powerpc/include/asm/book3s/64/pgalloc.h +index 1fcfa42..4746bc6 100644 +--- a/arch/powerpc/include/asm/book3s/64/pgalloc.h ++++ b/arch/powerpc/include/asm/book3s/64/pgalloc.h +@@ -73,10 +73,16 @@ static inline void radix__pgd_free(struct mm_struct *mm, pgd_t *pgd) + + static inline pgd_t *pgd_alloc(struct mm_struct *mm) + { ++ pgd_t *pgd; ++ + if (radix_enabled()) + return radix__pgd_alloc(mm); +- return kmem_cache_alloc(PGT_CACHE(PGD_INDEX_SIZE), +- pgtable_gfp_flags(mm, GFP_KERNEL)); ++ ++ pgd = kmem_cache_alloc(PGT_CACHE(PGD_INDEX_SIZE), ++ pgtable_gfp_flags(mm, GFP_KERNEL)); ++ memset(pgd, 0, PGD_TABLE_SIZE); ++ ++ return pgd; + } + + static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) +@@ -93,13 +99,13 @@ static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) + + static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) + { +- return kmem_cache_alloc(PGT_CACHE(PUD_INDEX_SIZE), ++ return kmem_cache_alloc(PGT_CACHE(PUD_CACHE_INDEX), + pgtable_gfp_flags(mm, GFP_KERNEL)); + } + + static inline void pud_free(struct mm_struct *mm, pud_t *pud) + { +- kmem_cache_free(PGT_CACHE(PUD_INDEX_SIZE), pud); ++ kmem_cache_free(PGT_CACHE(PUD_CACHE_INDEX), pud); + } + + static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) +@@ -115,7 +121,7 @@ static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud, + * ahead and flush the page walk cache + */ + flush_tlb_pgtable(tlb, address); +- pgtable_free_tlb(tlb, pud, PUD_INDEX_SIZE); ++ pgtable_free_tlb(tlb, pud, PUD_CACHE_INDEX); + } + + static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) +diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h +index 5101772..a6b9f1d 100644 +--- a/arch/powerpc/include/asm/book3s/64/pgtable.h ++++ b/arch/powerpc/include/asm/book3s/64/pgtable.h +@@ -232,11 +232,13 @@ extern unsigned long __pmd_index_size; + extern unsigned long __pud_index_size; + extern unsigned long __pgd_index_size; + extern unsigned long __pmd_cache_index; ++extern unsigned long __pud_cache_index; + #define PTE_INDEX_SIZE __pte_index_size + #define PMD_INDEX_SIZE __pmd_index_size + #define PUD_INDEX_SIZE __pud_index_size + #define PGD_INDEX_SIZE __pgd_index_size + #define PMD_CACHE_INDEX __pmd_cache_index ++#define PUD_CACHE_INDEX __pud_cache_index + /* + * Because of use of pte fragments and THP, size of page table + * are not always derived out of index size above. +@@ -348,7 +350,7 @@ extern unsigned long pci_io_base; + */ + #ifndef __real_pte + +-#define __real_pte(e,p) ((real_pte_t){(e)}) ++#define __real_pte(e, p, o) ((real_pte_t){(e)}) + #define __rpte_to_pte(r) ((r).pte) + #define __rpte_to_hidx(r,index) (pte_val(__rpte_to_pte(r)) >> H_PAGE_F_GIX_SHIFT) + +diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h +index 176dfb7..471b227 100644 +--- a/arch/powerpc/include/asm/exception-64s.h ++++ b/arch/powerpc/include/asm/exception-64s.h +@@ -645,7 +645,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943) + EXC_HV, SOFTEN_TEST_HV, bitmask) + + #define MASKABLE_RELON_EXCEPTION_HV_OOL(vec, label, bitmask) \ +- MASKABLE_EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_NOTEST_HV, vec, bitmask);\ ++ MASKABLE_EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_TEST_HV, vec, bitmask);\ + EXCEPTION_RELON_PROLOG_PSERIES_1(label, EXC_HV) + + /* +diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h +index 511acfd..535add3 100644 +--- a/arch/powerpc/include/asm/firmware.h ++++ b/arch/powerpc/include/asm/firmware.h +@@ -52,7 +52,7 @@ + #define FW_FEATURE_TYPE1_AFFINITY ASM_CONST(0x0000000100000000) + #define FW_FEATURE_PRRN ASM_CONST(0x0000000200000000) + #define FW_FEATURE_DRMEM_V2 ASM_CONST(0x0000000400000000) +-#define FW_FEATURE_DRC_INFO ASM_CONST(0x0000000400000000) ++#define FW_FEATURE_DRC_INFO ASM_CONST(0x0000000800000000) + + #ifndef __ASSEMBLY__ + +diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h +index 88e5e8f..855e17d 100644 +--- a/arch/powerpc/include/asm/hw_irq.h ++++ b/arch/powerpc/include/asm/hw_irq.h +@@ -30,6 +30,16 @@ + #define PACA_IRQ_PMI 0x40 + + /* ++ * Some soft-masked interrupts must be hard masked until they are replayed ++ * (e.g., because the soft-masked handler does not clear the exception). ++ */ ++#ifdef CONFIG_PPC_BOOK3S ++#define PACA_IRQ_MUST_HARD_MASK (PACA_IRQ_EE|PACA_IRQ_PMI) ++#else ++#define PACA_IRQ_MUST_HARD_MASK (PACA_IRQ_EE) ++#endif ++ ++/* + * flags for paca->irq_soft_mask + */ + #define IRQS_ENABLED 0 +@@ -244,7 +254,7 @@ static inline bool lazy_irq_pending(void) + static inline void may_hard_irq_enable(void) + { + get_paca()->irq_happened &= ~PACA_IRQ_HARD_DIS; +- if (!(get_paca()->irq_happened & PACA_IRQ_EE)) ++ if (!(get_paca()->irq_happened & PACA_IRQ_MUST_HARD_MASK)) + __hard_irq_enable(); + } + +diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h +index 9dcbfa6..d8b1e8e 100644 +--- a/arch/powerpc/include/asm/kexec.h ++++ b/arch/powerpc/include/asm/kexec.h +@@ -140,6 +140,12 @@ static inline bool kdump_in_progress(void) + return false; + } + ++static inline void crash_ipi_callback(struct pt_regs *regs) { } ++ ++static inline void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *)) ++{ ++} ++ + #endif /* CONFIG_KEXEC_CORE */ + #endif /* ! __ASSEMBLY__ */ + #endif /* __KERNEL__ */ +diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h +index 504a3c36..03bbd11 100644 +--- a/arch/powerpc/include/asm/nohash/32/pgtable.h ++++ b/arch/powerpc/include/asm/nohash/32/pgtable.h +@@ -24,6 +24,7 @@ extern int icache_44x_need_flush; + #define PGD_INDEX_SIZE (32 - PGDIR_SHIFT) + + #define PMD_CACHE_INDEX PMD_INDEX_SIZE ++#define PUD_CACHE_INDEX PUD_INDEX_SIZE + + #ifndef __ASSEMBLY__ + #define PTE_TABLE_SIZE (sizeof(pte_t) << PTE_INDEX_SIZE) +diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h +index abddf58..5c5f75d 100644 +--- a/arch/powerpc/include/asm/nohash/64/pgtable.h ++++ b/arch/powerpc/include/asm/nohash/64/pgtable.h +@@ -27,6 +27,7 @@ + #else + #define PMD_CACHE_INDEX PMD_INDEX_SIZE + #endif ++#define PUD_CACHE_INDEX PUD_INDEX_SIZE + + /* + * Define the address range of the kernel non-linear virtual area +diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h +index 88187c2..9f42164 100644 +--- a/arch/powerpc/include/asm/topology.h ++++ b/arch/powerpc/include/asm/topology.h +@@ -44,6 +44,11 @@ extern int sysfs_add_device_to_node(struct device *dev, int nid); + extern void sysfs_remove_device_from_node(struct device *dev, int nid); + extern int numa_update_cpu_topology(bool cpus_locked); + ++static inline void update_numa_cpu_lookup_table(unsigned int cpu, int node) ++{ ++ numa_cpu_lookup_table[cpu] = node; ++} ++ + static inline int early_cpu_to_node(int cpu) + { + int nid; +@@ -76,12 +81,16 @@ static inline int numa_update_cpu_topology(bool cpus_locked) + { + return 0; + } ++ ++static inline void update_numa_cpu_lookup_table(unsigned int cpu, int node) {} ++ + #endif /* CONFIG_NUMA */ + + #if defined(CONFIG_NUMA) && defined(CONFIG_PPC_SPLPAR) + extern int start_topology_update(void); + extern int stop_topology_update(void); + extern int prrn_is_enabled(void); ++extern int find_and_online_cpu_nid(int cpu); + #else + static inline int start_topology_update(void) + { +@@ -95,6 +104,10 @@ static inline int prrn_is_enabled(void) + { + return 0; + } ++static inline int find_and_online_cpu_nid(int cpu) ++{ ++ return 0; ++} + #endif /* CONFIG_NUMA && CONFIG_PPC_SPLPAR */ + + #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_NEED_MULTIPLE_NODES) +diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c +index beea218..0c0b66f 100644 +--- a/arch/powerpc/kernel/eeh_driver.c ++++ b/arch/powerpc/kernel/eeh_driver.c +@@ -384,7 +384,8 @@ static void *eeh_report_resume(void *data, void *userdata) + eeh_pcid_put(dev); + pci_uevent_ers(dev, PCI_ERS_RESULT_RECOVERED); + #ifdef CONFIG_PCI_IOV +- eeh_ops->notify_resume(eeh_dev_to_pdn(edev)); ++ if (eeh_ops->notify_resume && eeh_dev_to_pdn(edev)) ++ eeh_ops->notify_resume(eeh_dev_to_pdn(edev)); + #endif + return NULL; + } +diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S +index ee832d34..9b6e653 100644 +--- a/arch/powerpc/kernel/exceptions-64e.S ++++ b/arch/powerpc/kernel/exceptions-64e.S +@@ -943,6 +943,8 @@ kernel_dbg_exc: + /* + * An interrupt came in while soft-disabled; We mark paca->irq_happened + * accordingly and if the interrupt is level sensitive, we hard disable ++ * hard disable (full_mask) corresponds to PACA_IRQ_MUST_HARD_MASK, so ++ * keep these in synch. + */ + + .macro masked_interrupt_book3e paca_irq full_mask +diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S +index 243d072..3ac87e5 100644 +--- a/arch/powerpc/kernel/exceptions-64s.S ++++ b/arch/powerpc/kernel/exceptions-64s.S +@@ -1426,7 +1426,7 @@ EXC_COMMON_BEGIN(soft_nmi_common) + * triggered and won't automatically refire. + * - If it was a HMI we return immediately since we handled it in realmode + * and it won't refire. +- * - else we hard disable and return. ++ * - Else it is one of PACA_IRQ_MUST_HARD_MASK, so hard disable and return. + * This is called with r10 containing the value to OR to the paca field. + */ + #define MASKED_INTERRUPT(_H) \ +@@ -1441,8 +1441,8 @@ masked_##_H##interrupt: \ + ori r10,r10,0xffff; \ + mtspr SPRN_DEC,r10; \ + b MASKED_DEC_HANDLER_LABEL; \ +-1: andi. r10,r10,(PACA_IRQ_DBELL|PACA_IRQ_HMI); \ +- bne 2f; \ ++1: andi. r10,r10,PACA_IRQ_MUST_HARD_MASK; \ ++ beq 2f; \ + mfspr r10,SPRN_##_H##SRR1; \ + xori r10,r10,MSR_EE; /* clear MSR_EE */ \ + mtspr SPRN_##_H##SRR1,r10; \ +diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c +index adf044d..acf4b2e 100644 +--- a/arch/powerpc/kernel/prom_init.c ++++ b/arch/powerpc/kernel/prom_init.c +@@ -874,7 +874,6 @@ struct ibm_arch_vec __cacheline_aligned ibm_architecture_vec = { + .mmu = 0, + .hash_ext = 0, + .radix_ext = 0, +- .byte22 = OV5_FEAT(OV5_DRC_INFO), + }, + + /* option vector 6: IBM PAPR hints */ +diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c +index 5a8bfee..04d0bbd 100644 +--- a/arch/powerpc/kernel/sysfs.c ++++ b/arch/powerpc/kernel/sysfs.c +@@ -788,7 +788,8 @@ static int register_cpu_online(unsigned int cpu) + if (cpu_has_feature(CPU_FTR_PPCAS_ARCH_V2)) + device_create_file(s, &dev_attr_pir); + +- if (cpu_has_feature(CPU_FTR_ARCH_206)) ++ if (cpu_has_feature(CPU_FTR_ARCH_206) && ++ !firmware_has_feature(FW_FEATURE_LPAR)) + device_create_file(s, &dev_attr_tscr); + #endif /* CONFIG_PPC64 */ + +@@ -873,7 +874,8 @@ static int unregister_cpu_online(unsigned int cpu) + if (cpu_has_feature(CPU_FTR_PPCAS_ARCH_V2)) + device_remove_file(s, &dev_attr_pir); + +- if (cpu_has_feature(CPU_FTR_ARCH_206)) ++ if (cpu_has_feature(CPU_FTR_ARCH_206) && ++ !firmware_has_feature(FW_FEATURE_LPAR)) + device_remove_file(s, &dev_attr_tscr); + #endif /* CONFIG_PPC64 */ + +diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c +index 0c85481..5cb4e46 100644 +--- a/arch/powerpc/kvm/book3s_64_mmu_radix.c ++++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c +@@ -195,6 +195,12 @@ static void kvmppc_pte_free(pte_t *ptep) + kmem_cache_free(kvm_pte_cache, ptep); + } + ++/* Like pmd_huge() and pmd_large(), but works regardless of config options */ ++static inline int pmd_is_leaf(pmd_t pmd) ++{ ++ return !!(pmd_val(pmd) & _PAGE_PTE); ++} ++ + static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa, + unsigned int level, unsigned long mmu_seq) + { +@@ -219,7 +225,7 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa, + else + new_pmd = pmd_alloc_one(kvm->mm, gpa); + +- if (level == 0 && !(pmd && pmd_present(*pmd))) ++ if (level == 0 && !(pmd && pmd_present(*pmd) && !pmd_is_leaf(*pmd))) + new_ptep = kvmppc_pte_alloc(); + + /* Check if we might have been invalidated; let the guest retry if so */ +@@ -244,12 +250,30 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa, + new_pmd = NULL; + } + pmd = pmd_offset(pud, gpa); +- if (pmd_large(*pmd)) { +- /* Someone else has instantiated a large page here; retry */ +- ret = -EAGAIN; +- goto out_unlock; +- } +- if (level == 1 && !pmd_none(*pmd)) { ++ if (pmd_is_leaf(*pmd)) { ++ unsigned long lgpa = gpa & PMD_MASK; ++ ++ /* ++ * If we raced with another CPU which has just put ++ * a 2MB pte in after we saw a pte page, try again. ++ */ ++ if (level == 0 && !new_ptep) { ++ ret = -EAGAIN; ++ goto out_unlock; ++ } ++ /* Valid 2MB page here already, remove it */ ++ old = kvmppc_radix_update_pte(kvm, pmdp_ptep(pmd), ++ ~0UL, 0, lgpa, PMD_SHIFT); ++ kvmppc_radix_tlbie_page(kvm, lgpa, PMD_SHIFT); ++ if (old & _PAGE_DIRTY) { ++ unsigned long gfn = lgpa >> PAGE_SHIFT; ++ struct kvm_memory_slot *memslot; ++ memslot = gfn_to_memslot(kvm, gfn); ++ if (memslot && memslot->dirty_bitmap) ++ kvmppc_update_dirty_map(memslot, ++ gfn, PMD_SIZE); ++ } ++ } else if (level == 1 && !pmd_none(*pmd)) { + /* + * There's a page table page here, but we wanted + * to install a large page. Tell the caller and let +@@ -412,28 +436,24 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, + } else { + page = pages[0]; + pfn = page_to_pfn(page); +- if (PageHuge(page)) { +- page = compound_head(page); +- pte_size <<= compound_order(page); ++ if (PageCompound(page)) { ++ pte_size <<= compound_order(compound_head(page)); + /* See if we can insert a 2MB large-page PTE here */ + if (pte_size >= PMD_SIZE && +- (gpa & PMD_MASK & PAGE_MASK) == +- (hva & PMD_MASK & PAGE_MASK)) { ++ (gpa & (PMD_SIZE - PAGE_SIZE)) == ++ (hva & (PMD_SIZE - PAGE_SIZE))) { + level = 1; + pfn &= ~((PMD_SIZE >> PAGE_SHIFT) - 1); + } + } + /* See if we can provide write access */ + if (writing) { +- /* +- * We assume gup_fast has set dirty on the host PTE. +- */ + pgflags |= _PAGE_WRITE; + } else { + local_irq_save(flags); + ptep = find_current_mm_pte(current->mm->pgd, + hva, NULL, NULL); +- if (ptep && pte_write(*ptep) && pte_dirty(*ptep)) ++ if (ptep && pte_write(*ptep)) + pgflags |= _PAGE_WRITE; + local_irq_restore(flags); + } +@@ -459,18 +479,15 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, + pte = pfn_pte(pfn, __pgprot(pgflags)); + ret = kvmppc_create_pte(kvm, pte, gpa, level, mmu_seq); + } +- if (ret == 0 || ret == -EAGAIN) +- ret = RESUME_GUEST; + + if (page) { +- /* +- * We drop pages[0] here, not page because page might +- * have been set to the head page of a compound, but +- * we have to drop the reference on the correct tail +- * page to match the get inside gup() +- */ +- put_page(pages[0]); ++ if (!ret && (pgflags & _PAGE_WRITE)) ++ set_page_dirty_lock(page); ++ put_page(page); + } ++ ++ if (ret == 0 || ret == -EAGAIN) ++ ret = RESUME_GUEST; + return ret; + } + +@@ -644,7 +661,7 @@ void kvmppc_free_radix(struct kvm *kvm) + continue; + pmd = pmd_offset(pud, 0); + for (im = 0; im < PTRS_PER_PMD; ++im, ++pmd) { +- if (pmd_huge(*pmd)) { ++ if (pmd_is_leaf(*pmd)) { + pmd_clear(pmd); + continue; + } +diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c +index 8970735..9cb9448 100644 +--- a/arch/powerpc/kvm/book3s_hv.c ++++ b/arch/powerpc/kvm/book3s_hv.c +@@ -2885,7 +2885,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) + */ + trace_hardirqs_on(); + +- guest_enter(); ++ guest_enter_irqoff(); + + srcu_idx = srcu_read_lock(&vc->kvm->srcu); + +@@ -2893,8 +2893,6 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) + + srcu_read_unlock(&vc->kvm->srcu, srcu_idx); + +- guest_exit(); +- + trace_hardirqs_off(); + set_irq_happened(trap); + +@@ -2937,6 +2935,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) + kvmppc_set_host_core(pcpu); + + local_irq_enable(); ++ guest_exit(); + + /* Let secondaries go back to the offline loop */ + for (i = 0; i < controlled_threads; ++i) { +@@ -3656,15 +3655,17 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu) + goto up_out; + + psize = vma_kernel_pagesize(vma); +- porder = __ilog2(psize); + + up_read(¤t->mm->mmap_sem); + + /* We can handle 4k, 64k or 16M pages in the VRMA */ +- err = -EINVAL; +- if (!(psize == 0x1000 || psize == 0x10000 || +- psize == 0x1000000)) +- goto out_srcu; ++ if (psize >= 0x1000000) ++ psize = 0x1000000; ++ else if (psize >= 0x10000) ++ psize = 0x10000; ++ else ++ psize = 0x1000; ++ porder = __ilog2(psize); + + senc = slb_pgsize_encoding(psize); + kvm->arch.vrma_slb_v = senc | SLB_VSID_B_1T | +diff --git a/arch/powerpc/kvm/book3s_xive.c b/arch/powerpc/kvm/book3s_xive.c +index f0f5cd4..f9818d7 100644 +--- a/arch/powerpc/kvm/book3s_xive.c ++++ b/arch/powerpc/kvm/book3s_xive.c +@@ -188,7 +188,7 @@ static int xive_provision_queue(struct kvm_vcpu *vcpu, u8 prio) + if (!qpage) { + pr_err("Failed to allocate queue %d for VCPU %d\n", + prio, xc->server_num); +- return -ENOMEM;; ++ return -ENOMEM; + } + memset(qpage, 0, 1 << xive->q_order); + +diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c +index 403e642..52c2053 100644 +--- a/arch/powerpc/kvm/powerpc.c ++++ b/arch/powerpc/kvm/powerpc.c +@@ -1345,7 +1345,7 @@ static int kvmppc_emulate_mmio_vsx_loadstore(struct kvm_vcpu *vcpu, + int kvmppc_handle_load128_by2x64(struct kvm_run *run, struct kvm_vcpu *vcpu, + unsigned int rt, int is_default_endian) + { +- enum emulation_result emulated; ++ enum emulation_result emulated = EMULATE_DONE; + + while (vcpu->arch.mmio_vmx_copy_nums) { + emulated = __kvmppc_handle_load(run, vcpu, rt, 8, +@@ -1608,7 +1608,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) + + kvm_sigset_deactivate(vcpu); + ++#ifdef CONFIG_ALTIVEC + out: ++#endif + vcpu_put(vcpu); + return r; + } +diff --git a/arch/powerpc/mm/drmem.c b/arch/powerpc/mm/drmem.c +index 1604110..3f18036 100644 +--- a/arch/powerpc/mm/drmem.c ++++ b/arch/powerpc/mm/drmem.c +@@ -98,7 +98,7 @@ static void init_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell, + dr_cell->base_addr = cpu_to_be64(lmb->base_addr); + dr_cell->drc_index = cpu_to_be32(lmb->drc_index); + dr_cell->aa_index = cpu_to_be32(lmb->aa_index); +- dr_cell->flags = cpu_to_be32(lmb->flags); ++ dr_cell->flags = cpu_to_be32(drmem_lmb_flags(lmb)); + } + + static int drmem_update_dt_v2(struct device_node *memory, +@@ -121,7 +121,7 @@ static int drmem_update_dt_v2(struct device_node *memory, + } + + if (prev_lmb->aa_index != lmb->aa_index || +- prev_lmb->flags != lmb->flags) ++ drmem_lmb_flags(prev_lmb) != drmem_lmb_flags(lmb)) + lmb_sets++; + + prev_lmb = lmb; +@@ -150,7 +150,7 @@ static int drmem_update_dt_v2(struct device_node *memory, + } + + if (prev_lmb->aa_index != lmb->aa_index || +- prev_lmb->flags != lmb->flags) { ++ drmem_lmb_flags(prev_lmb) != drmem_lmb_flags(lmb)) { + /* end of one set, start of another */ + dr_cell->seq_lmbs = cpu_to_be32(seq_lmbs); + dr_cell++; +@@ -216,6 +216,8 @@ static void __init __walk_drmem_v1_lmbs(const __be32 *prop, const __be32 *usm, + u32 i, n_lmbs; + + n_lmbs = of_read_number(prop++, 1); ++ if (n_lmbs == 0) ++ return; + + for (i = 0; i < n_lmbs; i++) { + read_drconf_v1_cell(&lmb, &prop); +@@ -245,6 +247,8 @@ static void __init __walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *usm, + u32 i, j, lmb_sets; + + lmb_sets = of_read_number(prop++, 1); ++ if (lmb_sets == 0) ++ return; + + for (i = 0; i < lmb_sets; i++) { + read_drconf_v2_cell(&dr_cell, &prop); +@@ -354,6 +358,8 @@ static void __init init_drmem_v1_lmbs(const __be32 *prop) + struct drmem_lmb *lmb; + + drmem_info->n_lmbs = of_read_number(prop++, 1); ++ if (drmem_info->n_lmbs == 0) ++ return; + + drmem_info->lmbs = kcalloc(drmem_info->n_lmbs, sizeof(*lmb), + GFP_KERNEL); +@@ -373,6 +379,8 @@ static void __init init_drmem_v2_lmbs(const __be32 *prop) + int lmb_index; + + lmb_sets = of_read_number(prop++, 1); ++ if (lmb_sets == 0) ++ return; + + /* first pass, calculate the number of LMBs */ + p = prop; +diff --git a/arch/powerpc/mm/hash64_4k.c b/arch/powerpc/mm/hash64_4k.c +index 5a69b51..d573d7d 100644 +--- a/arch/powerpc/mm/hash64_4k.c ++++ b/arch/powerpc/mm/hash64_4k.c +@@ -55,7 +55,7 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, + * need to add in 0x1 if it's a read-only user page + */ + rflags = htab_convert_pte_flags(new_pte); +- rpte = __real_pte(__pte(old_pte), ptep); ++ rpte = __real_pte(__pte(old_pte), ptep, PTRS_PER_PTE); + + if (cpu_has_feature(CPU_FTR_NOEXECUTE) && + !cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) +@@ -117,7 +117,7 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, + return -1; + } + new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | H_PAGE_HASHPTE; +- new_pte |= pte_set_hidx(ptep, rpte, 0, slot); ++ new_pte |= pte_set_hidx(ptep, rpte, 0, slot, PTRS_PER_PTE); + } + *ptep = __pte(new_pte & ~H_PAGE_BUSY); + return 0; +diff --git a/arch/powerpc/mm/hash64_64k.c b/arch/powerpc/mm/hash64_64k.c +index 2253bbc..e601d95 100644 +--- a/arch/powerpc/mm/hash64_64k.c ++++ b/arch/powerpc/mm/hash64_64k.c +@@ -86,7 +86,7 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, + + subpg_index = (ea & (PAGE_SIZE - 1)) >> shift; + vpn = hpt_vpn(ea, vsid, ssize); +- rpte = __real_pte(__pte(old_pte), ptep); ++ rpte = __real_pte(__pte(old_pte), ptep, PTRS_PER_PTE); + /* + *None of the sub 4k page is hashed + */ +@@ -214,7 +214,7 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, + return -1; + } + +- new_pte |= pte_set_hidx(ptep, rpte, subpg_index, slot); ++ new_pte |= pte_set_hidx(ptep, rpte, subpg_index, slot, PTRS_PER_PTE); + new_pte |= H_PAGE_HASHPTE; + + *ptep = __pte(new_pte & ~H_PAGE_BUSY); +@@ -262,7 +262,7 @@ int __hash_page_64K(unsigned long ea, unsigned long access, + } while (!pte_xchg(ptep, __pte(old_pte), __pte(new_pte))); + + rflags = htab_convert_pte_flags(new_pte); +- rpte = __real_pte(__pte(old_pte), ptep); ++ rpte = __real_pte(__pte(old_pte), ptep, PTRS_PER_PTE); + + if (cpu_has_feature(CPU_FTR_NOEXECUTE) && + !cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) +@@ -327,7 +327,7 @@ int __hash_page_64K(unsigned long ea, unsigned long access, + } + + new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | H_PAGE_HASHPTE; +- new_pte |= pte_set_hidx(ptep, rpte, 0, slot); ++ new_pte |= pte_set_hidx(ptep, rpte, 0, slot, PTRS_PER_PTE); + } + *ptep = __pte(new_pte & ~H_PAGE_BUSY); + return 0; +diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c +index 7d07c7e1..cf290d41 100644 +--- a/arch/powerpc/mm/hash_utils_64.c ++++ b/arch/powerpc/mm/hash_utils_64.c +@@ -1008,6 +1008,7 @@ void __init hash__early_init_mmu(void) + __pmd_index_size = H_PMD_INDEX_SIZE; + __pud_index_size = H_PUD_INDEX_SIZE; + __pgd_index_size = H_PGD_INDEX_SIZE; ++ __pud_cache_index = H_PUD_CACHE_INDEX; + __pmd_cache_index = H_PMD_CACHE_INDEX; + __pte_table_size = H_PTE_TABLE_SIZE; + __pmd_table_size = H_PMD_TABLE_SIZE; +diff --git a/arch/powerpc/mm/hugetlbpage-hash64.c b/arch/powerpc/mm/hugetlbpage-hash64.c +index 12511f5..b320f50 100644 +--- a/arch/powerpc/mm/hugetlbpage-hash64.c ++++ b/arch/powerpc/mm/hugetlbpage-hash64.c +@@ -27,7 +27,7 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, + unsigned long vpn; + unsigned long old_pte, new_pte; + unsigned long rflags, pa, sz; +- long slot; ++ long slot, offset; + + BUG_ON(shift != mmu_psize_defs[mmu_psize].shift); + +@@ -63,7 +63,11 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, + } while(!pte_xchg(ptep, __pte(old_pte), __pte(new_pte))); + + rflags = htab_convert_pte_flags(new_pte); +- rpte = __real_pte(__pte(old_pte), ptep); ++ if (unlikely(mmu_psize == MMU_PAGE_16G)) ++ offset = PTRS_PER_PUD; ++ else ++ offset = PTRS_PER_PMD; ++ rpte = __real_pte(__pte(old_pte), ptep, offset); + + sz = ((1UL) << shift); + if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) +@@ -104,7 +108,7 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, + return -1; + } + +- new_pte |= pte_set_hidx(ptep, rpte, 0, slot); ++ new_pte |= pte_set_hidx(ptep, rpte, 0, slot, offset); + } + + /* +diff --git a/arch/powerpc/mm/init-common.c b/arch/powerpc/mm/init-common.c +index eb8c6c8..2b656e6 100644 +--- a/arch/powerpc/mm/init-common.c ++++ b/arch/powerpc/mm/init-common.c +@@ -100,6 +100,6 @@ void pgtable_cache_init(void) + * same size as either the pgd or pmd index except with THP enabled + * on book3s 64 + */ +- if (PUD_INDEX_SIZE && !PGT_CACHE(PUD_INDEX_SIZE)) +- pgtable_cache_add(PUD_INDEX_SIZE, pud_ctor); ++ if (PUD_CACHE_INDEX && !PGT_CACHE(PUD_CACHE_INDEX)) ++ pgtable_cache_add(PUD_CACHE_INDEX, pud_ctor); + } +diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c +index 314d19a..edd8d0b 100644 +--- a/arch/powerpc/mm/numa.c ++++ b/arch/powerpc/mm/numa.c +@@ -143,11 +143,6 @@ static void reset_numa_cpu_lookup_table(void) + numa_cpu_lookup_table[cpu] = -1; + } + +-static void update_numa_cpu_lookup_table(unsigned int cpu, int node) +-{ +- numa_cpu_lookup_table[cpu] = node; +-} +- + static void map_cpu_to_node(int cpu, int node) + { + update_numa_cpu_lookup_table(cpu, node); +diff --git a/arch/powerpc/mm/pgtable-radix.c b/arch/powerpc/mm/pgtable-radix.c +index 573a9a2..2e10a96 100644 +--- a/arch/powerpc/mm/pgtable-radix.c ++++ b/arch/powerpc/mm/pgtable-radix.c +@@ -17,9 +17,11 @@ + #include + #include + #include ++#include + + #include + #include ++#include + #include + #include + #include +@@ -333,6 +335,22 @@ static void __init radix_init_pgtable(void) + "r" (TLBIEL_INVAL_SET_LPID), "r" (0)); + asm volatile("eieio; tlbsync; ptesync" : : : "memory"); + trace_tlbie(0, 0, TLBIEL_INVAL_SET_LPID, 0, 2, 1, 1); ++ ++ /* ++ * The init_mm context is given the first available (non-zero) PID, ++ * which is the "guard PID" and contains no page table. PIDR should ++ * never be set to zero because that duplicates the kernel address ++ * space at the 0x0... offset (quadrant 0)! ++ * ++ * An arbitrary PID that may later be allocated by the PID allocator ++ * for userspace processes must not be used either, because that ++ * would cause stale user mappings for that PID on CPUs outside of ++ * the TLB invalidation scheme (because it won't be in mm_cpumask). ++ * ++ * So permanently carve out one PID for the purpose of a guard PID. ++ */ ++ init_mm.context.id = mmu_base_pid; ++ mmu_base_pid++; + } + + static void __init radix_init_partition_table(void) +@@ -535,6 +553,7 @@ void __init radix__early_init_mmu(void) + __pmd_index_size = RADIX_PMD_INDEX_SIZE; + __pud_index_size = RADIX_PUD_INDEX_SIZE; + __pgd_index_size = RADIX_PGD_INDEX_SIZE; ++ __pud_cache_index = RADIX_PUD_INDEX_SIZE; + __pmd_cache_index = RADIX_PMD_INDEX_SIZE; + __pte_table_size = RADIX_PTE_TABLE_SIZE; + __pmd_table_size = RADIX_PMD_TABLE_SIZE; +@@ -579,7 +598,8 @@ void __init radix__early_init_mmu(void) + + radix_init_iamr(); + radix_init_pgtable(); +- ++ /* Switch to the guard PID before turning on MMU */ ++ radix__switch_mmu_context(NULL, &init_mm); + if (cpu_has_feature(CPU_FTR_HVMODE)) + tlbiel_all(); + } +@@ -604,6 +624,7 @@ void radix__early_init_mmu_secondary(void) + } + radix_init_iamr(); + ++ radix__switch_mmu_context(NULL, &init_mm); + if (cpu_has_feature(CPU_FTR_HVMODE)) + tlbiel_all(); + } +@@ -666,6 +687,30 @@ static void free_pmd_table(pmd_t *pmd_start, pud_t *pud) + pud_clear(pud); + } + ++struct change_mapping_params { ++ pte_t *pte; ++ unsigned long start; ++ unsigned long end; ++ unsigned long aligned_start; ++ unsigned long aligned_end; ++}; ++ ++static int stop_machine_change_mapping(void *data) ++{ ++ struct change_mapping_params *params = ++ (struct change_mapping_params *)data; ++ ++ if (!data) ++ return -1; ++ ++ spin_unlock(&init_mm.page_table_lock); ++ pte_clear(&init_mm, params->aligned_start, params->pte); ++ create_physical_mapping(params->aligned_start, params->start); ++ create_physical_mapping(params->end, params->aligned_end); ++ spin_lock(&init_mm.page_table_lock); ++ return 0; ++} ++ + static void remove_pte_table(pte_t *pte_start, unsigned long addr, + unsigned long end) + { +@@ -694,6 +739,52 @@ static void remove_pte_table(pte_t *pte_start, unsigned long addr, + } + } + ++/* ++ * clear the pte and potentially split the mapping helper ++ */ ++static void split_kernel_mapping(unsigned long addr, unsigned long end, ++ unsigned long size, pte_t *pte) ++{ ++ unsigned long mask = ~(size - 1); ++ unsigned long aligned_start = addr & mask; ++ unsigned long aligned_end = addr + size; ++ struct change_mapping_params params; ++ bool split_region = false; ++ ++ if ((end - addr) < size) { ++ /* ++ * We're going to clear the PTE, but not flushed ++ * the mapping, time to remap and flush. The ++ * effects if visible outside the processor or ++ * if we are running in code close to the ++ * mapping we cleared, we are in trouble. ++ */ ++ if (overlaps_kernel_text(aligned_start, addr) || ++ overlaps_kernel_text(end, aligned_end)) { ++ /* ++ * Hack, just return, don't pte_clear ++ */ ++ WARN_ONCE(1, "Linear mapping %lx->%lx overlaps kernel " ++ "text, not splitting\n", addr, end); ++ return; ++ } ++ split_region = true; ++ } ++ ++ if (split_region) { ++ params.pte = pte; ++ params.start = addr; ++ params.end = end; ++ params.aligned_start = addr & ~(size - 1); ++ params.aligned_end = min_t(unsigned long, aligned_end, ++ (unsigned long)__va(memblock_end_of_DRAM())); ++ stop_machine(stop_machine_change_mapping, ¶ms, NULL); ++ return; ++ } ++ ++ pte_clear(&init_mm, addr, pte); ++} ++ + static void remove_pmd_table(pmd_t *pmd_start, unsigned long addr, + unsigned long end) + { +@@ -709,13 +800,7 @@ static void remove_pmd_table(pmd_t *pmd_start, unsigned long addr, + continue; + + if (pmd_huge(*pmd)) { +- if (!IS_ALIGNED(addr, PMD_SIZE) || +- !IS_ALIGNED(next, PMD_SIZE)) { +- WARN_ONCE(1, "%s: unaligned range\n", __func__); +- continue; +- } +- +- pte_clear(&init_mm, addr, (pte_t *)pmd); ++ split_kernel_mapping(addr, end, PMD_SIZE, (pte_t *)pmd); + continue; + } + +@@ -740,13 +825,7 @@ static void remove_pud_table(pud_t *pud_start, unsigned long addr, + continue; + + if (pud_huge(*pud)) { +- if (!IS_ALIGNED(addr, PUD_SIZE) || +- !IS_ALIGNED(next, PUD_SIZE)) { +- WARN_ONCE(1, "%s: unaligned range\n", __func__); +- continue; +- } +- +- pte_clear(&init_mm, addr, (pte_t *)pud); ++ split_kernel_mapping(addr, end, PUD_SIZE, (pte_t *)pud); + continue; + } + +@@ -772,13 +851,7 @@ static void remove_pagetable(unsigned long start, unsigned long end) + continue; + + if (pgd_huge(*pgd)) { +- if (!IS_ALIGNED(addr, PGDIR_SIZE) || +- !IS_ALIGNED(next, PGDIR_SIZE)) { +- WARN_ONCE(1, "%s: unaligned range\n", __func__); +- continue; +- } +- +- pte_clear(&init_mm, addr, (pte_t *)pgd); ++ split_kernel_mapping(addr, end, PGDIR_SIZE, (pte_t *)pgd); + continue; + } + +diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c +index c9a623c..28c980e 100644 +--- a/arch/powerpc/mm/pgtable_64.c ++++ b/arch/powerpc/mm/pgtable_64.c +@@ -82,6 +82,8 @@ unsigned long __pgd_index_size; + EXPORT_SYMBOL(__pgd_index_size); + unsigned long __pmd_cache_index; + EXPORT_SYMBOL(__pmd_cache_index); ++unsigned long __pud_cache_index; ++EXPORT_SYMBOL(__pud_cache_index); + unsigned long __pte_table_size; + EXPORT_SYMBOL(__pte_table_size); + unsigned long __pmd_table_size; +@@ -471,6 +473,8 @@ void mmu_partition_table_set_entry(unsigned int lpid, unsigned long dw0, + if (old & PATB_HR) { + asm volatile(PPC_TLBIE_5(%0,%1,2,0,1) : : + "r" (TLBIEL_INVAL_SET_LPID), "r" (lpid)); ++ asm volatile(PPC_TLBIE_5(%0,%1,2,1,1) : : ++ "r" (TLBIEL_INVAL_SET_LPID), "r" (lpid)); + trace_tlbie(lpid, 0, TLBIEL_INVAL_SET_LPID, lpid, 2, 0, 1); + } else { + asm volatile(PPC_TLBIE_5(%0,%1,2,0,0) : : +diff --git a/arch/powerpc/mm/tlb_hash64.c b/arch/powerpc/mm/tlb_hash64.c +index 881ebd5..9b23f12 100644 +--- a/arch/powerpc/mm/tlb_hash64.c ++++ b/arch/powerpc/mm/tlb_hash64.c +@@ -51,7 +51,7 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, + unsigned int psize; + int ssize; + real_pte_t rpte; +- int i; ++ int i, offset; + + i = batch->index; + +@@ -67,6 +67,10 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, + psize = get_slice_psize(mm, addr); + /* Mask the address for the correct page size */ + addr &= ~((1UL << mmu_psize_defs[psize].shift) - 1); ++ if (unlikely(psize == MMU_PAGE_16G)) ++ offset = PTRS_PER_PUD; ++ else ++ offset = PTRS_PER_PMD; + #else + BUG(); + psize = pte_pagesize_index(mm, addr, pte); /* shutup gcc */ +@@ -78,6 +82,7 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, + * support 64k pages, this might be different from the + * hardware page size encoded in the slice table. */ + addr &= PAGE_MASK; ++ offset = PTRS_PER_PTE; + } + + +@@ -91,7 +96,7 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, + } + WARN_ON(vsid == 0); + vpn = hpt_vpn(addr, vsid, ssize); +- rpte = __real_pte(__pte(pte), ptep); ++ rpte = __real_pte(__pte(pte), ptep, offset); + + /* + * Check if we have an active batch on this CPU. If not, just +diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c +index 872d1f6..a9636d8 100644 +--- a/arch/powerpc/net/bpf_jit_comp.c ++++ b/arch/powerpc/net/bpf_jit_comp.c +@@ -327,6 +327,9 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4); + PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff, len)); + break; ++ case BPF_LDX | BPF_W | BPF_ABS: /* A = *((u32 *)(seccomp_data + K)); */ ++ PPC_LWZ_OFFS(r_A, r_skb, K); ++ break; + case BPF_LDX | BPF_W | BPF_LEN: /* X = skb->len; */ + PPC_LWZ_OFFS(r_X, r_skb, offsetof(struct sk_buff, len)); + break; +diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c +index 0a34b0c..0ef3d95 100644 +--- a/arch/powerpc/net/bpf_jit_comp64.c ++++ b/arch/powerpc/net/bpf_jit_comp64.c +@@ -240,6 +240,7 @@ static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 + * goto out; + */ + PPC_LWZ(b2p[TMP_REG_1], b2p_bpf_array, offsetof(struct bpf_array, map.max_entries)); ++ PPC_RLWINM(b2p_index, b2p_index, 0, 0, 31); + PPC_CMPLW(b2p_index, b2p[TMP_REG_1]); + PPC_BCC(COND_GE, out); + +diff --git a/arch/powerpc/platforms/powernv/opal-imc.c b/arch/powerpc/platforms/powernv/opal-imc.c +index dd4c9b8..f6f55ab 100644 +--- a/arch/powerpc/platforms/powernv/opal-imc.c ++++ b/arch/powerpc/platforms/powernv/opal-imc.c +@@ -199,9 +199,11 @@ static void disable_nest_pmu_counters(void) + const struct cpumask *l_cpumask; + + get_online_cpus(); +- for_each_online_node(nid) { ++ for_each_node_with_cpus(nid) { + l_cpumask = cpumask_of_node(nid); +- cpu = cpumask_first(l_cpumask); ++ cpu = cpumask_first_and(l_cpumask, cpu_online_mask); ++ if (cpu >= nr_cpu_ids) ++ continue; + opal_imc_counters_stop(OPAL_IMC_COUNTERS_NEST, + get_hard_smp_processor_id(cpu)); + } +diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c +index 496e476..a6c92c7 100644 +--- a/arch/powerpc/platforms/powernv/pci-ioda.c ++++ b/arch/powerpc/platforms/powernv/pci-ioda.c +@@ -1854,7 +1854,7 @@ static int pnv_pci_ioda_dma_set_mask(struct pci_dev *pdev, u64 dma_mask) + s64 rc; + + if (WARN_ON(!pdn || pdn->pe_number == IODA_INVALID_PE)) +- return -ENODEV;; ++ return -ENODEV; + + pe = &phb->ioda.pe_array[pdn->pe_number]; + if (pe->tce_bypass_enabled) { +diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c +index 4fb21e1..092715b 100644 +--- a/arch/powerpc/platforms/powernv/setup.c ++++ b/arch/powerpc/platforms/powernv/setup.c +@@ -80,6 +80,10 @@ static void pnv_setup_rfi_flush(void) + if (np && of_property_read_bool(np, "disabled")) + enable--; + ++ np = of_get_child_by_name(fw_features, "speculation-policy-favor-security"); ++ if (np && of_property_read_bool(np, "disabled")) ++ enable = 0; ++ + of_node_put(np); + of_node_put(fw_features); + } +diff --git a/arch/powerpc/platforms/powernv/vas-window.c b/arch/powerpc/platforms/powernv/vas-window.c +index 2b3eb01..b7c53a5 100644 +--- a/arch/powerpc/platforms/powernv/vas-window.c ++++ b/arch/powerpc/platforms/powernv/vas-window.c +@@ -1063,16 +1063,16 @@ struct vas_window *vas_tx_win_open(int vasid, enum vas_cop_type cop, + rc = PTR_ERR(txwin->paste_kaddr); + goto free_window; + } ++ } else { ++ /* ++ * A user mapping must ensure that context switch issues ++ * CP_ABORT for this thread. ++ */ ++ rc = set_thread_uses_vas(); ++ if (rc) ++ goto free_window; + } + +- /* +- * Now that we have a send window, ensure context switch issues +- * CP_ABORT for this thread. +- */ +- rc = -EINVAL; +- if (set_thread_uses_vas() < 0) +- goto free_window; +- + set_vinst_win(vinst, txwin); + + return txwin; +diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c +index dceb514..652d3e96 100644 +--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c ++++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + #include "pseries.h" + #include "offline_states.h" +@@ -331,6 +332,7 @@ static void pseries_remove_processor(struct device_node *np) + BUG_ON(cpu_online(cpu)); + set_cpu_present(cpu, false); + set_hard_smp_processor_id(cpu, -1); ++ update_numa_cpu_lookup_table(cpu, -1); + break; + } + if (cpu >= nr_cpu_ids) +@@ -340,8 +342,6 @@ static void pseries_remove_processor(struct device_node *np) + cpu_maps_update_done(); + } + +-extern int find_and_online_cpu_nid(int cpu); +- + static int dlpar_online_cpu(struct device_node *dn) + { + int rc = 0; +diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c +index 81d8614..5e1ef91 100644 +--- a/arch/powerpc/platforms/pseries/ras.c ++++ b/arch/powerpc/platforms/pseries/ras.c +@@ -49,6 +49,28 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id); + + + /* ++ * Enable the hotplug interrupt late because processing them may touch other ++ * devices or systems (e.g. hugepages) that have not been initialized at the ++ * subsys stage. ++ */ ++int __init init_ras_hotplug_IRQ(void) ++{ ++ struct device_node *np; ++ ++ /* Hotplug Events */ ++ np = of_find_node_by_path("/event-sources/hot-plug-events"); ++ if (np != NULL) { ++ if (dlpar_workqueue_init() == 0) ++ request_event_sources_irqs(np, ras_hotplug_interrupt, ++ "RAS_HOTPLUG"); ++ of_node_put(np); ++ } ++ ++ return 0; ++} ++machine_late_initcall(pseries, init_ras_hotplug_IRQ); ++ ++/* + * Initialize handlers for the set of interrupts caused by hardware errors + * and power system events. + */ +@@ -66,15 +88,6 @@ static int __init init_ras_IRQ(void) + of_node_put(np); + } + +- /* Hotplug Events */ +- np = of_find_node_by_path("/event-sources/hot-plug-events"); +- if (np != NULL) { +- if (dlpar_workqueue_init() == 0) +- request_event_sources_irqs(np, ras_hotplug_interrupt, +- "RAS_HOTPLUG"); +- of_node_put(np); +- } +- + /* EPOW Events */ + np = of_find_node_by_path("/event-sources/epow-events"); + if (np != NULL) { +diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c +index 372d7ad..1a52762 100644 +--- a/arch/powerpc/platforms/pseries/setup.c ++++ b/arch/powerpc/platforms/pseries/setup.c +@@ -482,7 +482,8 @@ static void pseries_setup_rfi_flush(void) + if (types == L1D_FLUSH_NONE) + types = L1D_FLUSH_FALLBACK; + +- if (!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) ++ if ((!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) || ++ (!(result.behaviour & H_CPU_BEHAV_FAVOUR_SECURITY))) + enable = false; + } else { + /* Default to fallback if case hcall is not available */ +diff --git a/arch/powerpc/sysdev/xive/spapr.c b/arch/powerpc/sysdev/xive/spapr.c +index d9c4c93..091f1d0 100644 +--- a/arch/powerpc/sysdev/xive/spapr.c ++++ b/arch/powerpc/sysdev/xive/spapr.c +@@ -356,7 +356,8 @@ static int xive_spapr_configure_queue(u32 target, struct xive_q *q, u8 prio, + + rc = plpar_int_get_queue_info(0, target, prio, &esn_page, &esn_size); + if (rc) { +- pr_err("Error %lld getting queue info prio %d\n", rc, prio); ++ pr_err("Error %lld getting queue info CPU %d prio %d\n", rc, ++ target, prio); + rc = -EIO; + goto fail; + } +@@ -370,7 +371,8 @@ static int xive_spapr_configure_queue(u32 target, struct xive_q *q, u8 prio, + /* Configure and enable the queue in HW */ + rc = plpar_int_set_queue_config(flags, target, prio, qpage_phys, order); + if (rc) { +- pr_err("Error %lld setting queue for prio %d\n", rc, prio); ++ pr_err("Error %lld setting queue for CPU %d prio %d\n", rc, ++ target, prio); + rc = -EIO; + } else { + q->qpage = qpage; +@@ -389,8 +391,8 @@ static int xive_spapr_setup_queue(unsigned int cpu, struct xive_cpu *xc, + if (IS_ERR(qpage)) + return PTR_ERR(qpage); + +- return xive_spapr_configure_queue(cpu, q, prio, qpage, +- xive_queue_shift); ++ return xive_spapr_configure_queue(get_hard_smp_processor_id(cpu), ++ q, prio, qpage, xive_queue_shift); + } + + static void xive_spapr_cleanup_queue(unsigned int cpu, struct xive_cpu *xc, +@@ -399,10 +401,12 @@ static void xive_spapr_cleanup_queue(unsigned int cpu, struct xive_cpu *xc, + struct xive_q *q = &xc->queue[prio]; + unsigned int alloc_order; + long rc; ++ int hw_cpu = get_hard_smp_processor_id(cpu); + +- rc = plpar_int_set_queue_config(0, cpu, prio, 0, 0); ++ rc = plpar_int_set_queue_config(0, hw_cpu, prio, 0, 0); + if (rc) +- pr_err("Error %ld setting queue for prio %d\n", rc, prio); ++ pr_err("Error %ld setting queue for CPU %d prio %d\n", rc, ++ hw_cpu, prio); + + alloc_order = xive_alloc_order(xive_queue_shift); + free_pages((unsigned long)q->qpage, alloc_order); +diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig +index b6722c2..04807c7 100644 +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -8,7 +8,6 @@ config RISCV + select OF + select OF_EARLY_FLATTREE + select OF_IRQ +- select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE + select ARCH_WANT_FRAME_POINTERS + select CLONE_BACKWARDS + select COMMON_CLK +@@ -20,7 +19,6 @@ config RISCV + select GENERIC_STRNLEN_USER + select GENERIC_SMP_IDLE_THREAD + select GENERIC_ATOMIC64 if !64BIT || !RISCV_ISA_A +- select ARCH_WANT_OPTIONAL_GPIOLIB + select HAVE_MEMBLOCK + select HAVE_MEMBLOCK_NODE_MAP + select HAVE_DMA_API_DEBUG +@@ -34,7 +32,6 @@ config RISCV + select HAVE_ARCH_TRACEHOOK + select MODULES_USE_ELF_RELA if MODULES + select THREAD_INFO_IN_TASK +- select RISCV_IRQ_INTC + select RISCV_TIMER + + config MMU +diff --git a/arch/riscv/include/asm/barrier.h b/arch/riscv/include/asm/barrier.h +index c0319cb..5510366 100644 +--- a/arch/riscv/include/asm/barrier.h ++++ b/arch/riscv/include/asm/barrier.h +@@ -34,9 +34,9 @@ + #define wmb() RISCV_FENCE(ow,ow) + + /* These barriers do not need to enforce ordering on devices, just memory. */ +-#define smp_mb() RISCV_FENCE(rw,rw) +-#define smp_rmb() RISCV_FENCE(r,r) +-#define smp_wmb() RISCV_FENCE(w,w) ++#define __smp_mb() RISCV_FENCE(rw,rw) ++#define __smp_rmb() RISCV_FENCE(r,r) ++#define __smp_wmb() RISCV_FENCE(w,w) + + /* + * This is a very specific barrier: it's currently only used in two places in +diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S +index 87fc045..56fa592 100644 +--- a/arch/riscv/kernel/entry.S ++++ b/arch/riscv/kernel/entry.S +@@ -172,6 +172,9 @@ ENTRY(handle_exception) + move a1, sp /* pt_regs */ + tail do_IRQ + 1: ++ /* Exceptions run with interrupts enabled */ ++ csrs sstatus, SR_SIE ++ + /* Handle syscalls */ + li t0, EXC_SYSCALL + beq s4, t0, handle_syscall +@@ -198,8 +201,6 @@ handle_syscall: + */ + addi s2, s2, 0x4 + REG_S s2, PT_SEPC(sp) +- /* System calls run with interrupts enabled */ +- csrs sstatus, SR_SIE + /* Trace syscalls, but only if requested by the user. */ + REG_L t0, TASK_TI_FLAGS(tp) + andi t0, t0, _TIF_SYSCALL_TRACE +diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S +index 226eeb1..6e07ed3 100644 +--- a/arch/riscv/kernel/head.S ++++ b/arch/riscv/kernel/head.S +@@ -64,7 +64,7 @@ ENTRY(_start) + /* Start the kernel */ + mv a0, s0 + mv a1, s1 +- call sbi_save ++ call parse_dtb + tail start_kernel + + relocate: +diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c +index 09f7064..c11f40c 100644 +--- a/arch/riscv/kernel/setup.c ++++ b/arch/riscv/kernel/setup.c +@@ -144,7 +144,7 @@ asmlinkage void __init setup_vm(void) + #endif + } + +-void __init sbi_save(unsigned int hartid, void *dtb) ++void __init parse_dtb(unsigned int hartid, void *dtb) + { + early_init_dt_scan(__va(dtb)); + } +diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h +index 65154ea..6c8ce15 100644 +--- a/arch/s390/include/asm/mmu_context.h ++++ b/arch/s390/include/asm/mmu_context.h +@@ -63,6 +63,7 @@ static inline int init_new_context(struct task_struct *tsk, + _ASCE_USER_BITS | _ASCE_TYPE_SEGMENT; + /* pgd_alloc() did not account this pmd */ + mm_inc_nr_pmds(mm); ++ mm_inc_nr_puds(mm); + } + crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm)); + return 0; +diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S +index 13a133a..a5621ea 100644 +--- a/arch/s390/kernel/entry.S ++++ b/arch/s390/kernel/entry.S +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -230,7 +231,7 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART) + .hidden \name + .type \name,@function + \name: +- .cfi_startproc ++ CFI_STARTPROC + #ifdef CONFIG_HAVE_MARCH_Z10_FEATURES + exrl 0,0f + #else +@@ -239,7 +240,7 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART) + #endif + j . + 0: br \reg +- .cfi_endproc ++ CFI_ENDPROC + .endm + + GEN_BR_THUNK __s390x_indirect_jump_r1use_r9,%r9,%r1 +@@ -426,13 +427,13 @@ ENTRY(system_call) + UPDATE_VTIME %r8,%r9,__LC_SYNC_ENTER_TIMER + BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP + stmg %r0,%r7,__PT_R0(%r11) +- # clear user controlled register to prevent speculative use +- xgr %r0,%r0 + mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC + mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW + mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC + stg %r14,__PT_FLAGS(%r11) + .Lsysc_do_svc: ++ # clear user controlled register to prevent speculative use ++ xgr %r0,%r0 + # load address of system call table + lg %r10,__THREAD_sysc_table(%r13,%r12) + llgh %r8,__PT_INT_CODE+2(%r11) +@@ -1439,6 +1440,7 @@ cleanup_critical: + stg %r15,__LC_SYSTEM_TIMER + 0: # update accounting time stamp + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER ++ BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP + # set up saved register r11 + lg %r15,__LC_KERNEL_STACK + la %r9,STACK_FRAME_OVERHEAD(%r15) +diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c +index 69d7fcf..9aff72d 100644 +--- a/arch/s390/kernel/nospec-branch.c ++++ b/arch/s390/kernel/nospec-branch.c +@@ -2,8 +2,8 @@ + #include + #include + +-int nospec_call_disable = IS_ENABLED(EXPOLINE_OFF); +-int nospec_return_disable = !IS_ENABLED(EXPOLINE_FULL); ++int nospec_call_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); ++int nospec_return_disable = !IS_ENABLED(CONFIG_EXPOLINE_FULL); + + static int __init nospectre_v2_setup_early(char *str) + { +diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c +index 9c7d707..07c6e81 100644 +--- a/arch/s390/kvm/intercept.c ++++ b/arch/s390/kvm/intercept.c +@@ -22,22 +22,6 @@ + #include "trace.h" + #include "trace-s390.h" + +- +-static const intercept_handler_t instruction_handlers[256] = { +- [0x01] = kvm_s390_handle_01, +- [0x82] = kvm_s390_handle_lpsw, +- [0x83] = kvm_s390_handle_diag, +- [0xaa] = kvm_s390_handle_aa, +- [0xae] = kvm_s390_handle_sigp, +- [0xb2] = kvm_s390_handle_b2, +- [0xb6] = kvm_s390_handle_stctl, +- [0xb7] = kvm_s390_handle_lctl, +- [0xb9] = kvm_s390_handle_b9, +- [0xe3] = kvm_s390_handle_e3, +- [0xe5] = kvm_s390_handle_e5, +- [0xeb] = kvm_s390_handle_eb, +-}; +- + u8 kvm_s390_get_ilen(struct kvm_vcpu *vcpu) + { + struct kvm_s390_sie_block *sie_block = vcpu->arch.sie_block; +@@ -129,16 +113,39 @@ static int handle_validity(struct kvm_vcpu *vcpu) + + static int handle_instruction(struct kvm_vcpu *vcpu) + { +- intercept_handler_t handler; +- + vcpu->stat.exit_instruction++; + trace_kvm_s390_intercept_instruction(vcpu, + vcpu->arch.sie_block->ipa, + vcpu->arch.sie_block->ipb); +- handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8]; +- if (handler) +- return handler(vcpu); +- return -EOPNOTSUPP; ++ ++ switch (vcpu->arch.sie_block->ipa >> 8) { ++ case 0x01: ++ return kvm_s390_handle_01(vcpu); ++ case 0x82: ++ return kvm_s390_handle_lpsw(vcpu); ++ case 0x83: ++ return kvm_s390_handle_diag(vcpu); ++ case 0xaa: ++ return kvm_s390_handle_aa(vcpu); ++ case 0xae: ++ return kvm_s390_handle_sigp(vcpu); ++ case 0xb2: ++ return kvm_s390_handle_b2(vcpu); ++ case 0xb6: ++ return kvm_s390_handle_stctl(vcpu); ++ case 0xb7: ++ return kvm_s390_handle_lctl(vcpu); ++ case 0xb9: ++ return kvm_s390_handle_b9(vcpu); ++ case 0xe3: ++ return kvm_s390_handle_e3(vcpu); ++ case 0xe5: ++ return kvm_s390_handle_e5(vcpu); ++ case 0xeb: ++ return kvm_s390_handle_eb(vcpu); ++ default: ++ return -EOPNOTSUPP; ++ } + } + + static int inject_prog_on_prog_intercept(struct kvm_vcpu *vcpu) +diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c +index aabf46f..b04616b 100644 +--- a/arch/s390/kvm/interrupt.c ++++ b/arch/s390/kvm/interrupt.c +@@ -169,8 +169,15 @@ static int ckc_interrupts_enabled(struct kvm_vcpu *vcpu) + + static int ckc_irq_pending(struct kvm_vcpu *vcpu) + { +- if (vcpu->arch.sie_block->ckc >= kvm_s390_get_tod_clock_fast(vcpu->kvm)) ++ const u64 now = kvm_s390_get_tod_clock_fast(vcpu->kvm); ++ const u64 ckc = vcpu->arch.sie_block->ckc; ++ ++ if (vcpu->arch.sie_block->gcr[0] & 0x0020000000000000ul) { ++ if ((s64)ckc >= (s64)now) ++ return 0; ++ } else if (ckc >= now) { + return 0; ++ } + return ckc_interrupts_enabled(vcpu); + } + +@@ -187,12 +194,6 @@ static int cpu_timer_irq_pending(struct kvm_vcpu *vcpu) + return kvm_s390_get_cpu_timer(vcpu) >> 63; + } + +-static inline int is_ioirq(unsigned long irq_type) +-{ +- return ((irq_type >= IRQ_PEND_IO_ISC_7) && +- (irq_type <= IRQ_PEND_IO_ISC_0)); +-} +- + static uint64_t isc_to_isc_bits(int isc) + { + return (0x80 >> isc) << 24; +@@ -236,10 +237,15 @@ static inline int kvm_s390_gisa_tac_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gis + return test_and_clear_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa); + } + +-static inline unsigned long pending_irqs(struct kvm_vcpu *vcpu) ++static inline unsigned long pending_irqs_no_gisa(struct kvm_vcpu *vcpu) + { + return vcpu->kvm->arch.float_int.pending_irqs | +- vcpu->arch.local_int.pending_irqs | ++ vcpu->arch.local_int.pending_irqs; ++} ++ ++static inline unsigned long pending_irqs(struct kvm_vcpu *vcpu) ++{ ++ return pending_irqs_no_gisa(vcpu) | + kvm_s390_gisa_get_ipm(vcpu->kvm->arch.gisa) << IRQ_PEND_IO_ISC_7; + } + +@@ -337,7 +343,7 @@ static void __reset_intercept_indicators(struct kvm_vcpu *vcpu) + + static void set_intercept_indicators_io(struct kvm_vcpu *vcpu) + { +- if (!(pending_irqs(vcpu) & IRQ_PEND_IO_MASK)) ++ if (!(pending_irqs_no_gisa(vcpu) & IRQ_PEND_IO_MASK)) + return; + else if (psw_ioint_disabled(vcpu)) + kvm_s390_set_cpuflags(vcpu, CPUSTAT_IO_INT); +@@ -1011,24 +1017,6 @@ static int __must_check __deliver_io(struct kvm_vcpu *vcpu, + return rc; + } + +-typedef int (*deliver_irq_t)(struct kvm_vcpu *vcpu); +- +-static const deliver_irq_t deliver_irq_funcs[] = { +- [IRQ_PEND_MCHK_EX] = __deliver_machine_check, +- [IRQ_PEND_MCHK_REP] = __deliver_machine_check, +- [IRQ_PEND_PROG] = __deliver_prog, +- [IRQ_PEND_EXT_EMERGENCY] = __deliver_emergency_signal, +- [IRQ_PEND_EXT_EXTERNAL] = __deliver_external_call, +- [IRQ_PEND_EXT_CLOCK_COMP] = __deliver_ckc, +- [IRQ_PEND_EXT_CPU_TIMER] = __deliver_cpu_timer, +- [IRQ_PEND_RESTART] = __deliver_restart, +- [IRQ_PEND_SET_PREFIX] = __deliver_set_prefix, +- [IRQ_PEND_PFAULT_INIT] = __deliver_pfault_init, +- [IRQ_PEND_EXT_SERVICE] = __deliver_service, +- [IRQ_PEND_PFAULT_DONE] = __deliver_pfault_done, +- [IRQ_PEND_VIRTIO] = __deliver_virtio, +-}; +- + /* Check whether an external call is pending (deliverable or not) */ + int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu) + { +@@ -1066,13 +1054,19 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) + + static u64 __calculate_sltime(struct kvm_vcpu *vcpu) + { +- u64 now, cputm, sltime = 0; ++ const u64 now = kvm_s390_get_tod_clock_fast(vcpu->kvm); ++ const u64 ckc = vcpu->arch.sie_block->ckc; ++ u64 cputm, sltime = 0; + + if (ckc_interrupts_enabled(vcpu)) { +- now = kvm_s390_get_tod_clock_fast(vcpu->kvm); +- sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now); +- /* already expired or overflow? */ +- if (!sltime || vcpu->arch.sie_block->ckc <= now) ++ if (vcpu->arch.sie_block->gcr[0] & 0x0020000000000000ul) { ++ if ((s64)now < (s64)ckc) ++ sltime = tod_to_ns((s64)ckc - (s64)now); ++ } else if (now < ckc) { ++ sltime = tod_to_ns(ckc - now); ++ } ++ /* already expired */ ++ if (!sltime) + return 0; + if (cpu_timer_interrupts_enabled(vcpu)) { + cputm = kvm_s390_get_cpu_timer(vcpu); +@@ -1192,7 +1186,6 @@ void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu) + int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) + { + struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; +- deliver_irq_t func; + int rc = 0; + unsigned long irq_type; + unsigned long irqs; +@@ -1212,16 +1205,57 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) + while ((irqs = deliverable_irqs(vcpu)) && !rc) { + /* bits are in the reverse order of interrupt priority */ + irq_type = find_last_bit(&irqs, IRQ_PEND_COUNT); +- if (is_ioirq(irq_type)) { ++ switch (irq_type) { ++ case IRQ_PEND_IO_ISC_0: ++ case IRQ_PEND_IO_ISC_1: ++ case IRQ_PEND_IO_ISC_2: ++ case IRQ_PEND_IO_ISC_3: ++ case IRQ_PEND_IO_ISC_4: ++ case IRQ_PEND_IO_ISC_5: ++ case IRQ_PEND_IO_ISC_6: ++ case IRQ_PEND_IO_ISC_7: + rc = __deliver_io(vcpu, irq_type); +- } else { +- func = deliver_irq_funcs[irq_type]; +- if (!func) { +- WARN_ON_ONCE(func == NULL); +- clear_bit(irq_type, &li->pending_irqs); +- continue; +- } +- rc = func(vcpu); ++ break; ++ case IRQ_PEND_MCHK_EX: ++ case IRQ_PEND_MCHK_REP: ++ rc = __deliver_machine_check(vcpu); ++ break; ++ case IRQ_PEND_PROG: ++ rc = __deliver_prog(vcpu); ++ break; ++ case IRQ_PEND_EXT_EMERGENCY: ++ rc = __deliver_emergency_signal(vcpu); ++ break; ++ case IRQ_PEND_EXT_EXTERNAL: ++ rc = __deliver_external_call(vcpu); ++ break; ++ case IRQ_PEND_EXT_CLOCK_COMP: ++ rc = __deliver_ckc(vcpu); ++ break; ++ case IRQ_PEND_EXT_CPU_TIMER: ++ rc = __deliver_cpu_timer(vcpu); ++ break; ++ case IRQ_PEND_RESTART: ++ rc = __deliver_restart(vcpu); ++ break; ++ case IRQ_PEND_SET_PREFIX: ++ rc = __deliver_set_prefix(vcpu); ++ break; ++ case IRQ_PEND_PFAULT_INIT: ++ rc = __deliver_pfault_init(vcpu); ++ break; ++ case IRQ_PEND_EXT_SERVICE: ++ rc = __deliver_service(vcpu); ++ break; ++ case IRQ_PEND_PFAULT_DONE: ++ rc = __deliver_pfault_done(vcpu); ++ break; ++ case IRQ_PEND_VIRTIO: ++ rc = __deliver_virtio(vcpu); ++ break; ++ default: ++ WARN_ONCE(1, "Unknown pending irq type %ld", irq_type); ++ clear_bit(irq_type, &li->pending_irqs); + } + } + +@@ -1701,7 +1735,8 @@ static void __floating_irq_kick(struct kvm *kvm, u64 type) + kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_STOP_INT); + break; + case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: +- kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_IO_INT); ++ if (!(type & KVM_S390_INT_IO_AI_MASK && kvm->arch.gisa)) ++ kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_IO_INT); + break; + default: + kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_EXT_INT); +diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c +index ba4c709..339ac09 100644 +--- a/arch/s390/kvm/kvm-s390.c ++++ b/arch/s390/kvm/kvm-s390.c +@@ -86,6 +86,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { + { "deliver_prefix_signal", VCPU_STAT(deliver_prefix_signal) }, + { "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) }, + { "deliver_program_interruption", VCPU_STAT(deliver_program_int) }, ++ { "deliver_io_interrupt", VCPU_STAT(deliver_io_int) }, + { "exit_wait_state", VCPU_STAT(exit_wait_state) }, + { "instruction_epsw", VCPU_STAT(instruction_epsw) }, + { "instruction_gs", VCPU_STAT(instruction_gs) }, +@@ -179,6 +180,28 @@ int kvm_arch_hardware_enable(void) + static void kvm_gmap_notifier(struct gmap *gmap, unsigned long start, + unsigned long end); + ++static void kvm_clock_sync_scb(struct kvm_s390_sie_block *scb, u64 delta) ++{ ++ u8 delta_idx = 0; ++ ++ /* ++ * The TOD jumps by delta, we have to compensate this by adding ++ * -delta to the epoch. ++ */ ++ delta = -delta; ++ ++ /* sign-extension - we're adding to signed values below */ ++ if ((s64)delta < 0) ++ delta_idx = -1; ++ ++ scb->epoch += delta; ++ if (scb->ecd & ECD_MEF) { ++ scb->epdx += delta_idx; ++ if (scb->epoch < delta) ++ scb->epdx += 1; ++ } ++} ++ + /* + * This callback is executed during stop_machine(). All CPUs are therefore + * temporarily stopped. In order not to change guest behavior, we have to +@@ -194,13 +217,17 @@ static int kvm_clock_sync(struct notifier_block *notifier, unsigned long val, + unsigned long long *delta = v; + + list_for_each_entry(kvm, &vm_list, vm_list) { +- kvm->arch.epoch -= *delta; + kvm_for_each_vcpu(i, vcpu, kvm) { +- vcpu->arch.sie_block->epoch -= *delta; ++ kvm_clock_sync_scb(vcpu->arch.sie_block, *delta); ++ if (i == 0) { ++ kvm->arch.epoch = vcpu->arch.sie_block->epoch; ++ kvm->arch.epdx = vcpu->arch.sie_block->epdx; ++ } + if (vcpu->arch.cputm_enabled) + vcpu->arch.cputm_start += *delta; + if (vcpu->arch.vsie_block) +- vcpu->arch.vsie_block->epoch -= *delta; ++ kvm_clock_sync_scb(vcpu->arch.vsie_block, ++ *delta); + } + } + return NOTIFY_OK; +@@ -902,12 +929,9 @@ static int kvm_s390_set_tod_ext(struct kvm *kvm, struct kvm_device_attr *attr) + if (copy_from_user(>od, (void __user *)attr->addr, sizeof(gtod))) + return -EFAULT; + +- if (test_kvm_facility(kvm, 139)) +- kvm_s390_set_tod_clock_ext(kvm, >od); +- else if (gtod.epoch_idx == 0) +- kvm_s390_set_tod_clock(kvm, gtod.tod); +- else ++ if (!test_kvm_facility(kvm, 139) && gtod.epoch_idx) + return -EINVAL; ++ kvm_s390_set_tod_clock(kvm, >od); + + VM_EVENT(kvm, 3, "SET: TOD extension: 0x%x, TOD base: 0x%llx", + gtod.epoch_idx, gtod.tod); +@@ -932,13 +956,14 @@ static int kvm_s390_set_tod_high(struct kvm *kvm, struct kvm_device_attr *attr) + + static int kvm_s390_set_tod_low(struct kvm *kvm, struct kvm_device_attr *attr) + { +- u64 gtod; ++ struct kvm_s390_vm_tod_clock gtod = { 0 }; + +- if (copy_from_user(>od, (void __user *)attr->addr, sizeof(gtod))) ++ if (copy_from_user(>od.tod, (void __user *)attr->addr, ++ sizeof(gtod.tod))) + return -EFAULT; + +- kvm_s390_set_tod_clock(kvm, gtod); +- VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx", gtod); ++ kvm_s390_set_tod_clock(kvm, >od); ++ VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx", gtod.tod); + return 0; + } + +@@ -2122,6 +2147,7 @@ static void sca_add_vcpu(struct kvm_vcpu *vcpu) + /* we still need the basic sca for the ipte control */ + vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32); + vcpu->arch.sie_block->scaol = (__u32)(__u64)sca; ++ return; + } + read_lock(&vcpu->kvm->arch.sca_lock); + if (vcpu->kvm->arch.use_esca) { +@@ -2389,6 +2415,7 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) + mutex_lock(&vcpu->kvm->lock); + preempt_disable(); + vcpu->arch.sie_block->epoch = vcpu->kvm->arch.epoch; ++ vcpu->arch.sie_block->epdx = vcpu->kvm->arch.epdx; + preempt_enable(); + mutex_unlock(&vcpu->kvm->lock); + if (!kvm_is_ucontrol(vcpu->kvm)) { +@@ -3021,8 +3048,8 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu) + return 0; + } + +-void kvm_s390_set_tod_clock_ext(struct kvm *kvm, +- const struct kvm_s390_vm_tod_clock *gtod) ++void kvm_s390_set_tod_clock(struct kvm *kvm, ++ const struct kvm_s390_vm_tod_clock *gtod) + { + struct kvm_vcpu *vcpu; + struct kvm_s390_tod_clock_ext htod; +@@ -3034,10 +3061,12 @@ void kvm_s390_set_tod_clock_ext(struct kvm *kvm, + get_tod_clock_ext((char *)&htod); + + kvm->arch.epoch = gtod->tod - htod.tod; +- kvm->arch.epdx = gtod->epoch_idx - htod.epoch_idx; +- +- if (kvm->arch.epoch > gtod->tod) +- kvm->arch.epdx -= 1; ++ kvm->arch.epdx = 0; ++ if (test_kvm_facility(kvm, 139)) { ++ kvm->arch.epdx = gtod->epoch_idx - htod.epoch_idx; ++ if (kvm->arch.epoch > gtod->tod) ++ kvm->arch.epdx -= 1; ++ } + + kvm_s390_vcpu_block_all(kvm); + kvm_for_each_vcpu(i, vcpu, kvm) { +@@ -3050,22 +3079,6 @@ void kvm_s390_set_tod_clock_ext(struct kvm *kvm, + mutex_unlock(&kvm->lock); + } + +-void kvm_s390_set_tod_clock(struct kvm *kvm, u64 tod) +-{ +- struct kvm_vcpu *vcpu; +- int i; +- +- mutex_lock(&kvm->lock); +- preempt_disable(); +- kvm->arch.epoch = tod - get_tod_clock(); +- kvm_s390_vcpu_block_all(kvm); +- kvm_for_each_vcpu(i, vcpu, kvm) +- vcpu->arch.sie_block->epoch = kvm->arch.epoch; +- kvm_s390_vcpu_unblock_all(kvm); +- preempt_enable(); +- mutex_unlock(&kvm->lock); +-} +- + /** + * kvm_arch_fault_in_page - fault-in guest page if necessary + * @vcpu: The corresponding virtual cpu +diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h +index bd31b37..f55ac0e 100644 +--- a/arch/s390/kvm/kvm-s390.h ++++ b/arch/s390/kvm/kvm-s390.h +@@ -19,8 +19,6 @@ + #include + #include + +-typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu); +- + /* Transactional Memory Execution related macros */ + #define IS_TE_ENABLED(vcpu) ((vcpu->arch.sie_block->ecb & ECB_TE)) + #define TDB_FORMAT1 1 +@@ -283,9 +281,8 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); + int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu); + + /* implemented in kvm-s390.c */ +-void kvm_s390_set_tod_clock_ext(struct kvm *kvm, +- const struct kvm_s390_vm_tod_clock *gtod); +-void kvm_s390_set_tod_clock(struct kvm *kvm, u64 tod); ++void kvm_s390_set_tod_clock(struct kvm *kvm, ++ const struct kvm_s390_vm_tod_clock *gtod); + long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable); + int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr); + int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr); +diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c +index c4c4e15..f0b4185 100644 +--- a/arch/s390/kvm/priv.c ++++ b/arch/s390/kvm/priv.c +@@ -85,9 +85,10 @@ int kvm_s390_handle_e3(struct kvm_vcpu *vcpu) + /* Handle SCK (SET CLOCK) interception */ + static int handle_set_clock(struct kvm_vcpu *vcpu) + { ++ struct kvm_s390_vm_tod_clock gtod = { 0 }; + int rc; + u8 ar; +- u64 op2, val; ++ u64 op2; + + vcpu->stat.instruction_sck++; + +@@ -97,12 +98,12 @@ static int handle_set_clock(struct kvm_vcpu *vcpu) + op2 = kvm_s390_get_base_disp_s(vcpu, &ar); + if (op2 & 7) /* Operand must be on a doubleword boundary */ + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); +- rc = read_guest(vcpu, op2, ar, &val, sizeof(val)); ++ rc = read_guest(vcpu, op2, ar, >od.tod, sizeof(gtod.tod)); + if (rc) + return kvm_s390_inject_prog_cond(vcpu, rc); + +- VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", val); +- kvm_s390_set_tod_clock(vcpu->kvm, val); ++ VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", gtod.tod); ++ kvm_s390_set_tod_clock(vcpu->kvm, >od); + + kvm_s390_set_psw_cc(vcpu, 0); + return 0; +@@ -795,55 +796,60 @@ static int handle_stsi(struct kvm_vcpu *vcpu) + return rc; + } + +-static const intercept_handler_t b2_handlers[256] = { +- [0x02] = handle_stidp, +- [0x04] = handle_set_clock, +- [0x10] = handle_set_prefix, +- [0x11] = handle_store_prefix, +- [0x12] = handle_store_cpu_address, +- [0x14] = kvm_s390_handle_vsie, +- [0x21] = handle_ipte_interlock, +- [0x29] = handle_iske, +- [0x2a] = handle_rrbe, +- [0x2b] = handle_sske, +- [0x2c] = handle_test_block, +- [0x30] = handle_io_inst, +- [0x31] = handle_io_inst, +- [0x32] = handle_io_inst, +- [0x33] = handle_io_inst, +- [0x34] = handle_io_inst, +- [0x35] = handle_io_inst, +- [0x36] = handle_io_inst, +- [0x37] = handle_io_inst, +- [0x38] = handle_io_inst, +- [0x39] = handle_io_inst, +- [0x3a] = handle_io_inst, +- [0x3b] = handle_io_inst, +- [0x3c] = handle_io_inst, +- [0x50] = handle_ipte_interlock, +- [0x56] = handle_sthyi, +- [0x5f] = handle_io_inst, +- [0x74] = handle_io_inst, +- [0x76] = handle_io_inst, +- [0x7d] = handle_stsi, +- [0xb1] = handle_stfl, +- [0xb2] = handle_lpswe, +-}; +- + int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) + { +- intercept_handler_t handler; +- +- /* +- * A lot of B2 instructions are priviledged. Here we check for +- * the privileged ones, that we can handle in the kernel. +- * Anything else goes to userspace. +- */ +- handler = b2_handlers[vcpu->arch.sie_block->ipa & 0x00ff]; +- if (handler) +- return handler(vcpu); +- +- return -EOPNOTSUPP; ++ switch (vcpu->arch.sie_block->ipa & 0x00ff) { ++ case 0x02: ++ return handle_stidp(vcpu); ++ case 0x04: ++ return handle_set_clock(vcpu); ++ case 0x10: ++ return handle_set_prefix(vcpu); ++ case 0x11: ++ return handle_store_prefix(vcpu); ++ case 0x12: ++ return handle_store_cpu_address(vcpu); ++ case 0x14: ++ return kvm_s390_handle_vsie(vcpu); ++ case 0x21: ++ case 0x50: ++ return handle_ipte_interlock(vcpu); ++ case 0x29: ++ return handle_iske(vcpu); ++ case 0x2a: ++ return handle_rrbe(vcpu); ++ case 0x2b: ++ return handle_sske(vcpu); ++ case 0x2c: ++ return handle_test_block(vcpu); ++ case 0x30: ++ case 0x31: ++ case 0x32: ++ case 0x33: ++ case 0x34: ++ case 0x35: ++ case 0x36: ++ case 0x37: ++ case 0x38: ++ case 0x39: ++ case 0x3a: ++ case 0x3b: ++ case 0x3c: ++ case 0x5f: ++ case 0x74: ++ case 0x76: ++ return handle_io_inst(vcpu); ++ case 0x56: ++ return handle_sthyi(vcpu); ++ case 0x7d: ++ return handle_stsi(vcpu); ++ case 0xb1: ++ return handle_stfl(vcpu); ++ case 0xb2: ++ return handle_lpswe(vcpu); ++ default: ++ return -EOPNOTSUPP; ++ } + } + + static int handle_epsw(struct kvm_vcpu *vcpu) +@@ -1105,25 +1111,22 @@ static int handle_essa(struct kvm_vcpu *vcpu) + return 0; + } + +-static const intercept_handler_t b9_handlers[256] = { +- [0x8a] = handle_ipte_interlock, +- [0x8d] = handle_epsw, +- [0x8e] = handle_ipte_interlock, +- [0x8f] = handle_ipte_interlock, +- [0xab] = handle_essa, +- [0xaf] = handle_pfmf, +-}; +- + int kvm_s390_handle_b9(struct kvm_vcpu *vcpu) + { +- intercept_handler_t handler; +- +- /* This is handled just as for the B2 instructions. */ +- handler = b9_handlers[vcpu->arch.sie_block->ipa & 0x00ff]; +- if (handler) +- return handler(vcpu); +- +- return -EOPNOTSUPP; ++ switch (vcpu->arch.sie_block->ipa & 0x00ff) { ++ case 0x8a: ++ case 0x8e: ++ case 0x8f: ++ return handle_ipte_interlock(vcpu); ++ case 0x8d: ++ return handle_epsw(vcpu); ++ case 0xab: ++ return handle_essa(vcpu); ++ case 0xaf: ++ return handle_pfmf(vcpu); ++ default: ++ return -EOPNOTSUPP; ++ } + } + + int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu) +@@ -1271,22 +1274,20 @@ static int handle_stctg(struct kvm_vcpu *vcpu) + return rc ? kvm_s390_inject_prog_cond(vcpu, rc) : 0; + } + +-static const intercept_handler_t eb_handlers[256] = { +- [0x2f] = handle_lctlg, +- [0x25] = handle_stctg, +- [0x60] = handle_ri, +- [0x61] = handle_ri, +- [0x62] = handle_ri, +-}; +- + int kvm_s390_handle_eb(struct kvm_vcpu *vcpu) + { +- intercept_handler_t handler; +- +- handler = eb_handlers[vcpu->arch.sie_block->ipb & 0xff]; +- if (handler) +- return handler(vcpu); +- return -EOPNOTSUPP; ++ switch (vcpu->arch.sie_block->ipb & 0x000000ff) { ++ case 0x25: ++ return handle_stctg(vcpu); ++ case 0x2f: ++ return handle_lctlg(vcpu); ++ case 0x60: ++ case 0x61: ++ case 0x62: ++ return handle_ri(vcpu); ++ default: ++ return -EOPNOTSUPP; ++ } + } + + static int handle_tprot(struct kvm_vcpu *vcpu) +@@ -1346,10 +1347,12 @@ static int handle_tprot(struct kvm_vcpu *vcpu) + + int kvm_s390_handle_e5(struct kvm_vcpu *vcpu) + { +- /* For e5xx... instructions we only handle TPROT */ +- if ((vcpu->arch.sie_block->ipa & 0x00ff) == 0x01) ++ switch (vcpu->arch.sie_block->ipa & 0x00ff) { ++ case 0x01: + return handle_tprot(vcpu); +- return -EOPNOTSUPP; ++ default: ++ return -EOPNOTSUPP; ++ } + } + + static int handle_sckpf(struct kvm_vcpu *vcpu) +@@ -1380,17 +1383,14 @@ static int handle_ptff(struct kvm_vcpu *vcpu) + return 0; + } + +-static const intercept_handler_t x01_handlers[256] = { +- [0x04] = handle_ptff, +- [0x07] = handle_sckpf, +-}; +- + int kvm_s390_handle_01(struct kvm_vcpu *vcpu) + { +- intercept_handler_t handler; +- +- handler = x01_handlers[vcpu->arch.sie_block->ipa & 0x00ff]; +- if (handler) +- return handler(vcpu); +- return -EOPNOTSUPP; ++ switch (vcpu->arch.sie_block->ipa & 0x00ff) { ++ case 0x04: ++ return handle_ptff(vcpu); ++ case 0x07: ++ return handle_sckpf(vcpu); ++ default: ++ return -EOPNOTSUPP; ++ } + } +diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c +index ec77270..8961e39 100644 +--- a/arch/s390/kvm/vsie.c ++++ b/arch/s390/kvm/vsie.c +@@ -821,6 +821,7 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) + { + struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; + struct kvm_s390_sie_block *scb_o = vsie_page->scb_o; ++ int guest_bp_isolation; + int rc; + + handle_last_fault(vcpu, vsie_page); +@@ -831,6 +832,20 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) + s390_handle_mcck(); + + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); ++ ++ /* save current guest state of bp isolation override */ ++ guest_bp_isolation = test_thread_flag(TIF_ISOLATE_BP_GUEST); ++ ++ /* ++ * The guest is running with BPBC, so we have to force it on for our ++ * nested guest. This is done by enabling BPBC globally, so the BPBC ++ * control in the SCB (which the nested guest can modify) is simply ++ * ignored. ++ */ ++ if (test_kvm_facility(vcpu->kvm, 82) && ++ vcpu->arch.sie_block->fpf & FPF_BPBC) ++ set_thread_flag(TIF_ISOLATE_BP_GUEST); ++ + local_irq_disable(); + guest_enter_irqoff(); + local_irq_enable(); +@@ -840,6 +855,11 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) + local_irq_disable(); + guest_exit_irqoff(); + local_irq_enable(); ++ ++ /* restore guest state for bp isolation override */ ++ if (!guest_bp_isolation) ++ clear_thread_flag(TIF_ISOLATE_BP_GUEST); ++ + vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); + + if (rc == -EINTR) { +diff --git a/arch/sh/boot/dts/Makefile b/arch/sh/boot/dts/Makefile +index 715def0..01d0f7f 100644 +--- a/arch/sh/boot/dts/Makefile ++++ b/arch/sh/boot/dts/Makefile +@@ -1 +1,3 @@ +-obj-$(CONFIG_USE_BUILTIN_DTB) += $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_SOURCE)).dtb.o ++ifneq ($(CONFIG_BUILTIN_DTB_SOURCE),"") ++obj-y += $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_SOURCE)).dtb.o ++endif +diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig +index 6bf594a..8767e45 100644 +--- a/arch/sparc/Kconfig ++++ b/arch/sparc/Kconfig +@@ -430,6 +430,8 @@ config SPARC_LEON + depends on SPARC32 + select USB_EHCI_BIG_ENDIAN_MMIO + select USB_EHCI_BIG_ENDIAN_DESC ++ select USB_UHCI_BIG_ENDIAN_MMIO ++ select USB_UHCI_BIG_ENDIAN_DESC + ---help--- + If you say Y here if you are running on a SPARC-LEON processor. + The LEON processor is a synthesizable VHDL model of the +diff --git a/arch/sparc/include/asm/bug.h b/arch/sparc/include/asm/bug.h +index 6f17528..ea53e41 100644 +--- a/arch/sparc/include/asm/bug.h ++++ b/arch/sparc/include/asm/bug.h +@@ -9,10 +9,14 @@ + void do_BUG(const char *file, int line); + #define BUG() do { \ + do_BUG(__FILE__, __LINE__); \ ++ barrier_before_unreachable(); \ + __builtin_trap(); \ + } while (0) + #else +-#define BUG() __builtin_trap() ++#define BUG() do { \ ++ barrier_before_unreachable(); \ ++ __builtin_trap(); \ ++} while (0) + #endif + + #define HAVE_ARCH_BUG +diff --git a/arch/x86/.gitignore b/arch/x86/.gitignore +index aff152c..5a82bac 100644 +--- a/arch/x86/.gitignore ++++ b/arch/x86/.gitignore +@@ -1,6 +1,7 @@ + boot/compressed/vmlinux + tools/test_get_len + tools/insn_sanity ++tools/insn_decoder_test + purgatory/kexec-purgatory.c + purgatory/purgatory.ro + +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index 63bf349..0fa71a7 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -423,12 +423,6 @@ config X86_MPPARSE + For old smp systems that do not have proper acpi support. Newer systems + (esp with 64bit cpus) with acpi support, MADT and DSDT will override it + +-config X86_BIGSMP +- bool "Support for big SMP systems with more than 8 CPUs" +- depends on X86_32 && SMP +- ---help--- +- This option is needed for the systems that have more than 8 CPUs +- + config GOLDFISH + def_bool y + depends on X86_GOLDFISH +@@ -436,6 +430,7 @@ config GOLDFISH + config RETPOLINE + bool "Avoid speculative indirect branches in kernel" + default y ++ select STACK_VALIDATION if HAVE_STACK_VALIDATION + help + Compile kernel with the retpoline compiler options to guard against + kernel-to-user data leaks by avoiding speculative indirect +@@ -460,6 +455,12 @@ config INTEL_RDT + Say N if unsure. + + if X86_32 ++config X86_BIGSMP ++ bool "Support for big SMP systems with more than 8 CPUs" ++ depends on SMP ++ ---help--- ++ This option is needed for the systems that have more than 8 CPUs ++ + config X86_EXTENDED_PLATFORM + bool "Support for extended (non-PC) x86 platforms" + default y +@@ -949,25 +950,66 @@ config MAXSMP + Enable maximum number of CPUS and NUMA Nodes for this architecture. + If unsure, say N. + ++# ++# The maximum number of CPUs supported: ++# ++# The main config value is NR_CPUS, which defaults to NR_CPUS_DEFAULT, ++# and which can be configured interactively in the ++# [NR_CPUS_RANGE_BEGIN ... NR_CPUS_RANGE_END] range. ++# ++# The ranges are different on 32-bit and 64-bit kernels, depending on ++# hardware capabilities and scalability features of the kernel. ++# ++# ( If MAXSMP is enabled we just use the highest possible value and disable ++# interactive configuration. ) ++# ++ ++config NR_CPUS_RANGE_BEGIN ++ int ++ default NR_CPUS_RANGE_END if MAXSMP ++ default 1 if !SMP ++ default 2 ++ ++config NR_CPUS_RANGE_END ++ int ++ depends on X86_32 ++ default 64 if SMP && X86_BIGSMP ++ default 8 if SMP && !X86_BIGSMP ++ default 1 if !SMP ++ ++config NR_CPUS_RANGE_END ++ int ++ depends on X86_64 ++ default 8192 if SMP && ( MAXSMP || CPUMASK_OFFSTACK) ++ default 512 if SMP && (!MAXSMP && !CPUMASK_OFFSTACK) ++ default 1 if !SMP ++ ++config NR_CPUS_DEFAULT ++ int ++ depends on X86_32 ++ default 32 if X86_BIGSMP ++ default 8 if SMP ++ default 1 if !SMP ++ ++config NR_CPUS_DEFAULT ++ int ++ depends on X86_64 ++ default 8192 if MAXSMP ++ default 64 if SMP ++ default 1 if !SMP ++ + config NR_CPUS + int "Maximum number of CPUs" if SMP && !MAXSMP +- range 2 8 if SMP && X86_32 && !X86_BIGSMP +- range 2 64 if SMP && X86_32 && X86_BIGSMP +- range 2 512 if SMP && !MAXSMP && !CPUMASK_OFFSTACK && X86_64 +- range 2 8192 if SMP && !MAXSMP && CPUMASK_OFFSTACK && X86_64 +- default "1" if !SMP +- default "8192" if MAXSMP +- default "32" if SMP && X86_BIGSMP +- default "8" if SMP && X86_32 +- default "64" if SMP ++ range NR_CPUS_RANGE_BEGIN NR_CPUS_RANGE_END ++ default NR_CPUS_DEFAULT + ---help--- + This allows you to specify the maximum number of CPUs which this + kernel will support. If CPUMASK_OFFSTACK is enabled, the maximum + supported value is 8192, otherwise the maximum value is 512. The + minimum value which makes sense is 2. + +- This is purely to save memory - each supported CPU adds +- approximately eight kilobytes to the kernel image. ++ This is purely to save memory: each supported CPU adds about 8KB ++ to the kernel image. + + config SCHED_SMT + bool "SMT (Hyperthreading) scheduler support" +@@ -1363,7 +1405,7 @@ config HIGHMEM4G + + config HIGHMEM64G + bool "64GB" +- depends on !M486 ++ depends on !M486 && !M586 && !M586TSC && !M586MMX && !MGEODE_LX && !MGEODEGX1 && !MCYRIXIII && !MELAN && !MWINCHIPC6 && !WINCHIP3D && !MK6 + select X86_PAE + ---help--- + Select this if you have a 32-bit processor and more than 4 +@@ -2265,7 +2307,7 @@ choice + it can be used to assist security vulnerability exploitation. + + This setting can be changed at boot time via the kernel command +- line parameter vsyscall=[native|emulate|none]. ++ line parameter vsyscall=[emulate|none]. + + On a system with recent enough glibc (2.14 or newer) and no + static binaries, you can say None without a performance penalty +@@ -2273,15 +2315,6 @@ choice + + If unsure, select "Emulate". + +- config LEGACY_VSYSCALL_NATIVE +- bool "Native" +- help +- Actual executable code is located in the fixed vsyscall +- address mapping, implementing time() efficiently. Since +- this makes the mapping executable, it can be used during +- security vulnerability exploitation (traditionally as +- ROP gadgets). This configuration is not recommended. +- + config LEGACY_VSYSCALL_EMULATE + bool "Emulate" + help +diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu +index 65a9a47..8b8d229 100644 +--- a/arch/x86/Kconfig.cpu ++++ b/arch/x86/Kconfig.cpu +@@ -374,7 +374,7 @@ config X86_TSC + + config X86_CMPXCHG64 + def_bool y +- depends on X86_PAE || X86_64 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MATOM ++ depends on X86_PAE || X86_64 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586TSC || M586MMX || MATOM || MGEODE_LX || MGEODEGX1 || MK6 || MK7 || MK8 + + # this should be set for all -march=.. options where the compiler + # generates cmov. +@@ -385,7 +385,7 @@ config X86_CMOV + config X86_MINIMUM_CPU_FAMILY + int + default "64" if X86_64 +- default "6" if X86_32 && X86_P6_NOP ++ default "6" if X86_32 && (MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MEFFICEON || MATOM || MCRUSOE || MCORE2 || MK7 || MK8) + default "5" if X86_32 && X86_CMPXCHG64 + default "4" + +diff --git a/arch/x86/Makefile b/arch/x86/Makefile +index fad5516..498c1b8 100644 +--- a/arch/x86/Makefile ++++ b/arch/x86/Makefile +@@ -232,10 +232,9 @@ KBUILD_CFLAGS += -fno-asynchronous-unwind-tables + + # Avoid indirect branches in kernel to deal with Spectre + ifdef CONFIG_RETPOLINE +- RETPOLINE_CFLAGS += $(call cc-option,-mindirect-branch=thunk-extern -mindirect-branch-register) +- ifneq ($(RETPOLINE_CFLAGS),) +- KBUILD_CFLAGS += $(RETPOLINE_CFLAGS) -DRETPOLINE +- endif ++ifneq ($(RETPOLINE_CFLAGS),) ++ KBUILD_CFLAGS += $(RETPOLINE_CFLAGS) -DRETPOLINE ++endif + endif + + archscripts: scripts_basic +diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c +index 353e20c..886a911 100644 +--- a/arch/x86/boot/compressed/eboot.c ++++ b/arch/x86/boot/compressed/eboot.c +@@ -439,7 +439,7 @@ setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height) + struct efi_uga_draw_protocol *uga = NULL, *first_uga; + efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID; + unsigned long nr_ugas; +- u32 *handles = (u32 *)uga_handle;; ++ u32 *handles = (u32 *)uga_handle; + efi_status_t status = EFI_INVALID_PARAMETER; + int i; + +@@ -484,7 +484,7 @@ setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height) + struct efi_uga_draw_protocol *uga = NULL, *first_uga; + efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID; + unsigned long nr_ugas; +- u64 *handles = (u64 *)uga_handle;; ++ u64 *handles = (u64 *)uga_handle; + efi_status_t status = EFI_INVALID_PARAMETER; + int i; + +diff --git a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c b/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c +index 36870b2..d088050 100644 +--- a/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c ++++ b/arch/x86/crypto/sha512-mb/sha512_mb_mgr_init_avx2.c +@@ -57,10 +57,12 @@ void sha512_mb_mgr_init_avx2(struct sha512_mb_mgr *state) + { + unsigned int j; + +- state->lens[0] = 0; +- state->lens[1] = 1; +- state->lens[2] = 2; +- state->lens[3] = 3; ++ /* initially all lanes are unused */ ++ state->lens[0] = 0xFFFFFFFF00000000; ++ state->lens[1] = 0xFFFFFFFF00000001; ++ state->lens[2] = 0xFFFFFFFF00000002; ++ state->lens[3] = 0xFFFFFFFF00000003; ++ + state->unused_lanes = 0xFF03020100; + for (j = 0; j < 4; j++) + state->ldata[j].job_in_lane = NULL; +diff --git a/arch/x86/entry/calling.h b/arch/x86/entry/calling.h +index 3f48f69..be63330 100644 +--- a/arch/x86/entry/calling.h ++++ b/arch/x86/entry/calling.h +@@ -97,80 +97,78 @@ For 32-bit we have the following conventions - kernel is built with + + #define SIZEOF_PTREGS 21*8 + +- .macro ALLOC_PT_GPREGS_ON_STACK +- addq $-(15*8), %rsp +- .endm +- +- .macro SAVE_C_REGS_HELPER offset=0 rax=1 rcx=1 r8910=1 r11=1 +- .if \r11 +- movq %r11, 6*8+\offset(%rsp) +- .endif +- .if \r8910 +- movq %r10, 7*8+\offset(%rsp) +- movq %r9, 8*8+\offset(%rsp) +- movq %r8, 9*8+\offset(%rsp) +- .endif +- .if \rax +- movq %rax, 10*8+\offset(%rsp) ++.macro PUSH_AND_CLEAR_REGS rdx=%rdx rax=%rax save_ret=0 ++ /* ++ * Push registers and sanitize registers of values that a ++ * speculation attack might otherwise want to exploit. The ++ * lower registers are likely clobbered well before they ++ * could be put to use in a speculative execution gadget. ++ * Interleave XOR with PUSH for better uop scheduling: ++ */ ++ .if \save_ret ++ pushq %rsi /* pt_regs->si */ ++ movq 8(%rsp), %rsi /* temporarily store the return address in %rsi */ ++ movq %rdi, 8(%rsp) /* pt_regs->di (overwriting original return address) */ ++ .else ++ pushq %rdi /* pt_regs->di */ ++ pushq %rsi /* pt_regs->si */ + .endif +- .if \rcx +- movq %rcx, 11*8+\offset(%rsp) ++ pushq \rdx /* pt_regs->dx */ ++ pushq %rcx /* pt_regs->cx */ ++ pushq \rax /* pt_regs->ax */ ++ pushq %r8 /* pt_regs->r8 */ ++ xorl %r8d, %r8d /* nospec r8 */ ++ pushq %r9 /* pt_regs->r9 */ ++ xorl %r9d, %r9d /* nospec r9 */ ++ pushq %r10 /* pt_regs->r10 */ ++ xorl %r10d, %r10d /* nospec r10 */ ++ pushq %r11 /* pt_regs->r11 */ ++ xorl %r11d, %r11d /* nospec r11*/ ++ pushq %rbx /* pt_regs->rbx */ ++ xorl %ebx, %ebx /* nospec rbx*/ ++ pushq %rbp /* pt_regs->rbp */ ++ xorl %ebp, %ebp /* nospec rbp*/ ++ pushq %r12 /* pt_regs->r12 */ ++ xorl %r12d, %r12d /* nospec r12*/ ++ pushq %r13 /* pt_regs->r13 */ ++ xorl %r13d, %r13d /* nospec r13*/ ++ pushq %r14 /* pt_regs->r14 */ ++ xorl %r14d, %r14d /* nospec r14*/ ++ pushq %r15 /* pt_regs->r15 */ ++ xorl %r15d, %r15d /* nospec r15*/ ++ UNWIND_HINT_REGS ++ .if \save_ret ++ pushq %rsi /* return address on top of stack */ + .endif +- movq %rdx, 12*8+\offset(%rsp) +- movq %rsi, 13*8+\offset(%rsp) +- movq %rdi, 14*8+\offset(%rsp) +- UNWIND_HINT_REGS offset=\offset extra=0 +- .endm +- .macro SAVE_C_REGS offset=0 +- SAVE_C_REGS_HELPER \offset, 1, 1, 1, 1 +- .endm +- .macro SAVE_C_REGS_EXCEPT_RAX_RCX offset=0 +- SAVE_C_REGS_HELPER \offset, 0, 0, 1, 1 +- .endm +- .macro SAVE_C_REGS_EXCEPT_R891011 +- SAVE_C_REGS_HELPER 0, 1, 1, 0, 0 +- .endm +- .macro SAVE_C_REGS_EXCEPT_RCX_R891011 +- SAVE_C_REGS_HELPER 0, 1, 0, 0, 0 +- .endm +- .macro SAVE_C_REGS_EXCEPT_RAX_RCX_R11 +- SAVE_C_REGS_HELPER 0, 0, 0, 1, 0 +- .endm +- +- .macro SAVE_EXTRA_REGS offset=0 +- movq %r15, 0*8+\offset(%rsp) +- movq %r14, 1*8+\offset(%rsp) +- movq %r13, 2*8+\offset(%rsp) +- movq %r12, 3*8+\offset(%rsp) +- movq %rbp, 4*8+\offset(%rsp) +- movq %rbx, 5*8+\offset(%rsp) +- UNWIND_HINT_REGS offset=\offset +- .endm +- +- .macro POP_EXTRA_REGS ++.endm ++ ++.macro POP_REGS pop_rdi=1 skip_r11rcx=0 + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + popq %rbx +- .endm +- +- .macro POP_C_REGS ++ .if \skip_r11rcx ++ popq %rsi ++ .else + popq %r11 ++ .endif + popq %r10 + popq %r9 + popq %r8 + popq %rax ++ .if \skip_r11rcx ++ popq %rsi ++ .else + popq %rcx ++ .endif + popq %rdx + popq %rsi ++ .if \pop_rdi + popq %rdi +- .endm +- +- .macro icebp +- .byte 0xf1 +- .endm ++ .endif ++.endm + + /* + * This is a sneaky trick to help the unwinder find pt_regs on the stack. The +@@ -178,17 +176,12 @@ For 32-bit we have the following conventions - kernel is built with + * is just setting the LSB, which makes it an invalid stack address and is also + * a signal to the unwinder that it's a pt_regs pointer in disguise. + * +- * NOTE: This macro must be used *after* SAVE_EXTRA_REGS because it corrupts ++ * NOTE: This macro must be used *after* PUSH_AND_CLEAR_REGS because it corrupts + * the original rbp. + */ + .macro ENCODE_FRAME_POINTER ptregs_offset=0 + #ifdef CONFIG_FRAME_POINTER +- .if \ptregs_offset +- leaq \ptregs_offset(%rsp), %rbp +- .else +- mov %rsp, %rbp +- .endif +- orq $0x1, %rbp ++ leaq 1+\ptregs_offset(%rsp), %rbp + #endif + .endm + +diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S +index 16c2c02..6ad064c 100644 +--- a/arch/x86/entry/entry_32.S ++++ b/arch/x86/entry/entry_32.S +@@ -252,8 +252,7 @@ ENTRY(__switch_to_asm) + * exist, overwrite the RSB with entries which capture + * speculative execution to prevent attack. + */ +- /* Clobbers %ebx */ +- FILL_RETURN_BUFFER RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW ++ FILL_RETURN_BUFFER %ebx, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW + #endif + + /* restore callee-saved registers */ +diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S +index 30c8c53..805f527 100644 +--- a/arch/x86/entry/entry_64.S ++++ b/arch/x86/entry/entry_64.S +@@ -55,7 +55,7 @@ END(native_usergs_sysret64) + + .macro TRACE_IRQS_FLAGS flags:req + #ifdef CONFIG_TRACE_IRQFLAGS +- bt $9, \flags /* interrupts off? */ ++ btl $9, \flags /* interrupts off? */ + jnc 1f + TRACE_IRQS_ON + 1: +@@ -213,7 +213,7 @@ ENTRY(entry_SYSCALL_64) + + swapgs + /* +- * This path is not taken when PAGE_TABLE_ISOLATION is disabled so it ++ * This path is only taken when PAGE_TABLE_ISOLATION is disabled so it + * is not required to switch CR3. + */ + movq %rsp, PER_CPU_VAR(rsp_scratch) +@@ -227,22 +227,8 @@ ENTRY(entry_SYSCALL_64) + pushq %rcx /* pt_regs->ip */ + GLOBAL(entry_SYSCALL_64_after_hwframe) + pushq %rax /* pt_regs->orig_ax */ +- pushq %rdi /* pt_regs->di */ +- pushq %rsi /* pt_regs->si */ +- pushq %rdx /* pt_regs->dx */ +- pushq %rcx /* pt_regs->cx */ +- pushq $-ENOSYS /* pt_regs->ax */ +- pushq %r8 /* pt_regs->r8 */ +- pushq %r9 /* pt_regs->r9 */ +- pushq %r10 /* pt_regs->r10 */ +- pushq %r11 /* pt_regs->r11 */ +- pushq %rbx /* pt_regs->rbx */ +- pushq %rbp /* pt_regs->rbp */ +- pushq %r12 /* pt_regs->r12 */ +- pushq %r13 /* pt_regs->r13 */ +- pushq %r14 /* pt_regs->r14 */ +- pushq %r15 /* pt_regs->r15 */ +- UNWIND_HINT_REGS ++ ++ PUSH_AND_CLEAR_REGS rax=$-ENOSYS + + TRACE_IRQS_OFF + +@@ -321,15 +307,7 @@ GLOBAL(entry_SYSCALL_64_after_hwframe) + syscall_return_via_sysret: + /* rcx and r11 are already restored (see code above) */ + UNWIND_HINT_EMPTY +- POP_EXTRA_REGS +- popq %rsi /* skip r11 */ +- popq %r10 +- popq %r9 +- popq %r8 +- popq %rax +- popq %rsi /* skip rcx */ +- popq %rdx +- popq %rsi ++ POP_REGS pop_rdi=0 skip_r11rcx=1 + + /* + * Now all regs are restored except RSP and RDI. +@@ -386,8 +364,7 @@ ENTRY(__switch_to_asm) + * exist, overwrite the RSB with entries which capture + * speculative execution to prevent attack. + */ +- /* Clobbers %rbx */ +- FILL_RETURN_BUFFER RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW ++ FILL_RETURN_BUFFER %r12, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW + #endif + + /* restore callee-saved registers */ +@@ -471,9 +448,19 @@ END(irq_entries_start) + * + * The invariant is that, if irq_count != -1, then the IRQ stack is in use. + */ +-.macro ENTER_IRQ_STACK regs=1 old_rsp ++.macro ENTER_IRQ_STACK regs=1 old_rsp save_ret=0 + DEBUG_ENTRY_ASSERT_IRQS_OFF ++ ++ .if \save_ret ++ /* ++ * If save_ret is set, the original stack contains one additional ++ * entry -- the return address. Therefore, move the address one ++ * entry below %rsp to \old_rsp. ++ */ ++ leaq 8(%rsp), \old_rsp ++ .else + movq %rsp, \old_rsp ++ .endif + + .if \regs + UNWIND_HINT_REGS base=\old_rsp +@@ -519,6 +506,15 @@ END(irq_entries_start) + .if \regs + UNWIND_HINT_REGS indirect=1 + .endif ++ ++ .if \save_ret ++ /* ++ * Push the return address to the stack. This return address can ++ * be found at the "real" original RSP, which was offset by 8 at ++ * the beginning of this macro. ++ */ ++ pushq -8(\old_rsp) ++ .endif + .endm + + /* +@@ -542,29 +538,65 @@ END(irq_entries_start) + .endm + + /* +- * Interrupt entry/exit. +- * +- * Interrupt entry points save only callee clobbered registers in fast path. ++ * Interrupt entry helper function. + * +- * Entry runs with interrupts off. ++ * Entry runs with interrupts off. Stack layout at entry: ++ * +----------------------------------------------------+ ++ * | regs->ss | ++ * | regs->rsp | ++ * | regs->eflags | ++ * | regs->cs | ++ * | regs->ip | ++ * +----------------------------------------------------+ ++ * | regs->orig_ax = ~(interrupt number) | ++ * +----------------------------------------------------+ ++ * | return address | ++ * +----------------------------------------------------+ + */ +- +-/* 0(%rsp): ~(interrupt number) */ +- .macro interrupt func ++ENTRY(interrupt_entry) ++ UNWIND_HINT_FUNC ++ ASM_CLAC + cld + +- testb $3, CS-ORIG_RAX(%rsp) ++ testb $3, CS-ORIG_RAX+8(%rsp) + jz 1f + SWAPGS +- call switch_to_thread_stack ++ ++ /* ++ * Switch to the thread stack. The IRET frame and orig_ax are ++ * on the stack, as well as the return address. RDI..R12 are ++ * not (yet) on the stack and space has not (yet) been ++ * allocated for them. ++ */ ++ pushq %rdi ++ ++ /* Need to switch before accessing the thread stack. */ ++ SWITCH_TO_KERNEL_CR3 scratch_reg=%rdi ++ movq %rsp, %rdi ++ movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp ++ ++ /* ++ * We have RDI, return address, and orig_ax on the stack on ++ * top of the IRET frame. That means offset=24 ++ */ ++ UNWIND_HINT_IRET_REGS base=%rdi offset=24 ++ ++ pushq 7*8(%rdi) /* regs->ss */ ++ pushq 6*8(%rdi) /* regs->rsp */ ++ pushq 5*8(%rdi) /* regs->eflags */ ++ pushq 4*8(%rdi) /* regs->cs */ ++ pushq 3*8(%rdi) /* regs->ip */ ++ pushq 2*8(%rdi) /* regs->orig_ax */ ++ pushq 8(%rdi) /* return address */ ++ UNWIND_HINT_FUNC ++ ++ movq (%rdi), %rdi + 1: + +- ALLOC_PT_GPREGS_ON_STACK +- SAVE_C_REGS +- SAVE_EXTRA_REGS +- ENCODE_FRAME_POINTER ++ PUSH_AND_CLEAR_REGS save_ret=1 ++ ENCODE_FRAME_POINTER 8 + +- testb $3, CS(%rsp) ++ testb $3, CS+8(%rsp) + jz 1f + + /* +@@ -572,7 +604,7 @@ END(irq_entries_start) + * + * We need to tell lockdep that IRQs are off. We can't do this until + * we fix gsbase, and we should do it before enter_from_user_mode +- * (which can take locks). Since TRACE_IRQS_OFF idempotent, ++ * (which can take locks). Since TRACE_IRQS_OFF is idempotent, + * the simplest way to handle it is to just call it twice if + * we enter from user mode. There's no reason to optimize this since + * TRACE_IRQS_OFF is a no-op if lockdep is off. +@@ -582,12 +614,15 @@ END(irq_entries_start) + CALL_enter_from_user_mode + + 1: +- ENTER_IRQ_STACK old_rsp=%rdi ++ ENTER_IRQ_STACK old_rsp=%rdi save_ret=1 + /* We entered an interrupt context - irqs are off: */ + TRACE_IRQS_OFF + +- call \func /* rdi points to pt_regs */ +- .endm ++ ret ++END(interrupt_entry) ++ ++ ++/* Interrupt entry/exit. */ + + /* + * The interrupt stubs push (~vector+0x80) onto the stack and +@@ -595,9 +630,10 @@ END(irq_entries_start) + */ + .p2align CONFIG_X86_L1_CACHE_SHIFT + common_interrupt: +- ASM_CLAC + addq $-0x80, (%rsp) /* Adjust vector to [-256, -1] range */ +- interrupt do_IRQ ++ call interrupt_entry ++ UNWIND_HINT_REGS indirect=1 ++ call do_IRQ /* rdi points to pt_regs */ + /* 0(%rsp): old RSP */ + ret_from_intr: + DISABLE_INTERRUPTS(CLBR_ANY) +@@ -622,15 +658,7 @@ GLOBAL(swapgs_restore_regs_and_return_to_usermode) + ud2 + 1: + #endif +- POP_EXTRA_REGS +- popq %r11 +- popq %r10 +- popq %r9 +- popq %r8 +- popq %rax +- popq %rcx +- popq %rdx +- popq %rsi ++ POP_REGS pop_rdi=0 + + /* + * The stack is now user RDI, orig_ax, RIP, CS, EFLAGS, RSP, SS. +@@ -688,8 +716,7 @@ GLOBAL(restore_regs_and_return_to_kernel) + ud2 + 1: + #endif +- POP_EXTRA_REGS +- POP_C_REGS ++ POP_REGS + addq $8, %rsp /* skip regs->orig_ax */ + /* + * ARCH_HAS_MEMBARRIER_SYNC_CORE rely on IRET core serialization +@@ -799,10 +826,11 @@ END(common_interrupt) + .macro apicinterrupt3 num sym do_sym + ENTRY(\sym) + UNWIND_HINT_IRET_REGS +- ASM_CLAC + pushq $~(\num) + .Lcommon_\sym: +- interrupt \do_sym ++ call interrupt_entry ++ UNWIND_HINT_REGS indirect=1 ++ call \do_sym /* rdi points to pt_regs */ + jmp ret_from_intr + END(\sym) + .endm +@@ -865,34 +893,6 @@ apicinterrupt IRQ_WORK_VECTOR irq_work_interrupt smp_irq_work_interrupt + */ + #define CPU_TSS_IST(x) PER_CPU_VAR(cpu_tss_rw) + (TSS_ist + ((x) - 1) * 8) + +-/* +- * Switch to the thread stack. This is called with the IRET frame and +- * orig_ax on the stack. (That is, RDI..R12 are not on the stack and +- * space has not been allocated for them.) +- */ +-ENTRY(switch_to_thread_stack) +- UNWIND_HINT_FUNC +- +- pushq %rdi +- /* Need to switch before accessing the thread stack. */ +- SWITCH_TO_KERNEL_CR3 scratch_reg=%rdi +- movq %rsp, %rdi +- movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp +- UNWIND_HINT sp_offset=16 sp_reg=ORC_REG_DI +- +- pushq 7*8(%rdi) /* regs->ss */ +- pushq 6*8(%rdi) /* regs->rsp */ +- pushq 5*8(%rdi) /* regs->eflags */ +- pushq 4*8(%rdi) /* regs->cs */ +- pushq 3*8(%rdi) /* regs->ip */ +- pushq 2*8(%rdi) /* regs->orig_ax */ +- pushq 8(%rdi) /* return address */ +- UNWIND_HINT_FUNC +- +- movq (%rdi), %rdi +- ret +-END(switch_to_thread_stack) +- + .macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1 + ENTRY(\sym) + UNWIND_HINT_IRET_REGS offset=\has_error_code*8 +@@ -908,10 +908,8 @@ ENTRY(\sym) + pushq $-1 /* ORIG_RAX: no syscall to restart */ + .endif + +- ALLOC_PT_GPREGS_ON_STACK +- + .if \paranoid < 2 +- testb $3, CS(%rsp) /* If coming from userspace, switch stacks */ ++ testb $3, CS-ORIG_RAX(%rsp) /* If coming from userspace, switch stacks */ + jnz .Lfrom_usermode_switch_stack_\@ + .endif + +@@ -1121,9 +1119,7 @@ ENTRY(xen_failsafe_callback) + addq $0x30, %rsp + UNWIND_HINT_IRET_REGS + pushq $-1 /* orig_ax = -1 => not a system call */ +- ALLOC_PT_GPREGS_ON_STACK +- SAVE_C_REGS +- SAVE_EXTRA_REGS ++ PUSH_AND_CLEAR_REGS + ENCODE_FRAME_POINTER + jmp error_exit + END(xen_failsafe_callback) +@@ -1170,8 +1166,7 @@ idtentry machine_check do_mce has_error_code=0 paranoid=1 + ENTRY(paranoid_entry) + UNWIND_HINT_FUNC + cld +- SAVE_C_REGS 8 +- SAVE_EXTRA_REGS 8 ++ PUSH_AND_CLEAR_REGS save_ret=1 + ENCODE_FRAME_POINTER 8 + movl $1, %ebx + movl $MSR_GS_BASE, %ecx +@@ -1211,21 +1206,20 @@ ENTRY(paranoid_exit) + jmp .Lparanoid_exit_restore + .Lparanoid_exit_no_swapgs: + TRACE_IRQS_IRETQ_DEBUG ++ RESTORE_CR3 scratch_reg=%rbx save_reg=%r14 + .Lparanoid_exit_restore: + jmp restore_regs_and_return_to_kernel + END(paranoid_exit) + + /* +- * Save all registers in pt_regs, and switch gs if needed. ++ * Save all registers in pt_regs, and switch GS if needed. + * Return: EBX=0: came from user mode; EBX=1: otherwise + */ + ENTRY(error_entry) + UNWIND_HINT_FUNC + cld +- SAVE_C_REGS 8 +- SAVE_EXTRA_REGS 8 ++ PUSH_AND_CLEAR_REGS save_ret=1 + ENCODE_FRAME_POINTER 8 +- xorl %ebx, %ebx + testb $3, CS+8(%rsp) + jz .Lerror_kernelspace + +@@ -1406,22 +1400,7 @@ ENTRY(nmi) + pushq 1*8(%rdx) /* pt_regs->rip */ + UNWIND_HINT_IRET_REGS + pushq $-1 /* pt_regs->orig_ax */ +- pushq %rdi /* pt_regs->di */ +- pushq %rsi /* pt_regs->si */ +- pushq (%rdx) /* pt_regs->dx */ +- pushq %rcx /* pt_regs->cx */ +- pushq %rax /* pt_regs->ax */ +- pushq %r8 /* pt_regs->r8 */ +- pushq %r9 /* pt_regs->r9 */ +- pushq %r10 /* pt_regs->r10 */ +- pushq %r11 /* pt_regs->r11 */ +- pushq %rbx /* pt_regs->rbx */ +- pushq %rbp /* pt_regs->rbp */ +- pushq %r12 /* pt_regs->r12 */ +- pushq %r13 /* pt_regs->r13 */ +- pushq %r14 /* pt_regs->r14 */ +- pushq %r15 /* pt_regs->r15 */ +- UNWIND_HINT_REGS ++ PUSH_AND_CLEAR_REGS rdx=(%rdx) + ENCODE_FRAME_POINTER + + /* +@@ -1631,7 +1610,6 @@ end_repeat_nmi: + * frame to point back to repeat_nmi. + */ + pushq $-1 /* ORIG_RAX: no syscall to restart */ +- ALLOC_PT_GPREGS_ON_STACK + + /* + * Use paranoid_entry to handle SWAPGS, but no need to use paranoid_exit +@@ -1655,8 +1633,7 @@ end_repeat_nmi: + nmi_swapgs: + SWAPGS_UNSAFE_STACK + nmi_restore: +- POP_EXTRA_REGS +- POP_C_REGS ++ POP_REGS + + /* + * Skip orig_ax and the "outermost" frame to point RSP at the "iret" +diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S +index 98d5358..08425c4 100644 +--- a/arch/x86/entry/entry_64_compat.S ++++ b/arch/x86/entry/entry_64_compat.S +@@ -85,15 +85,25 @@ ENTRY(entry_SYSENTER_compat) + pushq %rcx /* pt_regs->cx */ + pushq $-ENOSYS /* pt_regs->ax */ + pushq $0 /* pt_regs->r8 = 0 */ ++ xorl %r8d, %r8d /* nospec r8 */ + pushq $0 /* pt_regs->r9 = 0 */ ++ xorl %r9d, %r9d /* nospec r9 */ + pushq $0 /* pt_regs->r10 = 0 */ ++ xorl %r10d, %r10d /* nospec r10 */ + pushq $0 /* pt_regs->r11 = 0 */ ++ xorl %r11d, %r11d /* nospec r11 */ + pushq %rbx /* pt_regs->rbx */ ++ xorl %ebx, %ebx /* nospec rbx */ + pushq %rbp /* pt_regs->rbp (will be overwritten) */ ++ xorl %ebp, %ebp /* nospec rbp */ + pushq $0 /* pt_regs->r12 = 0 */ ++ xorl %r12d, %r12d /* nospec r12 */ + pushq $0 /* pt_regs->r13 = 0 */ ++ xorl %r13d, %r13d /* nospec r13 */ + pushq $0 /* pt_regs->r14 = 0 */ ++ xorl %r14d, %r14d /* nospec r14 */ + pushq $0 /* pt_regs->r15 = 0 */ ++ xorl %r15d, %r15d /* nospec r15 */ + cld + + /* +@@ -214,15 +224,25 @@ GLOBAL(entry_SYSCALL_compat_after_hwframe) + pushq %rbp /* pt_regs->cx (stashed in bp) */ + pushq $-ENOSYS /* pt_regs->ax */ + pushq $0 /* pt_regs->r8 = 0 */ ++ xorl %r8d, %r8d /* nospec r8 */ + pushq $0 /* pt_regs->r9 = 0 */ ++ xorl %r9d, %r9d /* nospec r9 */ + pushq $0 /* pt_regs->r10 = 0 */ ++ xorl %r10d, %r10d /* nospec r10 */ + pushq $0 /* pt_regs->r11 = 0 */ ++ xorl %r11d, %r11d /* nospec r11 */ + pushq %rbx /* pt_regs->rbx */ ++ xorl %ebx, %ebx /* nospec rbx */ + pushq %rbp /* pt_regs->rbp (will be overwritten) */ ++ xorl %ebp, %ebp /* nospec rbp */ + pushq $0 /* pt_regs->r12 = 0 */ ++ xorl %r12d, %r12d /* nospec r12 */ + pushq $0 /* pt_regs->r13 = 0 */ ++ xorl %r13d, %r13d /* nospec r13 */ + pushq $0 /* pt_regs->r14 = 0 */ ++ xorl %r14d, %r14d /* nospec r14 */ + pushq $0 /* pt_regs->r15 = 0 */ ++ xorl %r15d, %r15d /* nospec r15 */ + + /* + * User mode is traced as though IRQs are on, and SYSENTER +@@ -278,9 +298,9 @@ sysret32_from_system_call: + */ + SWITCH_TO_USER_CR3_NOSTACK scratch_reg=%r8 scratch_reg2=%r9 + +- xorq %r8, %r8 +- xorq %r9, %r9 +- xorq %r10, %r10 ++ xorl %r8d, %r8d ++ xorl %r9d, %r9d ++ xorl %r10d, %r10d + swapgs + sysretl + END(entry_SYSCALL_compat) +@@ -327,26 +347,47 @@ ENTRY(entry_INT80_compat) + */ + movl %eax, %eax + ++ /* switch to thread stack expects orig_ax and rdi to be pushed */ + pushq %rax /* pt_regs->orig_ax */ ++ pushq %rdi /* pt_regs->di */ + +- /* switch to thread stack expects orig_ax to be pushed */ +- call switch_to_thread_stack ++ /* Need to switch before accessing the thread stack. */ ++ SWITCH_TO_KERNEL_CR3 scratch_reg=%rdi ++ movq %rsp, %rdi ++ movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp + +- pushq %rdi /* pt_regs->di */ ++ pushq 6*8(%rdi) /* regs->ss */ ++ pushq 5*8(%rdi) /* regs->rsp */ ++ pushq 4*8(%rdi) /* regs->eflags */ ++ pushq 3*8(%rdi) /* regs->cs */ ++ pushq 2*8(%rdi) /* regs->ip */ ++ pushq 1*8(%rdi) /* regs->orig_ax */ ++ ++ pushq (%rdi) /* pt_regs->di */ + pushq %rsi /* pt_regs->si */ + pushq %rdx /* pt_regs->dx */ + pushq %rcx /* pt_regs->cx */ + pushq $-ENOSYS /* pt_regs->ax */ + pushq $0 /* pt_regs->r8 = 0 */ ++ xorl %r8d, %r8d /* nospec r8 */ + pushq $0 /* pt_regs->r9 = 0 */ ++ xorl %r9d, %r9d /* nospec r9 */ + pushq $0 /* pt_regs->r10 = 0 */ ++ xorl %r10d, %r10d /* nospec r10 */ + pushq $0 /* pt_regs->r11 = 0 */ ++ xorl %r11d, %r11d /* nospec r11 */ + pushq %rbx /* pt_regs->rbx */ ++ xorl %ebx, %ebx /* nospec rbx */ + pushq %rbp /* pt_regs->rbp */ ++ xorl %ebp, %ebp /* nospec rbp */ + pushq %r12 /* pt_regs->r12 */ ++ xorl %r12d, %r12d /* nospec r12 */ + pushq %r13 /* pt_regs->r13 */ ++ xorl %r13d, %r13d /* nospec r13 */ + pushq %r14 /* pt_regs->r14 */ ++ xorl %r14d, %r14d /* nospec r14 */ + pushq %r15 /* pt_regs->r15 */ ++ xorl %r15d, %r15d /* nospec r15 */ + cld + + /* +@@ -363,15 +404,3 @@ ENTRY(entry_INT80_compat) + TRACE_IRQS_ON + jmp swapgs_restore_regs_and_return_to_usermode + END(entry_INT80_compat) +- +-ENTRY(stub32_clone) +- /* +- * The 32-bit clone ABI is: clone(..., int tls_val, int *child_tidptr). +- * The 64-bit clone ABI is: clone(..., int *child_tidptr, int tls_val). +- * +- * The native 64-bit kernel's sys_clone() implements the latter, +- * so we need to swap arguments here before calling it: +- */ +- xchg %r8, %rcx +- jmp sys_clone +-ENDPROC(stub32_clone) +diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl +index 448ac21..2a5e99c 100644 +--- a/arch/x86/entry/syscalls/syscall_32.tbl ++++ b/arch/x86/entry/syscalls/syscall_32.tbl +@@ -8,12 +8,12 @@ + # + 0 i386 restart_syscall sys_restart_syscall + 1 i386 exit sys_exit +-2 i386 fork sys_fork sys_fork ++2 i386 fork sys_fork + 3 i386 read sys_read + 4 i386 write sys_write + 5 i386 open sys_open compat_sys_open + 6 i386 close sys_close +-7 i386 waitpid sys_waitpid sys32_waitpid ++7 i386 waitpid sys_waitpid compat_sys_x86_waitpid + 8 i386 creat sys_creat + 9 i386 link sys_link + 10 i386 unlink sys_unlink +@@ -78,7 +78,7 @@ + 69 i386 ssetmask sys_ssetmask + 70 i386 setreuid sys_setreuid16 + 71 i386 setregid sys_setregid16 +-72 i386 sigsuspend sys_sigsuspend sys_sigsuspend ++72 i386 sigsuspend sys_sigsuspend + 73 i386 sigpending sys_sigpending compat_sys_sigpending + 74 i386 sethostname sys_sethostname + 75 i386 setrlimit sys_setrlimit compat_sys_setrlimit +@@ -96,7 +96,7 @@ + 87 i386 swapon sys_swapon + 88 i386 reboot sys_reboot + 89 i386 readdir sys_old_readdir compat_sys_old_readdir +-90 i386 mmap sys_old_mmap sys32_mmap ++90 i386 mmap sys_old_mmap compat_sys_x86_mmap + 91 i386 munmap sys_munmap + 92 i386 truncate sys_truncate compat_sys_truncate + 93 i386 ftruncate sys_ftruncate compat_sys_ftruncate +@@ -126,7 +126,7 @@ + 117 i386 ipc sys_ipc compat_sys_ipc + 118 i386 fsync sys_fsync + 119 i386 sigreturn sys_sigreturn sys32_sigreturn +-120 i386 clone sys_clone stub32_clone ++120 i386 clone sys_clone compat_sys_x86_clone + 121 i386 setdomainname sys_setdomainname + 122 i386 uname sys_newuname + 123 i386 modify_ldt sys_modify_ldt +@@ -186,8 +186,8 @@ + 177 i386 rt_sigtimedwait sys_rt_sigtimedwait compat_sys_rt_sigtimedwait + 178 i386 rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo + 179 i386 rt_sigsuspend sys_rt_sigsuspend +-180 i386 pread64 sys_pread64 sys32_pread +-181 i386 pwrite64 sys_pwrite64 sys32_pwrite ++180 i386 pread64 sys_pread64 compat_sys_x86_pread ++181 i386 pwrite64 sys_pwrite64 compat_sys_x86_pwrite + 182 i386 chown sys_chown16 + 183 i386 getcwd sys_getcwd + 184 i386 capget sys_capget +@@ -196,14 +196,14 @@ + 187 i386 sendfile sys_sendfile compat_sys_sendfile + 188 i386 getpmsg + 189 i386 putpmsg +-190 i386 vfork sys_vfork sys_vfork ++190 i386 vfork sys_vfork + 191 i386 ugetrlimit sys_getrlimit compat_sys_getrlimit + 192 i386 mmap2 sys_mmap_pgoff +-193 i386 truncate64 sys_truncate64 sys32_truncate64 +-194 i386 ftruncate64 sys_ftruncate64 sys32_ftruncate64 +-195 i386 stat64 sys_stat64 sys32_stat64 +-196 i386 lstat64 sys_lstat64 sys32_lstat64 +-197 i386 fstat64 sys_fstat64 sys32_fstat64 ++193 i386 truncate64 sys_truncate64 compat_sys_x86_truncate64 ++194 i386 ftruncate64 sys_ftruncate64 compat_sys_x86_ftruncate64 ++195 i386 stat64 sys_stat64 compat_sys_x86_stat64 ++196 i386 lstat64 sys_lstat64 compat_sys_x86_lstat64 ++197 i386 fstat64 sys_fstat64 compat_sys_x86_fstat64 + 198 i386 lchown32 sys_lchown + 199 i386 getuid32 sys_getuid + 200 i386 getgid32 sys_getgid +@@ -231,7 +231,7 @@ + # 222 is unused + # 223 is unused + 224 i386 gettid sys_gettid +-225 i386 readahead sys_readahead sys32_readahead ++225 i386 readahead sys_readahead compat_sys_x86_readahead + 226 i386 setxattr sys_setxattr + 227 i386 lsetxattr sys_lsetxattr + 228 i386 fsetxattr sys_fsetxattr +@@ -256,7 +256,7 @@ + 247 i386 io_getevents sys_io_getevents compat_sys_io_getevents + 248 i386 io_submit sys_io_submit compat_sys_io_submit + 249 i386 io_cancel sys_io_cancel +-250 i386 fadvise64 sys_fadvise64 sys32_fadvise64 ++250 i386 fadvise64 sys_fadvise64 compat_sys_x86_fadvise64 + # 251 is available for reuse (was briefly sys_set_zone_reclaim) + 252 i386 exit_group sys_exit_group + 253 i386 lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie +@@ -278,7 +278,7 @@ + 269 i386 fstatfs64 sys_fstatfs64 compat_sys_fstatfs64 + 270 i386 tgkill sys_tgkill + 271 i386 utimes sys_utimes compat_sys_utimes +-272 i386 fadvise64_64 sys_fadvise64_64 sys32_fadvise64_64 ++272 i386 fadvise64_64 sys_fadvise64_64 compat_sys_x86_fadvise64_64 + 273 i386 vserver + 274 i386 mbind sys_mbind + 275 i386 get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy +@@ -306,7 +306,7 @@ + 297 i386 mknodat sys_mknodat + 298 i386 fchownat sys_fchownat + 299 i386 futimesat sys_futimesat compat_sys_futimesat +-300 i386 fstatat64 sys_fstatat64 sys32_fstatat ++300 i386 fstatat64 sys_fstatat64 compat_sys_x86_fstatat + 301 i386 unlinkat sys_unlinkat + 302 i386 renameat sys_renameat + 303 i386 linkat sys_linkat +@@ -320,7 +320,7 @@ + 311 i386 set_robust_list sys_set_robust_list compat_sys_set_robust_list + 312 i386 get_robust_list sys_get_robust_list compat_sys_get_robust_list + 313 i386 splice sys_splice +-314 i386 sync_file_range sys_sync_file_range sys32_sync_file_range ++314 i386 sync_file_range sys_sync_file_range compat_sys_x86_sync_file_range + 315 i386 tee sys_tee + 316 i386 vmsplice sys_vmsplice compat_sys_vmsplice + 317 i386 move_pages sys_move_pages compat_sys_move_pages +@@ -330,7 +330,7 @@ + 321 i386 signalfd sys_signalfd compat_sys_signalfd + 322 i386 timerfd_create sys_timerfd_create + 323 i386 eventfd sys_eventfd +-324 i386 fallocate sys_fallocate sys32_fallocate ++324 i386 fallocate sys_fallocate compat_sys_x86_fallocate + 325 i386 timerfd_settime sys_timerfd_settime compat_sys_timerfd_settime + 326 i386 timerfd_gettime sys_timerfd_gettime compat_sys_timerfd_gettime + 327 i386 signalfd4 sys_signalfd4 compat_sys_signalfd4 +diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c +index 577fa8a..8560ef6 100644 +--- a/arch/x86/entry/vsyscall/vsyscall_64.c ++++ b/arch/x86/entry/vsyscall/vsyscall_64.c +@@ -42,10 +42,8 @@ + #define CREATE_TRACE_POINTS + #include "vsyscall_trace.h" + +-static enum { EMULATE, NATIVE, NONE } vsyscall_mode = +-#if defined(CONFIG_LEGACY_VSYSCALL_NATIVE) +- NATIVE; +-#elif defined(CONFIG_LEGACY_VSYSCALL_NONE) ++static enum { EMULATE, NONE } vsyscall_mode = ++#ifdef CONFIG_LEGACY_VSYSCALL_NONE + NONE; + #else + EMULATE; +@@ -56,8 +54,6 @@ static int __init vsyscall_setup(char *str) + if (str) { + if (!strcmp("emulate", str)) + vsyscall_mode = EMULATE; +- else if (!strcmp("native", str)) +- vsyscall_mode = NATIVE; + else if (!strcmp("none", str)) + vsyscall_mode = NONE; + else +@@ -139,10 +135,6 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) + + WARN_ON_ONCE(address != regs->ip); + +- /* This should be unreachable in NATIVE mode. */ +- if (WARN_ON(vsyscall_mode == NATIVE)) +- return false; +- + if (vsyscall_mode == NONE) { + warn_bad_vsyscall(KERN_INFO, regs, + "vsyscall attempted with vsyscall=none"); +@@ -370,9 +362,7 @@ void __init map_vsyscall(void) + + if (vsyscall_mode != NONE) { + __set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall, +- vsyscall_mode == NATIVE +- ? PAGE_KERNEL_VSYSCALL +- : PAGE_KERNEL_VVAR); ++ PAGE_KERNEL_VVAR); + set_vsyscall_pgtable_user_bits(swapper_pg_dir); + } + +diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c +index 731153a..56457cb 100644 +--- a/arch/x86/events/intel/core.c ++++ b/arch/x86/events/intel/core.c +@@ -3559,7 +3559,7 @@ static int intel_snb_pebs_broken(int cpu) + break; + + case INTEL_FAM6_SANDYBRIDGE_X: +- switch (cpu_data(cpu).x86_mask) { ++ switch (cpu_data(cpu).x86_stepping) { + case 6: rev = 0x618; break; + case 7: rev = 0x70c; break; + } +diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c +index ae64d0b..cf372b9 100644 +--- a/arch/x86/events/intel/lbr.c ++++ b/arch/x86/events/intel/lbr.c +@@ -1186,7 +1186,7 @@ void __init intel_pmu_lbr_init_atom(void) + * on PMU interrupt + */ + if (boot_cpu_data.x86_model == 28 +- && boot_cpu_data.x86_mask < 10) { ++ && boot_cpu_data.x86_stepping < 10) { + pr_cont("LBR disabled due to erratum"); + return; + } +diff --git a/arch/x86/events/intel/p6.c b/arch/x86/events/intel/p6.c +index a5604c3..408879b 100644 +--- a/arch/x86/events/intel/p6.c ++++ b/arch/x86/events/intel/p6.c +@@ -234,7 +234,7 @@ static __initconst const struct x86_pmu p6_pmu = { + + static __init void p6_pmu_rdpmc_quirk(void) + { +- if (boot_cpu_data.x86_mask < 9) { ++ if (boot_cpu_data.x86_stepping < 9) { + /* + * PPro erratum 26; fixed in stepping 9 and above. + */ +diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c +index 6d8044a..22ec65b 100644 +--- a/arch/x86/events/intel/uncore_snbep.c ++++ b/arch/x86/events/intel/uncore_snbep.c +@@ -3606,7 +3606,7 @@ static struct intel_uncore_type skx_uncore_imc = { + }; + + static struct attribute *skx_upi_uncore_formats_attr[] = { +- &format_attr_event_ext.attr, ++ &format_attr_event.attr, + &format_attr_umask_ext.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, +diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c +index 96cd33b..6512498 100644 +--- a/arch/x86/ia32/sys_ia32.c ++++ b/arch/x86/ia32/sys_ia32.c +@@ -51,15 +51,14 @@ + #define AA(__x) ((unsigned long)(__x)) + + +-asmlinkage long sys32_truncate64(const char __user *filename, +- unsigned long offset_low, +- unsigned long offset_high) ++COMPAT_SYSCALL_DEFINE3(x86_truncate64, const char __user *, filename, ++ unsigned long, offset_low, unsigned long, offset_high) + { + return sys_truncate(filename, ((loff_t) offset_high << 32) | offset_low); + } + +-asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long offset_low, +- unsigned long offset_high) ++COMPAT_SYSCALL_DEFINE3(x86_ftruncate64, unsigned int, fd, ++ unsigned long, offset_low, unsigned long, offset_high) + { + return sys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low); + } +@@ -96,8 +95,8 @@ static int cp_stat64(struct stat64 __user *ubuf, struct kstat *stat) + return 0; + } + +-asmlinkage long sys32_stat64(const char __user *filename, +- struct stat64 __user *statbuf) ++COMPAT_SYSCALL_DEFINE2(x86_stat64, const char __user *, filename, ++ struct stat64 __user *, statbuf) + { + struct kstat stat; + int ret = vfs_stat(filename, &stat); +@@ -107,8 +106,8 @@ asmlinkage long sys32_stat64(const char __user *filename, + return ret; + } + +-asmlinkage long sys32_lstat64(const char __user *filename, +- struct stat64 __user *statbuf) ++COMPAT_SYSCALL_DEFINE2(x86_lstat64, const char __user *, filename, ++ struct stat64 __user *, statbuf) + { + struct kstat stat; + int ret = vfs_lstat(filename, &stat); +@@ -117,7 +116,8 @@ asmlinkage long sys32_lstat64(const char __user *filename, + return ret; + } + +-asmlinkage long sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf) ++COMPAT_SYSCALL_DEFINE2(x86_fstat64, unsigned int, fd, ++ struct stat64 __user *, statbuf) + { + struct kstat stat; + int ret = vfs_fstat(fd, &stat); +@@ -126,8 +126,9 @@ asmlinkage long sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf) + return ret; + } + +-asmlinkage long sys32_fstatat(unsigned int dfd, const char __user *filename, +- struct stat64 __user *statbuf, int flag) ++COMPAT_SYSCALL_DEFINE4(x86_fstatat, unsigned int, dfd, ++ const char __user *, filename, ++ struct stat64 __user *, statbuf, int, flag) + { + struct kstat stat; + int error; +@@ -153,7 +154,7 @@ struct mmap_arg_struct32 { + unsigned int offset; + }; + +-asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *arg) ++COMPAT_SYSCALL_DEFINE1(x86_mmap, struct mmap_arg_struct32 __user *, arg) + { + struct mmap_arg_struct32 a; + +@@ -167,22 +168,22 @@ asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *arg) + a.offset>>PAGE_SHIFT); + } + +-asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int __user *stat_addr, +- int options) ++COMPAT_SYSCALL_DEFINE3(x86_waitpid, compat_pid_t, pid, unsigned int __user *, ++ stat_addr, int, options) + { + return compat_sys_wait4(pid, stat_addr, options, NULL); + } + + /* warning: next two assume little endian */ +-asmlinkage long sys32_pread(unsigned int fd, char __user *ubuf, u32 count, +- u32 poslo, u32 poshi) ++COMPAT_SYSCALL_DEFINE5(x86_pread, unsigned int, fd, char __user *, ubuf, ++ u32, count, u32, poslo, u32, poshi) + { + return sys_pread64(fd, ubuf, count, + ((loff_t)AA(poshi) << 32) | AA(poslo)); + } + +-asmlinkage long sys32_pwrite(unsigned int fd, const char __user *ubuf, +- u32 count, u32 poslo, u32 poshi) ++COMPAT_SYSCALL_DEFINE5(x86_pwrite, unsigned int, fd, const char __user *, ubuf, ++ u32, count, u32, poslo, u32, poshi) + { + return sys_pwrite64(fd, ubuf, count, + ((loff_t)AA(poshi) << 32) | AA(poslo)); +@@ -193,8 +194,9 @@ asmlinkage long sys32_pwrite(unsigned int fd, const char __user *ubuf, + * Some system calls that need sign extended arguments. This could be + * done by a generic wrapper. + */ +-long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, +- __u32 len_low, __u32 len_high, int advice) ++COMPAT_SYSCALL_DEFINE6(x86_fadvise64_64, int, fd, __u32, offset_low, ++ __u32, offset_high, __u32, len_low, __u32, len_high, ++ int, advice) + { + return sys_fadvise64_64(fd, + (((u64)offset_high)<<32) | offset_low, +@@ -202,31 +204,43 @@ long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, + advice); + } + +-asmlinkage ssize_t sys32_readahead(int fd, unsigned off_lo, unsigned off_hi, +- size_t count) ++COMPAT_SYSCALL_DEFINE4(x86_readahead, int, fd, unsigned int, off_lo, ++ unsigned int, off_hi, size_t, count) + { + return sys_readahead(fd, ((u64)off_hi << 32) | off_lo, count); + } + +-asmlinkage long sys32_sync_file_range(int fd, unsigned off_low, unsigned off_hi, +- unsigned n_low, unsigned n_hi, int flags) ++COMPAT_SYSCALL_DEFINE6(x86_sync_file_range, int, fd, unsigned int, off_low, ++ unsigned int, off_hi, unsigned int, n_low, ++ unsigned int, n_hi, int, flags) + { + return sys_sync_file_range(fd, + ((u64)off_hi << 32) | off_low, + ((u64)n_hi << 32) | n_low, flags); + } + +-asmlinkage long sys32_fadvise64(int fd, unsigned offset_lo, unsigned offset_hi, +- size_t len, int advice) ++COMPAT_SYSCALL_DEFINE5(x86_fadvise64, int, fd, unsigned int, offset_lo, ++ unsigned int, offset_hi, size_t, len, int, advice) + { + return sys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo, + len, advice); + } + +-asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo, +- unsigned offset_hi, unsigned len_lo, +- unsigned len_hi) ++COMPAT_SYSCALL_DEFINE6(x86_fallocate, int, fd, int, mode, ++ unsigned int, offset_lo, unsigned int, offset_hi, ++ unsigned int, len_lo, unsigned int, len_hi) + { + return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo, + ((u64)len_hi << 32) | len_lo); + } ++ ++/* ++ * The 32-bit clone ABI is CONFIG_CLONE_BACKWARDS ++ */ ++COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags, ++ unsigned long, newsp, int __user *, parent_tidptr, ++ unsigned long, tls_val, int __user *, child_tidptr) ++{ ++ return sys_clone(clone_flags, newsp, parent_tidptr, child_tidptr, ++ tls_val); ++} +diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h +index 44f5d79..1188172 100644 +--- a/arch/x86/include/asm/acpi.h ++++ b/arch/x86/include/asm/acpi.h +@@ -94,7 +94,7 @@ static inline unsigned int acpi_processor_cstate_check(unsigned int max_cstate) + if (boot_cpu_data.x86 == 0x0F && + boot_cpu_data.x86_vendor == X86_VENDOR_AMD && + boot_cpu_data.x86_model <= 0x05 && +- boot_cpu_data.x86_mask < 0x0A) ++ boot_cpu_data.x86_stepping < 0x0A) + return 1; + else if (boot_cpu_has(X86_BUG_AMD_APIC_C1E)) + return 1; +diff --git a/arch/x86/include/asm/apm.h b/arch/x86/include/asm/apm.h +index 4d4015d..c356098 100644 +--- a/arch/x86/include/asm/apm.h ++++ b/arch/x86/include/asm/apm.h +@@ -7,6 +7,8 @@ + #ifndef _ASM_X86_MACH_DEFAULT_APM_H + #define _ASM_X86_MACH_DEFAULT_APM_H + ++#include ++ + #ifdef APM_ZERO_SEGS + # define APM_DO_ZERO_SEGS \ + "pushl %%ds\n\t" \ +@@ -32,6 +34,7 @@ static inline void apm_bios_call_asm(u32 func, u32 ebx_in, u32 ecx_in, + * N.B. We do NOT need a cld after the BIOS call + * because we always save and restore the flags. + */ ++ firmware_restrict_branch_speculation_start(); + __asm__ __volatile__(APM_DO_ZERO_SEGS + "pushl %%edi\n\t" + "pushl %%ebp\n\t" +@@ -44,6 +47,7 @@ static inline void apm_bios_call_asm(u32 func, u32 ebx_in, u32 ecx_in, + "=S" (*esi) + : "a" (func), "b" (ebx_in), "c" (ecx_in) + : "memory", "cc"); ++ firmware_restrict_branch_speculation_end(); + } + + static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in, +@@ -56,6 +60,7 @@ static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in, + * N.B. We do NOT need a cld after the BIOS call + * because we always save and restore the flags. + */ ++ firmware_restrict_branch_speculation_start(); + __asm__ __volatile__(APM_DO_ZERO_SEGS + "pushl %%edi\n\t" + "pushl %%ebp\n\t" +@@ -68,6 +73,7 @@ static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in, + "=S" (si) + : "a" (func), "b" (ebx_in), "c" (ecx_in) + : "memory", "cc"); ++ firmware_restrict_branch_speculation_end(); + return error; + } + +diff --git a/arch/x86/include/asm/asm-prototypes.h b/arch/x86/include/asm/asm-prototypes.h +index 4d11161..1908214 100644 +--- a/arch/x86/include/asm/asm-prototypes.h ++++ b/arch/x86/include/asm/asm-prototypes.h +@@ -38,7 +38,4 @@ INDIRECT_THUNK(dx) + INDIRECT_THUNK(si) + INDIRECT_THUNK(di) + INDIRECT_THUNK(bp) +-asmlinkage void __fill_rsb(void); +-asmlinkage void __clear_rsb(void); +- + #endif /* CONFIG_RETPOLINE */ +diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h +index 30d4061..e1259f0 100644 +--- a/arch/x86/include/asm/barrier.h ++++ b/arch/x86/include/asm/barrier.h +@@ -40,7 +40,7 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, + + asm ("cmp %1,%2; sbb %0,%0;" + :"=r" (mask) +- :"r"(size),"r" (index) ++ :"g"(size),"r" (index) + :"cc"); + return mask; + } +diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h +index 3fa0398..9f645ba 100644 +--- a/arch/x86/include/asm/bitops.h ++++ b/arch/x86/include/asm/bitops.h +@@ -78,7 +78,7 @@ set_bit(long nr, volatile unsigned long *addr) + : "iq" ((u8)CONST_MASK(nr)) + : "memory"); + } else { +- asm volatile(LOCK_PREFIX "bts %1,%0" ++ asm volatile(LOCK_PREFIX __ASM_SIZE(bts) " %1,%0" + : BITOP_ADDR(addr) : "Ir" (nr) : "memory"); + } + } +@@ -94,7 +94,7 @@ set_bit(long nr, volatile unsigned long *addr) + */ + static __always_inline void __set_bit(long nr, volatile unsigned long *addr) + { +- asm volatile("bts %1,%0" : ADDR : "Ir" (nr) : "memory"); ++ asm volatile(__ASM_SIZE(bts) " %1,%0" : ADDR : "Ir" (nr) : "memory"); + } + + /** +@@ -115,7 +115,7 @@ clear_bit(long nr, volatile unsigned long *addr) + : CONST_MASK_ADDR(nr, addr) + : "iq" ((u8)~CONST_MASK(nr))); + } else { +- asm volatile(LOCK_PREFIX "btr %1,%0" ++ asm volatile(LOCK_PREFIX __ASM_SIZE(btr) " %1,%0" + : BITOP_ADDR(addr) + : "Ir" (nr)); + } +@@ -137,7 +137,7 @@ static __always_inline void clear_bit_unlock(long nr, volatile unsigned long *ad + + static __always_inline void __clear_bit(long nr, volatile unsigned long *addr) + { +- asm volatile("btr %1,%0" : ADDR : "Ir" (nr)); ++ asm volatile(__ASM_SIZE(btr) " %1,%0" : ADDR : "Ir" (nr)); + } + + static __always_inline bool clear_bit_unlock_is_negative_byte(long nr, volatile unsigned long *addr) +@@ -182,7 +182,7 @@ static __always_inline void __clear_bit_unlock(long nr, volatile unsigned long * + */ + static __always_inline void __change_bit(long nr, volatile unsigned long *addr) + { +- asm volatile("btc %1,%0" : ADDR : "Ir" (nr)); ++ asm volatile(__ASM_SIZE(btc) " %1,%0" : ADDR : "Ir" (nr)); + } + + /** +@@ -201,7 +201,7 @@ static __always_inline void change_bit(long nr, volatile unsigned long *addr) + : CONST_MASK_ADDR(nr, addr) + : "iq" ((u8)CONST_MASK(nr))); + } else { +- asm volatile(LOCK_PREFIX "btc %1,%0" ++ asm volatile(LOCK_PREFIX __ASM_SIZE(btc) " %1,%0" + : BITOP_ADDR(addr) + : "Ir" (nr)); + } +@@ -217,7 +217,8 @@ static __always_inline void change_bit(long nr, volatile unsigned long *addr) + */ + static __always_inline bool test_and_set_bit(long nr, volatile unsigned long *addr) + { +- GEN_BINARY_RMWcc(LOCK_PREFIX "bts", *addr, "Ir", nr, "%0", c); ++ GEN_BINARY_RMWcc(LOCK_PREFIX __ASM_SIZE(bts), ++ *addr, "Ir", nr, "%0", c); + } + + /** +@@ -246,7 +247,7 @@ static __always_inline bool __test_and_set_bit(long nr, volatile unsigned long * + { + bool oldbit; + +- asm("bts %2,%1" ++ asm(__ASM_SIZE(bts) " %2,%1" + CC_SET(c) + : CC_OUT(c) (oldbit), ADDR + : "Ir" (nr)); +@@ -263,7 +264,8 @@ static __always_inline bool __test_and_set_bit(long nr, volatile unsigned long * + */ + static __always_inline bool test_and_clear_bit(long nr, volatile unsigned long *addr) + { +- GEN_BINARY_RMWcc(LOCK_PREFIX "btr", *addr, "Ir", nr, "%0", c); ++ GEN_BINARY_RMWcc(LOCK_PREFIX __ASM_SIZE(btr), ++ *addr, "Ir", nr, "%0", c); + } + + /** +@@ -286,7 +288,7 @@ static __always_inline bool __test_and_clear_bit(long nr, volatile unsigned long + { + bool oldbit; + +- asm volatile("btr %2,%1" ++ asm volatile(__ASM_SIZE(btr) " %2,%1" + CC_SET(c) + : CC_OUT(c) (oldbit), ADDR + : "Ir" (nr)); +@@ -298,7 +300,7 @@ static __always_inline bool __test_and_change_bit(long nr, volatile unsigned lon + { + bool oldbit; + +- asm volatile("btc %2,%1" ++ asm volatile(__ASM_SIZE(btc) " %2,%1" + CC_SET(c) + : CC_OUT(c) (oldbit), ADDR + : "Ir" (nr) : "memory"); +@@ -316,7 +318,8 @@ static __always_inline bool __test_and_change_bit(long nr, volatile unsigned lon + */ + static __always_inline bool test_and_change_bit(long nr, volatile unsigned long *addr) + { +- GEN_BINARY_RMWcc(LOCK_PREFIX "btc", *addr, "Ir", nr, "%0", c); ++ GEN_BINARY_RMWcc(LOCK_PREFIX __ASM_SIZE(btc), ++ *addr, "Ir", nr, "%0", c); + } + + static __always_inline bool constant_test_bit(long nr, const volatile unsigned long *addr) +@@ -329,7 +332,7 @@ static __always_inline bool variable_test_bit(long nr, volatile const unsigned l + { + bool oldbit; + +- asm volatile("bt %2,%1" ++ asm volatile(__ASM_SIZE(bt) " %2,%1" + CC_SET(c) + : CC_OUT(c) (oldbit) + : "m" (*(unsigned long *)addr), "Ir" (nr)); +diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h +index 34d99af4..6804d66 100644 +--- a/arch/x86/include/asm/bug.h ++++ b/arch/x86/include/asm/bug.h +@@ -5,23 +5,20 @@ + #include + + /* +- * Since some emulators terminate on UD2, we cannot use it for WARN. +- * Since various instruction decoders disagree on the length of UD1, +- * we cannot use it either. So use UD0 for WARN. ++ * Despite that some emulators terminate on UD2, we use it for WARN(). + * +- * (binutils knows about "ud1" but {en,de}codes it as 2 bytes, whereas +- * our kernel decoder thinks it takes a ModRM byte, which seems consistent +- * with various things like the Intel SDM instruction encoding rules) ++ * Since various instruction decoders/specs disagree on the encoding of ++ * UD0/UD1. + */ + +-#define ASM_UD0 ".byte 0x0f, 0xff" ++#define ASM_UD0 ".byte 0x0f, 0xff" /* + ModRM (for Intel) */ + #define ASM_UD1 ".byte 0x0f, 0xb9" /* + ModRM */ + #define ASM_UD2 ".byte 0x0f, 0x0b" + + #define INSN_UD0 0xff0f + #define INSN_UD2 0x0b0f + +-#define LEN_UD0 2 ++#define LEN_UD2 2 + + #ifdef CONFIG_GENERIC_BUG + +@@ -77,7 +74,11 @@ do { \ + unreachable(); \ + } while (0) + +-#define __WARN_FLAGS(flags) _BUG_FLAGS(ASM_UD0, BUGFLAG_WARNING|(flags)) ++#define __WARN_FLAGS(flags) \ ++do { \ ++ _BUG_FLAGS(ASM_UD2, BUGFLAG_WARNING|(flags)); \ ++ annotate_reachable(); \ ++} while (0) + + #include + +diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h +index 70eddb3..736771c 100644 +--- a/arch/x86/include/asm/cpufeature.h ++++ b/arch/x86/include/asm/cpufeature.h +@@ -148,45 +148,46 @@ extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit); + */ + static __always_inline __pure bool _static_cpu_has(u16 bit) + { +- asm_volatile_goto("1: jmp 6f\n" +- "2:\n" +- ".skip -(((5f-4f) - (2b-1b)) > 0) * " +- "((5f-4f) - (2b-1b)),0x90\n" +- "3:\n" +- ".section .altinstructions,\"a\"\n" +- " .long 1b - .\n" /* src offset */ +- " .long 4f - .\n" /* repl offset */ +- " .word %P1\n" /* always replace */ +- " .byte 3b - 1b\n" /* src len */ +- " .byte 5f - 4f\n" /* repl len */ +- " .byte 3b - 2b\n" /* pad len */ +- ".previous\n" +- ".section .altinstr_replacement,\"ax\"\n" +- "4: jmp %l[t_no]\n" +- "5:\n" +- ".previous\n" +- ".section .altinstructions,\"a\"\n" +- " .long 1b - .\n" /* src offset */ +- " .long 0\n" /* no replacement */ +- " .word %P0\n" /* feature bit */ +- " .byte 3b - 1b\n" /* src len */ +- " .byte 0\n" /* repl len */ +- " .byte 0\n" /* pad len */ +- ".previous\n" +- ".section .altinstr_aux,\"ax\"\n" +- "6:\n" +- " testb %[bitnum],%[cap_byte]\n" +- " jnz %l[t_yes]\n" +- " jmp %l[t_no]\n" +- ".previous\n" +- : : "i" (bit), "i" (X86_FEATURE_ALWAYS), +- [bitnum] "i" (1 << (bit & 7)), +- [cap_byte] "m" (((const char *)boot_cpu_data.x86_capability)[bit >> 3]) +- : : t_yes, t_no); +- t_yes: +- return true; +- t_no: +- return false; ++ asm_volatile_goto("1: jmp 6f\n" ++ "2:\n" ++ ".skip -(((5f-4f) - (2b-1b)) > 0) * " ++ "((5f-4f) - (2b-1b)),0x90\n" ++ "3:\n" ++ ".section .altinstructions,\"a\"\n" ++ " .long 1b - .\n" /* src offset */ ++ " .long 4f - .\n" /* repl offset */ ++ " .word %P[always]\n" /* always replace */ ++ " .byte 3b - 1b\n" /* src len */ ++ " .byte 5f - 4f\n" /* repl len */ ++ " .byte 3b - 2b\n" /* pad len */ ++ ".previous\n" ++ ".section .altinstr_replacement,\"ax\"\n" ++ "4: jmp %l[t_no]\n" ++ "5:\n" ++ ".previous\n" ++ ".section .altinstructions,\"a\"\n" ++ " .long 1b - .\n" /* src offset */ ++ " .long 0\n" /* no replacement */ ++ " .word %P[feature]\n" /* feature bit */ ++ " .byte 3b - 1b\n" /* src len */ ++ " .byte 0\n" /* repl len */ ++ " .byte 0\n" /* pad len */ ++ ".previous\n" ++ ".section .altinstr_aux,\"ax\"\n" ++ "6:\n" ++ " testb %[bitnum],%[cap_byte]\n" ++ " jnz %l[t_yes]\n" ++ " jmp %l[t_no]\n" ++ ".previous\n" ++ : : [feature] "i" (bit), ++ [always] "i" (X86_FEATURE_ALWAYS), ++ [bitnum] "i" (1 << (bit & 7)), ++ [cap_byte] "m" (((const char *)boot_cpu_data.x86_capability)[bit >> 3]) ++ : : t_yes, t_no); ++t_yes: ++ return true; ++t_no: ++ return false; + } + + #define static_cpu_has(bit) \ +diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h +index 0dfe4d3..f41079d 100644 +--- a/arch/x86/include/asm/cpufeatures.h ++++ b/arch/x86/include/asm/cpufeatures.h +@@ -213,6 +213,7 @@ + #define X86_FEATURE_SEV ( 7*32+20) /* AMD Secure Encrypted Virtualization */ + + #define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */ ++#define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* "" Use IBRS during runtime firmware calls */ + + /* Virtualization flags: Linux defined, word 8 */ + #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ +diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h +index 85f6ccb..a399c1e 100644 +--- a/arch/x86/include/asm/efi.h ++++ b/arch/x86/include/asm/efi.h +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + /* + * We map the EFI regions needed for runtime services non-contiguously, +@@ -36,8 +37,18 @@ + + extern asmlinkage unsigned long efi_call_phys(void *, ...); + +-#define arch_efi_call_virt_setup() kernel_fpu_begin() +-#define arch_efi_call_virt_teardown() kernel_fpu_end() ++#define arch_efi_call_virt_setup() \ ++({ \ ++ kernel_fpu_begin(); \ ++ firmware_restrict_branch_speculation_start(); \ ++}) ++ ++#define arch_efi_call_virt_teardown() \ ++({ \ ++ firmware_restrict_branch_speculation_end(); \ ++ kernel_fpu_end(); \ ++}) ++ + + /* + * Wrap all the virtual calls in a way that forces the parameters on the stack. +@@ -73,6 +84,7 @@ struct efi_scratch { + efi_sync_low_kernel_mappings(); \ + preempt_disable(); \ + __kernel_fpu_begin(); \ ++ firmware_restrict_branch_speculation_start(); \ + \ + if (efi_scratch.use_pgd) { \ + efi_scratch.prev_cr3 = __read_cr3(); \ +@@ -91,6 +103,7 @@ struct efi_scratch { + __flush_tlb_all(); \ + } \ + \ ++ firmware_restrict_branch_speculation_end(); \ + __kernel_fpu_end(); \ + preempt_enable(); \ + }) +diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h +index dd6f57a..b605a5b 100644 +--- a/arch/x86/include/asm/kvm_host.h ++++ b/arch/x86/include/asm/kvm_host.h +@@ -507,6 +507,7 @@ struct kvm_vcpu_arch { + u64 smi_count; + bool tpr_access_reporting; + u64 ia32_xss; ++ u64 microcode_version; + + /* + * Paging state of the vcpu +@@ -1095,6 +1096,8 @@ struct kvm_x86_ops { + int (*mem_enc_op)(struct kvm *kvm, void __user *argp); + int (*mem_enc_reg_region)(struct kvm *kvm, struct kvm_enc_region *argp); + int (*mem_enc_unreg_region)(struct kvm *kvm, struct kvm_enc_region *argp); ++ ++ int (*get_msr_feature)(struct kvm_msr_entry *entry); + }; + + struct kvm_arch_async_pf { +@@ -1464,7 +1467,4 @@ static inline int kvm_cpu_get_apicid(int mps_cpu) + #define put_smstate(type, buf, offset, val) \ + *(type *)((buf) + (offset) - 0x7e00) = val + +-void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm, +- unsigned long start, unsigned long end); +- + #endif /* _ASM_X86_KVM_HOST_H */ +diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h +index 55520cec..7fb1047 100644 +--- a/arch/x86/include/asm/microcode.h ++++ b/arch/x86/include/asm/microcode.h +@@ -37,7 +37,12 @@ struct cpu_signature { + + struct device; + +-enum ucode_state { UCODE_ERROR, UCODE_OK, UCODE_NFOUND }; ++enum ucode_state { ++ UCODE_OK = 0, ++ UCODE_UPDATED, ++ UCODE_NFOUND, ++ UCODE_ERROR, ++}; + + struct microcode_ops { + enum ucode_state (*request_microcode_user) (int cpu, +@@ -54,7 +59,7 @@ struct microcode_ops { + * are being called. + * See also the "Synchronization" section in microcode_core.c. + */ +- int (*apply_microcode) (int cpu); ++ enum ucode_state (*apply_microcode) (int cpu); + int (*collect_cpu_info) (int cpu, struct cpu_signature *csig); + }; + +diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h +index c931b88..1de72ce 100644 +--- a/arch/x86/include/asm/mmu_context.h ++++ b/arch/x86/include/asm/mmu_context.h +@@ -74,6 +74,7 @@ static inline void *ldt_slot_va(int slot) + return (void *)(LDT_BASE_ADDR + LDT_SLOT_STRIDE * slot); + #else + BUG(); ++ return (void *)fix_to_virt(FIX_HOLE); + #endif + } + +diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h +index 4d57894..d0dabea 100644 +--- a/arch/x86/include/asm/nospec-branch.h ++++ b/arch/x86/include/asm/nospec-branch.h +@@ -6,6 +6,51 @@ + #include + #include + #include ++#include ++ ++/* ++ * Fill the CPU return stack buffer. ++ * ++ * Each entry in the RSB, if used for a speculative 'ret', contains an ++ * infinite 'pause; lfence; jmp' loop to capture speculative execution. ++ * ++ * This is required in various cases for retpoline and IBRS-based ++ * mitigations for the Spectre variant 2 vulnerability. Sometimes to ++ * eliminate potentially bogus entries from the RSB, and sometimes ++ * purely to ensure that it doesn't get empty, which on some CPUs would ++ * allow predictions from other (unwanted!) sources to be used. ++ * ++ * We define a CPP macro such that it can be used from both .S files and ++ * inline assembly. It's possible to do a .macro and then include that ++ * from C via asm(".include ") but let's not go there. ++ */ ++ ++#define RSB_CLEAR_LOOPS 32 /* To forcibly overwrite all entries */ ++#define RSB_FILL_LOOPS 16 /* To avoid underflow */ ++ ++/* ++ * Google experimented with loop-unrolling and this turned out to be ++ * the optimal version — two calls, each with their own speculation ++ * trap should their return address end up getting used, in a loop. ++ */ ++#define __FILL_RETURN_BUFFER(reg, nr, sp) \ ++ mov $(nr/2), reg; \ ++771: \ ++ call 772f; \ ++773: /* speculation trap */ \ ++ pause; \ ++ lfence; \ ++ jmp 773b; \ ++772: \ ++ call 774f; \ ++775: /* speculation trap */ \ ++ pause; \ ++ lfence; \ ++ jmp 775b; \ ++774: \ ++ dec reg; \ ++ jnz 771b; \ ++ add $(BITS_PER_LONG/8) * nr, sp; + + #ifdef __ASSEMBLY__ + +@@ -23,6 +68,18 @@ + .endm + + /* ++ * This should be used immediately before an indirect jump/call. It tells ++ * objtool the subsequent indirect jump/call is vouched safe for retpoline ++ * builds. ++ */ ++.macro ANNOTATE_RETPOLINE_SAFE ++ .Lannotate_\@: ++ .pushsection .discard.retpoline_safe ++ _ASM_PTR .Lannotate_\@ ++ .popsection ++.endm ++ ++/* + * These are the bare retpoline primitives for indirect jmp and call. + * Do not use these directly; they only exist to make the ALTERNATIVE + * invocation below less ugly. +@@ -58,9 +115,9 @@ + .macro JMP_NOSPEC reg:req + #ifdef CONFIG_RETPOLINE + ANNOTATE_NOSPEC_ALTERNATIVE +- ALTERNATIVE_2 __stringify(jmp *\reg), \ ++ ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *\reg), \ + __stringify(RETPOLINE_JMP \reg), X86_FEATURE_RETPOLINE, \ +- __stringify(lfence; jmp *\reg), X86_FEATURE_RETPOLINE_AMD ++ __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *\reg), X86_FEATURE_RETPOLINE_AMD + #else + jmp *\reg + #endif +@@ -69,18 +126,25 @@ + .macro CALL_NOSPEC reg:req + #ifdef CONFIG_RETPOLINE + ANNOTATE_NOSPEC_ALTERNATIVE +- ALTERNATIVE_2 __stringify(call *\reg), \ ++ ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; call *\reg), \ + __stringify(RETPOLINE_CALL \reg), X86_FEATURE_RETPOLINE,\ +- __stringify(lfence; call *\reg), X86_FEATURE_RETPOLINE_AMD ++ __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; call *\reg), X86_FEATURE_RETPOLINE_AMD + #else + call *\reg + #endif + .endm + +-/* This clobbers the BX register */ +-.macro FILL_RETURN_BUFFER nr:req ftr:req ++ /* ++ * A simpler FILL_RETURN_BUFFER macro. Don't make people use the CPP ++ * monstrosity above, manually. ++ */ ++.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req + #ifdef CONFIG_RETPOLINE +- ALTERNATIVE "", "call __clear_rsb", \ftr ++ ANNOTATE_NOSPEC_ALTERNATIVE ++ ALTERNATIVE "jmp .Lskip_rsb_\@", \ ++ __stringify(__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)) \ ++ \ftr ++.Lskip_rsb_\@: + #endif + .endm + +@@ -92,6 +156,12 @@ + ".long 999b - .\n\t" \ + ".popsection\n\t" + ++#define ANNOTATE_RETPOLINE_SAFE \ ++ "999:\n\t" \ ++ ".pushsection .discard.retpoline_safe\n\t" \ ++ _ASM_PTR " 999b\n\t" \ ++ ".popsection\n\t" ++ + #if defined(CONFIG_X86_64) && defined(RETPOLINE) + + /* +@@ -101,6 +171,7 @@ + # define CALL_NOSPEC \ + ANNOTATE_NOSPEC_ALTERNATIVE \ + ALTERNATIVE( \ ++ ANNOTATE_RETPOLINE_SAFE \ + "call *%[thunk_target]\n", \ + "call __x86_indirect_thunk_%V[thunk_target]\n", \ + X86_FEATURE_RETPOLINE) +@@ -155,20 +226,90 @@ extern char __indirect_thunk_end[]; + static inline void vmexit_fill_RSB(void) + { + #ifdef CONFIG_RETPOLINE +- alternative_input("", +- "call __fill_rsb", +- X86_FEATURE_RETPOLINE, +- ASM_NO_INPUT_CLOBBER(_ASM_BX, "memory")); ++ unsigned long loops; ++ ++ asm volatile (ANNOTATE_NOSPEC_ALTERNATIVE ++ ALTERNATIVE("jmp 910f", ++ __stringify(__FILL_RETURN_BUFFER(%0, RSB_CLEAR_LOOPS, %1)), ++ X86_FEATURE_RETPOLINE) ++ "910:" ++ : "=r" (loops), ASM_CALL_CONSTRAINT ++ : : "memory" ); + #endif + } + ++#define alternative_msr_write(_msr, _val, _feature) \ ++ asm volatile(ALTERNATIVE("", \ ++ "movl %[msr], %%ecx\n\t" \ ++ "movl %[val], %%eax\n\t" \ ++ "movl $0, %%edx\n\t" \ ++ "wrmsr", \ ++ _feature) \ ++ : : [msr] "i" (_msr), [val] "i" (_val) \ ++ : "eax", "ecx", "edx", "memory") ++ + static inline void indirect_branch_prediction_barrier(void) + { +- alternative_input("", +- "call __ibp_barrier", +- X86_FEATURE_USE_IBPB, +- ASM_NO_INPUT_CLOBBER("eax", "ecx", "edx", "memory")); ++ alternative_msr_write(MSR_IA32_PRED_CMD, PRED_CMD_IBPB, ++ X86_FEATURE_USE_IBPB); + } + ++/* ++ * With retpoline, we must use IBRS to restrict branch prediction ++ * before calling into firmware. ++ * ++ * (Implemented as CPP macros due to header hell.) ++ */ ++#define firmware_restrict_branch_speculation_start() \ ++do { \ ++ preempt_disable(); \ ++ alternative_msr_write(MSR_IA32_SPEC_CTRL, SPEC_CTRL_IBRS, \ ++ X86_FEATURE_USE_IBRS_FW); \ ++} while (0) ++ ++#define firmware_restrict_branch_speculation_end() \ ++do { \ ++ alternative_msr_write(MSR_IA32_SPEC_CTRL, 0, \ ++ X86_FEATURE_USE_IBRS_FW); \ ++ preempt_enable(); \ ++} while (0) ++ + #endif /* __ASSEMBLY__ */ ++ ++/* ++ * Below is used in the eBPF JIT compiler and emits the byte sequence ++ * for the following assembly: ++ * ++ * With retpolines configured: ++ * ++ * callq do_rop ++ * spec_trap: ++ * pause ++ * lfence ++ * jmp spec_trap ++ * do_rop: ++ * mov %rax,(%rsp) ++ * retq ++ * ++ * Without retpolines configured: ++ * ++ * jmp *%rax ++ */ ++#ifdef CONFIG_RETPOLINE ++# define RETPOLINE_RAX_BPF_JIT_SIZE 17 ++# define RETPOLINE_RAX_BPF_JIT() \ ++ EMIT1_off32(0xE8, 7); /* callq do_rop */ \ ++ /* spec_trap: */ \ ++ EMIT2(0xF3, 0x90); /* pause */ \ ++ EMIT3(0x0F, 0xAE, 0xE8); /* lfence */ \ ++ EMIT2(0xEB, 0xF9); /* jmp spec_trap */ \ ++ /* do_rop: */ \ ++ EMIT4(0x48, 0x89, 0x04, 0x24); /* mov %rax,(%rsp) */ \ ++ EMIT1(0xC3); /* retq */ ++#else ++# define RETPOLINE_RAX_BPF_JIT_SIZE 2 ++# define RETPOLINE_RAX_BPF_JIT() \ ++ EMIT2(0xFF, 0xE0); /* jmp *%rax */ ++#endif ++ + #endif /* _ASM_X86_NOSPEC_BRANCH_H_ */ +diff --git a/arch/x86/include/asm/page_64.h b/arch/x86/include/asm/page_64.h +index 4baa6bc..d652a38 100644 +--- a/arch/x86/include/asm/page_64.h ++++ b/arch/x86/include/asm/page_64.h +@@ -52,10 +52,6 @@ static inline void clear_page(void *page) + + void copy_page(void *to, void *from); + +-#ifdef CONFIG_X86_MCE +-#define arch_unmap_kpfn arch_unmap_kpfn +-#endif +- + #endif /* !__ASSEMBLY__ */ + + #ifdef CONFIG_X86_VSYSCALL_EMULATION +diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h +index 892df37..c83a2f4 100644 +--- a/arch/x86/include/asm/paravirt.h ++++ b/arch/x86/include/asm/paravirt.h +@@ -7,6 +7,7 @@ + #ifdef CONFIG_PARAVIRT + #include + #include ++#include + + #include + +@@ -297,9 +298,9 @@ static inline void __flush_tlb_global(void) + { + PVOP_VCALL0(pv_mmu_ops.flush_tlb_kernel); + } +-static inline void __flush_tlb_single(unsigned long addr) ++static inline void __flush_tlb_one_user(unsigned long addr) + { +- PVOP_VCALL1(pv_mmu_ops.flush_tlb_single, addr); ++ PVOP_VCALL1(pv_mmu_ops.flush_tlb_one_user, addr); + } + + static inline void flush_tlb_others(const struct cpumask *cpumask, +@@ -879,23 +880,27 @@ extern void default_banner(void); + + #define INTERRUPT_RETURN \ + PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_iret), CLBR_NONE, \ +- jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_iret)) ++ ANNOTATE_RETPOLINE_SAFE; \ ++ jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_iret);) + + #define DISABLE_INTERRUPTS(clobbers) \ + PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_irq_disable), clobbers, \ + PV_SAVE_REGS(clobbers | CLBR_CALLEE_SAVE); \ ++ ANNOTATE_RETPOLINE_SAFE; \ + call PARA_INDIRECT(pv_irq_ops+PV_IRQ_irq_disable); \ + PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);) + + #define ENABLE_INTERRUPTS(clobbers) \ + PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_irq_enable), clobbers, \ + PV_SAVE_REGS(clobbers | CLBR_CALLEE_SAVE); \ ++ ANNOTATE_RETPOLINE_SAFE; \ + call PARA_INDIRECT(pv_irq_ops+PV_IRQ_irq_enable); \ + PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);) + + #ifdef CONFIG_X86_32 + #define GET_CR0_INTO_EAX \ + push %ecx; push %edx; \ ++ ANNOTATE_RETPOLINE_SAFE; \ + call PARA_INDIRECT(pv_cpu_ops+PV_CPU_read_cr0); \ + pop %edx; pop %ecx + #else /* !CONFIG_X86_32 */ +@@ -917,21 +922,25 @@ extern void default_banner(void); + */ + #define SWAPGS \ + PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_swapgs), CLBR_NONE, \ +- call PARA_INDIRECT(pv_cpu_ops+PV_CPU_swapgs) \ ++ ANNOTATE_RETPOLINE_SAFE; \ ++ call PARA_INDIRECT(pv_cpu_ops+PV_CPU_swapgs); \ + ) + + #define GET_CR2_INTO_RAX \ +- call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2) ++ ANNOTATE_RETPOLINE_SAFE; \ ++ call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2); + + #define USERGS_SYSRET64 \ + PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret64), \ + CLBR_NONE, \ +- jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret64)) ++ ANNOTATE_RETPOLINE_SAFE; \ ++ jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret64);) + + #ifdef CONFIG_DEBUG_ENTRY + #define SAVE_FLAGS(clobbers) \ + PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_save_fl), clobbers, \ + PV_SAVE_REGS(clobbers | CLBR_CALLEE_SAVE); \ ++ ANNOTATE_RETPOLINE_SAFE; \ + call PARA_INDIRECT(pv_irq_ops+PV_IRQ_save_fl); \ + PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);) + #endif +diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h +index 6ec54d0..180bc0b 100644 +--- a/arch/x86/include/asm/paravirt_types.h ++++ b/arch/x86/include/asm/paravirt_types.h +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + + struct page; + struct thread_struct; +@@ -217,7 +218,7 @@ struct pv_mmu_ops { + /* TLB operations */ + void (*flush_tlb_user)(void); + void (*flush_tlb_kernel)(void); +- void (*flush_tlb_single)(unsigned long addr); ++ void (*flush_tlb_one_user)(unsigned long addr); + void (*flush_tlb_others)(const struct cpumask *cpus, + const struct flush_tlb_info *info); + +@@ -392,7 +393,9 @@ int paravirt_disable_iospace(void); + * offset into the paravirt_patch_template structure, and can therefore be + * freely converted back into a structure offset. + */ +-#define PARAVIRT_CALL "call *%c[paravirt_opptr];" ++#define PARAVIRT_CALL \ ++ ANNOTATE_RETPOLINE_SAFE \ ++ "call *%c[paravirt_opptr];" + + /* + * These macros are intended to wrap calls through one of the paravirt +diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h +index ba3c523..a06b073 100644 +--- a/arch/x86/include/asm/percpu.h ++++ b/arch/x86/include/asm/percpu.h +@@ -526,7 +526,7 @@ static inline bool x86_this_cpu_variable_test_bit(int nr, + { + bool oldbit; + +- asm volatile("bt "__percpu_arg(2)",%1" ++ asm volatile("btl "__percpu_arg(2)",%1" + CC_SET(c) + : CC_OUT(c) (oldbit) + : "m" (*(unsigned long __percpu *)addr), "Ir" (nr)); +diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h +index 63c2552..b444d83 100644 +--- a/arch/x86/include/asm/pgtable.h ++++ b/arch/x86/include/asm/pgtable.h +@@ -350,14 +350,14 @@ static inline pmd_t pmd_set_flags(pmd_t pmd, pmdval_t set) + { + pmdval_t v = native_pmd_val(pmd); + +- return __pmd(v | set); ++ return native_make_pmd(v | set); + } + + static inline pmd_t pmd_clear_flags(pmd_t pmd, pmdval_t clear) + { + pmdval_t v = native_pmd_val(pmd); + +- return __pmd(v & ~clear); ++ return native_make_pmd(v & ~clear); + } + + static inline pmd_t pmd_mkold(pmd_t pmd) +@@ -409,14 +409,14 @@ static inline pud_t pud_set_flags(pud_t pud, pudval_t set) + { + pudval_t v = native_pud_val(pud); + +- return __pud(v | set); ++ return native_make_pud(v | set); + } + + static inline pud_t pud_clear_flags(pud_t pud, pudval_t clear) + { + pudval_t v = native_pud_val(pud); + +- return __pud(v & ~clear); ++ return native_make_pud(v & ~clear); + } + + static inline pud_t pud_mkold(pud_t pud) +diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h +index e67c062..b3ec519 100644 +--- a/arch/x86/include/asm/pgtable_32.h ++++ b/arch/x86/include/asm/pgtable_32.h +@@ -32,6 +32,7 @@ extern pmd_t initial_pg_pmd[]; + static inline void pgtable_cache_init(void) { } + static inline void check_pgt_cache(void) { } + void paging_init(void); ++void sync_initial_page_table(void); + + /* + * Define this if things work differently on an i386 and an i486: +@@ -61,7 +62,7 @@ void paging_init(void); + #define kpte_clear_flush(ptep, vaddr) \ + do { \ + pte_clear(&init_mm, (vaddr), (ptep)); \ +- __flush_tlb_one((vaddr)); \ ++ __flush_tlb_one_kernel((vaddr)); \ + } while (0) + + #endif /* !__ASSEMBLY__ */ +diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h +index 81462e9..1149d21 100644 +--- a/arch/x86/include/asm/pgtable_64.h ++++ b/arch/x86/include/asm/pgtable_64.h +@@ -28,6 +28,7 @@ extern pgd_t init_top_pgt[]; + #define swapper_pg_dir init_top_pgt + + extern void paging_init(void); ++static inline void sync_initial_page_table(void) { } + + #define pte_ERROR(e) \ + pr_err("%s:%d: bad pte %p(%016lx)\n", \ +diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h +index 3696398..acfe755 100644 +--- a/arch/x86/include/asm/pgtable_types.h ++++ b/arch/x86/include/asm/pgtable_types.h +@@ -174,7 +174,6 @@ enum page_cache_mode { + #define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) + #define __PAGE_KERNEL_RX (__PAGE_KERNEL_EXEC & ~_PAGE_RW) + #define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_NOCACHE) +-#define __PAGE_KERNEL_VSYSCALL (__PAGE_KERNEL_RX | _PAGE_USER) + #define __PAGE_KERNEL_VVAR (__PAGE_KERNEL_RO | _PAGE_USER) + #define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) + #define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) +@@ -206,7 +205,6 @@ enum page_cache_mode { + #define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE | _PAGE_ENC) + #define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE | _PAGE_ENC) + #define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC | _PAGE_ENC) +-#define PAGE_KERNEL_VSYSCALL __pgprot(__PAGE_KERNEL_VSYSCALL | _PAGE_ENC) + #define PAGE_KERNEL_VVAR __pgprot(__PAGE_KERNEL_VVAR | _PAGE_ENC) + + #define PAGE_KERNEL_IO __pgprot(__PAGE_KERNEL_IO) +@@ -323,6 +321,11 @@ static inline pudval_t native_pud_val(pud_t pud) + #else + #include + ++static inline pud_t native_make_pud(pudval_t val) ++{ ++ return (pud_t) { .p4d.pgd = native_make_pgd(val) }; ++} ++ + static inline pudval_t native_pud_val(pud_t pud) + { + return native_pgd_val(pud.p4d.pgd); +@@ -344,6 +347,11 @@ static inline pmdval_t native_pmd_val(pmd_t pmd) + #else + #include + ++static inline pmd_t native_make_pmd(pmdval_t val) ++{ ++ return (pmd_t) { .pud.p4d.pgd = native_make_pgd(val) }; ++} ++ + static inline pmdval_t native_pmd_val(pmd_t pmd) + { + return native_pgd_val(pmd.pud.p4d.pgd); +diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h +index 793bae7..b0ccd48 100644 +--- a/arch/x86/include/asm/processor.h ++++ b/arch/x86/include/asm/processor.h +@@ -91,7 +91,7 @@ struct cpuinfo_x86 { + __u8 x86; /* CPU family */ + __u8 x86_vendor; /* CPU vendor */ + __u8 x86_model; +- __u8 x86_mask; ++ __u8 x86_stepping; + #ifdef CONFIG_X86_64 + /* Number of 4K pages in DTLB/ITLB combined(in pages): */ + int x86_tlbsize; +@@ -109,7 +109,7 @@ struct cpuinfo_x86 { + char x86_vendor_id[16]; + char x86_model_id[64]; + /* in KB - valid for CPUS which support this call: */ +- int x86_cache_size; ++ unsigned int x86_cache_size; + int x86_cache_alignment; /* In bytes */ + /* Cache QoS architectural values: */ + int x86_cache_max_rmid; /* max index */ +@@ -977,7 +977,5 @@ bool xen_set_default_idle(void); + + void stop_this_cpu(void *dummy); + void df_debug(struct pt_regs *regs, long error_code); +- +-void __ibp_barrier(void); +- ++void microcode_check(void); + #endif /* _ASM_X86_PROCESSOR_H */ +diff --git a/arch/x86/include/asm/refcount.h b/arch/x86/include/asm/refcount.h +index 4e44250..4cf11d8 100644 +--- a/arch/x86/include/asm/refcount.h ++++ b/arch/x86/include/asm/refcount.h +@@ -17,7 +17,7 @@ + #define _REFCOUNT_EXCEPTION \ + ".pushsection .text..refcount\n" \ + "111:\tlea %[counter], %%" _ASM_CX "\n" \ +- "112:\t" ASM_UD0 "\n" \ ++ "112:\t" ASM_UD2 "\n" \ + ASM_UNREACHABLE \ + ".popsection\n" \ + "113:\n" \ +@@ -67,13 +67,13 @@ static __always_inline __must_check + bool refcount_sub_and_test(unsigned int i, refcount_t *r) + { + GEN_BINARY_SUFFIXED_RMWcc(LOCK_PREFIX "subl", REFCOUNT_CHECK_LT_ZERO, +- r->refs.counter, "er", i, "%0", e); ++ r->refs.counter, "er", i, "%0", e, "cx"); + } + + static __always_inline __must_check bool refcount_dec_and_test(refcount_t *r) + { + GEN_UNARY_SUFFIXED_RMWcc(LOCK_PREFIX "decl", REFCOUNT_CHECK_LT_ZERO, +- r->refs.counter, "%0", e); ++ r->refs.counter, "%0", e, "cx"); + } + + static __always_inline __must_check +diff --git a/arch/x86/include/asm/rmwcc.h b/arch/x86/include/asm/rmwcc.h +index f91c365..4914a3e 100644 +--- a/arch/x86/include/asm/rmwcc.h ++++ b/arch/x86/include/asm/rmwcc.h +@@ -2,8 +2,7 @@ + #ifndef _ASM_X86_RMWcc + #define _ASM_X86_RMWcc + +-#define __CLOBBERS_MEM "memory" +-#define __CLOBBERS_MEM_CC_CX "memory", "cc", "cx" ++#define __CLOBBERS_MEM(clb...) "memory", ## clb + + #if !defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(CC_HAVE_ASM_GOTO) + +@@ -40,18 +39,19 @@ do { \ + #endif /* defined(__GCC_ASM_FLAG_OUTPUTS__) || !defined(CC_HAVE_ASM_GOTO) */ + + #define GEN_UNARY_RMWcc(op, var, arg0, cc) \ +- __GEN_RMWcc(op " " arg0, var, cc, __CLOBBERS_MEM) ++ __GEN_RMWcc(op " " arg0, var, cc, __CLOBBERS_MEM()) + +-#define GEN_UNARY_SUFFIXED_RMWcc(op, suffix, var, arg0, cc) \ ++#define GEN_UNARY_SUFFIXED_RMWcc(op, suffix, var, arg0, cc, clobbers...)\ + __GEN_RMWcc(op " " arg0 "\n\t" suffix, var, cc, \ +- __CLOBBERS_MEM_CC_CX) ++ __CLOBBERS_MEM(clobbers)) + + #define GEN_BINARY_RMWcc(op, var, vcon, val, arg0, cc) \ + __GEN_RMWcc(op __BINARY_RMWcc_ARG arg0, var, cc, \ +- __CLOBBERS_MEM, vcon (val)) ++ __CLOBBERS_MEM(), vcon (val)) + +-#define GEN_BINARY_SUFFIXED_RMWcc(op, suffix, var, vcon, val, arg0, cc) \ ++#define GEN_BINARY_SUFFIXED_RMWcc(op, suffix, var, vcon, val, arg0, cc, \ ++ clobbers...) \ + __GEN_RMWcc(op __BINARY_RMWcc_ARG arg0 "\n\t" suffix, var, cc, \ +- __CLOBBERS_MEM_CC_CX, vcon (val)) ++ __CLOBBERS_MEM(clobbers), vcon (val)) + + #endif /* _ASM_X86_RMWcc */ +diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h +index d6baf23..5c019d2 100644 +--- a/arch/x86/include/asm/sections.h ++++ b/arch/x86/include/asm/sections.h +@@ -10,6 +10,7 @@ extern struct exception_table_entry __stop___ex_table[]; + + #if defined(CONFIG_X86_64) + extern char __end_rodata_hpage_align[]; ++extern char __entry_trampoline_start[], __entry_trampoline_end[]; + #endif + + #endif /* _ASM_X86_SECTIONS_H */ +diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h +index 461f53d..a418976 100644 +--- a/arch/x86/include/asm/smp.h ++++ b/arch/x86/include/asm/smp.h +@@ -129,6 +129,7 @@ static inline void arch_send_call_function_ipi_mask(const struct cpumask *mask) + void cpu_disable_common(void); + void native_smp_prepare_boot_cpu(void); + void native_smp_prepare_cpus(unsigned int max_cpus); ++void calculate_max_logical_packages(void); + void native_smp_cpus_done(unsigned int max_cpus); + void common_cpu_up(unsigned int cpunum, struct task_struct *tidle); + int native_cpu_up(unsigned int cpunum, struct task_struct *tidle); +diff --git a/arch/x86/include/asm/sys_ia32.h b/arch/x86/include/asm/sys_ia32.h +index 82c34ee..906794a 100644 +--- a/arch/x86/include/asm/sys_ia32.h ++++ b/arch/x86/include/asm/sys_ia32.h +@@ -20,31 +20,43 @@ + #include + + /* ia32/sys_ia32.c */ +-asmlinkage long sys32_truncate64(const char __user *, unsigned long, unsigned long); +-asmlinkage long sys32_ftruncate64(unsigned int, unsigned long, unsigned long); ++asmlinkage long compat_sys_x86_truncate64(const char __user *, unsigned long, ++ unsigned long); ++asmlinkage long compat_sys_x86_ftruncate64(unsigned int, unsigned long, ++ unsigned long); + +-asmlinkage long sys32_stat64(const char __user *, struct stat64 __user *); +-asmlinkage long sys32_lstat64(const char __user *, struct stat64 __user *); +-asmlinkage long sys32_fstat64(unsigned int, struct stat64 __user *); +-asmlinkage long sys32_fstatat(unsigned int, const char __user *, ++asmlinkage long compat_sys_x86_stat64(const char __user *, ++ struct stat64 __user *); ++asmlinkage long compat_sys_x86_lstat64(const char __user *, ++ struct stat64 __user *); ++asmlinkage long compat_sys_x86_fstat64(unsigned int, struct stat64 __user *); ++asmlinkage long compat_sys_x86_fstatat(unsigned int, const char __user *, + struct stat64 __user *, int); + struct mmap_arg_struct32; +-asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *); ++asmlinkage long compat_sys_x86_mmap(struct mmap_arg_struct32 __user *); + +-asmlinkage long sys32_waitpid(compat_pid_t, unsigned int __user *, int); ++asmlinkage long compat_sys_x86_waitpid(compat_pid_t, unsigned int __user *, ++ int); + +-asmlinkage long sys32_pread(unsigned int, char __user *, u32, u32, u32); +-asmlinkage long sys32_pwrite(unsigned int, const char __user *, u32, u32, u32); ++asmlinkage long compat_sys_x86_pread(unsigned int, char __user *, u32, u32, ++ u32); ++asmlinkage long compat_sys_x86_pwrite(unsigned int, const char __user *, u32, ++ u32, u32); + +-long sys32_fadvise64_64(int, __u32, __u32, __u32, __u32, int); +-long sys32_vm86_warning(void); ++asmlinkage long compat_sys_x86_fadvise64_64(int, __u32, __u32, __u32, __u32, ++ int); + +-asmlinkage ssize_t sys32_readahead(int, unsigned, unsigned, size_t); +-asmlinkage long sys32_sync_file_range(int, unsigned, unsigned, +- unsigned, unsigned, int); +-asmlinkage long sys32_fadvise64(int, unsigned, unsigned, size_t, int); +-asmlinkage long sys32_fallocate(int, int, unsigned, +- unsigned, unsigned, unsigned); ++asmlinkage ssize_t compat_sys_x86_readahead(int, unsigned int, unsigned int, ++ size_t); ++asmlinkage long compat_sys_x86_sync_file_range(int, unsigned int, unsigned int, ++ unsigned int, unsigned int, ++ int); ++asmlinkage long compat_sys_x86_fadvise64(int, unsigned int, unsigned int, ++ size_t, int); ++asmlinkage long compat_sys_x86_fallocate(int, int, unsigned int, unsigned int, ++ unsigned int, unsigned int); ++asmlinkage long compat_sys_x86_clone(unsigned long, unsigned long, int __user *, ++ unsigned long, int __user *); + + /* ia32/ia32_signal.c */ + asmlinkage long sys32_sigreturn(void); +diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h +index 2b8f18c..84137c2 100644 +--- a/arch/x86/include/asm/tlbflush.h ++++ b/arch/x86/include/asm/tlbflush.h +@@ -140,7 +140,7 @@ static inline unsigned long build_cr3_noflush(pgd_t *pgd, u16 asid) + #else + #define __flush_tlb() __native_flush_tlb() + #define __flush_tlb_global() __native_flush_tlb_global() +-#define __flush_tlb_single(addr) __native_flush_tlb_single(addr) ++#define __flush_tlb_one_user(addr) __native_flush_tlb_one_user(addr) + #endif + + static inline bool tlb_defer_switch_to_init_mm(void) +@@ -400,7 +400,7 @@ static inline void __native_flush_tlb_global(void) + /* + * flush one page in the user mapping + */ +-static inline void __native_flush_tlb_single(unsigned long addr) ++static inline void __native_flush_tlb_one_user(unsigned long addr) + { + u32 loaded_mm_asid = this_cpu_read(cpu_tlbstate.loaded_mm_asid); + +@@ -437,18 +437,31 @@ static inline void __flush_tlb_all(void) + /* + * flush one page in the kernel mapping + */ +-static inline void __flush_tlb_one(unsigned long addr) ++static inline void __flush_tlb_one_kernel(unsigned long addr) + { + count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ONE); +- __flush_tlb_single(addr); ++ ++ /* ++ * If PTI is off, then __flush_tlb_one_user() is just INVLPG or its ++ * paravirt equivalent. Even with PCID, this is sufficient: we only ++ * use PCID if we also use global PTEs for the kernel mapping, and ++ * INVLPG flushes global translations across all address spaces. ++ * ++ * If PTI is on, then the kernel is mapped with non-global PTEs, and ++ * __flush_tlb_one_user() will flush the given address for the current ++ * kernel address space and for its usermode counterpart, but it does ++ * not flush it for other address spaces. ++ */ ++ __flush_tlb_one_user(addr); + + if (!static_cpu_has(X86_FEATURE_PTI)) + return; + + /* +- * __flush_tlb_single() will have cleared the TLB entry for this ASID, +- * but since kernel space is replicated across all, we must also +- * invalidate all others. ++ * See above. We need to propagate the flush to all other address ++ * spaces. In principle, we only need to propagate it to kernelmode ++ * address spaces, but the extra bookkeeping we would need is not ++ * worth it. + */ + invalidate_other_asid(); + } +diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h +index 197c2e6..0994143 100644 +--- a/arch/x86/include/uapi/asm/hyperv.h ++++ b/arch/x86/include/uapi/asm/hyperv.h +@@ -241,24 +241,24 @@ + #define HV_X64_MSR_REENLIGHTENMENT_CONTROL 0x40000106 + + struct hv_reenlightenment_control { +- u64 vector:8; +- u64 reserved1:8; +- u64 enabled:1; +- u64 reserved2:15; +- u64 target_vp:32; ++ __u64 vector:8; ++ __u64 reserved1:8; ++ __u64 enabled:1; ++ __u64 reserved2:15; ++ __u64 target_vp:32; + }; + + #define HV_X64_MSR_TSC_EMULATION_CONTROL 0x40000107 + #define HV_X64_MSR_TSC_EMULATION_STATUS 0x40000108 + + struct hv_tsc_emulation_control { +- u64 enabled:1; +- u64 reserved:63; ++ __u64 enabled:1; ++ __u64 reserved:63; + }; + + struct hv_tsc_emulation_status { +- u64 inprogress:1; +- u64 reserved:63; ++ __u64 inprogress:1; ++ __u64 reserved:63; + }; + + #define HV_X64_MSR_HYPERCALL_ENABLE 0x00000001 +diff --git a/arch/x86/include/uapi/asm/kvm_para.h b/arch/x86/include/uapi/asm/kvm_para.h +index 7a2ade4..6cfa9c8 100644 +--- a/arch/x86/include/uapi/asm/kvm_para.h ++++ b/arch/x86/include/uapi/asm/kvm_para.h +@@ -26,6 +26,7 @@ + #define KVM_FEATURE_PV_EOI 6 + #define KVM_FEATURE_PV_UNHALT 7 + #define KVM_FEATURE_PV_TLB_FLUSH 9 ++#define KVM_FEATURE_ASYNC_PF_VMEXIT 10 + + /* The last 8 bits are used to indicate how to interpret the flags field + * in pvclock structure. If no bits are set, all flags are ignored. +diff --git a/arch/x86/include/uapi/asm/mce.h b/arch/x86/include/uapi/asm/mce.h +index 91723461..435db58 100644 +--- a/arch/x86/include/uapi/asm/mce.h ++++ b/arch/x86/include/uapi/asm/mce.h +@@ -30,6 +30,7 @@ struct mce { + __u64 synd; /* MCA_SYND MSR: only valid on SMCA systems */ + __u64 ipid; /* MCA_IPID MSR: only valid on SMCA systems */ + __u64 ppin; /* Protected Processor Inventory Number */ ++ __u32 microcode;/* Microcode revision */ + }; + + #define MCE_GET_RECORD_LEN _IOR('M', 1, int) +diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c +index 6db28f1..c88e0b1 100644 +--- a/arch/x86/kernel/amd_nb.c ++++ b/arch/x86/kernel/amd_nb.c +@@ -235,7 +235,7 @@ int amd_cache_northbridges(void) + if (boot_cpu_data.x86 == 0x10 && + boot_cpu_data.x86_model >= 0x8 && + (boot_cpu_data.x86_model > 0x9 || +- boot_cpu_data.x86_mask >= 0x1)) ++ boot_cpu_data.x86_stepping >= 0x1)) + amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE; + + if (boot_cpu_data.x86 == 0x15) +diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c +index 25ddf02..b203af0 100644 +--- a/arch/x86/kernel/apic/apic.c ++++ b/arch/x86/kernel/apic/apic.c +@@ -546,7 +546,7 @@ static DEFINE_PER_CPU(struct clock_event_device, lapic_events); + + static u32 hsx_deadline_rev(void) + { +- switch (boot_cpu_data.x86_mask) { ++ switch (boot_cpu_data.x86_stepping) { + case 0x02: return 0x3a; /* EP */ + case 0x04: return 0x0f; /* EX */ + } +@@ -556,7 +556,7 @@ static u32 hsx_deadline_rev(void) + + static u32 bdx_deadline_rev(void) + { +- switch (boot_cpu_data.x86_mask) { ++ switch (boot_cpu_data.x86_stepping) { + case 0x02: return 0x00000011; + case 0x03: return 0x0700000e; + case 0x04: return 0x0f00000c; +@@ -568,7 +568,7 @@ static u32 bdx_deadline_rev(void) + + static u32 skx_deadline_rev(void) + { +- switch (boot_cpu_data.x86_mask) { ++ switch (boot_cpu_data.x86_stepping) { + case 0x03: return 0x01000136; + case 0x04: return 0x02000014; + } +diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c +index 8ad2e41..7c55387 100644 +--- a/arch/x86/kernel/apic/io_apic.c ++++ b/arch/x86/kernel/apic/io_apic.c +@@ -1603,7 +1603,7 @@ static void __init delay_with_tsc(void) + do { + rep_nop(); + now = rdtsc(); +- } while ((now - start) < 40000000000UL / HZ && ++ } while ((now - start) < 40000000000ULL / HZ && + time_before_eq(jiffies, end)); + } + +diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c +index 3cc471b..bb6f7a2 100644 +--- a/arch/x86/kernel/apic/vector.c ++++ b/arch/x86/kernel/apic/vector.c +@@ -134,21 +134,40 @@ static void apic_update_vector(struct irq_data *irqd, unsigned int newvec, + { + struct apic_chip_data *apicd = apic_chip_data(irqd); + struct irq_desc *desc = irq_data_to_desc(irqd); ++ bool managed = irqd_affinity_is_managed(irqd); + + lockdep_assert_held(&vector_lock); + + trace_vector_update(irqd->irq, newvec, newcpu, apicd->vector, + apicd->cpu); + +- /* Setup the vector move, if required */ +- if (apicd->vector && cpu_online(apicd->cpu)) { ++ /* ++ * If there is no vector associated or if the associated vector is ++ * the shutdown vector, which is associated to make PCI/MSI ++ * shutdown mode work, then there is nothing to release. Clear out ++ * prev_vector for this and the offlined target case. ++ */ ++ apicd->prev_vector = 0; ++ if (!apicd->vector || apicd->vector == MANAGED_IRQ_SHUTDOWN_VECTOR) ++ goto setnew; ++ /* ++ * If the target CPU of the previous vector is online, then mark ++ * the vector as move in progress and store it for cleanup when the ++ * first interrupt on the new vector arrives. If the target CPU is ++ * offline then the regular release mechanism via the cleanup ++ * vector is not possible and the vector can be immediately freed ++ * in the underlying matrix allocator. ++ */ ++ if (cpu_online(apicd->cpu)) { + apicd->move_in_progress = true; + apicd->prev_vector = apicd->vector; + apicd->prev_cpu = apicd->cpu; + } else { +- apicd->prev_vector = 0; ++ irq_matrix_free(vector_matrix, apicd->cpu, apicd->vector, ++ managed); + } + ++setnew: + apicd->vector = newvec; + apicd->cpu = newcpu; + BUG_ON(!IS_ERR_OR_NULL(per_cpu(vector_irq, newcpu)[newvec])); +diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c +index 46b675a..f11910b 100644 +--- a/arch/x86/kernel/apic/x2apic_uv_x.c ++++ b/arch/x86/kernel/apic/x2apic_uv_x.c +@@ -1176,16 +1176,25 @@ static void __init decode_gam_rng_tbl(unsigned long ptr) + + uv_gre_table = gre; + for (; gre->type != UV_GAM_RANGE_TYPE_UNUSED; gre++) { ++ unsigned long size = ((unsigned long)(gre->limit - lgre) ++ << UV_GAM_RANGE_SHFT); ++ int order = 0; ++ char suffix[] = " KMGTPE"; ++ ++ while (size > 9999 && order < sizeof(suffix)) { ++ size /= 1024; ++ order++; ++ } ++ + if (!index) { + pr_info("UV: GAM Range Table...\n"); + pr_info("UV: # %20s %14s %5s %4s %5s %3s %2s\n", "Range", "", "Size", "Type", "NASID", "SID", "PN"); + } +- pr_info("UV: %2d: 0x%014lx-0x%014lx %5luG %3d %04x %02x %02x\n", ++ pr_info("UV: %2d: 0x%014lx-0x%014lx %5lu%c %3d %04x %02x %02x\n", + index++, + (unsigned long)lgre << UV_GAM_RANGE_SHFT, + (unsigned long)gre->limit << UV_GAM_RANGE_SHFT, +- ((unsigned long)(gre->limit - lgre)) >> +- (30 - UV_GAM_RANGE_SHFT), /* 64M -> 1G */ ++ size, suffix[order], + gre->type, gre->nasid, gre->sockid, gre->pnode); + + lgre = gre->limit; +diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c +index fa1261e..f91ba53 100644 +--- a/arch/x86/kernel/asm-offsets_32.c ++++ b/arch/x86/kernel/asm-offsets_32.c +@@ -18,7 +18,7 @@ void foo(void) + OFFSET(CPUINFO_x86, cpuinfo_x86, x86); + OFFSET(CPUINFO_x86_vendor, cpuinfo_x86, x86_vendor); + OFFSET(CPUINFO_x86_model, cpuinfo_x86, x86_model); +- OFFSET(CPUINFO_x86_mask, cpuinfo_x86, x86_mask); ++ OFFSET(CPUINFO_x86_stepping, cpuinfo_x86, x86_stepping); + OFFSET(CPUINFO_cpuid_level, cpuinfo_x86, cpuid_level); + OFFSET(CPUINFO_x86_capability, cpuinfo_x86, x86_capability); + OFFSET(CPUINFO_x86_vendor_id, cpuinfo_x86, x86_vendor_id); +diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c +index 5bddbdc..f0e6456 100644 +--- a/arch/x86/kernel/cpu/amd.c ++++ b/arch/x86/kernel/cpu/amd.c +@@ -119,7 +119,7 @@ static void init_amd_k6(struct cpuinfo_x86 *c) + return; + } + +- if (c->x86_model == 6 && c->x86_mask == 1) { ++ if (c->x86_model == 6 && c->x86_stepping == 1) { + const int K6_BUG_LOOP = 1000000; + int n; + void (*f_vide)(void); +@@ -149,7 +149,7 @@ static void init_amd_k6(struct cpuinfo_x86 *c) + + /* K6 with old style WHCR */ + if (c->x86_model < 8 || +- (c->x86_model == 8 && c->x86_mask < 8)) { ++ (c->x86_model == 8 && c->x86_stepping < 8)) { + /* We can only write allocate on the low 508Mb */ + if (mbytes > 508) + mbytes = 508; +@@ -168,7 +168,7 @@ static void init_amd_k6(struct cpuinfo_x86 *c) + return; + } + +- if ((c->x86_model == 8 && c->x86_mask > 7) || ++ if ((c->x86_model == 8 && c->x86_stepping > 7) || + c->x86_model == 9 || c->x86_model == 13) { + /* The more serious chips .. */ + +@@ -221,7 +221,7 @@ static void init_amd_k7(struct cpuinfo_x86 *c) + * are more robust with CLK_CTL set to 200xxxxx instead of 600xxxxx + * As per AMD technical note 27212 0.2 + */ +- if ((c->x86_model == 8 && c->x86_mask >= 1) || (c->x86_model > 8)) { ++ if ((c->x86_model == 8 && c->x86_stepping >= 1) || (c->x86_model > 8)) { + rdmsr(MSR_K7_CLK_CTL, l, h); + if ((l & 0xfff00000) != 0x20000000) { + pr_info("CPU: CLK_CTL MSR was %x. Reprogramming to %x\n", +@@ -241,12 +241,12 @@ static void init_amd_k7(struct cpuinfo_x86 *c) + * but they are not certified as MP capable. + */ + /* Athlon 660/661 is valid. */ +- if ((c->x86_model == 6) && ((c->x86_mask == 0) || +- (c->x86_mask == 1))) ++ if ((c->x86_model == 6) && ((c->x86_stepping == 0) || ++ (c->x86_stepping == 1))) + return; + + /* Duron 670 is valid */ +- if ((c->x86_model == 7) && (c->x86_mask == 0)) ++ if ((c->x86_model == 7) && (c->x86_stepping == 0)) + return; + + /* +@@ -256,8 +256,8 @@ static void init_amd_k7(struct cpuinfo_x86 *c) + * See http://www.heise.de/newsticker/data/jow-18.10.01-000 for + * more. + */ +- if (((c->x86_model == 6) && (c->x86_mask >= 2)) || +- ((c->x86_model == 7) && (c->x86_mask >= 1)) || ++ if (((c->x86_model == 6) && (c->x86_stepping >= 2)) || ++ ((c->x86_model == 7) && (c->x86_stepping >= 1)) || + (c->x86_model > 7)) + if (cpu_has(c, X86_FEATURE_MP)) + return; +@@ -628,7 +628,7 @@ static void early_init_amd(struct cpuinfo_x86 *c) + /* Set MTRR capability flag if appropriate */ + if (c->x86 == 5) + if (c->x86_model == 13 || c->x86_model == 9 || +- (c->x86_model == 8 && c->x86_mask >= 8)) ++ (c->x86_model == 8 && c->x86_stepping >= 8)) + set_cpu_cap(c, X86_FEATURE_K6_MTRR); + #endif + #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PCI) +@@ -795,7 +795,7 @@ static void init_amd_zn(struct cpuinfo_x86 *c) + * Fix erratum 1076: CPB feature bit not being set in CPUID. It affects + * all up to and including B1. + */ +- if (c->x86_model <= 1 && c->x86_mask <= 1) ++ if (c->x86_model <= 1 && c->x86_stepping <= 1) + set_cpu_cap(c, X86_FEATURE_CPB); + } + +@@ -906,11 +906,11 @@ static unsigned int amd_size_cache(struct cpuinfo_x86 *c, unsigned int size) + /* AMD errata T13 (order #21922) */ + if ((c->x86 == 6)) { + /* Duron Rev A0 */ +- if (c->x86_model == 3 && c->x86_mask == 0) ++ if (c->x86_model == 3 && c->x86_stepping == 0) + size = 64; + /* Tbird rev A1/A2 */ + if (c->x86_model == 4 && +- (c->x86_mask == 0 || c->x86_mask == 1)) ++ (c->x86_stepping == 0 || c->x86_stepping == 1)) + size = 256; + } + return size; +@@ -1047,7 +1047,7 @@ static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum) + } + + /* OSVW unavailable or ID unknown, match family-model-stepping range */ +- ms = (cpu->x86_model << 4) | cpu->x86_mask; ++ ms = (cpu->x86_model << 4) | cpu->x86_stepping; + while ((range = *erratum++)) + if ((cpu->x86 == AMD_MODEL_RANGE_FAMILY(range)) && + (ms >= AMD_MODEL_RANGE_START(range)) && +diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c +index 71949bf..bfca937 100644 +--- a/arch/x86/kernel/cpu/bugs.c ++++ b/arch/x86/kernel/cpu/bugs.c +@@ -162,8 +162,7 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) + if (cmdline_find_option_bool(boot_command_line, "nospectre_v2")) + return SPECTRE_V2_CMD_NONE; + else { +- ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, +- sizeof(arg)); ++ ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, sizeof(arg)); + if (ret < 0) + return SPECTRE_V2_CMD_AUTO; + +@@ -175,8 +174,7 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) + } + + if (i >= ARRAY_SIZE(mitigation_options)) { +- pr_err("unknown option (%s). Switching to AUTO select\n", +- mitigation_options[i].option); ++ pr_err("unknown option (%s). Switching to AUTO select\n", arg); + return SPECTRE_V2_CMD_AUTO; + } + } +@@ -185,8 +183,7 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) + cmd == SPECTRE_V2_CMD_RETPOLINE_AMD || + cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC) && + !IS_ENABLED(CONFIG_RETPOLINE)) { +- pr_err("%s selected but not compiled in. Switching to AUTO select\n", +- mitigation_options[i].option); ++ pr_err("%s selected but not compiled in. Switching to AUTO select\n", mitigation_options[i].option); + return SPECTRE_V2_CMD_AUTO; + } + +@@ -256,14 +253,14 @@ static void __init spectre_v2_select_mitigation(void) + goto retpoline_auto; + break; + } +- pr_err("kernel not compiled with retpoline; no mitigation available!"); ++ pr_err("Spectre mitigation: kernel not compiled with retpoline; no mitigation available!"); + return; + + retpoline_auto: + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { + retpoline_amd: + if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) { +- pr_err("LFENCE not serializing. Switching to generic retpoline\n"); ++ pr_err("Spectre mitigation: LFENCE not serializing, switching to generic retpoline\n"); + goto retpoline_generic; + } + mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_AMD : +@@ -281,7 +278,7 @@ static void __init spectre_v2_select_mitigation(void) + pr_info("%s\n", spectre_v2_strings[mode]); + + /* +- * If neither SMEP or KPTI are available, there is a risk of ++ * If neither SMEP nor PTI are available, there is a risk of + * hitting userspace addresses in the RSB after a context switch + * from a shallow call stack to a deeper one. To prevent this fill + * the entire RSB, even when using IBRS. +@@ -295,21 +292,29 @@ static void __init spectre_v2_select_mitigation(void) + if ((!boot_cpu_has(X86_FEATURE_PTI) && + !boot_cpu_has(X86_FEATURE_SMEP)) || is_skylake_era()) { + setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW); +- pr_info("Filling RSB on context switch\n"); ++ pr_info("Spectre v2 mitigation: Filling RSB on context switch\n"); + } + + /* Initialize Indirect Branch Prediction Barrier if supported */ + if (boot_cpu_has(X86_FEATURE_IBPB)) { + setup_force_cpu_cap(X86_FEATURE_USE_IBPB); +- pr_info("Enabling Indirect Branch Prediction Barrier\n"); ++ pr_info("Spectre v2 mitigation: Enabling Indirect Branch Prediction Barrier\n"); ++ } ++ ++ /* ++ * Retpoline means the kernel is safe because it has no indirect ++ * branches. But firmware isn't, so use IBRS to protect that. ++ */ ++ if (boot_cpu_has(X86_FEATURE_IBRS)) { ++ setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW); ++ pr_info("Enabling Restricted Speculation for firmware calls\n"); + } + } + + #undef pr_fmt + + #ifdef CONFIG_SYSFS +-ssize_t cpu_show_meltdown(struct device *dev, +- struct device_attribute *attr, char *buf) ++ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) + { + if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN)) + return sprintf(buf, "Not affected\n"); +@@ -318,28 +323,21 @@ ssize_t cpu_show_meltdown(struct device *dev, + return sprintf(buf, "Vulnerable\n"); + } + +-ssize_t cpu_show_spectre_v1(struct device *dev, +- struct device_attribute *attr, char *buf) ++ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf) + { + if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1)) + return sprintf(buf, "Not affected\n"); + return sprintf(buf, "Mitigation: __user pointer sanitization\n"); + } + +-ssize_t cpu_show_spectre_v2(struct device *dev, +- struct device_attribute *attr, char *buf) ++ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf) + { + if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) + return sprintf(buf, "Not affected\n"); + +- return sprintf(buf, "%s%s%s\n", spectre_v2_strings[spectre_v2_enabled], ++ return sprintf(buf, "%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled], + boot_cpu_has(X86_FEATURE_USE_IBPB) ? ", IBPB" : "", ++ boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "", + spectre_v2_module_string()); + } + #endif +- +-void __ibp_barrier(void) +-{ +- __wrmsr(MSR_IA32_PRED_CMD, PRED_CMD_IBPB, 0); +-} +-EXPORT_SYMBOL_GPL(__ibp_barrier); +diff --git a/arch/x86/kernel/cpu/centaur.c b/arch/x86/kernel/cpu/centaur.c +index c578cd2..e5ec0f1 100644 +--- a/arch/x86/kernel/cpu/centaur.c ++++ b/arch/x86/kernel/cpu/centaur.c +@@ -140,7 +140,7 @@ static void init_centaur(struct cpuinfo_x86 *c) + clear_cpu_cap(c, X86_FEATURE_TSC); + break; + case 8: +- switch (c->x86_mask) { ++ switch (c->x86_stepping) { + default: + name = "2"; + break; +@@ -215,7 +215,7 @@ centaur_size_cache(struct cpuinfo_x86 *c, unsigned int size) + * - Note, it seems this may only be in engineering samples. + */ + if ((c->x86 == 6) && (c->x86_model == 9) && +- (c->x86_mask == 1) && (size == 65)) ++ (c->x86_stepping == 1) && (size == 65)) + size -= 1; + return size; + } +diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c +index d63f4b57..348cf48 100644 +--- a/arch/x86/kernel/cpu/common.c ++++ b/arch/x86/kernel/cpu/common.c +@@ -731,7 +731,7 @@ void cpu_detect(struct cpuinfo_x86 *c) + cpuid(0x00000001, &tfms, &misc, &junk, &cap0); + c->x86 = x86_family(tfms); + c->x86_model = x86_model(tfms); +- c->x86_mask = x86_stepping(tfms); ++ c->x86_stepping = x86_stepping(tfms); + + if (cap0 & (1<<19)) { + c->x86_clflush_size = ((misc >> 8) & 0xff) * 8; +@@ -1184,9 +1184,9 @@ static void identify_cpu(struct cpuinfo_x86 *c) + int i; + + c->loops_per_jiffy = loops_per_jiffy; +- c->x86_cache_size = -1; ++ c->x86_cache_size = 0; + c->x86_vendor = X86_VENDOR_UNKNOWN; +- c->x86_model = c->x86_mask = 0; /* So far unknown... */ ++ c->x86_model = c->x86_stepping = 0; /* So far unknown... */ + c->x86_vendor_id[0] = '\0'; /* Unset */ + c->x86_model_id[0] = '\0'; /* Unset */ + c->x86_max_cores = 1; +@@ -1378,8 +1378,8 @@ void print_cpu_info(struct cpuinfo_x86 *c) + + pr_cont(" (family: 0x%x, model: 0x%x", c->x86, c->x86_model); + +- if (c->x86_mask || c->cpuid_level >= 0) +- pr_cont(", stepping: 0x%x)\n", c->x86_mask); ++ if (c->x86_stepping || c->cpuid_level >= 0) ++ pr_cont(", stepping: 0x%x)\n", c->x86_stepping); + else + pr_cont(")\n"); + } +@@ -1749,3 +1749,33 @@ static int __init init_cpu_syscore(void) + return 0; + } + core_initcall(init_cpu_syscore); ++ ++/* ++ * The microcode loader calls this upon late microcode load to recheck features, ++ * only when microcode has been updated. Caller holds microcode_mutex and CPU ++ * hotplug lock. ++ */ ++void microcode_check(void) ++{ ++ struct cpuinfo_x86 info; ++ ++ perf_check_microcode(); ++ ++ /* Reload CPUID max function as it might've changed. */ ++ info.cpuid_level = cpuid_eax(0); ++ ++ /* ++ * Copy all capability leafs to pick up the synthetic ones so that ++ * memcmp() below doesn't fail on that. The ones coming from CPUID will ++ * get overwritten in get_cpu_cap(). ++ */ ++ memcpy(&info.x86_capability, &boot_cpu_data.x86_capability, sizeof(info.x86_capability)); ++ ++ get_cpu_cap(&info); ++ ++ if (!memcmp(&info.x86_capability, &boot_cpu_data.x86_capability, sizeof(info.x86_capability))) ++ return; ++ ++ pr_warn("x86/CPU: CPU features have changed after loading microcode, but might not take effect.\n"); ++ pr_warn("x86/CPU: Please consider either early loading through initrd/built-in or a potential BIOS update.\n"); ++} +diff --git a/arch/x86/kernel/cpu/cyrix.c b/arch/x86/kernel/cpu/cyrix.c +index 6b4bb33..8949b7a 100644 +--- a/arch/x86/kernel/cpu/cyrix.c ++++ b/arch/x86/kernel/cpu/cyrix.c +@@ -215,7 +215,7 @@ static void init_cyrix(struct cpuinfo_x86 *c) + + /* common case step number/rev -- exceptions handled below */ + c->x86_model = (dir1 >> 4) + 1; +- c->x86_mask = dir1 & 0xf; ++ c->x86_stepping = dir1 & 0xf; + + /* Now cook; the original recipe is by Channing Corn, from Cyrix. + * We do the same thing for each generation: we work out +diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c +index 319bf98..4aa9fd3 100644 +--- a/arch/x86/kernel/cpu/intel.c ++++ b/arch/x86/kernel/cpu/intel.c +@@ -116,14 +116,13 @@ struct sku_microcode { + u32 microcode; + }; + static const struct sku_microcode spectre_bad_microcodes[] = { +- { INTEL_FAM6_KABYLAKE_DESKTOP, 0x0B, 0x84 }, +- { INTEL_FAM6_KABYLAKE_DESKTOP, 0x0A, 0x84 }, +- { INTEL_FAM6_KABYLAKE_DESKTOP, 0x09, 0x84 }, +- { INTEL_FAM6_KABYLAKE_MOBILE, 0x0A, 0x84 }, +- { INTEL_FAM6_KABYLAKE_MOBILE, 0x09, 0x84 }, ++ { INTEL_FAM6_KABYLAKE_DESKTOP, 0x0B, 0x80 }, ++ { INTEL_FAM6_KABYLAKE_DESKTOP, 0x0A, 0x80 }, ++ { INTEL_FAM6_KABYLAKE_DESKTOP, 0x09, 0x80 }, ++ { INTEL_FAM6_KABYLAKE_MOBILE, 0x0A, 0x80 }, ++ { INTEL_FAM6_KABYLAKE_MOBILE, 0x09, 0x80 }, + { INTEL_FAM6_SKYLAKE_X, 0x03, 0x0100013e }, + { INTEL_FAM6_SKYLAKE_X, 0x04, 0x0200003c }, +- { INTEL_FAM6_SKYLAKE_MOBILE, 0x03, 0xc2 }, + { INTEL_FAM6_SKYLAKE_DESKTOP, 0x03, 0xc2 }, + { INTEL_FAM6_BROADWELL_CORE, 0x04, 0x28 }, + { INTEL_FAM6_BROADWELL_GT3E, 0x01, 0x1b }, +@@ -136,8 +135,6 @@ static const struct sku_microcode spectre_bad_microcodes[] = { + { INTEL_FAM6_HASWELL_X, 0x02, 0x3b }, + { INTEL_FAM6_HASWELL_X, 0x04, 0x10 }, + { INTEL_FAM6_IVYBRIDGE_X, 0x04, 0x42a }, +- /* Updated in the 20180108 release; blacklist until we know otherwise */ +- { INTEL_FAM6_ATOM_GEMINI_LAKE, 0x01, 0x22 }, + /* Observed in the wild */ + { INTEL_FAM6_SANDYBRIDGE_X, 0x06, 0x61b }, + { INTEL_FAM6_SANDYBRIDGE_X, 0x07, 0x712 }, +@@ -147,9 +144,16 @@ static bool bad_spectre_microcode(struct cpuinfo_x86 *c) + { + int i; + ++ /* ++ * We know that the hypervisor lie to us on the microcode version so ++ * we may as well hope that it is running the correct version. ++ */ ++ if (cpu_has(c, X86_FEATURE_HYPERVISOR)) ++ return false; ++ + for (i = 0; i < ARRAY_SIZE(spectre_bad_microcodes); i++) { + if (c->x86_model == spectre_bad_microcodes[i].model && +- c->x86_mask == spectre_bad_microcodes[i].stepping) ++ c->x86_stepping == spectre_bad_microcodes[i].stepping) + return (c->microcode <= spectre_bad_microcodes[i].microcode); + } + return false; +@@ -196,7 +200,7 @@ static void early_init_intel(struct cpuinfo_x86 *c) + * need the microcode to have already been loaded... so if it is + * not, recommend a BIOS update and disable large pages. + */ +- if (c->x86 == 6 && c->x86_model == 0x1c && c->x86_mask <= 2 && ++ if (c->x86 == 6 && c->x86_model == 0x1c && c->x86_stepping <= 2 && + c->microcode < 0x20e) { + pr_warn("Atom PSE erratum detected, BIOS microcode update recommended\n"); + clear_cpu_cap(c, X86_FEATURE_PSE); +@@ -212,7 +216,7 @@ static void early_init_intel(struct cpuinfo_x86 *c) + + /* CPUID workaround for 0F33/0F34 CPU */ + if (c->x86 == 0xF && c->x86_model == 0x3 +- && (c->x86_mask == 0x3 || c->x86_mask == 0x4)) ++ && (c->x86_stepping == 0x3 || c->x86_stepping == 0x4)) + c->x86_phys_bits = 36; + + /* +@@ -310,7 +314,7 @@ int ppro_with_ram_bug(void) + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && + boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model == 1 && +- boot_cpu_data.x86_mask < 8) { ++ boot_cpu_data.x86_stepping < 8) { + pr_info("Pentium Pro with Errata#50 detected. Taking evasive action.\n"); + return 1; + } +@@ -327,7 +331,7 @@ static void intel_smp_check(struct cpuinfo_x86 *c) + * Mask B, Pentium, but not Pentium MMX + */ + if (c->x86 == 5 && +- c->x86_mask >= 1 && c->x86_mask <= 4 && ++ c->x86_stepping >= 1 && c->x86_stepping <= 4 && + c->x86_model <= 3) { + /* + * Remember we have B step Pentia with bugs +@@ -370,7 +374,7 @@ static void intel_workarounds(struct cpuinfo_x86 *c) + * SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until + * model 3 mask 3 + */ +- if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633) ++ if ((c->x86<<8 | c->x86_model<<4 | c->x86_stepping) < 0x633) + clear_cpu_cap(c, X86_FEATURE_SEP); + + /* +@@ -388,7 +392,7 @@ static void intel_workarounds(struct cpuinfo_x86 *c) + * P4 Xeon erratum 037 workaround. + * Hardware prefetcher may cause stale data to be loaded into the cache. + */ +- if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_mask == 1)) { ++ if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_stepping == 1)) { + if (msr_set_bit(MSR_IA32_MISC_ENABLE, + MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT) > 0) { + pr_info("CPU: C0 stepping P4 Xeon detected.\n"); +@@ -403,7 +407,7 @@ static void intel_workarounds(struct cpuinfo_x86 *c) + * Specification Update"). + */ + if (boot_cpu_has(X86_FEATURE_APIC) && (c->x86<<8 | c->x86_model<<4) == 0x520 && +- (c->x86_mask < 0x6 || c->x86_mask == 0xb)) ++ (c->x86_stepping < 0x6 || c->x86_stepping == 0xb)) + set_cpu_bug(c, X86_BUG_11AP); + + +@@ -650,7 +654,7 @@ static void init_intel(struct cpuinfo_x86 *c) + case 6: + if (l2 == 128) + p = "Celeron (Mendocino)"; +- else if (c->x86_mask == 0 || c->x86_mask == 5) ++ else if (c->x86_stepping == 0 || c->x86_stepping == 5) + p = "Celeron-A"; + break; + +diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c +index 410629f..589b948 100644 +--- a/arch/x86/kernel/cpu/intel_rdt.c ++++ b/arch/x86/kernel/cpu/intel_rdt.c +@@ -819,7 +819,7 @@ static __init void rdt_quirks(void) + cache_alloc_hsw_probe(); + break; + case INTEL_FAM6_SKYLAKE_X: +- if (boot_cpu_data.x86_mask <= 4) ++ if (boot_cpu_data.x86_stepping <= 4) + set_rdt_options("!cmt,!mbmtotal,!mbmlocal,!l3cat"); + } + } +diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c +index bdab7d2..fca759d 100644 +--- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c ++++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c +@@ -1804,6 +1804,7 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn, + goto out_common_fail; + } + closid = ret; ++ ret = 0; + + rdtgrp->closid = closid; + list_add(&rdtgrp->rdtgroup_list, &rdt_all_groups); +diff --git a/arch/x86/kernel/cpu/mcheck/mce-internal.h b/arch/x86/kernel/cpu/mcheck/mce-internal.h +index aa0d5df..e956eb2 100644 +--- a/arch/x86/kernel/cpu/mcheck/mce-internal.h ++++ b/arch/x86/kernel/cpu/mcheck/mce-internal.h +@@ -115,4 +115,19 @@ static inline void mce_unregister_injector_chain(struct notifier_block *nb) { } + + extern struct mca_config mca_cfg; + ++#ifndef CONFIG_X86_64 ++/* ++ * On 32-bit systems it would be difficult to safely unmap a poison page ++ * from the kernel 1:1 map because there are no non-canonical addresses that ++ * we can use to refer to the address without risking a speculative access. ++ * However, this isn't much of an issue because: ++ * 1) Few unmappable pages are in the 1:1 map. Most are in HIGHMEM which ++ * are only mapped into the kernel as needed ++ * 2) Few people would run a 32-bit kernel on a machine that supports ++ * recoverable errors because they have too much memory to boot 32-bit. ++ */ ++static inline void mce_unmap_kpfn(unsigned long pfn) {} ++#define mce_unmap_kpfn mce_unmap_kpfn ++#endif ++ + #endif /* __X86_MCE_INTERNAL_H__ */ +diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c +index 3a8e88a..466f473 100644 +--- a/arch/x86/kernel/cpu/mcheck/mce.c ++++ b/arch/x86/kernel/cpu/mcheck/mce.c +@@ -56,6 +56,9 @@ + + static DEFINE_MUTEX(mce_log_mutex); + ++/* sysfs synchronization */ ++static DEFINE_MUTEX(mce_sysfs_mutex); ++ + #define CREATE_TRACE_POINTS + #include + +@@ -105,6 +108,10 @@ static struct irq_work mce_irq_work; + + static void (*quirk_no_way_out)(int bank, struct mce *m, struct pt_regs *regs); + ++#ifndef mce_unmap_kpfn ++static void mce_unmap_kpfn(unsigned long pfn); ++#endif ++ + /* + * CPU/chipset specific EDAC code can register a notifier call here to print + * MCE errors in a human-readable form. +@@ -126,6 +133,8 @@ void mce_setup(struct mce *m) + + if (this_cpu_has(X86_FEATURE_INTEL_PPIN)) + rdmsrl(MSR_PPIN, m->ppin); ++ ++ m->microcode = boot_cpu_data.microcode; + } + + DEFINE_PER_CPU(struct mce, injectm); +@@ -234,7 +243,7 @@ static void __print_mce(struct mce *m) + m->cs, m->ip); + + if (m->cs == __KERNEL_CS) +- pr_cont("{%pS}", (void *)m->ip); ++ pr_cont("{%pS}", (void *)(unsigned long)m->ip); + pr_cont("\n"); + } + +@@ -258,7 +267,7 @@ static void __print_mce(struct mce *m) + */ + pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x microcode %x\n", + m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid, +- cpu_data(m->extcpu).microcode); ++ m->microcode); + } + + static void print_mce(struct mce *m) +@@ -590,7 +599,8 @@ static int srao_decode_notifier(struct notifier_block *nb, unsigned long val, + + if (mce_usable_address(mce) && (mce->severity == MCE_AO_SEVERITY)) { + pfn = mce->addr >> PAGE_SHIFT; +- memory_failure(pfn, 0); ++ if (!memory_failure(pfn, 0)) ++ mce_unmap_kpfn(pfn); + } + + return NOTIFY_OK; +@@ -1057,12 +1067,13 @@ static int do_memory_failure(struct mce *m) + ret = memory_failure(m->addr >> PAGE_SHIFT, flags); + if (ret) + pr_err("Memory error not recovered"); ++ else ++ mce_unmap_kpfn(m->addr >> PAGE_SHIFT); + return ret; + } + +-#if defined(arch_unmap_kpfn) && defined(CONFIG_MEMORY_FAILURE) +- +-void arch_unmap_kpfn(unsigned long pfn) ++#ifndef mce_unmap_kpfn ++static void mce_unmap_kpfn(unsigned long pfn) + { + unsigned long decoy_addr; + +@@ -1073,7 +1084,7 @@ void arch_unmap_kpfn(unsigned long pfn) + * We would like to just call: + * set_memory_np((unsigned long)pfn_to_kaddr(pfn), 1); + * but doing that would radically increase the odds of a +- * speculative access to the posion page because we'd have ++ * speculative access to the poison page because we'd have + * the virtual address of the kernel 1:1 mapping sitting + * around in registers. + * Instead we get tricky. We create a non-canonical address +@@ -1098,7 +1109,6 @@ void arch_unmap_kpfn(unsigned long pfn) + + if (set_memory_np(decoy_addr, 1)) + pr_warn("Could not invalidate pfn=0x%lx from 1:1 map\n", pfn); +- + } + #endif + +@@ -2081,6 +2091,7 @@ static ssize_t set_ignore_ce(struct device *s, + if (kstrtou64(buf, 0, &new) < 0) + return -EINVAL; + ++ mutex_lock(&mce_sysfs_mutex); + if (mca_cfg.ignore_ce ^ !!new) { + if (new) { + /* disable ce features */ +@@ -2093,6 +2104,8 @@ static ssize_t set_ignore_ce(struct device *s, + on_each_cpu(mce_enable_ce, (void *)1, 1); + } + } ++ mutex_unlock(&mce_sysfs_mutex); ++ + return size; + } + +@@ -2105,6 +2118,7 @@ static ssize_t set_cmci_disabled(struct device *s, + if (kstrtou64(buf, 0, &new) < 0) + return -EINVAL; + ++ mutex_lock(&mce_sysfs_mutex); + if (mca_cfg.cmci_disabled ^ !!new) { + if (new) { + /* disable cmci */ +@@ -2116,6 +2130,8 @@ static ssize_t set_cmci_disabled(struct device *s, + on_each_cpu(mce_enable_ce, NULL, 1); + } + } ++ mutex_unlock(&mce_sysfs_mutex); ++ + return size; + } + +@@ -2123,8 +2139,19 @@ static ssize_t store_int_with_restart(struct device *s, + struct device_attribute *attr, + const char *buf, size_t size) + { +- ssize_t ret = device_store_int(s, attr, buf, size); ++ unsigned long old_check_interval = check_interval; ++ ssize_t ret = device_store_ulong(s, attr, buf, size); ++ ++ if (check_interval == old_check_interval) ++ return ret; ++ ++ if (check_interval < 1) ++ check_interval = 1; ++ ++ mutex_lock(&mce_sysfs_mutex); + mce_restart(); ++ mutex_unlock(&mce_sysfs_mutex); ++ + return ret; + } + +diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c +index 330b846..a998e1a 100644 +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -498,7 +498,7 @@ static unsigned int verify_patch_size(u8 family, u32 patch_size, + return patch_size; + } + +-static int apply_microcode_amd(int cpu) ++static enum ucode_state apply_microcode_amd(int cpu) + { + struct cpuinfo_x86 *c = &cpu_data(cpu); + struct microcode_amd *mc_amd; +@@ -512,7 +512,7 @@ static int apply_microcode_amd(int cpu) + + p = find_patch(cpu); + if (!p) +- return 0; ++ return UCODE_NFOUND; + + mc_amd = p->data; + uci->mc = p->data; +@@ -523,13 +523,13 @@ static int apply_microcode_amd(int cpu) + if (rev >= mc_amd->hdr.patch_id) { + c->microcode = rev; + uci->cpu_sig.rev = rev; +- return 0; ++ return UCODE_OK; + } + + if (__apply_microcode_amd(mc_amd)) { + pr_err("CPU%d: update failed for patch_level=0x%08x\n", + cpu, mc_amd->hdr.patch_id); +- return -1; ++ return UCODE_ERROR; + } + pr_info("CPU%d: new patch_level=0x%08x\n", cpu, + mc_amd->hdr.patch_id); +@@ -537,7 +537,7 @@ static int apply_microcode_amd(int cpu) + uci->cpu_sig.rev = mc_amd->hdr.patch_id; + c->microcode = mc_amd->hdr.patch_id; + +- return 0; ++ return UCODE_UPDATED; + } + + static int install_equiv_cpu_table(const u8 *buf) +diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c +index 319dd65..70ecbc8 100644 +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -22,13 +22,16 @@ + #define pr_fmt(fmt) "microcode: " fmt + + #include ++#include + #include + #include + #include + #include + #include ++#include + #include + #include ++#include + #include + #include + +@@ -64,6 +67,11 @@ LIST_HEAD(microcode_cache); + */ + static DEFINE_MUTEX(microcode_mutex); + ++/* ++ * Serialize late loading so that CPUs get updated one-by-one. ++ */ ++static DEFINE_SPINLOCK(update_lock); ++ + struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; + + struct cpu_info_ctx { +@@ -373,26 +381,23 @@ static int collect_cpu_info(int cpu) + return ret; + } + +-struct apply_microcode_ctx { +- int err; +-}; +- + static void apply_microcode_local(void *arg) + { +- struct apply_microcode_ctx *ctx = arg; ++ enum ucode_state *err = arg; + +- ctx->err = microcode_ops->apply_microcode(smp_processor_id()); ++ *err = microcode_ops->apply_microcode(smp_processor_id()); + } + + static int apply_microcode_on_target(int cpu) + { +- struct apply_microcode_ctx ctx = { .err = 0 }; ++ enum ucode_state err; + int ret; + +- ret = smp_call_function_single(cpu, apply_microcode_local, &ctx, 1); +- if (!ret) +- ret = ctx.err; +- ++ ret = smp_call_function_single(cpu, apply_microcode_local, &err, 1); ++ if (!ret) { ++ if (err == UCODE_ERROR) ++ ret = 1; ++ } + return ret; + } + +@@ -489,31 +494,110 @@ static void __exit microcode_dev_exit(void) + /* fake device for request_firmware */ + static struct platform_device *microcode_pdev; + +-static int reload_for_cpu(int cpu) ++/* ++ * Late loading dance. Why the heavy-handed stomp_machine effort? ++ * ++ * - HT siblings must be idle and not execute other code while the other sibling ++ * is loading microcode in order to avoid any negative interactions caused by ++ * the loading. ++ * ++ * - In addition, microcode update on the cores must be serialized until this ++ * requirement can be relaxed in the future. Right now, this is conservative ++ * and good. ++ */ ++#define SPINUNIT 100 /* 100 nsec */ ++ ++static int check_online_cpus(void) + { +- struct ucode_cpu_info *uci = ucode_cpu_info + cpu; +- enum ucode_state ustate; +- int err = 0; ++ if (num_online_cpus() == num_present_cpus()) ++ return 0; + +- if (!uci->valid) +- return err; ++ pr_err("Not all CPUs online, aborting microcode update.\n"); + +- ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, true); +- if (ustate == UCODE_OK) +- apply_microcode_on_target(cpu); +- else +- if (ustate == UCODE_ERROR) +- err = -EINVAL; +- return err; ++ return -EINVAL; ++} ++ ++static atomic_t late_cpus; ++ ++/* ++ * Returns: ++ * < 0 - on error ++ * 0 - no update done ++ * 1 - microcode was updated ++ */ ++static int __reload_late(void *info) ++{ ++ unsigned int timeout = NSEC_PER_SEC; ++ int all_cpus = num_online_cpus(); ++ int cpu = smp_processor_id(); ++ enum ucode_state err; ++ int ret = 0; ++ ++ atomic_dec(&late_cpus); ++ ++ /* ++ * Wait for all CPUs to arrive. A load will not be attempted unless all ++ * CPUs show up. ++ * */ ++ while (atomic_read(&late_cpus)) { ++ if (timeout < SPINUNIT) { ++ pr_err("Timeout while waiting for CPUs rendezvous, remaining: %d\n", ++ atomic_read(&late_cpus)); ++ return -1; ++ } ++ ++ ndelay(SPINUNIT); ++ timeout -= SPINUNIT; ++ ++ touch_nmi_watchdog(); ++ } ++ ++ spin_lock(&update_lock); ++ apply_microcode_local(&err); ++ spin_unlock(&update_lock); ++ ++ if (err > UCODE_NFOUND) { ++ pr_warn("Error reloading microcode on CPU %d\n", cpu); ++ ret = -1; ++ } else if (err == UCODE_UPDATED) { ++ ret = 1; ++ } ++ ++ atomic_inc(&late_cpus); ++ ++ while (atomic_read(&late_cpus) != all_cpus) ++ cpu_relax(); ++ ++ return ret; ++} ++ ++/* ++ * Reload microcode late on all CPUs. Wait for a sec until they ++ * all gather together. ++ */ ++static int microcode_reload_late(void) ++{ ++ int ret; ++ ++ atomic_set(&late_cpus, num_online_cpus()); ++ ++ ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask); ++ if (ret < 0) ++ return ret; ++ else if (ret > 0) ++ microcode_check(); ++ ++ return ret; + } + + static ssize_t reload_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) + { ++ enum ucode_state tmp_ret = UCODE_OK; ++ int bsp = boot_cpu_data.cpu_index; + unsigned long val; +- int cpu; +- ssize_t ret = 0, tmp_ret; ++ ssize_t ret = 0; + + ret = kstrtoul(buf, 0, &val); + if (ret) +@@ -522,23 +606,24 @@ static ssize_t reload_store(struct device *dev, + if (val != 1) + return size; + ++ tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev, true); ++ if (tmp_ret != UCODE_OK) ++ return size; ++ + get_online_cpus(); +- mutex_lock(µcode_mutex); +- for_each_online_cpu(cpu) { +- tmp_ret = reload_for_cpu(cpu); +- if (tmp_ret != 0) +- pr_warn("Error reloading microcode on CPU %d\n", cpu); + +- /* save retval of the first encountered reload error */ +- if (!ret) +- ret = tmp_ret; +- } +- if (!ret) +- perf_check_microcode(); ++ ret = check_online_cpus(); ++ if (ret) ++ goto put; ++ ++ mutex_lock(µcode_mutex); ++ ret = microcode_reload_late(); + mutex_unlock(µcode_mutex); ++ ++put: + put_online_cpus(); + +- if (!ret) ++ if (ret >= 0) + ret = size; + + return ret; +diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c +index f7c55b0..2aded9d 100644 +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -589,6 +589,23 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early) + if (!mc) + return 0; + ++ /* ++ * Save us the MSR write below - which is a particular expensive ++ * operation - when the other hyperthread has updated the microcode ++ * already. ++ */ ++ rev = intel_get_microcode_revision(); ++ if (rev >= mc->hdr.rev) { ++ uci->cpu_sig.rev = rev; ++ return UCODE_OK; ++ } ++ ++ /* ++ * Writeback and invalidate caches before updating microcode to avoid ++ * internal issues depending on what the microcode is updating. ++ */ ++ native_wbinvd(); ++ + /* write microcode via MSR 0x79 */ + native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); + +@@ -772,27 +789,44 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) + return 0; + } + +-static int apply_microcode_intel(int cpu) ++static enum ucode_state apply_microcode_intel(int cpu) + { ++ struct ucode_cpu_info *uci = ucode_cpu_info + cpu; ++ struct cpuinfo_x86 *c = &cpu_data(cpu); + struct microcode_intel *mc; +- struct ucode_cpu_info *uci; +- struct cpuinfo_x86 *c; + static int prev_rev; + u32 rev; + + /* We should bind the task to the CPU */ + if (WARN_ON(raw_smp_processor_id() != cpu)) +- return -1; ++ return UCODE_ERROR; + +- uci = ucode_cpu_info + cpu; +- mc = uci->mc; ++ /* Look for a newer patch in our cache: */ ++ mc = find_patch(uci); + if (!mc) { +- /* Look for a newer patch in our cache: */ +- mc = find_patch(uci); ++ mc = uci->mc; + if (!mc) +- return 0; ++ return UCODE_NFOUND; + } + ++ /* ++ * Save us the MSR write below - which is a particular expensive ++ * operation - when the other hyperthread has updated the microcode ++ * already. ++ */ ++ rev = intel_get_microcode_revision(); ++ if (rev >= mc->hdr.rev) { ++ uci->cpu_sig.rev = rev; ++ c->microcode = rev; ++ return UCODE_OK; ++ } ++ ++ /* ++ * Writeback and invalidate caches before updating microcode to avoid ++ * internal issues depending on what the microcode is updating. ++ */ ++ native_wbinvd(); ++ + /* write microcode via MSR 0x79 */ + wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); + +@@ -801,7 +835,7 @@ static int apply_microcode_intel(int cpu) + if (rev != mc->hdr.rev) { + pr_err("CPU%d update to revision 0x%x failed\n", + cpu, mc->hdr.rev); +- return -1; ++ return UCODE_ERROR; + } + + if (rev != prev_rev) { +@@ -813,12 +847,10 @@ static int apply_microcode_intel(int cpu) + prev_rev = rev; + } + +- c = &cpu_data(cpu); +- + uci->cpu_sig.rev = rev; + c->microcode = rev; + +- return 0; ++ return UCODE_UPDATED; + } + + static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, +@@ -921,7 +953,7 @@ static bool is_blacklisted(unsigned int cpu) + */ + if (c->x86 == 6 && + c->x86_model == INTEL_FAM6_BROADWELL_X && +- c->x86_mask == 0x01 && ++ c->x86_stepping == 0x01 && + llc_size_per_core > 2621440 && + c->microcode < 0x0b000021) { + pr_err_once("Erratum BDF90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode); +@@ -944,7 +976,7 @@ static enum ucode_state request_microcode_fw(int cpu, struct device *device, + return UCODE_NFOUND; + + sprintf(name, "intel-ucode/%02x-%02x-%02x", +- c->x86, c->x86_model, c->x86_mask); ++ c->x86, c->x86_model, c->x86_stepping); + + if (request_firmware_direct(&firmware, name, device)) { + pr_debug("data file %s load failed\n", name); +@@ -982,7 +1014,7 @@ static struct microcode_ops microcode_intel_ops = { + + static int __init calc_llc_size_per_core(struct cpuinfo_x86 *c) + { +- u64 llc_size = c->x86_cache_size * 1024; ++ u64 llc_size = c->x86_cache_size * 1024ULL; + + do_div(llc_size, c->x86_max_cores); + +diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c +index fdc5521..e12ee86 100644 +--- a/arch/x86/kernel/cpu/mtrr/generic.c ++++ b/arch/x86/kernel/cpu/mtrr/generic.c +@@ -859,7 +859,7 @@ int generic_validate_add_page(unsigned long base, unsigned long size, + */ + if (is_cpu(INTEL) && boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model == 1 && +- boot_cpu_data.x86_mask <= 7) { ++ boot_cpu_data.x86_stepping <= 7) { + if (base & ((1 << (22 - PAGE_SHIFT)) - 1)) { + pr_warn("mtrr: base(0x%lx000) is not 4 MiB aligned\n", base); + return -EINVAL; +diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c +index 40d5a8a..7468de4 100644 +--- a/arch/x86/kernel/cpu/mtrr/main.c ++++ b/arch/x86/kernel/cpu/mtrr/main.c +@@ -711,8 +711,8 @@ void __init mtrr_bp_init(void) + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && + boot_cpu_data.x86 == 0xF && + boot_cpu_data.x86_model == 0x3 && +- (boot_cpu_data.x86_mask == 0x3 || +- boot_cpu_data.x86_mask == 0x4)) ++ (boot_cpu_data.x86_stepping == 0x3 || ++ boot_cpu_data.x86_stepping == 0x4)) + phys_addr = 36; + + size_or_mask = SIZE_OR_MASK_BITS(phys_addr); +diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c +index e7eceda..2c8522a 100644 +--- a/arch/x86/kernel/cpu/proc.c ++++ b/arch/x86/kernel/cpu/proc.c +@@ -72,8 +72,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) + c->x86_model, + c->x86_model_id[0] ? c->x86_model_id : "unknown"); + +- if (c->x86_mask || c->cpuid_level >= 0) +- seq_printf(m, "stepping\t: %d\n", c->x86_mask); ++ if (c->x86_stepping || c->cpuid_level >= 0) ++ seq_printf(m, "stepping\t: %d\n", c->x86_stepping); + else + seq_puts(m, "stepping\t: unknown\n"); + if (c->microcode) +@@ -91,8 +91,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) + } + + /* Cache size */ +- if (c->x86_cache_size >= 0) +- seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); ++ if (c->x86_cache_size) ++ seq_printf(m, "cache size\t: %u KB\n", c->x86_cache_size); + + show_cpuinfo_core(m, c, cpu); + show_cpuinfo_misc(m, c); +diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S +index c290209..b59e4fb 100644 +--- a/arch/x86/kernel/head_32.S ++++ b/arch/x86/kernel/head_32.S +@@ -37,7 +37,7 @@ + #define X86 new_cpu_data+CPUINFO_x86 + #define X86_VENDOR new_cpu_data+CPUINFO_x86_vendor + #define X86_MODEL new_cpu_data+CPUINFO_x86_model +-#define X86_MASK new_cpu_data+CPUINFO_x86_mask ++#define X86_STEPPING new_cpu_data+CPUINFO_x86_stepping + #define X86_HARD_MATH new_cpu_data+CPUINFO_hard_math + #define X86_CPUID new_cpu_data+CPUINFO_cpuid_level + #define X86_CAPABILITY new_cpu_data+CPUINFO_x86_capability +@@ -332,7 +332,7 @@ ENTRY(startup_32_smp) + shrb $4,%al + movb %al,X86_MODEL + andb $0x0f,%cl # mask mask revision +- movb %cl,X86_MASK ++ movb %cl,X86_STEPPING + movl %edx,X86_CAPABILITY + + .Lis486: +diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S +index 04a625f..0f545b3 100644 +--- a/arch/x86/kernel/head_64.S ++++ b/arch/x86/kernel/head_64.S +@@ -23,6 +23,7 @@ + #include + #include "../entry/calling.h" + #include ++#include + + #ifdef CONFIG_PARAVIRT + #include +@@ -134,6 +135,7 @@ ENTRY(secondary_startup_64) + + /* Ensure I am executing from virtual addresses */ + movq $1f, %rax ++ ANNOTATE_RETPOLINE_SAFE + jmp *%rax + 1: + UNWIND_HINT_EMPTY +diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c +index 2f72330..38deafe 100644 +--- a/arch/x86/kernel/ioport.c ++++ b/arch/x86/kernel/ioport.c +@@ -23,7 +23,7 @@ + /* + * this changes the io permissions bitmap in the current task. + */ +-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) ++SYSCALL_DEFINE3(ioperm, unsigned long, from, unsigned long, num, int, turn_on) + { + struct thread_struct *t = ¤t->thread; + struct tss_struct *tss; +diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c +index bd36f3c..0715f82 100644 +--- a/arch/x86/kernel/kprobes/core.c ++++ b/arch/x86/kernel/kprobes/core.c +@@ -1168,10 +1168,18 @@ NOKPROBE_SYMBOL(longjmp_break_handler); + + bool arch_within_kprobe_blacklist(unsigned long addr) + { ++ bool is_in_entry_trampoline_section = false; ++ ++#ifdef CONFIG_X86_64 ++ is_in_entry_trampoline_section = ++ (addr >= (unsigned long)__entry_trampoline_start && ++ addr < (unsigned long)__entry_trampoline_end); ++#endif + return (addr >= (unsigned long)__kprobes_text_start && + addr < (unsigned long)__kprobes_text_end) || + (addr >= (unsigned long)__entry_text_start && +- addr < (unsigned long)__entry_text_end); ++ addr < (unsigned long)__entry_text_end) || ++ is_in_entry_trampoline_section; + } + + int __init arch_init_kprobes(void) +diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c +index 4e37d1a..bc1a272 100644 +--- a/arch/x86/kernel/kvm.c ++++ b/arch/x86/kernel/kvm.c +@@ -49,7 +49,7 @@ + + static int kvmapf = 1; + +-static int parse_no_kvmapf(char *arg) ++static int __init parse_no_kvmapf(char *arg) + { + kvmapf = 0; + return 0; +@@ -58,7 +58,7 @@ static int parse_no_kvmapf(char *arg) + early_param("no-kvmapf", parse_no_kvmapf); + + static int steal_acc = 1; +-static int parse_no_stealacc(char *arg) ++static int __init parse_no_stealacc(char *arg) + { + steal_acc = 0; + return 0; +@@ -67,7 +67,7 @@ static int parse_no_stealacc(char *arg) + early_param("no-steal-acc", parse_no_stealacc); + + static int kvmclock_vsyscall = 1; +-static int parse_no_kvmclock_vsyscall(char *arg) ++static int __init parse_no_kvmclock_vsyscall(char *arg) + { + kvmclock_vsyscall = 0; + return 0; +@@ -341,10 +341,10 @@ static void kvm_guest_cpu_init(void) + #endif + pa |= KVM_ASYNC_PF_ENABLED; + +- /* Async page fault support for L1 hypervisor is optional */ +- if (wrmsr_safe(MSR_KVM_ASYNC_PF_EN, +- (pa | KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT) & 0xffffffff, pa >> 32) < 0) +- wrmsrl(MSR_KVM_ASYNC_PF_EN, pa); ++ if (kvm_para_has_feature(KVM_FEATURE_ASYNC_PF_VMEXIT)) ++ pa |= KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT; ++ ++ wrmsrl(MSR_KVM_ASYNC_PF_EN, pa); + __this_cpu_write(apf_reason.enabled, 1); + printk(KERN_INFO"KVM setup async PF for cpu %d\n", + smp_processor_id()); +@@ -545,7 +545,8 @@ static void __init kvm_guest_init(void) + pv_time_ops.steal_clock = kvm_steal_clock; + } + +- if (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH)) ++ if (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH) && ++ !kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) + pv_mmu_ops.flush_tlb_others = kvm_flush_tlb_others; + + if (kvm_para_has_feature(KVM_FEATURE_PV_EOI)) +@@ -633,7 +634,8 @@ static __init int kvm_setup_pv_tlb_flush(void) + { + int cpu; + +- if (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH)) { ++ if (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH) && ++ !kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) { + for_each_possible_cpu(cpu) { + zalloc_cpumask_var_node(per_cpu_ptr(&__pv_tlb_mask, cpu), + GFP_KERNEL, cpu_to_node(cpu)); +diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c +index 1f790cf..3b7427a 100644 +--- a/arch/x86/kernel/machine_kexec_64.c ++++ b/arch/x86/kernel/machine_kexec_64.c +@@ -542,6 +542,7 @@ int arch_kexec_apply_relocations_add(const Elf64_Ehdr *ehdr, + goto overflow; + break; + case R_X86_64_PC32: ++ case R_X86_64_PLT32: + value -= (u64)address; + *(u32 *)location = value; + break; +diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c +index da0c160..f58336a 100644 +--- a/arch/x86/kernel/module.c ++++ b/arch/x86/kernel/module.c +@@ -191,6 +191,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, + goto overflow; + break; + case R_X86_64_PC32: ++ case R_X86_64_PLT32: + if (*(u32 *)loc != 0) + goto invalid_relocation; + val -= (u64)loc; +diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c +index 27d0a17..f1c5eb9 100644 +--- a/arch/x86/kernel/mpparse.c ++++ b/arch/x86/kernel/mpparse.c +@@ -410,7 +410,7 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type) + processor.apicver = mpc_default_type > 4 ? 0x10 : 0x01; + processor.cpuflag = CPU_ENABLED; + processor.cpufeature = (boot_cpu_data.x86 << 8) | +- (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask; ++ (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_stepping; + processor.featureflag = boot_cpu_data.x86_capability[CPUID_1_EDX]; + processor.reserved[0] = 0; + processor.reserved[1] = 0; +diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c +index 041096b..99dc79e 100644 +--- a/arch/x86/kernel/paravirt.c ++++ b/arch/x86/kernel/paravirt.c +@@ -200,9 +200,9 @@ static void native_flush_tlb_global(void) + __native_flush_tlb_global(); + } + +-static void native_flush_tlb_single(unsigned long addr) ++static void native_flush_tlb_one_user(unsigned long addr) + { +- __native_flush_tlb_single(addr); ++ __native_flush_tlb_one_user(addr); + } + + struct static_key paravirt_steal_enabled; +@@ -401,7 +401,7 @@ struct pv_mmu_ops pv_mmu_ops __ro_after_init = { + + .flush_tlb_user = native_flush_tlb, + .flush_tlb_kernel = native_flush_tlb_global, +- .flush_tlb_single = native_flush_tlb_single, ++ .flush_tlb_one_user = native_flush_tlb_one_user, + .flush_tlb_others = native_flush_tlb_others, + + .pgd_alloc = __paravirt_pgd_alloc, +diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c +index 1ae67e9..4c616be 100644 +--- a/arch/x86/kernel/setup.c ++++ b/arch/x86/kernel/setup.c +@@ -1204,20 +1204,13 @@ void __init setup_arch(char **cmdline_p) + + kasan_init(); + +-#ifdef CONFIG_X86_32 +- /* sync back kernel address range */ +- clone_pgd_range(initial_page_table + KERNEL_PGD_BOUNDARY, +- swapper_pg_dir + KERNEL_PGD_BOUNDARY, +- KERNEL_PGD_PTRS); +- + /* +- * sync back low identity map too. It is used for example +- * in the 32-bit EFI stub. ++ * Sync back kernel address range. ++ * ++ * FIXME: Can the later sync in setup_cpu_entry_areas() replace ++ * this call? + */ +- clone_pgd_range(initial_page_table, +- swapper_pg_dir + KERNEL_PGD_BOUNDARY, +- min(KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY)); +-#endif ++ sync_initial_page_table(); + + tboot_probe(); + +diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c +index 497aa76..ea554f8 100644 +--- a/arch/x86/kernel/setup_percpu.c ++++ b/arch/x86/kernel/setup_percpu.c +@@ -287,24 +287,15 @@ void __init setup_per_cpu_areas(void) + /* Setup cpu initialized, callin, callout masks */ + setup_cpu_local_masks(); + +-#ifdef CONFIG_X86_32 + /* + * Sync back kernel address range again. We already did this in + * setup_arch(), but percpu data also needs to be available in + * the smpboot asm. We can't reliably pick up percpu mappings + * using vmalloc_fault(), because exception dispatch needs + * percpu data. ++ * ++ * FIXME: Can the later sync in setup_cpu_entry_areas() replace ++ * this call? + */ +- clone_pgd_range(initial_page_table + KERNEL_PGD_BOUNDARY, +- swapper_pg_dir + KERNEL_PGD_BOUNDARY, +- KERNEL_PGD_PTRS); +- +- /* +- * sync back low identity map too. It is used for example +- * in the 32-bit EFI stub. +- */ +- clone_pgd_range(initial_page_table, +- swapper_pg_dir + KERNEL_PGD_BOUNDARY, +- min(KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY)); +-#endif ++ sync_initial_page_table(); + } +diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c +index ac057f9..0d930d8 100644 +--- a/arch/x86/kernel/signal_compat.c ++++ b/arch/x86/kernel/signal_compat.c +@@ -43,6 +43,13 @@ static inline void signal_compat_build_tests(void) + BUILD_BUG_ON(offsetof(compat_siginfo_t, _sifields) != 3 * sizeof(int)); + #define CHECK_CSI_OFFSET(name) BUILD_BUG_ON(_sifields_offset != offsetof(compat_siginfo_t, _sifields.name)) + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_signo) != 0); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_errno) != 4); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_code) != 8); ++ ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_signo) != 0); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_errno) != 4); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_code) != 8); + /* + * Ensure that the size of each si_field never changes. + * If it does, it is a sign that the +@@ -63,36 +70,94 @@ static inline void signal_compat_build_tests(void) + CHECK_CSI_SIZE (_kill, 2*sizeof(int)); + CHECK_SI_SIZE (_kill, 2*sizeof(int)); + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_pid) != 0x10); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_uid) != 0x14); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_pid) != 0xC); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_uid) != 0x10); ++ + CHECK_CSI_OFFSET(_timer); + CHECK_CSI_SIZE (_timer, 3*sizeof(int)); + CHECK_SI_SIZE (_timer, 6*sizeof(int)); + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_tid) != 0x10); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_overrun) != 0x14); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_value) != 0x18); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_tid) != 0x0C); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_overrun) != 0x10); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_value) != 0x14); ++ + CHECK_CSI_OFFSET(_rt); + CHECK_CSI_SIZE (_rt, 3*sizeof(int)); + CHECK_SI_SIZE (_rt, 4*sizeof(int)); + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_pid) != 0x10); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_uid) != 0x14); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_value) != 0x18); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_pid) != 0x0C); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_uid) != 0x10); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_value) != 0x14); ++ + CHECK_CSI_OFFSET(_sigchld); + CHECK_CSI_SIZE (_sigchld, 5*sizeof(int)); + CHECK_SI_SIZE (_sigchld, 8*sizeof(int)); + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_pid) != 0x10); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_uid) != 0x14); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_status) != 0x18); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_utime) != 0x20); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_stime) != 0x28); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_pid) != 0x0C); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_uid) != 0x10); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_status) != 0x14); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_utime) != 0x18); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_stime) != 0x1C); ++ + #ifdef CONFIG_X86_X32_ABI + CHECK_CSI_OFFSET(_sigchld_x32); + CHECK_CSI_SIZE (_sigchld_x32, 7*sizeof(int)); + /* no _sigchld_x32 in the generic siginfo_t */ ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, _sifields._sigchld_x32._utime) != 0x18); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, _sifields._sigchld_x32._stime) != 0x20); + #endif + + CHECK_CSI_OFFSET(_sigfault); + CHECK_CSI_SIZE (_sigfault, 4*sizeof(int)); + CHECK_SI_SIZE (_sigfault, 8*sizeof(int)); + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_addr) != 0x10); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_addr) != 0x0C); ++ ++ BUILD_BUG_ON(offsetof(siginfo_t, si_addr_lsb) != 0x18); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_addr_lsb) != 0x10); ++ ++ BUILD_BUG_ON(offsetof(siginfo_t, si_lower) != 0x20); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_upper) != 0x28); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_lower) != 0x14); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_upper) != 0x18); ++ ++ BUILD_BUG_ON(offsetof(siginfo_t, si_pkey) != 0x20); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_pkey) != 0x14); ++ + CHECK_CSI_OFFSET(_sigpoll); + CHECK_CSI_SIZE (_sigpoll, 2*sizeof(int)); + CHECK_SI_SIZE (_sigpoll, 4*sizeof(int)); + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_band) != 0x10); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_fd) != 0x18); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_band) != 0x0C); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_fd) != 0x10); ++ + CHECK_CSI_OFFSET(_sigsys); + CHECK_CSI_SIZE (_sigsys, 3*sizeof(int)); + CHECK_SI_SIZE (_sigsys, 4*sizeof(int)); + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_call_addr) != 0x10); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_syscall) != 0x18); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_arch) != 0x1C); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_call_addr) != 0x0C); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_syscall) != 0x10); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_arch) != 0x14); ++ + /* any new si_fields should be added here */ + } + +diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c +index 6f27fac..ff99e2b 100644 +--- a/arch/x86/kernel/smpboot.c ++++ b/arch/x86/kernel/smpboot.c +@@ -1281,11 +1281,10 @@ void __init native_smp_prepare_boot_cpu(void) + cpu_set_state_online(me); + } + +-void __init native_smp_cpus_done(unsigned int max_cpus) ++void __init calculate_max_logical_packages(void) + { + int ncpus; + +- pr_debug("Boot done\n"); + /* + * Today neither Intel nor AMD support heterogenous systems so + * extrapolate the boot cpu's data to all packages. +@@ -1293,6 +1292,13 @@ void __init native_smp_cpus_done(unsigned int max_cpus) + ncpus = cpu_data(0).booted_cores * topology_max_smt_threads(); + __max_logical_packages = DIV_ROUND_UP(nr_cpu_ids, ncpus); + pr_info("Max logical packages: %u\n", __max_logical_packages); ++} ++ ++void __init native_smp_cpus_done(unsigned int max_cpus) ++{ ++ pr_debug("Boot done\n"); ++ ++ calculate_max_logical_packages(); + + if (x86_has_numa_in_package) + set_sched_topology(x86_numa_in_package_topology); +@@ -1430,8 +1436,8 @@ static void remove_siblinginfo(int cpu) + cpumask_clear(cpu_llc_shared_mask(cpu)); + cpumask_clear(topology_sibling_cpumask(cpu)); + cpumask_clear(topology_core_cpumask(cpu)); +- c->phys_proc_id = 0; + c->cpu_core_id = 0; ++ c->booted_cores = 0; + cpumask_clear_cpu(cpu, cpu_sibling_setup_mask); + recompute_smt_state(); + } +diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c +index 446c9ef..3d9b230 100644 +--- a/arch/x86/kernel/traps.c ++++ b/arch/x86/kernel/traps.c +@@ -181,7 +181,7 @@ int fixup_bug(struct pt_regs *regs, int trapnr) + break; + + case BUG_TRAP_TYPE_WARN: +- regs->ip += LEN_UD0; ++ regs->ip += LEN_UD2; + return 1; + } + +diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c +index 1f9188f..feb28fe 100644 +--- a/arch/x86/kernel/unwind_orc.c ++++ b/arch/x86/kernel/unwind_orc.c +@@ -5,7 +5,6 @@ + #include + #include + #include +-#include + + #define orc_warn(fmt, ...) \ + printk_deferred_once(KERN_WARNING pr_fmt("WARNING: " fmt), ##__VA_ARGS__) +@@ -148,7 +147,7 @@ static struct orc_entry *orc_find(unsigned long ip) + } + + /* vmlinux .init slow lookup: */ +- if (ip >= (unsigned long)_sinittext && ip < (unsigned long)_einittext) ++ if (init_kernel_text(ip)) + return __orc_find(__start_orc_unwind_ip, __start_orc_unwind, + __stop_orc_unwind_ip - __start_orc_unwind_ip, ip); + +diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S +index 9b138a0..b854ebf 100644 +--- a/arch/x86/kernel/vmlinux.lds.S ++++ b/arch/x86/kernel/vmlinux.lds.S +@@ -118,9 +118,11 @@ SECTIONS + + #ifdef CONFIG_X86_64 + . = ALIGN(PAGE_SIZE); ++ VMLINUX_SYMBOL(__entry_trampoline_start) = .; + _entry_trampoline = .; + *(.entry_trampoline) + . = ALIGN(PAGE_SIZE); ++ VMLINUX_SYMBOL(__entry_trampoline_end) = .; + ASSERT(. - _entry_trampoline == PAGE_SIZE, "entry trampoline is too big"); + #endif + +diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c +index a0c5a69..b671fc2 100644 +--- a/arch/x86/kvm/cpuid.c ++++ b/arch/x86/kvm/cpuid.c +@@ -607,7 +607,8 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, + (1 << KVM_FEATURE_PV_EOI) | + (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT) | + (1 << KVM_FEATURE_PV_UNHALT) | +- (1 << KVM_FEATURE_PV_TLB_FLUSH); ++ (1 << KVM_FEATURE_PV_TLB_FLUSH) | ++ (1 << KVM_FEATURE_ASYNC_PF_VMEXIT); + + if (sched_info_on()) + entry->eax |= (1 << KVM_FEATURE_STEAL_TIME); +diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c +index 924ac8c..391dda8 100644 +--- a/arch/x86/kvm/lapic.c ++++ b/arch/x86/kvm/lapic.c +@@ -2002,14 +2002,13 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) + + void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event) + { +- struct kvm_lapic *apic; ++ struct kvm_lapic *apic = vcpu->arch.apic; + int i; + +- apic_debug("%s\n", __func__); ++ if (!apic) ++ return; + +- ASSERT(vcpu); +- apic = vcpu->arch.apic; +- ASSERT(apic != NULL); ++ apic_debug("%s\n", __func__); + + /* Stop the timer in case it's a reset to an active apic */ + hrtimer_cancel(&apic->lapic_timer.timer); +@@ -2165,7 +2164,6 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu) + */ + vcpu->arch.apic_base = MSR_IA32_APICBASE_ENABLE; + static_key_slow_inc(&apic_sw_disabled.key); /* sw disabled at reset */ +- kvm_lapic_reset(vcpu, false); + kvm_iodevice_init(&apic->dev, &apic_mmio_ops); + + return 0; +@@ -2569,7 +2567,6 @@ void kvm_apic_accept_events(struct kvm_vcpu *vcpu) + + pe = xchg(&apic->pending_events, 0); + if (test_bit(KVM_APIC_INIT, &pe)) { +- kvm_lapic_reset(vcpu, true); + kvm_vcpu_reset(vcpu, true); + if (kvm_vcpu_is_bsp(apic->vcpu)) + vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; +diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c +index 8eca1d0..f551962 100644 +--- a/arch/x86/kvm/mmu.c ++++ b/arch/x86/kvm/mmu.c +@@ -3029,7 +3029,7 @@ static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn) + return RET_PF_RETRY; + } + +- return -EFAULT; ++ return RET_PF_EMULATE; + } + + static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu, +@@ -5080,7 +5080,7 @@ void kvm_mmu_uninit_vm(struct kvm *kvm) + typedef bool (*slot_level_handler) (struct kvm *kvm, struct kvm_rmap_head *rmap_head); + + /* The caller should hold mmu-lock before calling this function. */ +-static bool ++static __always_inline bool + slot_handle_level_range(struct kvm *kvm, struct kvm_memory_slot *memslot, + slot_level_handler fn, int start_level, int end_level, + gfn_t start_gfn, gfn_t end_gfn, bool lock_flush_tlb) +@@ -5110,7 +5110,7 @@ slot_handle_level_range(struct kvm *kvm, struct kvm_memory_slot *memslot, + return flush; + } + +-static bool ++static __always_inline bool + slot_handle_level(struct kvm *kvm, struct kvm_memory_slot *memslot, + slot_level_handler fn, int start_level, int end_level, + bool lock_flush_tlb) +@@ -5121,7 +5121,7 @@ slot_handle_level(struct kvm *kvm, struct kvm_memory_slot *memslot, + lock_flush_tlb); + } + +-static bool ++static __always_inline bool + slot_handle_all_level(struct kvm *kvm, struct kvm_memory_slot *memslot, + slot_level_handler fn, bool lock_flush_tlb) + { +@@ -5129,7 +5129,7 @@ slot_handle_all_level(struct kvm *kvm, struct kvm_memory_slot *memslot, + PT_MAX_HUGEPAGE_LEVEL, lock_flush_tlb); + } + +-static bool ++static __always_inline bool + slot_handle_large_level(struct kvm *kvm, struct kvm_memory_slot *memslot, + slot_level_handler fn, bool lock_flush_tlb) + { +@@ -5137,7 +5137,7 @@ slot_handle_large_level(struct kvm *kvm, struct kvm_memory_slot *memslot, + PT_MAX_HUGEPAGE_LEVEL, lock_flush_tlb); + } + +-static bool ++static __always_inline bool + slot_handle_leaf(struct kvm *kvm, struct kvm_memory_slot *memslot, + slot_level_handler fn, bool lock_flush_tlb) + { +diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c +index b3e488a..be9c839 100644 +--- a/arch/x86/kvm/svm.c ++++ b/arch/x86/kvm/svm.c +@@ -49,6 +49,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -178,6 +179,8 @@ struct vcpu_svm { + uint64_t sysenter_eip; + uint64_t tsc_aux; + ++ u64 msr_decfg; ++ + u64 next_rip; + + u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS]; +@@ -300,6 +303,8 @@ module_param(vgif, int, 0444); + static int sev = IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT); + module_param(sev, int, 0444); + ++static u8 rsm_ins_bytes[] = "\x0f\xaa"; ++ + static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); + static void svm_flush_tlb(struct kvm_vcpu *vcpu, bool invalidate_gpa); + static void svm_complete_interrupts(struct vcpu_svm *svm); +@@ -1383,6 +1388,7 @@ static void init_vmcb(struct vcpu_svm *svm) + set_intercept(svm, INTERCEPT_SKINIT); + set_intercept(svm, INTERCEPT_WBINVD); + set_intercept(svm, INTERCEPT_XSETBV); ++ set_intercept(svm, INTERCEPT_RSM); + + if (!kvm_mwait_in_guest()) { + set_intercept(svm, INTERCEPT_MONITOR); +@@ -1902,6 +1908,7 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) + u32 dummy; + u32 eax = 1; + ++ vcpu->arch.microcode_version = 0x01000065; + svm->spec_ctrl = 0; + + if (!init_event) { +@@ -3699,6 +3706,12 @@ static int emulate_on_interception(struct vcpu_svm *svm) + return emulate_instruction(&svm->vcpu, 0) == EMULATE_DONE; + } + ++static int rsm_interception(struct vcpu_svm *svm) ++{ ++ return x86_emulate_instruction(&svm->vcpu, 0, 0, ++ rsm_ins_bytes, 2) == EMULATE_DONE; ++} ++ + static int rdpmc_interception(struct vcpu_svm *svm) + { + int err; +@@ -3860,6 +3873,22 @@ static int cr8_write_interception(struct vcpu_svm *svm) + return 0; + } + ++static int svm_get_msr_feature(struct kvm_msr_entry *msr) ++{ ++ msr->data = 0; ++ ++ switch (msr->index) { ++ case MSR_F10H_DECFG: ++ if (boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) ++ msr->data |= MSR_F10H_DECFG_LFENCE_SERIALIZE; ++ break; ++ default: ++ return 1; ++ } ++ ++ return 0; ++} ++ + static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + { + struct vcpu_svm *svm = to_svm(vcpu); +@@ -3935,9 +3964,6 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + + msr_info->data = svm->spec_ctrl; + break; +- case MSR_IA32_UCODE_REV: +- msr_info->data = 0x01000065; +- break; + case MSR_F15H_IC_CFG: { + + int family, model; +@@ -3955,6 +3981,9 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + msr_info->data = 0x1E; + } + break; ++ case MSR_F10H_DECFG: ++ msr_info->data = svm->msr_decfg; ++ break; + default: + return kvm_get_msr_common(vcpu, msr_info); + } +@@ -4133,6 +4162,24 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) + case MSR_VM_IGNNE: + vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data); + break; ++ case MSR_F10H_DECFG: { ++ struct kvm_msr_entry msr_entry; ++ ++ msr_entry.index = msr->index; ++ if (svm_get_msr_feature(&msr_entry)) ++ return 1; ++ ++ /* Check the supported bits */ ++ if (data & ~msr_entry.data) ++ return 1; ++ ++ /* Don't allow the guest to change a bit, #GP */ ++ if (!msr->host_initiated && (data ^ msr_entry.data)) ++ return 1; ++ ++ svm->msr_decfg = data; ++ break; ++ } + case MSR_IA32_APICBASE: + if (kvm_vcpu_apicv_active(vcpu)) + avic_update_vapic_bar(to_svm(vcpu), data); +@@ -4541,7 +4588,7 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = { + [SVM_EXIT_MWAIT] = mwait_interception, + [SVM_EXIT_XSETBV] = xsetbv_interception, + [SVM_EXIT_NPF] = npf_interception, +- [SVM_EXIT_RSM] = emulate_on_interception, ++ [SVM_EXIT_RSM] = rsm_interception, + [SVM_EXIT_AVIC_INCOMPLETE_IPI] = avic_incomplete_ipi_interception, + [SVM_EXIT_AVIC_UNACCELERATED_ACCESS] = avic_unaccelerated_access_interception, + }; +@@ -5355,7 +5402,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) + * being speculatively taken. + */ + if (svm->spec_ctrl) +- wrmsrl(MSR_IA32_SPEC_CTRL, svm->spec_ctrl); ++ native_wrmsrl(MSR_IA32_SPEC_CTRL, svm->spec_ctrl); + + asm volatile ( + "push %%" _ASM_BP "; \n\t" +@@ -5464,11 +5511,11 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) + * If the L02 MSR bitmap does not intercept the MSR, then we need to + * save it. + */ +- if (!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL)) +- rdmsrl(MSR_IA32_SPEC_CTRL, svm->spec_ctrl); ++ if (unlikely(!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))) ++ svm->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL); + + if (svm->spec_ctrl) +- wrmsrl(MSR_IA32_SPEC_CTRL, 0); ++ native_wrmsrl(MSR_IA32_SPEC_CTRL, 0); + + /* Eliminate branch target predictions from guest mode */ + vmexit_fill_RSB(); +@@ -6236,16 +6283,18 @@ static int sev_launch_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp) + + static int sev_launch_measure(struct kvm *kvm, struct kvm_sev_cmd *argp) + { ++ void __user *measure = (void __user *)(uintptr_t)argp->data; + struct kvm_sev_info *sev = &kvm->arch.sev_info; + struct sev_data_launch_measure *data; + struct kvm_sev_launch_measure params; ++ void __user *p = NULL; + void *blob = NULL; + int ret; + + if (!sev_guest(kvm)) + return -ENOTTY; + +- if (copy_from_user(¶ms, (void __user *)(uintptr_t)argp->data, sizeof(params))) ++ if (copy_from_user(¶ms, measure, sizeof(params))) + return -EFAULT; + + data = kzalloc(sizeof(*data), GFP_KERNEL); +@@ -6256,17 +6305,13 @@ static int sev_launch_measure(struct kvm *kvm, struct kvm_sev_cmd *argp) + if (!params.len) + goto cmd; + +- if (params.uaddr) { ++ p = (void __user *)(uintptr_t)params.uaddr; ++ if (p) { + if (params.len > SEV_FW_BLOB_MAX_SIZE) { + ret = -EINVAL; + goto e_free; + } + +- if (!access_ok(VERIFY_WRITE, params.uaddr, params.len)) { +- ret = -EFAULT; +- goto e_free; +- } +- + ret = -ENOMEM; + blob = kmalloc(params.len, GFP_KERNEL); + if (!blob) +@@ -6290,13 +6335,13 @@ static int sev_launch_measure(struct kvm *kvm, struct kvm_sev_cmd *argp) + goto e_free_blob; + + if (blob) { +- if (copy_to_user((void __user *)(uintptr_t)params.uaddr, blob, params.len)) ++ if (copy_to_user(p, blob, params.len)) + ret = -EFAULT; + } + + done: + params.len = data->len; +- if (copy_to_user((void __user *)(uintptr_t)argp->data, ¶ms, sizeof(params))) ++ if (copy_to_user(measure, ¶ms, sizeof(params))) + ret = -EFAULT; + e_free_blob: + kfree(blob); +@@ -6597,7 +6642,7 @@ static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp) + struct page **pages; + void *blob, *hdr; + unsigned long n; +- int ret; ++ int ret, offset; + + if (!sev_guest(kvm)) + return -ENOTTY; +@@ -6623,6 +6668,10 @@ static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp) + if (!data) + goto e_unpin_memory; + ++ offset = params.guest_uaddr & (PAGE_SIZE - 1); ++ data->guest_address = __sme_page_pa(pages[0]) + offset; ++ data->guest_len = params.guest_len; ++ + blob = psp_copy_user_blob(params.trans_uaddr, params.trans_len); + if (IS_ERR(blob)) { + ret = PTR_ERR(blob); +@@ -6637,8 +6686,8 @@ static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp) + ret = PTR_ERR(hdr); + goto e_free_blob; + } +- data->trans_address = __psp_pa(blob); +- data->trans_len = params.trans_len; ++ data->hdr_address = __psp_pa(hdr); ++ data->hdr_len = params.hdr_len; + + data->handle = sev->handle; + ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_SECRET, data, &argp->error); +@@ -6821,6 +6870,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = { + .vcpu_unblocking = svm_vcpu_unblocking, + + .update_bp_intercept = update_bp_intercept, ++ .get_msr_feature = svm_get_msr_feature, + .get_msr = svm_get_msr, + .set_msr = svm_set_msr, + .get_segment_base = svm_get_segment_base, +diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c +index f427723..051dab7 100644 +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -51,6 +51,7 @@ + #include + #include + #include ++#include + #include + + #include "trace.h" +@@ -3226,6 +3227,11 @@ static inline bool vmx_feature_control_msr_valid(struct kvm_vcpu *vcpu, + return !(val & ~valid_bits); + } + ++static int vmx_get_msr_feature(struct kvm_msr_entry *msr) ++{ ++ return 1; ++} ++ + /* + * Reads an msr value (of 'msr_index') into 'pdata'. + * Returns 0 on success, non-0 otherwise. +@@ -4485,7 +4491,8 @@ static int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) + vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL, + SECONDARY_EXEC_DESC); + hw_cr4 &= ~X86_CR4_UMIP; +- } else ++ } else if (!is_guest_mode(vcpu) || ++ !nested_cpu_has2(get_vmcs12(vcpu), SECONDARY_EXEC_DESC)) + vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL, + SECONDARY_EXEC_DESC); + +@@ -5765,6 +5772,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) + vmx->rmode.vm86_active = 0; + vmx->spec_ctrl = 0; + ++ vcpu->arch.microcode_version = 0x100000000ULL; + vmx->vcpu.arch.regs[VCPU_REGS_RDX] = get_rdx_init_val(); + kvm_set_cr8(vcpu, 0); + +@@ -9452,7 +9460,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) + * being speculatively taken. + */ + if (vmx->spec_ctrl) +- wrmsrl(MSR_IA32_SPEC_CTRL, vmx->spec_ctrl); ++ native_wrmsrl(MSR_IA32_SPEC_CTRL, vmx->spec_ctrl); + + vmx->__launched = vmx->loaded_vmcs->launched; + asm( +@@ -9587,11 +9595,11 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) + * If the L02 MSR bitmap does not intercept the MSR, then we need to + * save it. + */ +- if (!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL)) +- rdmsrl(MSR_IA32_SPEC_CTRL, vmx->spec_ctrl); ++ if (unlikely(!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))) ++ vmx->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL); + + if (vmx->spec_ctrl) +- wrmsrl(MSR_IA32_SPEC_CTRL, 0); ++ native_wrmsrl(MSR_IA32_SPEC_CTRL, 0); + + /* Eliminate branch target predictions from guest mode */ + vmexit_fill_RSB(); +@@ -10136,7 +10144,10 @@ static void nested_get_vmcs12_pages(struct kvm_vcpu *vcpu, + (unsigned long)(vmcs12->posted_intr_desc_addr & + (PAGE_SIZE - 1))); + } +- if (!nested_vmx_prepare_msr_bitmap(vcpu, vmcs12)) ++ if (nested_vmx_prepare_msr_bitmap(vcpu, vmcs12)) ++ vmcs_set_bits(CPU_BASED_VM_EXEC_CONTROL, ++ CPU_BASED_USE_MSR_BITMAPS); ++ else + vmcs_clear_bits(CPU_BASED_VM_EXEC_CONTROL, + CPU_BASED_USE_MSR_BITMAPS); + } +@@ -10224,8 +10235,8 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu, + * updated to reflect this when L1 (or its L2s) actually write to + * the MSR. + */ +- bool pred_cmd = msr_write_intercepted_l01(vcpu, MSR_IA32_PRED_CMD); +- bool spec_ctrl = msr_write_intercepted_l01(vcpu, MSR_IA32_SPEC_CTRL); ++ bool pred_cmd = !msr_write_intercepted_l01(vcpu, MSR_IA32_PRED_CMD); ++ bool spec_ctrl = !msr_write_intercepted_l01(vcpu, MSR_IA32_SPEC_CTRL); + + /* Nothing to do if the MSR bitmap is not in use. */ + if (!cpu_has_vmx_msr_bitmap() || +@@ -11196,7 +11207,12 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) + if (ret) + return ret; + +- if (vmcs12->guest_activity_state == GUEST_ACTIVITY_HLT) ++ /* ++ * If we're entering a halted L2 vcpu and the L2 vcpu won't be woken ++ * by event injection, halt vcpu. ++ */ ++ if ((vmcs12->guest_activity_state == GUEST_ACTIVITY_HLT) && ++ !(vmcs12->vm_entry_intr_info_field & INTR_INFO_VALID_MASK)) + return kvm_vcpu_halt(vcpu); + + vmx->nested.nested_run_pending = 1; +@@ -12287,6 +12303,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = { + .vcpu_put = vmx_vcpu_put, + + .update_bp_intercept = update_exception_bitmap, ++ .get_msr_feature = vmx_get_msr_feature, + .get_msr = vmx_get_msr, + .set_msr = vmx_set_msr, + .get_segment_base = vmx_get_segment_base, +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index c8a0b54..18b5ca7 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -1049,6 +1049,45 @@ static u32 emulated_msrs[] = { + + static unsigned num_emulated_msrs; + ++/* ++ * List of msr numbers which are used to expose MSR-based features that ++ * can be used by a hypervisor to validate requested CPU features. ++ */ ++static u32 msr_based_features[] = { ++ MSR_F10H_DECFG, ++ MSR_IA32_UCODE_REV, ++}; ++ ++static unsigned int num_msr_based_features; ++ ++static int kvm_get_msr_feature(struct kvm_msr_entry *msr) ++{ ++ switch (msr->index) { ++ case MSR_IA32_UCODE_REV: ++ rdmsrl(msr->index, msr->data); ++ break; ++ default: ++ if (kvm_x86_ops->get_msr_feature(msr)) ++ return 1; ++ } ++ return 0; ++} ++ ++static int do_get_msr_feature(struct kvm_vcpu *vcpu, unsigned index, u64 *data) ++{ ++ struct kvm_msr_entry msr; ++ int r; ++ ++ msr.index = index; ++ r = kvm_get_msr_feature(&msr); ++ if (r) ++ return r; ++ ++ *data = msr.data; ++ ++ return 0; ++} ++ + bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer) + { + if (efer & efer_reserved_bits) +@@ -2222,7 +2261,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + + switch (msr) { + case MSR_AMD64_NB_CFG: +- case MSR_IA32_UCODE_REV: + case MSR_IA32_UCODE_WRITE: + case MSR_VM_HSAVE_PA: + case MSR_AMD64_PATCH_LOADER: +@@ -2230,6 +2268,10 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + case MSR_AMD64_DC_CFG: + break; + ++ case MSR_IA32_UCODE_REV: ++ if (msr_info->host_initiated) ++ vcpu->arch.microcode_version = data; ++ break; + case MSR_EFER: + return set_efer(vcpu, data); + case MSR_K7_HWCR: +@@ -2525,7 +2567,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + msr_info->data = 0; + break; + case MSR_IA32_UCODE_REV: +- msr_info->data = 0x100000000ULL; ++ msr_info->data = vcpu->arch.microcode_version; + break; + case MSR_MTRRcap: + case 0x200 ... 0x2ff: +@@ -2680,13 +2722,11 @@ static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs, + int (*do_msr)(struct kvm_vcpu *vcpu, + unsigned index, u64 *data)) + { +- int i, idx; ++ int i; + +- idx = srcu_read_lock(&vcpu->kvm->srcu); + for (i = 0; i < msrs->nmsrs; ++i) + if (do_msr(vcpu, entries[i].index, &entries[i].data)) + break; +- srcu_read_unlock(&vcpu->kvm->srcu, idx); + + return i; + } +@@ -2785,6 +2825,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) + case KVM_CAP_SET_BOOT_CPU_ID: + case KVM_CAP_SPLIT_IRQCHIP: + case KVM_CAP_IMMEDIATE_EXIT: ++ case KVM_CAP_GET_MSR_FEATURES: + r = 1; + break; + case KVM_CAP_ADJUST_CLOCK: +@@ -2899,6 +2940,31 @@ long kvm_arch_dev_ioctl(struct file *filp, + goto out; + r = 0; + break; ++ case KVM_GET_MSR_FEATURE_INDEX_LIST: { ++ struct kvm_msr_list __user *user_msr_list = argp; ++ struct kvm_msr_list msr_list; ++ unsigned int n; ++ ++ r = -EFAULT; ++ if (copy_from_user(&msr_list, user_msr_list, sizeof(msr_list))) ++ goto out; ++ n = msr_list.nmsrs; ++ msr_list.nmsrs = num_msr_based_features; ++ if (copy_to_user(user_msr_list, &msr_list, sizeof(msr_list))) ++ goto out; ++ r = -E2BIG; ++ if (n < msr_list.nmsrs) ++ goto out; ++ r = -EFAULT; ++ if (copy_to_user(user_msr_list->indices, &msr_based_features, ++ num_msr_based_features * sizeof(u32))) ++ goto out; ++ r = 0; ++ break; ++ } ++ case KVM_GET_MSRS: ++ r = msr_io(NULL, argp, do_get_msr_feature, 1); ++ break; + } + default: + r = -EINVAL; +@@ -3636,12 +3702,18 @@ long kvm_arch_vcpu_ioctl(struct file *filp, + r = 0; + break; + } +- case KVM_GET_MSRS: ++ case KVM_GET_MSRS: { ++ int idx = srcu_read_lock(&vcpu->kvm->srcu); + r = msr_io(vcpu, argp, do_get_msr, 1); ++ srcu_read_unlock(&vcpu->kvm->srcu, idx); + break; +- case KVM_SET_MSRS: ++ } ++ case KVM_SET_MSRS: { ++ int idx = srcu_read_lock(&vcpu->kvm->srcu); + r = msr_io(vcpu, argp, do_set_msr, 0); ++ srcu_read_unlock(&vcpu->kvm->srcu, idx); + break; ++ } + case KVM_TPR_ACCESS_REPORTING: { + struct kvm_tpr_access_ctl tac; + +@@ -4464,6 +4536,19 @@ static void kvm_init_msr_list(void) + j++; + } + num_emulated_msrs = j; ++ ++ for (i = j = 0; i < ARRAY_SIZE(msr_based_features); i++) { ++ struct kvm_msr_entry msr; ++ ++ msr.index = msr_based_features[i]; ++ if (kvm_get_msr_feature(&msr)) ++ continue; ++ ++ if (j < i) ++ msr_based_features[j] = msr_based_features[i]; ++ j++; ++ } ++ num_msr_based_features = j; + } + + static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len, +@@ -8017,6 +8102,8 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) + + void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) + { ++ kvm_lapic_reset(vcpu, init_event); ++ + vcpu->arch.hflags = 0; + + vcpu->arch.smi_pending = 0; +@@ -8460,10 +8547,8 @@ int __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa, u32 size) + return r; + } + +- if (!size) { +- r = vm_munmap(old.userspace_addr, old.npages * PAGE_SIZE); +- WARN_ON(r < 0); +- } ++ if (!size) ++ vm_munmap(old.userspace_addr, old.npages * PAGE_SIZE); + + return 0; + } +diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile +index 91e9700..25a972c 100644 +--- a/arch/x86/lib/Makefile ++++ b/arch/x86/lib/Makefile +@@ -28,7 +28,6 @@ lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o insn-eval.o + lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o + lib-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o + lib-$(CONFIG_RETPOLINE) += retpoline.o +-OBJECT_FILES_NON_STANDARD_retpoline.o :=y + + obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o + +diff --git a/arch/x86/lib/cpu.c b/arch/x86/lib/cpu.c +index d6f848d..2dd1fe13 100644 +--- a/arch/x86/lib/cpu.c ++++ b/arch/x86/lib/cpu.c +@@ -18,7 +18,7 @@ unsigned int x86_model(unsigned int sig) + { + unsigned int fam, model; + +- fam = x86_family(sig); ++ fam = x86_family(sig); + + model = (sig >> 4) & 0xf; + +diff --git a/arch/x86/lib/error-inject.c b/arch/x86/lib/error-inject.c +index 7b881d0..3cdf061 100644 +--- a/arch/x86/lib/error-inject.c ++++ b/arch/x86/lib/error-inject.c +@@ -7,6 +7,7 @@ asmlinkage void just_return_func(void); + + asm( + ".type just_return_func, @function\n" ++ ".globl just_return_func\n" + "just_return_func:\n" + " ret\n" + ".size just_return_func, .-just_return_func\n" +diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S +index 480edc3..c909961 100644 +--- a/arch/x86/lib/retpoline.S ++++ b/arch/x86/lib/retpoline.S +@@ -7,7 +7,6 @@ + #include + #include + #include +-#include + + .macro THUNK reg + .section .text.__x86.indirect_thunk +@@ -47,58 +46,3 @@ GENERATE_THUNK(r13) + GENERATE_THUNK(r14) + GENERATE_THUNK(r15) + #endif +- +-/* +- * Fill the CPU return stack buffer. +- * +- * Each entry in the RSB, if used for a speculative 'ret', contains an +- * infinite 'pause; lfence; jmp' loop to capture speculative execution. +- * +- * This is required in various cases for retpoline and IBRS-based +- * mitigations for the Spectre variant 2 vulnerability. Sometimes to +- * eliminate potentially bogus entries from the RSB, and sometimes +- * purely to ensure that it doesn't get empty, which on some CPUs would +- * allow predictions from other (unwanted!) sources to be used. +- * +- * Google experimented with loop-unrolling and this turned out to be +- * the optimal version - two calls, each with their own speculation +- * trap should their return address end up getting used, in a loop. +- */ +-.macro STUFF_RSB nr:req sp:req +- mov $(\nr / 2), %_ASM_BX +- .align 16 +-771: +- call 772f +-773: /* speculation trap */ +- pause +- lfence +- jmp 773b +- .align 16 +-772: +- call 774f +-775: /* speculation trap */ +- pause +- lfence +- jmp 775b +- .align 16 +-774: +- dec %_ASM_BX +- jnz 771b +- add $((BITS_PER_LONG/8) * \nr), \sp +-.endm +- +-#define RSB_FILL_LOOPS 16 /* To avoid underflow */ +- +-ENTRY(__fill_rsb) +- STUFF_RSB RSB_FILL_LOOPS, %_ASM_SP +- ret +-END(__fill_rsb) +-EXPORT_SYMBOL_GPL(__fill_rsb) +- +-#define RSB_CLEAR_LOOPS 32 /* To forcibly overwrite all entries */ +- +-ENTRY(__clear_rsb) +- STUFF_RSB RSB_CLEAR_LOOPS, %_ASM_SP +- ret +-END(__clear_rsb) +-EXPORT_SYMBOL_GPL(__clear_rsb) +diff --git a/arch/x86/mm/cpu_entry_area.c b/arch/x86/mm/cpu_entry_area.c +index b9283cc..476d810 100644 +--- a/arch/x86/mm/cpu_entry_area.c ++++ b/arch/x86/mm/cpu_entry_area.c +@@ -163,4 +163,10 @@ void __init setup_cpu_entry_areas(void) + + for_each_possible_cpu(cpu) + setup_cpu_entry_area(cpu); ++ ++ /* ++ * This is the last essential update to swapper_pgdir which needs ++ * to be synchronized to initial_page_table on 32bit. ++ */ ++ sync_initial_page_table(); + } +diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c +index 800de81..c88573d 100644 +--- a/arch/x86/mm/fault.c ++++ b/arch/x86/mm/fault.c +@@ -1248,10 +1248,6 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, + tsk = current; + mm = tsk->mm; + +- /* +- * Detect and handle instructions that would cause a page fault for +- * both a tracked kernel page and a userspace page. +- */ + prefetchw(&mm->mmap_sem); + + if (unlikely(kmmio_fault(regs, address))) +diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c +index 79cb066..396e1f0 100644 +--- a/arch/x86/mm/init_32.c ++++ b/arch/x86/mm/init_32.c +@@ -453,6 +453,21 @@ static inline void permanent_kmaps_init(pgd_t *pgd_base) + } + #endif /* CONFIG_HIGHMEM */ + ++void __init sync_initial_page_table(void) ++{ ++ clone_pgd_range(initial_page_table + KERNEL_PGD_BOUNDARY, ++ swapper_pg_dir + KERNEL_PGD_BOUNDARY, ++ KERNEL_PGD_PTRS); ++ ++ /* ++ * sync back low identity map too. It is used for example ++ * in the 32-bit EFI stub. ++ */ ++ clone_pgd_range(initial_page_table, ++ swapper_pg_dir + KERNEL_PGD_BOUNDARY, ++ min(KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY)); ++} ++ + void __init native_pagetable_init(void) + { + unsigned long pfn, va; +diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c +index 1ab42c8..8b72923 100644 +--- a/arch/x86/mm/init_64.c ++++ b/arch/x86/mm/init_64.c +@@ -256,7 +256,7 @@ static void __set_pte_vaddr(pud_t *pud, unsigned long vaddr, pte_t new_pte) + * It's enough to flush this one mapping. + * (PGE mappings get flushed as well) + */ +- __flush_tlb_one(vaddr); ++ __flush_tlb_one_kernel(vaddr); + } + + void set_pte_vaddr_p4d(p4d_t *p4d_page, unsigned long vaddr, pte_t new_pte) +@@ -1193,8 +1193,8 @@ void __init mem_init(void) + register_page_bootmem_info(); + + /* Register memory areas for /proc/kcore */ +- kclist_add(&kcore_vsyscall, (void *)VSYSCALL_ADDR, +- PAGE_SIZE, KCORE_OTHER); ++ if (get_gate_vma(&init_mm)) ++ kclist_add(&kcore_vsyscall, (void *)VSYSCALL_ADDR, PAGE_SIZE, KCORE_USER); + + mem_init_print_info(NULL); + } +diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c +index c45b6ec..e2db83b 100644 +--- a/arch/x86/mm/ioremap.c ++++ b/arch/x86/mm/ioremap.c +@@ -820,5 +820,5 @@ void __init __early_set_fixmap(enum fixed_addresses idx, + set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags)); + else + pte_clear(&init_mm, addr, pte); +- __flush_tlb_one(addr); ++ __flush_tlb_one_kernel(addr); + } +diff --git a/arch/x86/mm/kmmio.c b/arch/x86/mm/kmmio.c +index 58477ec..7c86867 100644 +--- a/arch/x86/mm/kmmio.c ++++ b/arch/x86/mm/kmmio.c +@@ -168,7 +168,7 @@ static int clear_page_presence(struct kmmio_fault_page *f, bool clear) + return -1; + } + +- __flush_tlb_one(f->addr); ++ __flush_tlb_one_kernel(f->addr); + return 0; + } + +diff --git a/arch/x86/mm/mem_encrypt_boot.S b/arch/x86/mm/mem_encrypt_boot.S +index 01f682c..40a6085 100644 +--- a/arch/x86/mm/mem_encrypt_boot.S ++++ b/arch/x86/mm/mem_encrypt_boot.S +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + .text + .code64 +@@ -59,6 +60,7 @@ ENTRY(sme_encrypt_execute) + movq %rax, %r8 /* Workarea encryption routine */ + addq $PAGE_SIZE, %r8 /* Workarea intermediate copy buffer */ + ++ ANNOTATE_RETPOLINE_SAFE + call *%rax /* Call the encryption routine */ + + pop %r12 +diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c +index c3c5274..9bb7f0a 100644 +--- a/arch/x86/mm/pgtable_32.c ++++ b/arch/x86/mm/pgtable_32.c +@@ -63,7 +63,7 @@ void set_pte_vaddr(unsigned long vaddr, pte_t pteval) + * It's enough to flush this one mapping. + * (PGE mappings get flushed as well) + */ +- __flush_tlb_one(vaddr); ++ __flush_tlb_one_kernel(vaddr); + } + + unsigned long __FIXADDR_TOP = 0xfffff000; +diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c +index ce38f16..631507f 100644 +--- a/arch/x86/mm/pti.c ++++ b/arch/x86/mm/pti.c +@@ -332,7 +332,7 @@ static void __init pti_clone_user_shared(void) + } + + /* +- * Clone the ESPFIX P4D into the user space visinble page table ++ * Clone the ESPFIX P4D into the user space visible page table + */ + static void __init pti_setup_espfix64(void) + { +diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c +index 8dcc060..7f1a513 100644 +--- a/arch/x86/mm/tlb.c ++++ b/arch/x86/mm/tlb.c +@@ -498,7 +498,7 @@ static void flush_tlb_func_common(const struct flush_tlb_info *f, + * flush that changes context.tlb_gen from 2 to 3. If they get + * processed on this CPU in reverse order, we'll see + * local_tlb_gen == 1, mm_tlb_gen == 3, and end != TLB_FLUSH_ALL. +- * If we were to use __flush_tlb_single() and set local_tlb_gen to ++ * If we were to use __flush_tlb_one_user() and set local_tlb_gen to + * 3, we'd be break the invariant: we'd update local_tlb_gen above + * 1 without the full flush that's needed for tlb_gen 2. + * +@@ -519,7 +519,7 @@ static void flush_tlb_func_common(const struct flush_tlb_info *f, + + addr = f->start; + while (addr < f->end) { +- __flush_tlb_single(addr); ++ __flush_tlb_one_user(addr); + addr += PAGE_SIZE; + } + if (local) +@@ -666,7 +666,7 @@ static void do_kernel_range_flush(void *info) + + /* flush range by one by one 'invlpg' */ + for (addr = f->start; addr < f->end; addr += PAGE_SIZE) +- __flush_tlb_one(addr); ++ __flush_tlb_one_kernel(addr); + } + + void flush_tlb_kernel_range(unsigned long start, unsigned long end) +diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c +index 4923d92..45e4eb5 100644 +--- a/arch/x86/net/bpf_jit_comp.c ++++ b/arch/x86/net/bpf_jit_comp.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + /* +@@ -290,7 +291,7 @@ static void emit_bpf_tail_call(u8 **pprog) + EMIT2(0x89, 0xD2); /* mov edx, edx */ + EMIT3(0x39, 0x56, /* cmp dword ptr [rsi + 16], edx */ + offsetof(struct bpf_array, map.max_entries)); +-#define OFFSET1 43 /* number of bytes to jump */ ++#define OFFSET1 (41 + RETPOLINE_RAX_BPF_JIT_SIZE) /* number of bytes to jump */ + EMIT2(X86_JBE, OFFSET1); /* jbe out */ + label1 = cnt; + +@@ -299,7 +300,7 @@ static void emit_bpf_tail_call(u8 **pprog) + */ + EMIT2_off32(0x8B, 0x85, 36); /* mov eax, dword ptr [rbp + 36] */ + EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT); /* cmp eax, MAX_TAIL_CALL_CNT */ +-#define OFFSET2 32 ++#define OFFSET2 (30 + RETPOLINE_RAX_BPF_JIT_SIZE) + EMIT2(X86_JA, OFFSET2); /* ja out */ + label2 = cnt; + EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */ +@@ -313,7 +314,7 @@ static void emit_bpf_tail_call(u8 **pprog) + * goto out; + */ + EMIT3(0x48, 0x85, 0xC0); /* test rax,rax */ +-#define OFFSET3 10 ++#define OFFSET3 (8 + RETPOLINE_RAX_BPF_JIT_SIZE) + EMIT2(X86_JE, OFFSET3); /* je out */ + label3 = cnt; + +@@ -326,7 +327,7 @@ static void emit_bpf_tail_call(u8 **pprog) + * rdi == ctx (1st arg) + * rax == prog->bpf_func + prologue_size + */ +- EMIT2(0xFF, 0xE0); /* jmp rax */ ++ RETPOLINE_RAX_BPF_JIT(); + + /* out: */ + BUILD_BUG_ON(cnt - label1 != OFFSET1); +diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c +index 174c597..a7a7677 100644 +--- a/arch/x86/oprofile/nmi_int.c ++++ b/arch/x86/oprofile/nmi_int.c +@@ -460,7 +460,7 @@ static int nmi_setup(void) + goto fail; + + for_each_possible_cpu(cpu) { +- if (!cpu) ++ if (!IS_ENABLED(CONFIG_SMP) || !cpu) + continue; + + memcpy(per_cpu(cpu_msrs, cpu).counters, +diff --git a/arch/x86/platform/intel-mid/intel-mid.c b/arch/x86/platform/intel-mid/intel-mid.c +index 2c67bae..fb1df94 100644 +--- a/arch/x86/platform/intel-mid/intel-mid.c ++++ b/arch/x86/platform/intel-mid/intel-mid.c +@@ -79,7 +79,7 @@ static void intel_mid_power_off(void) + + static void intel_mid_reboot(void) + { +- intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0); ++ intel_scu_ipc_simple_command(IPCMSG_COLD_RESET, 0); + } + + static unsigned long __init intel_mid_calibrate_tsc(void) +diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c +index c2e9285..db77e087 100644 +--- a/arch/x86/platform/uv/tlb_uv.c ++++ b/arch/x86/platform/uv/tlb_uv.c +@@ -299,7 +299,7 @@ static void bau_process_message(struct msg_desc *mdp, struct bau_control *bcp, + local_flush_tlb(); + stat->d_alltlb++; + } else { +- __flush_tlb_single(msg->address); ++ __flush_tlb_one_user(msg->address); + stat->d_onetlb++; + } + stat->d_requestee++; +diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S +index de53bd1..24bb759 100644 +--- a/arch/x86/realmode/rm/trampoline_64.S ++++ b/arch/x86/realmode/rm/trampoline_64.S +@@ -102,7 +102,7 @@ ENTRY(startup_32) + * don't we'll eventually crash trying to execute encrypted + * instructions. + */ +- bt $TH_FLAGS_SME_ACTIVE_BIT, pa_tr_flags ++ btl $TH_FLAGS_SME_ACTIVE_BIT, pa_tr_flags + jnc .Ldone + movl $MSR_K8_SYSCFG, %ecx + rdmsr +diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c +index 5d73c44..220e978 100644 +--- a/arch/x86/tools/relocs.c ++++ b/arch/x86/tools/relocs.c +@@ -770,9 +770,12 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, + break; + + case R_X86_64_PC32: ++ case R_X86_64_PLT32: + /* + * PC relative relocations don't need to be adjusted unless + * referencing a percpu symbol. ++ * ++ * NB: R_X86_64_PLT32 can be treated as R_X86_64_PC32. + */ + if (is_percpu_sym(sym, symname)) + add_reloc(&relocs32neg, offset); +diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c +index c047f42..3c2c253 100644 +--- a/arch/x86/xen/enlighten_pv.c ++++ b/arch/x86/xen/enlighten_pv.c +@@ -1376,8 +1376,6 @@ asmlinkage __visible void __init xen_start_kernel(void) + + if (!xen_initial_domain()) { + add_preferred_console("xenboot", 0, NULL); +- add_preferred_console("tty", 0, NULL); +- add_preferred_console("hvc", 0, NULL); + if (pci_xen) + x86_init.pci.arch_init = pci_xen_init; + } else { +@@ -1410,6 +1408,10 @@ asmlinkage __visible void __init xen_start_kernel(void) + + xen_boot_params_init_edd(); + } ++ ++ add_preferred_console("tty", 0, NULL); ++ add_preferred_console("hvc", 0, NULL); ++ + #ifdef CONFIG_PCI + /* PCI BIOS service won't work from a PV guest. */ + pci_probe &= ~PCI_PROBE_BIOS; +diff --git a/arch/x86/xen/mmu_pv.c b/arch/x86/xen/mmu_pv.c +index d850762..aae88fe 100644 +--- a/arch/x86/xen/mmu_pv.c ++++ b/arch/x86/xen/mmu_pv.c +@@ -1300,12 +1300,12 @@ static void xen_flush_tlb(void) + preempt_enable(); + } + +-static void xen_flush_tlb_single(unsigned long addr) ++static void xen_flush_tlb_one_user(unsigned long addr) + { + struct mmuext_op *op; + struct multicall_space mcs; + +- trace_xen_mmu_flush_tlb_single(addr); ++ trace_xen_mmu_flush_tlb_one_user(addr); + + preempt_disable(); + +@@ -2370,7 +2370,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = { + + .flush_tlb_user = xen_flush_tlb, + .flush_tlb_kernel = xen_flush_tlb, +- .flush_tlb_single = xen_flush_tlb_single, ++ .flush_tlb_one_user = xen_flush_tlb_one_user, + .flush_tlb_others = xen_flush_tlb_others, + + .pgd_alloc = xen_pgd_alloc, +diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c +index 77c959c..7a43b2a 100644 +--- a/arch/x86/xen/smp.c ++++ b/arch/x86/xen/smp.c +@@ -122,6 +122,8 @@ void __init xen_smp_cpus_done(unsigned int max_cpus) + + if (xen_hvm_domain()) + native_smp_cpus_done(max_cpus); ++ else ++ calculate_max_logical_packages(); + + if (xen_have_vcpu_info_placement) + return; +diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c +index d9f96cc..1d83152 100644 +--- a/arch/x86/xen/suspend.c ++++ b/arch/x86/xen/suspend.c +@@ -1,12 +1,15 @@ + // SPDX-License-Identifier: GPL-2.0 + #include + #include ++#include + + #include + #include + #include + #include + ++#include ++#include + #include + #include + #include +@@ -15,6 +18,8 @@ + #include "mmu.h" + #include "pmu.h" + ++static DEFINE_PER_CPU(u64, spec_ctrl); ++ + void xen_arch_pre_suspend(void) + { + xen_save_time_memory_area(); +@@ -35,6 +40,9 @@ void xen_arch_post_suspend(int cancelled) + + static void xen_vcpu_notify_restore(void *data) + { ++ if (xen_pv_domain() && boot_cpu_has(X86_FEATURE_SPEC_CTRL)) ++ wrmsrl(MSR_IA32_SPEC_CTRL, this_cpu_read(spec_ctrl)); ++ + /* Boot processor notified via generic timekeeping_resume() */ + if (smp_processor_id() == 0) + return; +@@ -44,7 +52,15 @@ static void xen_vcpu_notify_restore(void *data) + + static void xen_vcpu_notify_suspend(void *data) + { ++ u64 tmp; ++ + tick_suspend_local(); ++ ++ if (xen_pv_domain() && boot_cpu_has(X86_FEATURE_SPEC_CTRL)) { ++ rdmsrl(MSR_IA32_SPEC_CTRL, tmp); ++ this_cpu_write(spec_ctrl, tmp); ++ wrmsrl(MSR_IA32_SPEC_CTRL, 0); ++ } + } + + void xen_arch_resume(void) +diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c +index 623720a..732631c 100644 +--- a/arch/xtensa/kernel/pci-dma.c ++++ b/arch/xtensa/kernel/pci-dma.c +@@ -16,6 +16,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -123,7 +124,7 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size, + unsigned long attrs) + { + unsigned long ret; +- unsigned long uncached = 0; ++ unsigned long uncached; + unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; + struct page *page = NULL; + +@@ -144,15 +145,27 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size, + if (!page) + return NULL; + +- ret = (unsigned long)page_address(page); ++ *handle = phys_to_dma(dev, page_to_phys(page)); + +- /* We currently don't support coherent memory outside KSEG */ ++#ifdef CONFIG_MMU ++ if (PageHighMem(page)) { ++ void *p; + ++ p = dma_common_contiguous_remap(page, size, VM_MAP, ++ pgprot_noncached(PAGE_KERNEL), ++ __builtin_return_address(0)); ++ if (!p) { ++ if (!dma_release_from_contiguous(dev, page, count)) ++ __free_pages(page, get_order(size)); ++ } ++ return p; ++ } ++#endif ++ ret = (unsigned long)page_address(page); + BUG_ON(ret < XCHAL_KSEG_CACHED_VADDR || + ret > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1); + + uncached = ret + XCHAL_KSEG_BYPASS_VADDR - XCHAL_KSEG_CACHED_VADDR; +- *handle = virt_to_bus((void *)ret); + __invalidate_dcache_range(ret, size); + + return (void *)uncached; +@@ -161,13 +174,20 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size, + static void xtensa_dma_free(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle, unsigned long attrs) + { +- unsigned long addr = (unsigned long)vaddr + +- XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR; +- struct page *page = virt_to_page(addr); + unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; +- +- BUG_ON(addr < XCHAL_KSEG_CACHED_VADDR || +- addr > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1); ++ unsigned long addr = (unsigned long)vaddr; ++ struct page *page; ++ ++ if (addr >= XCHAL_KSEG_BYPASS_VADDR && ++ addr - XCHAL_KSEG_BYPASS_VADDR < XCHAL_KSEG_SIZE) { ++ addr += XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR; ++ page = virt_to_page(addr); ++ } else { ++#ifdef CONFIG_MMU ++ dma_common_free_remap(vaddr, size, VM_MAP); ++#endif ++ page = pfn_to_page(PHYS_PFN(dma_to_phys(dev, dma_handle))); ++ } + + if (!dma_release_from_contiguous(dev, page, count)) + __free_pages(page, get_order(size)); +diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c +index d776ec0..34aead7 100644 +--- a/arch/xtensa/mm/init.c ++++ b/arch/xtensa/mm/init.c +@@ -79,19 +79,75 @@ void __init zones_init(void) + free_area_init_node(0, zones_size, ARCH_PFN_OFFSET, NULL); + } + ++#ifdef CONFIG_HIGHMEM ++static void __init free_area_high(unsigned long pfn, unsigned long end) ++{ ++ for (; pfn < end; pfn++) ++ free_highmem_page(pfn_to_page(pfn)); ++} ++ ++static void __init free_highpages(void) ++{ ++ unsigned long max_low = max_low_pfn; ++ struct memblock_region *mem, *res; ++ ++ reset_all_zones_managed_pages(); ++ /* set highmem page free */ ++ for_each_memblock(memory, mem) { ++ unsigned long start = memblock_region_memory_base_pfn(mem); ++ unsigned long end = memblock_region_memory_end_pfn(mem); ++ ++ /* Ignore complete lowmem entries */ ++ if (end <= max_low) ++ continue; ++ ++ if (memblock_is_nomap(mem)) ++ continue; ++ ++ /* Truncate partial highmem entries */ ++ if (start < max_low) ++ start = max_low; ++ ++ /* Find and exclude any reserved regions */ ++ for_each_memblock(reserved, res) { ++ unsigned long res_start, res_end; ++ ++ res_start = memblock_region_reserved_base_pfn(res); ++ res_end = memblock_region_reserved_end_pfn(res); ++ ++ if (res_end < start) ++ continue; ++ if (res_start < start) ++ res_start = start; ++ if (res_start > end) ++ res_start = end; ++ if (res_end > end) ++ res_end = end; ++ if (res_start != start) ++ free_area_high(start, res_start); ++ start = res_end; ++ if (start == end) ++ break; ++ } ++ ++ /* And now free anything which remains */ ++ if (start < end) ++ free_area_high(start, end); ++ } ++} ++#else ++static void __init free_highpages(void) ++{ ++} ++#endif ++ + /* + * Initialize memory pages. + */ + + void __init mem_init(void) + { +-#ifdef CONFIG_HIGHMEM +- unsigned long tmp; +- +- reset_all_zones_managed_pages(); +- for (tmp = max_low_pfn; tmp < max_pfn; tmp++) +- free_highmem_page(pfn_to_page(tmp)); +-#endif ++ free_highpages(); + + max_mapnr = max_pfn - ARCH_PFN_OFFSET; + high_memory = (void *)__va(max_low_pfn << PAGE_SHIFT); +diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c +index 4117524..c2033a2 100644 +--- a/block/blk-cgroup.c ++++ b/block/blk-cgroup.c +@@ -812,7 +812,6 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol, + struct gendisk *disk; + struct request_queue *q; + struct blkcg_gq *blkg; +- struct module *owner; + unsigned int major, minor; + int key_len, part, ret; + char *body; +@@ -904,9 +903,7 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol, + spin_unlock_irq(q->queue_lock); + rcu_read_unlock(); + fail: +- owner = disk->fops->owner; +- put_disk(disk); +- module_put(owner); ++ put_disk_and_module(disk); + /* + * If queue was bypassing, we should retry. Do so after a + * short msleep(). It isn't strictly necessary but queue +@@ -931,13 +928,9 @@ EXPORT_SYMBOL_GPL(blkg_conf_prep); + void blkg_conf_finish(struct blkg_conf_ctx *ctx) + __releases(ctx->disk->queue->queue_lock) __releases(rcu) + { +- struct module *owner; +- + spin_unlock_irq(ctx->disk->queue->queue_lock); + rcu_read_unlock(); +- owner = ctx->disk->fops->owner; +- put_disk(ctx->disk); +- module_put(owner); ++ put_disk_and_module(ctx->disk); + } + EXPORT_SYMBOL_GPL(blkg_conf_finish); + +diff --git a/block/blk-core.c b/block/blk-core.c +index 2d1a7bb..6d82c4f 100644 +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -2434,7 +2434,7 @@ blk_qc_t submit_bio(struct bio *bio) + unsigned int count; + + if (unlikely(bio_op(bio) == REQ_OP_WRITE_SAME)) +- count = queue_logical_block_size(bio->bi_disk->queue); ++ count = queue_logical_block_size(bio->bi_disk->queue) >> 9; + else + count = bio_sectors(bio); + +diff --git a/block/blk-mq.c b/block/blk-mq.c +index df93102..16e83e6 100644 +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -712,7 +712,6 @@ static void __blk_mq_requeue_request(struct request *rq) + + trace_block_rq_requeue(q, rq); + wbt_requeue(q->rq_wb, &rq->issue_stat); +- blk_mq_sched_requeue_request(rq); + + if (blk_mq_rq_state(rq) != MQ_RQ_IDLE) { + blk_mq_rq_update_state(rq, MQ_RQ_IDLE); +@@ -725,6 +724,9 @@ void blk_mq_requeue_request(struct request *rq, bool kick_requeue_list) + { + __blk_mq_requeue_request(rq); + ++ /* this request will be re-inserted to io scheduler queue */ ++ blk_mq_sched_requeue_request(rq); ++ + BUG_ON(blk_queued_rq(rq)); + blk_mq_add_to_requeue_list(rq, true, kick_requeue_list); + } +@@ -3164,6 +3166,7 @@ static bool __blk_mq_poll(struct blk_mq_hw_ctx *hctx, struct request *rq) + cpu_relax(); + } + ++ __set_current_state(TASK_RUNNING); + return false; + } + +diff --git a/block/genhd.c b/block/genhd.c +index 88a53c1..9656f9e 100644 +--- a/block/genhd.c ++++ b/block/genhd.c +@@ -547,7 +547,7 @@ static int exact_lock(dev_t devt, void *data) + { + struct gendisk *p = data; + +- if (!get_disk(p)) ++ if (!get_disk_and_module(p)) + return -1; + return 0; + } +@@ -717,6 +717,11 @@ void del_gendisk(struct gendisk *disk) + blk_integrity_del(disk); + disk_del_events(disk); + ++ /* ++ * Block lookups of the disk until all bdevs are unhashed and the ++ * disk is marked as dead (GENHD_FL_UP cleared). ++ */ ++ down_write(&disk->lookup_sem); + /* invalidate stuff */ + disk_part_iter_init(&piter, disk, + DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE); +@@ -731,6 +736,7 @@ void del_gendisk(struct gendisk *disk) + bdev_unhash_inode(disk_devt(disk)); + set_capacity(disk, 0); + disk->flags &= ~GENHD_FL_UP; ++ up_write(&disk->lookup_sem); + + if (!(disk->flags & GENHD_FL_HIDDEN)) + sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi"); +@@ -809,16 +815,28 @@ struct gendisk *get_gendisk(dev_t devt, int *partno) + + spin_lock_bh(&ext_devt_lock); + part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt))); +- if (part && get_disk(part_to_disk(part))) { ++ if (part && get_disk_and_module(part_to_disk(part))) { + *partno = part->partno; + disk = part_to_disk(part); + } + spin_unlock_bh(&ext_devt_lock); + } + +- if (disk && unlikely(disk->flags & GENHD_FL_HIDDEN)) { +- put_disk(disk); ++ if (!disk) ++ return NULL; ++ ++ /* ++ * Synchronize with del_gendisk() to not return disk that is being ++ * destroyed. ++ */ ++ down_read(&disk->lookup_sem); ++ if (unlikely((disk->flags & GENHD_FL_HIDDEN) || ++ !(disk->flags & GENHD_FL_UP))) { ++ up_read(&disk->lookup_sem); ++ put_disk_and_module(disk); + disk = NULL; ++ } else { ++ up_read(&disk->lookup_sem); + } + return disk; + } +@@ -1418,6 +1436,7 @@ struct gendisk *__alloc_disk_node(int minors, int node_id) + kfree(disk); + return NULL; + } ++ init_rwsem(&disk->lookup_sem); + disk->node_id = node_id; + if (disk_expand_part_tbl(disk, 0)) { + free_part_stats(&disk->part0); +@@ -1453,7 +1472,7 @@ struct gendisk *__alloc_disk_node(int minors, int node_id) + } + EXPORT_SYMBOL(__alloc_disk_node); + +-struct kobject *get_disk(struct gendisk *disk) ++struct kobject *get_disk_and_module(struct gendisk *disk) + { + struct module *owner; + struct kobject *kobj; +@@ -1471,17 +1490,30 @@ struct kobject *get_disk(struct gendisk *disk) + return kobj; + + } +- +-EXPORT_SYMBOL(get_disk); ++EXPORT_SYMBOL(get_disk_and_module); + + void put_disk(struct gendisk *disk) + { + if (disk) + kobject_put(&disk_to_dev(disk)->kobj); + } +- + EXPORT_SYMBOL(put_disk); + ++/* ++ * This is a counterpart of get_disk_and_module() and thus also of ++ * get_gendisk(). ++ */ ++void put_disk_and_module(struct gendisk *disk) ++{ ++ if (disk) { ++ struct module *owner = disk->fops->owner; ++ ++ put_disk(disk); ++ module_put(owner); ++ } ++} ++EXPORT_SYMBOL(put_disk_and_module); ++ + static void set_disk_ro_uevent(struct gendisk *gd, int ro) + { + char event[] = "DISK_RO=1"; +diff --git a/block/ioctl.c b/block/ioctl.c +index 1668506..3884d81 100644 +--- a/block/ioctl.c ++++ b/block/ioctl.c +@@ -225,7 +225,7 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode, + + if (start + len > i_size_read(bdev->bd_inode)) + return -EINVAL; +- truncate_inode_pages_range(mapping, start, start + len); ++ truncate_inode_pages_range(mapping, start, start + len - 1); + return blkdev_issue_discard(bdev, start >> 9, len >> 9, + GFP_KERNEL, flags); + } +diff --git a/block/kyber-iosched.c b/block/kyber-iosched.c +index f95c607..0d6d25e3 100644 +--- a/block/kyber-iosched.c ++++ b/block/kyber-iosched.c +@@ -833,6 +833,7 @@ static struct elevator_type kyber_sched = { + .limit_depth = kyber_limit_depth, + .prepare_request = kyber_prepare_request, + .finish_request = kyber_finish_request, ++ .requeue_request = kyber_finish_request, + .completed_request = kyber_completed_request, + .dispatch_request = kyber_dispatch_request, + .has_work = kyber_has_work, +diff --git a/block/mq-deadline.c b/block/mq-deadline.c +index c56f211..8ec0ba9 100644 +--- a/block/mq-deadline.c ++++ b/block/mq-deadline.c +@@ -536,12 +536,21 @@ static void dd_insert_requests(struct blk_mq_hw_ctx *hctx, + } + + /* ++ * Nothing to do here. This is defined only to ensure that .finish_request ++ * method is called upon request completion. ++ */ ++static void dd_prepare_request(struct request *rq, struct bio *bio) ++{ ++} ++ ++/* + * For zoned block devices, write unlock the target zone of + * completed write requests. Do this while holding the zone lock + * spinlock so that the zone is never unlocked while deadline_fifo_request() +- * while deadline_next_request() are executing. ++ * or deadline_next_request() are executing. This function is called for ++ * all requests, whether or not these requests complete successfully. + */ +-static void dd_completed_request(struct request *rq) ++static void dd_finish_request(struct request *rq) + { + struct request_queue *q = rq->q; + +@@ -756,7 +765,8 @@ static struct elevator_type mq_deadline = { + .ops.mq = { + .insert_requests = dd_insert_requests, + .dispatch_request = dd_dispatch_request, +- .completed_request = dd_completed_request, ++ .prepare_request = dd_prepare_request, ++ .finish_request = dd_finish_request, + .next_request = elv_rb_latter_request, + .former_request = elv_rb_former_request, + .bio_merge = dd_bio_merge, +diff --git a/block/partition-generic.c b/block/partition-generic.c +index 91622db..08dabcd 100644 +--- a/block/partition-generic.c ++++ b/block/partition-generic.c +@@ -51,6 +51,12 @@ const char *bdevname(struct block_device *bdev, char *buf) + + EXPORT_SYMBOL(bdevname); + ++const char *bio_devname(struct bio *bio, char *buf) ++{ ++ return disk_name(bio->bi_disk, bio->bi_partno, buf); ++} ++EXPORT_SYMBOL(bio_devname); ++ + /* + * There's very little reason to use this, you should really + * have a struct block_device just about everywhere and use +diff --git a/block/sed-opal.c b/block/sed-opal.c +index 9ed51d0c..e4929ee 100644 +--- a/block/sed-opal.c ++++ b/block/sed-opal.c +@@ -490,7 +490,7 @@ static int opal_discovery0_end(struct opal_dev *dev) + + if (!found_com_id) { + pr_debug("Could not find OPAL comid for device. Returning early\n"); +- return -EOPNOTSUPP;; ++ return -EOPNOTSUPP; + } + + dev->comid = comid; +diff --git a/certs/blacklist_nohashes.c b/certs/blacklist_nohashes.c +index 73fd990..753b703 100644 +--- a/certs/blacklist_nohashes.c ++++ b/certs/blacklist_nohashes.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + #include "blacklist.h" + +-const char __initdata *const blacklist_hashes[] = { ++const char __initconst *const blacklist_hashes[] = { + NULL + }; +diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c +index 1f4e25f..598906b 100644 +--- a/crypto/asymmetric_keys/pkcs7_trust.c ++++ b/crypto/asymmetric_keys/pkcs7_trust.c +@@ -106,6 +106,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, + pr_devel("sinfo %u: Direct signer is key %x\n", + sinfo->index, key_serial(key)); + x509 = NULL; ++ sig = sinfo->sig; + goto matched; + } + if (PTR_ERR(key) != -ENOKEY) +diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c +index 39e6de0..97c77f6 100644 +--- a/crypto/asymmetric_keys/pkcs7_verify.c ++++ b/crypto/asymmetric_keys/pkcs7_verify.c +@@ -270,7 +270,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, + sinfo->index); + return 0; + } +- ret = public_key_verify_signature(p->pub, p->sig); ++ ret = public_key_verify_signature(p->pub, x509->sig); + if (ret < 0) + return ret; + x509->signer = p; +@@ -366,8 +366,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, + * + * (*) -EBADMSG if some part of the message was invalid, or: + * +- * (*) 0 if no signature chains were found to be blacklisted or to contain +- * unsupported crypto, or: ++ * (*) 0 if a signature chain passed verification, or: + * + * (*) -EKEYREJECTED if a blacklisted key was encountered, or: + * +@@ -423,8 +422,11 @@ int pkcs7_verify(struct pkcs7_message *pkcs7, + + for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { + ret = pkcs7_verify_one(pkcs7, sinfo); +- if (sinfo->blacklisted && actual_ret == -ENOPKG) +- actual_ret = -EKEYREJECTED; ++ if (sinfo->blacklisted) { ++ if (actual_ret == -ENOPKG) ++ actual_ret = -EKEYREJECTED; ++ continue; ++ } + if (ret < 0) { + if (ret == -ENOPKG) { + sinfo->unsupported_crypto = true; +diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c +index de99658..e929fe1 100644 +--- a/crypto/asymmetric_keys/public_key.c ++++ b/crypto/asymmetric_keys/public_key.c +@@ -79,9 +79,11 @@ int public_key_verify_signature(const struct public_key *pkey, + + BUG_ON(!pkey); + BUG_ON(!sig); +- BUG_ON(!sig->digest); + BUG_ON(!sig->s); + ++ if (!sig->digest) ++ return -ENOPKG; ++ + alg_name = sig->pkey_algo; + if (strcmp(sig->pkey_algo, "rsa") == 0) { + /* The data wangled by the RSA algorithm is typically padded +diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c +index 86fb685..7c93c77 100644 +--- a/crypto/asymmetric_keys/restrict.c ++++ b/crypto/asymmetric_keys/restrict.c +@@ -67,8 +67,9 @@ __setup("ca_keys=", ca_keys_setup); + * + * Returns 0 if the new certificate was accepted, -ENOKEY if we couldn't find a + * matching parent certificate in the trusted list, -EKEYREJECTED if the +- * signature check fails or the key is blacklisted and some other error if +- * there is a matching certificate but the signature check cannot be performed. ++ * signature check fails or the key is blacklisted, -ENOPKG if the signature ++ * uses unsupported crypto, or some other error if there is a matching ++ * certificate but the signature check cannot be performed. + */ + int restrict_link_by_signature(struct key *dest_keyring, + const struct key_type *type, +@@ -88,6 +89,8 @@ int restrict_link_by_signature(struct key *dest_keyring, + return -EOPNOTSUPP; + + sig = payload->data[asym_auth]; ++ if (!sig) ++ return -ENOPKG; + if (!sig->auth_ids[0] && !sig->auth_ids[1]) + return -ENOKEY; + +@@ -139,6 +142,8 @@ static int key_or_keyring_common(struct key *dest_keyring, + return -EOPNOTSUPP; + + sig = payload->data[asym_auth]; ++ if (!sig) ++ return -ENOPKG; + if (!sig->auth_ids[0] && !sig->auth_ids[1]) + return -ENOKEY; + +@@ -222,9 +227,9 @@ static int key_or_keyring_common(struct key *dest_keyring, + * + * Returns 0 if the new certificate was accepted, -ENOKEY if we + * couldn't find a matching parent certificate in the trusted list, +- * -EKEYREJECTED if the signature check fails, and some other error if +- * there is a matching certificate but the signature check cannot be +- * performed. ++ * -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses ++ * unsupported crypto, or some other error if there is a matching certificate ++ * but the signature check cannot be performed. + */ + int restrict_link_by_key_or_keyring(struct key *dest_keyring, + const struct key_type *type, +@@ -249,9 +254,9 @@ int restrict_link_by_key_or_keyring(struct key *dest_keyring, + * + * Returns 0 if the new certificate was accepted, -ENOKEY if we + * couldn't find a matching parent certificate in the trusted list, +- * -EKEYREJECTED if the signature check fails, and some other error if +- * there is a matching certificate but the signature check cannot be +- * performed. ++ * -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses ++ * unsupported crypto, or some other error if there is a matching certificate ++ * but the signature check cannot be performed. + */ + int restrict_link_by_key_or_keyring_chain(struct key *dest_keyring, + const struct key_type *type, +diff --git a/crypto/sha3_generic.c b/crypto/sha3_generic.c +index a965b9d..ded1487 100644 +--- a/crypto/sha3_generic.c ++++ b/crypto/sha3_generic.c +@@ -20,6 +20,20 @@ + #include + #include + ++/* ++ * On some 32-bit architectures (mn10300 and h8300), GCC ends up using ++ * over 1 KB of stack if we inline the round calculation into the loop ++ * in keccakf(). On the other hand, on 64-bit architectures with plenty ++ * of [64-bit wide] general purpose registers, not inlining it severely ++ * hurts performance. So let's use 64-bitness as a heuristic to decide ++ * whether to inline or not. ++ */ ++#ifdef CONFIG_64BIT ++#define SHA3_INLINE inline ++#else ++#define SHA3_INLINE noinline ++#endif ++ + #define KECCAK_ROUNDS 24 + + static const u64 keccakf_rndc[24] = { +@@ -35,111 +49,115 @@ static const u64 keccakf_rndc[24] = { + + /* update the state with given number of rounds */ + +-static void __attribute__((__optimize__("O3"))) keccakf(u64 st[25]) ++static SHA3_INLINE void keccakf_round(u64 st[25]) + { + u64 t[5], tt, bc[5]; +- int round; + +- for (round = 0; round < KECCAK_ROUNDS; round++) { ++ /* Theta */ ++ bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20]; ++ bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21]; ++ bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22]; ++ bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23]; ++ bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24]; ++ ++ t[0] = bc[4] ^ rol64(bc[1], 1); ++ t[1] = bc[0] ^ rol64(bc[2], 1); ++ t[2] = bc[1] ^ rol64(bc[3], 1); ++ t[3] = bc[2] ^ rol64(bc[4], 1); ++ t[4] = bc[3] ^ rol64(bc[0], 1); ++ ++ st[0] ^= t[0]; ++ ++ /* Rho Pi */ ++ tt = st[1]; ++ st[ 1] = rol64(st[ 6] ^ t[1], 44); ++ st[ 6] = rol64(st[ 9] ^ t[4], 20); ++ st[ 9] = rol64(st[22] ^ t[2], 61); ++ st[22] = rol64(st[14] ^ t[4], 39); ++ st[14] = rol64(st[20] ^ t[0], 18); ++ st[20] = rol64(st[ 2] ^ t[2], 62); ++ st[ 2] = rol64(st[12] ^ t[2], 43); ++ st[12] = rol64(st[13] ^ t[3], 25); ++ st[13] = rol64(st[19] ^ t[4], 8); ++ st[19] = rol64(st[23] ^ t[3], 56); ++ st[23] = rol64(st[15] ^ t[0], 41); ++ st[15] = rol64(st[ 4] ^ t[4], 27); ++ st[ 4] = rol64(st[24] ^ t[4], 14); ++ st[24] = rol64(st[21] ^ t[1], 2); ++ st[21] = rol64(st[ 8] ^ t[3], 55); ++ st[ 8] = rol64(st[16] ^ t[1], 45); ++ st[16] = rol64(st[ 5] ^ t[0], 36); ++ st[ 5] = rol64(st[ 3] ^ t[3], 28); ++ st[ 3] = rol64(st[18] ^ t[3], 21); ++ st[18] = rol64(st[17] ^ t[2], 15); ++ st[17] = rol64(st[11] ^ t[1], 10); ++ st[11] = rol64(st[ 7] ^ t[2], 6); ++ st[ 7] = rol64(st[10] ^ t[0], 3); ++ st[10] = rol64( tt ^ t[1], 1); ++ ++ /* Chi */ ++ bc[ 0] = ~st[ 1] & st[ 2]; ++ bc[ 1] = ~st[ 2] & st[ 3]; ++ bc[ 2] = ~st[ 3] & st[ 4]; ++ bc[ 3] = ~st[ 4] & st[ 0]; ++ bc[ 4] = ~st[ 0] & st[ 1]; ++ st[ 0] ^= bc[ 0]; ++ st[ 1] ^= bc[ 1]; ++ st[ 2] ^= bc[ 2]; ++ st[ 3] ^= bc[ 3]; ++ st[ 4] ^= bc[ 4]; ++ ++ bc[ 0] = ~st[ 6] & st[ 7]; ++ bc[ 1] = ~st[ 7] & st[ 8]; ++ bc[ 2] = ~st[ 8] & st[ 9]; ++ bc[ 3] = ~st[ 9] & st[ 5]; ++ bc[ 4] = ~st[ 5] & st[ 6]; ++ st[ 5] ^= bc[ 0]; ++ st[ 6] ^= bc[ 1]; ++ st[ 7] ^= bc[ 2]; ++ st[ 8] ^= bc[ 3]; ++ st[ 9] ^= bc[ 4]; ++ ++ bc[ 0] = ~st[11] & st[12]; ++ bc[ 1] = ~st[12] & st[13]; ++ bc[ 2] = ~st[13] & st[14]; ++ bc[ 3] = ~st[14] & st[10]; ++ bc[ 4] = ~st[10] & st[11]; ++ st[10] ^= bc[ 0]; ++ st[11] ^= bc[ 1]; ++ st[12] ^= bc[ 2]; ++ st[13] ^= bc[ 3]; ++ st[14] ^= bc[ 4]; ++ ++ bc[ 0] = ~st[16] & st[17]; ++ bc[ 1] = ~st[17] & st[18]; ++ bc[ 2] = ~st[18] & st[19]; ++ bc[ 3] = ~st[19] & st[15]; ++ bc[ 4] = ~st[15] & st[16]; ++ st[15] ^= bc[ 0]; ++ st[16] ^= bc[ 1]; ++ st[17] ^= bc[ 2]; ++ st[18] ^= bc[ 3]; ++ st[19] ^= bc[ 4]; ++ ++ bc[ 0] = ~st[21] & st[22]; ++ bc[ 1] = ~st[22] & st[23]; ++ bc[ 2] = ~st[23] & st[24]; ++ bc[ 3] = ~st[24] & st[20]; ++ bc[ 4] = ~st[20] & st[21]; ++ st[20] ^= bc[ 0]; ++ st[21] ^= bc[ 1]; ++ st[22] ^= bc[ 2]; ++ st[23] ^= bc[ 3]; ++ st[24] ^= bc[ 4]; ++} + +- /* Theta */ +- bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20]; +- bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21]; +- bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22]; +- bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23]; +- bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24]; +- +- t[0] = bc[4] ^ rol64(bc[1], 1); +- t[1] = bc[0] ^ rol64(bc[2], 1); +- t[2] = bc[1] ^ rol64(bc[3], 1); +- t[3] = bc[2] ^ rol64(bc[4], 1); +- t[4] = bc[3] ^ rol64(bc[0], 1); +- +- st[0] ^= t[0]; +- +- /* Rho Pi */ +- tt = st[1]; +- st[ 1] = rol64(st[ 6] ^ t[1], 44); +- st[ 6] = rol64(st[ 9] ^ t[4], 20); +- st[ 9] = rol64(st[22] ^ t[2], 61); +- st[22] = rol64(st[14] ^ t[4], 39); +- st[14] = rol64(st[20] ^ t[0], 18); +- st[20] = rol64(st[ 2] ^ t[2], 62); +- st[ 2] = rol64(st[12] ^ t[2], 43); +- st[12] = rol64(st[13] ^ t[3], 25); +- st[13] = rol64(st[19] ^ t[4], 8); +- st[19] = rol64(st[23] ^ t[3], 56); +- st[23] = rol64(st[15] ^ t[0], 41); +- st[15] = rol64(st[ 4] ^ t[4], 27); +- st[ 4] = rol64(st[24] ^ t[4], 14); +- st[24] = rol64(st[21] ^ t[1], 2); +- st[21] = rol64(st[ 8] ^ t[3], 55); +- st[ 8] = rol64(st[16] ^ t[1], 45); +- st[16] = rol64(st[ 5] ^ t[0], 36); +- st[ 5] = rol64(st[ 3] ^ t[3], 28); +- st[ 3] = rol64(st[18] ^ t[3], 21); +- st[18] = rol64(st[17] ^ t[2], 15); +- st[17] = rol64(st[11] ^ t[1], 10); +- st[11] = rol64(st[ 7] ^ t[2], 6); +- st[ 7] = rol64(st[10] ^ t[0], 3); +- st[10] = rol64( tt ^ t[1], 1); +- +- /* Chi */ +- bc[ 0] = ~st[ 1] & st[ 2]; +- bc[ 1] = ~st[ 2] & st[ 3]; +- bc[ 2] = ~st[ 3] & st[ 4]; +- bc[ 3] = ~st[ 4] & st[ 0]; +- bc[ 4] = ~st[ 0] & st[ 1]; +- st[ 0] ^= bc[ 0]; +- st[ 1] ^= bc[ 1]; +- st[ 2] ^= bc[ 2]; +- st[ 3] ^= bc[ 3]; +- st[ 4] ^= bc[ 4]; +- +- bc[ 0] = ~st[ 6] & st[ 7]; +- bc[ 1] = ~st[ 7] & st[ 8]; +- bc[ 2] = ~st[ 8] & st[ 9]; +- bc[ 3] = ~st[ 9] & st[ 5]; +- bc[ 4] = ~st[ 5] & st[ 6]; +- st[ 5] ^= bc[ 0]; +- st[ 6] ^= bc[ 1]; +- st[ 7] ^= bc[ 2]; +- st[ 8] ^= bc[ 3]; +- st[ 9] ^= bc[ 4]; +- +- bc[ 0] = ~st[11] & st[12]; +- bc[ 1] = ~st[12] & st[13]; +- bc[ 2] = ~st[13] & st[14]; +- bc[ 3] = ~st[14] & st[10]; +- bc[ 4] = ~st[10] & st[11]; +- st[10] ^= bc[ 0]; +- st[11] ^= bc[ 1]; +- st[12] ^= bc[ 2]; +- st[13] ^= bc[ 3]; +- st[14] ^= bc[ 4]; +- +- bc[ 0] = ~st[16] & st[17]; +- bc[ 1] = ~st[17] & st[18]; +- bc[ 2] = ~st[18] & st[19]; +- bc[ 3] = ~st[19] & st[15]; +- bc[ 4] = ~st[15] & st[16]; +- st[15] ^= bc[ 0]; +- st[16] ^= bc[ 1]; +- st[17] ^= bc[ 2]; +- st[18] ^= bc[ 3]; +- st[19] ^= bc[ 4]; +- +- bc[ 0] = ~st[21] & st[22]; +- bc[ 1] = ~st[22] & st[23]; +- bc[ 2] = ~st[23] & st[24]; +- bc[ 3] = ~st[24] & st[20]; +- bc[ 4] = ~st[20] & st[21]; +- st[20] ^= bc[ 0]; +- st[21] ^= bc[ 1]; +- st[22] ^= bc[ 2]; +- st[23] ^= bc[ 3]; +- st[24] ^= bc[ 4]; ++static void __optimize("O3") keccakf(u64 st[25]) ++{ ++ int round; + ++ for (round = 0; round < KECCAK_ROUNDS; round++) { ++ keccakf_round(st); + /* Iota */ + st[0] ^= keccakf_rndc[round]; + } +diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c +index 676c978..0dad0bd 100644 +--- a/drivers/acpi/bus.c ++++ b/drivers/acpi/bus.c +@@ -660,13 +660,15 @@ struct acpi_device *acpi_companion_match(const struct device *dev) + * acpi_of_match_device - Match device object using the "compatible" property. + * @adev: ACPI device object to match. + * @of_match_table: List of device IDs to match against. ++ * @of_id: OF ID if matched + * + * If @dev has an ACPI companion which has ACPI_DT_NAMESPACE_HID in its list of + * identifiers and a _DSD object with the "compatible" property, use that + * property to match against the given list of identifiers. + */ + static bool acpi_of_match_device(struct acpi_device *adev, +- const struct of_device_id *of_match_table) ++ const struct of_device_id *of_match_table, ++ const struct of_device_id **of_id) + { + const union acpi_object *of_compatible, *obj; + int i, nval; +@@ -690,8 +692,11 @@ static bool acpi_of_match_device(struct acpi_device *adev, + const struct of_device_id *id; + + for (id = of_match_table; id->compatible[0]; id++) +- if (!strcasecmp(obj->string.pointer, id->compatible)) ++ if (!strcasecmp(obj->string.pointer, id->compatible)) { ++ if (of_id) ++ *of_id = id; + return true; ++ } + } + + return false; +@@ -762,10 +767,11 @@ static bool __acpi_match_device_cls(const struct acpi_device_id *id, + return true; + } + +-static const struct acpi_device_id *__acpi_match_device( +- struct acpi_device *device, +- const struct acpi_device_id *ids, +- const struct of_device_id *of_ids) ++static bool __acpi_match_device(struct acpi_device *device, ++ const struct acpi_device_id *acpi_ids, ++ const struct of_device_id *of_ids, ++ const struct acpi_device_id **acpi_id, ++ const struct of_device_id **of_id) + { + const struct acpi_device_id *id; + struct acpi_hardware_id *hwid; +@@ -775,30 +781,32 @@ static const struct acpi_device_id *__acpi_match_device( + * driver for it. + */ + if (!device || !device->status.present) +- return NULL; ++ return false; + + list_for_each_entry(hwid, &device->pnp.ids, list) { + /* First, check the ACPI/PNP IDs provided by the caller. */ +- for (id = ids; id->id[0] || id->cls; id++) { +- if (id->id[0] && !strcmp((char *) id->id, hwid->id)) +- return id; +- else if (id->cls && __acpi_match_device_cls(id, hwid)) +- return id; ++ if (acpi_ids) { ++ for (id = acpi_ids; id->id[0] || id->cls; id++) { ++ if (id->id[0] && !strcmp((char *)id->id, hwid->id)) ++ goto out_acpi_match; ++ if (id->cls && __acpi_match_device_cls(id, hwid)) ++ goto out_acpi_match; ++ } + } + + /* + * Next, check ACPI_DT_NAMESPACE_HID and try to match the + * "compatible" property if found. +- * +- * The id returned by the below is not valid, but the only +- * caller passing non-NULL of_ids here is only interested in +- * whether or not the return value is NULL. + */ +- if (!strcmp(ACPI_DT_NAMESPACE_HID, hwid->id) +- && acpi_of_match_device(device, of_ids)) +- return id; ++ if (!strcmp(ACPI_DT_NAMESPACE_HID, hwid->id)) ++ return acpi_of_match_device(device, of_ids, of_id); + } +- return NULL; ++ return false; ++ ++out_acpi_match: ++ if (acpi_id) ++ *acpi_id = id; ++ return true; + } + + /** +@@ -815,32 +823,29 @@ static const struct acpi_device_id *__acpi_match_device( + const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, + const struct device *dev) + { +- return __acpi_match_device(acpi_companion_match(dev), ids, NULL); ++ const struct acpi_device_id *id = NULL; ++ ++ __acpi_match_device(acpi_companion_match(dev), ids, NULL, &id, NULL); ++ return id; + } + EXPORT_SYMBOL_GPL(acpi_match_device); + +-void *acpi_get_match_data(const struct device *dev) ++const void *acpi_device_get_match_data(const struct device *dev) + { + const struct acpi_device_id *match; + +- if (!dev->driver) +- return NULL; +- +- if (!dev->driver->acpi_match_table) +- return NULL; +- + match = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!match) + return NULL; + +- return (void *)match->driver_data; ++ return (const void *)match->driver_data; + } +-EXPORT_SYMBOL_GPL(acpi_get_match_data); ++EXPORT_SYMBOL_GPL(acpi_device_get_match_data); + + int acpi_match_device_ids(struct acpi_device *device, + const struct acpi_device_id *ids) + { +- return __acpi_match_device(device, ids, NULL) ? 0 : -ENOENT; ++ return __acpi_match_device(device, ids, NULL, NULL, NULL) ? 0 : -ENOENT; + } + EXPORT_SYMBOL(acpi_match_device_ids); + +@@ -849,10 +854,12 @@ bool acpi_driver_match_device(struct device *dev, + { + if (!drv->acpi_match_table) + return acpi_of_match_device(ACPI_COMPANION(dev), +- drv->of_match_table); ++ drv->of_match_table, ++ NULL); + +- return !!__acpi_match_device(acpi_companion_match(dev), +- drv->acpi_match_table, drv->of_match_table); ++ return __acpi_match_device(acpi_companion_match(dev), ++ drv->acpi_match_table, drv->of_match_table, ++ NULL, NULL); + } + EXPORT_SYMBOL_GPL(acpi_driver_match_device); + +diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c +index d9f38c6..30a5729 100644 +--- a/drivers/acpi/ec.c ++++ b/drivers/acpi/ec.c +@@ -1927,6 +1927,9 @@ static int acpi_ec_suspend_noirq(struct device *dev) + ec->reference_count >= 1) + acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE); + ++ if (acpi_sleep_no_ec_events()) ++ acpi_ec_enter_noirq(ec); ++ + return 0; + } + +@@ -1934,6 +1937,9 @@ static int acpi_ec_resume_noirq(struct device *dev) + { + struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev)); + ++ if (acpi_sleep_no_ec_events()) ++ acpi_ec_leave_noirq(ec); ++ + if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) && + ec->reference_count >= 1) + acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE); +diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c +index 466d150..5815356 100644 +--- a/drivers/acpi/property.c ++++ b/drivers/acpi/property.c +@@ -1271,11 +1271,11 @@ static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, + return 0; + } + +-static void * ++static const void * + acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, + const struct device *dev) + { +- return acpi_get_match_data(dev); ++ return acpi_device_get_match_data(dev); + } + + #define DECLARE_ACPI_FWNODE_OPS(ops) \ +diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c +index 89e97d2..9d52743 100644 +--- a/drivers/acpi/spcr.c ++++ b/drivers/acpi/spcr.c +@@ -115,6 +115,7 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console) + table->serial_port.access_width))) { + default: + pr_err("Unexpected SPCR Access Width. Defaulting to byte size\n"); ++ /* fall through */ + case 8: + iotype = "mmio"; + break; +diff --git a/drivers/android/binder.c b/drivers/android/binder.c +index 15e3d3c..764b63a 100644 +--- a/drivers/android/binder.c ++++ b/drivers/android/binder.c +@@ -1991,8 +1991,14 @@ static void binder_send_failed_reply(struct binder_transaction *t, + &target_thread->reply_error.work); + wake_up_interruptible(&target_thread->wait); + } else { +- WARN(1, "Unexpected reply error: %u\n", +- target_thread->reply_error.cmd); ++ /* ++ * Cannot get here for normal operation, but ++ * we can if multiple synchronous transactions ++ * are sent without blocking for responses. ++ * Just ignore the 2nd error in this case. ++ */ ++ pr_warn("Unexpected reply error: %u\n", ++ target_thread->reply_error.cmd); + } + binder_inner_proc_unlock(target_thread->proc); + binder_thread_dec_tmpref(target_thread); +@@ -2193,7 +2199,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, + int debug_id = buffer->debug_id; + + binder_debug(BINDER_DEBUG_TRANSACTION, +- "%d buffer release %d, size %zd-%zd, failed at %p\n", ++ "%d buffer release %d, size %zd-%zd, failed at %pK\n", + proc->pid, buffer->debug_id, + buffer->data_size, buffer->offsets_size, failed_at); + +@@ -3705,7 +3711,7 @@ static int binder_thread_write(struct binder_proc *proc, + } + } + binder_debug(BINDER_DEBUG_DEAD_BINDER, +- "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n", ++ "%d:%d BC_DEAD_BINDER_DONE %016llx found %pK\n", + proc->pid, thread->pid, (u64)cookie, + death); + if (death == NULL) { +@@ -4376,6 +4382,15 @@ static int binder_thread_release(struct binder_proc *proc, + + binder_inner_proc_unlock(thread->proc); + ++ /* ++ * This is needed to avoid races between wake_up_poll() above and ++ * and ep_remove_waitqueue() called for other reasons (eg the epoll file ++ * descriptor being closed); ep_remove_waitqueue() holds an RCU read ++ * lock, so we can be sure it's done after calling synchronize_rcu(). ++ */ ++ if (thread->looper & BINDER_LOOPER_STATE_POLL) ++ synchronize_rcu(); ++ + if (send_reply) + binder_send_failed_reply(send_reply, BR_DEAD_REPLY); + binder_release_work(proc, &thread->todo); +@@ -4391,6 +4406,8 @@ static __poll_t binder_poll(struct file *filp, + bool wait_for_proc_work; + + thread = binder_get_thread(proc); ++ if (!thread) ++ return POLLERR; + + binder_inner_proc_lock(thread->proc); + thread->looper |= BINDER_LOOPER_STATE_POLL; +@@ -5034,7 +5051,7 @@ static void print_binder_transaction_ilocked(struct seq_file *m, + spin_lock(&t->lock); + to_proc = t->to_proc; + seq_printf(m, +- "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d", ++ "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %ld r%d", + prefix, t->debug_id, t, + t->from ? t->from->proc->pid : 0, + t->from ? t->from->pid : 0, +@@ -5058,7 +5075,7 @@ static void print_binder_transaction_ilocked(struct seq_file *m, + } + if (buffer->target_node) + seq_printf(m, " node %d", buffer->target_node->debug_id); +- seq_printf(m, " size %zd:%zd data %p\n", ++ seq_printf(m, " size %zd:%zd data %pK\n", + buffer->data_size, buffer->offsets_size, + buffer->data); + } +diff --git a/drivers/base/core.c b/drivers/base/core.c +index b2261f9..5847364 100644 +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -310,6 +310,9 @@ static void __device_link_del(struct device_link *link) + dev_info(link->consumer, "Dropping the link to %s\n", + dev_name(link->supplier)); + ++ if (link->flags & DL_FLAG_PM_RUNTIME) ++ pm_runtime_drop_link(link->consumer); ++ + list_del(&link->s_node); + list_del(&link->c_node); + device_link_free(link); +diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c +index a8ac86e..6637fc3 100644 +--- a/drivers/base/power/wakeirq.c ++++ b/drivers/base/power/wakeirq.c +@@ -321,7 +321,8 @@ void dev_pm_arm_wake_irq(struct wake_irq *wirq) + return; + + if (device_may_wakeup(wirq->dev)) { +- if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED) ++ if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED && ++ !pm_runtime_status_suspended(wirq->dev)) + enable_irq(wirq->irq); + + enable_irq_wake(wirq->irq); +@@ -343,7 +344,8 @@ void dev_pm_disarm_wake_irq(struct wake_irq *wirq) + if (device_may_wakeup(wirq->dev)) { + disable_irq_wake(wirq->irq); + +- if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED) ++ if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED && ++ !pm_runtime_status_suspended(wirq->dev)) + disable_irq_nosync(wirq->irq); + } + } +diff --git a/drivers/base/property.c b/drivers/base/property.c +index 3022362..8f205f6 100644 +--- a/drivers/base/property.c ++++ b/drivers/base/property.c +@@ -1410,9 +1410,8 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, + } + EXPORT_SYMBOL(fwnode_graph_parse_endpoint); + +-void *device_get_match_data(struct device *dev) ++const void *device_get_match_data(struct device *dev) + { +- return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, +- dev); ++ return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, dev); + } + EXPORT_SYMBOL_GPL(device_get_match_data); +diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c +index e5aa62f..3aaf6af 100644 +--- a/drivers/block/amiflop.c ++++ b/drivers/block/amiflop.c +@@ -1758,7 +1758,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) + if (unit[drive].type->code == FD_NODRIVE) + return NULL; + *part = 0; +- return get_disk(unit[drive].gendisk); ++ return get_disk_and_module(unit[drive].gendisk); + } + + static int __init amiga_floppy_probe(struct platform_device *pdev) +diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c +index 8bc3b9f..dfb2c26 100644 +--- a/drivers/block/ataflop.c ++++ b/drivers/block/ataflop.c +@@ -1917,7 +1917,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) + if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS) + return NULL; + *part = 0; +- return get_disk(unit[drive].disk); ++ return get_disk_and_module(unit[drive].disk); + } + + static int __init atari_floppy_init (void) +diff --git a/drivers/block/brd.c b/drivers/block/brd.c +index 8028a3a..deea78e 100644 +--- a/drivers/block/brd.c ++++ b/drivers/block/brd.c +@@ -456,7 +456,7 @@ static struct kobject *brd_probe(dev_t dev, int *part, void *data) + + mutex_lock(&brd_devices_mutex); + brd = brd_init_one(MINOR(dev) / max_part, &new); +- kobj = brd ? get_disk(brd->brd_disk) : NULL; ++ kobj = brd ? get_disk_and_module(brd->brd_disk) : NULL; + mutex_unlock(&brd_devices_mutex); + + if (new) +diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c +index eae484a..8ec7235 100644 +--- a/drivers/block/floppy.c ++++ b/drivers/block/floppy.c +@@ -4505,7 +4505,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) + if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type)) + return NULL; + *part = 0; +- return get_disk(disks[drive]); ++ return get_disk_and_module(disks[drive]); + } + + static int __init do_floppy_init(void) +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index d5fe720..ee62d2d 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -266,7 +266,7 @@ static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos) + struct iov_iter i; + ssize_t bw; + +- iov_iter_bvec(&i, ITER_BVEC, bvec, 1, bvec->bv_len); ++ iov_iter_bvec(&i, ITER_BVEC | WRITE, bvec, 1, bvec->bv_len); + + file_start_write(file); + bw = vfs_iter_write(file, &i, ppos, 0); +@@ -1922,7 +1922,7 @@ static struct kobject *loop_probe(dev_t dev, int *part, void *data) + if (err < 0) + kobj = NULL; + else +- kobj = get_disk(lo->lo_disk); ++ kobj = get_disk_and_module(lo->lo_disk); + mutex_unlock(&loop_index_mutex); + + *part = 0; +diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c +index 5f2a424..86258b0 100644 +--- a/drivers/block/nbd.c ++++ b/drivers/block/nbd.c +@@ -1591,7 +1591,7 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) + if (new_index < 0) { + mutex_unlock(&nbd_index_mutex); + printk(KERN_ERR "nbd: failed to add new device\n"); +- return ret; ++ return new_index; + } + nbd = idr_find(&nbd_index_idr, new_index); + } +diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c +index 531a091..c61d20c 100644 +--- a/drivers/block/pktcdvd.c ++++ b/drivers/block/pktcdvd.c +@@ -1122,7 +1122,7 @@ static int pkt_start_recovery(struct packet_data *pkt) + pkt->sector = new_sector; + + bio_reset(pkt->bio); +- bio_set_set(pkt->bio, pd->bdev); ++ bio_set_dev(pkt->bio, pd->bdev); + bio_set_op_attrs(pkt->bio, REQ_OP_WRITE, 0); + pkt->bio->bi_iter.bi_sector = new_sector; + pkt->bio->bi_iter.bi_size = pkt->frames * CD_FRAMESIZE; +diff --git a/drivers/block/swim.c b/drivers/block/swim.c +index 84434d3..64e066e 100644 +--- a/drivers/block/swim.c ++++ b/drivers/block/swim.c +@@ -799,7 +799,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) + return NULL; + + *part = 0; +- return get_disk(swd->unit[drive].disk); ++ return get_disk_and_module(swd->unit[drive].disk); + } + + static int swim_add_floppy(struct swim_priv *swd, enum drive_location location) +diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c +index e126e4c..92ec1bb 100644 +--- a/drivers/block/xen-blkfront.c ++++ b/drivers/block/xen-blkfront.c +@@ -262,6 +262,7 @@ static DEFINE_SPINLOCK(minor_lock); + + static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo); + static void blkfront_gather_backend_features(struct blkfront_info *info); ++static int negotiate_mq(struct blkfront_info *info); + + static int get_id_from_freelist(struct blkfront_ring_info *rinfo) + { +@@ -1774,11 +1775,18 @@ static int talk_to_blkback(struct xenbus_device *dev, + unsigned int i, max_page_order; + unsigned int ring_page_order; + ++ if (!info) ++ return -ENODEV; ++ + max_page_order = xenbus_read_unsigned(info->xbdev->otherend, + "max-ring-page-order", 0); + ring_page_order = min(xen_blkif_max_ring_order, max_page_order); + info->nr_ring_pages = 1 << ring_page_order; + ++ err = negotiate_mq(info); ++ if (err) ++ goto destroy_blkring; ++ + for (i = 0; i < info->nr_rings; i++) { + struct blkfront_ring_info *rinfo = &info->rinfo[i]; + +@@ -1978,11 +1986,6 @@ static int blkfront_probe(struct xenbus_device *dev, + } + + info->xbdev = dev; +- err = negotiate_mq(info); +- if (err) { +- kfree(info); +- return err; +- } + + mutex_init(&info->mutex); + info->vdevice = vdevice; +@@ -2099,10 +2102,6 @@ static int blkfront_resume(struct xenbus_device *dev) + + blkif_free(info, info->connected == BLKIF_STATE_CONNECTED); + +- err = negotiate_mq(info); +- if (err) +- return err; +- + err = talk_to_blkback(dev, info); + if (!err) + blk_mq_update_nr_hw_queues(&info->tag_set, info->nr_rings); +diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c +index 41c95c9..8f9130a 100644 +--- a/drivers/block/z2ram.c ++++ b/drivers/block/z2ram.c +@@ -332,7 +332,7 @@ static const struct block_device_operations z2_fops = + static struct kobject *z2_find(dev_t dev, int *part, void *data) + { + *part = 0; +- return get_disk(z2ram_gendisk); ++ return get_disk_and_module(z2ram_gendisk); + } + + static struct request_queue *z2_queue; +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 2a55380..60bf04b 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -21,6 +21,7 @@ + * + */ + ++#include + #include + #include + #include +@@ -379,6 +380,21 @@ static const struct usb_device_id blacklist_table[] = { + { } /* Terminating entry */ + }; + ++/* The Bluetooth USB module build into some devices needs to be reset on resume, ++ * this is a problem with the platform (likely shutting off all power) not with ++ * the module itself. So we use a DMI list to match known broken platforms. ++ */ ++static const struct dmi_system_id btusb_needs_reset_resume_table[] = { ++ { ++ /* Lenovo Yoga 920 (QCA Rome device 0cf3:e300) */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 920"), ++ }, ++ }, ++ {} ++}; ++ + #define BTUSB_MAX_ISOC_FRAMES 10 + + #define BTUSB_INTR_RUNNING 0 +@@ -2945,6 +2961,9 @@ static int btusb_probe(struct usb_interface *intf, + hdev->send = btusb_send_frame; + hdev->notify = btusb_notify; + ++ if (dmi_check_system(btusb_needs_reset_resume_table)) ++ interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME; ++ + #ifdef CONFIG_PM + err = btusb_config_oob_wake(hdev); + if (err) +@@ -3031,12 +3050,6 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_QCA_ROME) { + data->setup_on_usb = btusb_setup_qca; + hdev->set_bdaddr = btusb_set_bdaddr_ath3012; +- +- /* QCA Rome devices lose their updated firmware over suspend, +- * but the USB hub doesn't notice any status change. +- * explicitly request a device reset on resume. +- */ +- interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME; + } + + #ifdef CONFIG_BT_HCIBTUSB_RTL +diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c +index 0438a64..6314dfb 100644 +--- a/drivers/bluetooth/hci_bcm.c ++++ b/drivers/bluetooth/hci_bcm.c +@@ -922,12 +922,13 @@ static int bcm_get_resources(struct bcm_device *dev) + + dev->clk = devm_clk_get(dev->dev, NULL); + +- dev->device_wakeup = devm_gpiod_get(dev->dev, "device-wakeup", +- GPIOD_OUT_LOW); ++ dev->device_wakeup = devm_gpiod_get_optional(dev->dev, "device-wakeup", ++ GPIOD_OUT_LOW); + if (IS_ERR(dev->device_wakeup)) + return PTR_ERR(dev->device_wakeup); + +- dev->shutdown = devm_gpiod_get(dev->dev, "shutdown", GPIOD_OUT_LOW); ++ dev->shutdown = devm_gpiod_get_optional(dev->dev, "shutdown", ++ GPIOD_OUT_LOW); + if (IS_ERR(dev->shutdown)) + return PTR_ERR(dev->shutdown); + +diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c +index 4d46003..cdaeeea 100644 +--- a/drivers/bus/ti-sysc.c ++++ b/drivers/bus/ti-sysc.c +@@ -630,7 +630,7 @@ static int sysc_init_dts_quirks(struct sysc *ddata) + for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) { + prop = of_get_property(np, sysc_dts_quirks[i].name, &len); + if (!prop) +- break; ++ continue; + + ddata->cfg.quirks |= sysc_dts_quirks[i].mask; + } +diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c +index d1f5bb5..6e9df55 100644 +--- a/drivers/char/hw_random/via-rng.c ++++ b/drivers/char/hw_random/via-rng.c +@@ -162,7 +162,7 @@ static int via_rng_init(struct hwrng *rng) + /* Enable secondary noise source on CPUs where it is present. */ + + /* Nehemiah stepping 8 and higher */ +- if ((c->x86_model == 9) && (c->x86_mask > 7)) ++ if ((c->x86_model == 9) && (c->x86_stepping > 7)) + lo |= VIA_NOISESRC2; + + /* Esther */ +diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c +index 4d1dc8b..f95b9c7 100644 +--- a/drivers/char/tpm/st33zp24/st33zp24.c ++++ b/drivers/char/tpm/st33zp24/st33zp24.c +@@ -457,7 +457,7 @@ static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf, + size_t count) + { + int size = 0; +- int expected; ++ u32 expected; + + if (!chip) + return -EBUSY; +@@ -474,7 +474,7 @@ static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf, + } + + expected = be32_to_cpu(*(__be32 *)(buf + 2)); +- if (expected > count) { ++ if (expected > count || expected < TPM_HEADER_SIZE) { + size = -EIO; + goto out; + } +diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c +index 76df4fb..9e80a95 100644 +--- a/drivers/char/tpm/tpm-interface.c ++++ b/drivers/char/tpm/tpm-interface.c +@@ -1190,6 +1190,10 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) + break; + + recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len); ++ if (recd > num_bytes) { ++ total = -EFAULT; ++ break; ++ } + + rlength = be32_to_cpu(tpm_cmd.header.out.length); + if (rlength < offsetof(struct tpm_getrandom_out, rng_data) + +diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c +index c17e753..a700f8f 100644 +--- a/drivers/char/tpm/tpm2-cmd.c ++++ b/drivers/char/tpm/tpm2-cmd.c +@@ -683,6 +683,10 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, + if (!rc) { + data_len = be16_to_cpup( + (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]); ++ if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE + 1) { ++ rc = -EFAULT; ++ goto out; ++ } + + rlength = be32_to_cpu(((struct tpm2_cmd *)&buf) + ->header.out.length); +diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c +index c1dd39e..6116cd0 100644 +--- a/drivers/char/tpm/tpm_i2c_infineon.c ++++ b/drivers/char/tpm/tpm_i2c_infineon.c +@@ -473,7 +473,8 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) + static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) + { + int size = 0; +- int expected, status; ++ int status; ++ u32 expected; + + if (count < TPM_HEADER_SIZE) { + size = -EIO; +@@ -488,7 +489,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) + } + + expected = be32_to_cpu(*(__be32 *)(buf + 2)); +- if ((size_t) expected > count) { ++ if (((size_t) expected > count) || (expected < TPM_HEADER_SIZE)) { + size = -EIO; + goto out; + } +diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c +index c642877..caa86b1 100644 +--- a/drivers/char/tpm/tpm_i2c_nuvoton.c ++++ b/drivers/char/tpm/tpm_i2c_nuvoton.c +@@ -281,7 +281,11 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) + struct device *dev = chip->dev.parent; + struct i2c_client *client = to_i2c_client(dev); + s32 rc; +- int expected, status, burst_count, retries, size = 0; ++ int status; ++ int burst_count; ++ int retries; ++ int size = 0; ++ u32 expected; + + if (count < TPM_HEADER_SIZE) { + i2c_nuvoton_ready(chip); /* return to idle */ +@@ -323,7 +327,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) + * to machine native + */ + expected = be32_to_cpu(*(__be32 *) (buf + 2)); +- if (expected > count) { ++ if (expected > count || expected < size) { + dev_err(dev, "%s() expected > count\n", __func__); + size = -EIO; + continue; +diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c +index 183a5f5..da074e3 100644 +--- a/drivers/char/tpm/tpm_tis_core.c ++++ b/drivers/char/tpm/tpm_tis_core.c +@@ -270,7 +270,8 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) + { + struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); + int size = 0; +- int expected, status; ++ int status; ++ u32 expected; + + if (count < TPM_HEADER_SIZE) { + size = -EIO; +@@ -285,7 +286,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) + } + + expected = be32_to_cpu(*(__be32 *) (buf + 2)); +- if (expected > count) { ++ if (expected > count || expected < TPM_HEADER_SIZE) { + size = -EIO; + goto out; + } +diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig +index b3b4ed9..d2e5382 100644 +--- a/drivers/clocksource/Kconfig ++++ b/drivers/clocksource/Kconfig +@@ -386,6 +386,7 @@ config ATMEL_PIT + + config ATMEL_ST + bool "Atmel ST timer support" if COMPILE_TEST ++ depends on HAS_IOMEM + select TIMER_OF + select MFD_SYSCON + help +diff --git a/drivers/clocksource/arc_timer.c b/drivers/clocksource/arc_timer.c +index 4927355..471b428 100644 +--- a/drivers/clocksource/arc_timer.c ++++ b/drivers/clocksource/arc_timer.c +@@ -251,9 +251,14 @@ static irqreturn_t timer_irq_handler(int irq, void *dev_id) + int irq_reenable = clockevent_state_periodic(evt); + + /* +- * Any write to CTRL reg ACks the interrupt, we rewrite the +- * Count when [N]ot [H]alted bit. +- * And re-arm it if perioid by [I]nterrupt [E]nable bit ++ * 1. ACK the interrupt ++ * - For ARC700, any write to CTRL reg ACKs it, so just rewrite ++ * Count when [N]ot [H]alted bit. ++ * - For HS3x, it is a bit subtle. On taken count-down interrupt, ++ * IP bit [3] is set, which needs to be cleared for ACK'ing. ++ * The write below can only update the other two bits, hence ++ * explicitly clears IP bit ++ * 2. Re-arm interrupt if periodic by writing to IE bit [0] + */ + write_aux_reg(ARC_REG_TIMER0_CTRL, irq_reenable | TIMER_CTRL_NH); + +diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c +index 3ee7e6f..846d18d 100644 +--- a/drivers/clocksource/fsl_ftm_timer.c ++++ b/drivers/clocksource/fsl_ftm_timer.c +@@ -281,7 +281,7 @@ static int __init __ftm_clk_init(struct device_node *np, char *cnt_name, + + static unsigned long __init ftm_clk_init(struct device_node *np) + { +- unsigned long freq; ++ long freq; + + freq = __ftm_clk_init(np, "ftm-evt-counter-en", "ftm-evt"); + if (freq <= 0) +diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c +index a04808a..986b679 100644 +--- a/drivers/clocksource/mips-gic-timer.c ++++ b/drivers/clocksource/mips-gic-timer.c +@@ -166,7 +166,7 @@ static int __init __gic_clocksource_init(void) + + /* Set clocksource mask. */ + count_width = read_gic_config() & GIC_CONFIG_COUNTBITS; +- count_width >>= __fls(GIC_CONFIG_COUNTBITS); ++ count_width >>= __ffs(GIC_CONFIG_COUNTBITS); + count_width *= 4; + count_width += 32; + gic_clocksource.mask = CLOCKSOURCE_MASK(count_width); +@@ -205,12 +205,12 @@ static int __init gic_clocksource_of_init(struct device_node *node) + } else if (of_property_read_u32(node, "clock-frequency", + &gic_frequency)) { + pr_err("GIC frequency not specified.\n"); +- return -EINVAL;; ++ return -EINVAL; + } + gic_timer_irq = irq_of_parse_and_map(node, 0); + if (!gic_timer_irq) { + pr_err("GIC timer IRQ not specified.\n"); +- return -EINVAL;; ++ return -EINVAL; + } + + ret = __gic_clocksource_init(); +diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c +index 2a3fe83..3b56ea3 100644 +--- a/drivers/clocksource/timer-sun5i.c ++++ b/drivers/clocksource/timer-sun5i.c +@@ -334,7 +334,7 @@ static int __init sun5i_timer_init(struct device_node *node) + timer_base = of_io_request_and_map(node, 0, of_node_full_name(node)); + if (IS_ERR(timer_base)) { + pr_err("Can't map registers\n"); +- return PTR_ERR(timer_base);; ++ return PTR_ERR(timer_base); + } + + irq = irq_of_parse_and_map(node, 0); +diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm +index 3a88e33..fb586e0 100644 +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -44,10 +44,10 @@ config ARM_DT_BL_CPUFREQ + + config ARM_SCPI_CPUFREQ + tristate "SCPI based CPUfreq driver" +- depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI ++ depends on ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI + help +- This adds the CPUfreq driver support for ARM big.LITTLE platforms +- using SCPI protocol for CPU power management. ++ This adds the CPUfreq driver support for ARM platforms using SCPI ++ protocol for CPU power management. + + This driver uses SCPI Message Protocol driver to interact with the + firmware providing the CPU DVFS functionality. +diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c +index 3a2ca0f..d0c34df 100644 +--- a/drivers/cpufreq/acpi-cpufreq.c ++++ b/drivers/cpufreq/acpi-cpufreq.c +@@ -629,7 +629,7 @@ static int acpi_cpufreq_blacklist(struct cpuinfo_x86 *c) + if (c->x86_vendor == X86_VENDOR_INTEL) { + if ((c->x86 == 15) && + (c->x86_model == 6) && +- (c->x86_mask == 8)) { ++ (c->x86_stepping == 8)) { + pr_info("Intel(R) Xeon(R) 7100 Errata AL30, processors may lock up on frequency changes: disabling acpi-cpufreq\n"); + return -ENODEV; + } +diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c +index 942632a..f730b65 100644 +--- a/drivers/cpufreq/longhaul.c ++++ b/drivers/cpufreq/longhaul.c +@@ -775,7 +775,7 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy) + break; + + case 7: +- switch (c->x86_mask) { ++ switch (c->x86_stepping) { + case 0: + longhaul_version = TYPE_LONGHAUL_V1; + cpu_model = CPU_SAMUEL2; +@@ -787,7 +787,7 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy) + break; + case 1 ... 15: + longhaul_version = TYPE_LONGHAUL_V2; +- if (c->x86_mask < 8) { ++ if (c->x86_stepping < 8) { + cpu_model = CPU_SAMUEL2; + cpuname = "C3 'Samuel 2' [C5B]"; + } else { +@@ -814,7 +814,7 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy) + numscales = 32; + memcpy(mults, nehemiah_mults, sizeof(nehemiah_mults)); + memcpy(eblcr, nehemiah_eblcr, sizeof(nehemiah_eblcr)); +- switch (c->x86_mask) { ++ switch (c->x86_stepping) { + case 0 ... 1: + cpu_model = CPU_NEHEMIAH; + cpuname = "C3 'Nehemiah A' [C5XLOE]"; +diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c +index fd77812..a25741b 100644 +--- a/drivers/cpufreq/p4-clockmod.c ++++ b/drivers/cpufreq/p4-clockmod.c +@@ -168,7 +168,7 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) + #endif + + /* Errata workaround */ +- cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask; ++ cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_stepping; + switch (cpuid) { + case 0x0f07: + case 0x0f0a: +diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c +index 80ac313..302e9ce 100644 +--- a/drivers/cpufreq/powernow-k7.c ++++ b/drivers/cpufreq/powernow-k7.c +@@ -131,7 +131,7 @@ static int check_powernow(void) + return 0; + } + +- if ((c->x86_model == 6) && (c->x86_mask == 0)) { ++ if ((c->x86_model == 6) && (c->x86_stepping == 0)) { + pr_info("K7 660[A0] core detected, enabling errata workarounds\n"); + have_a0 = 1; + } +diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c +index 7b596fa..6bebc1f 100644 +--- a/drivers/cpufreq/s3c24xx-cpufreq.c ++++ b/drivers/cpufreq/s3c24xx-cpufreq.c +@@ -351,7 +351,13 @@ struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name) + static int s3c_cpufreq_init(struct cpufreq_policy *policy) + { + policy->clk = clk_arm; +- return cpufreq_generic_init(policy, ftab, cpu_cur.info->latency); ++ ++ policy->cpuinfo.transition_latency = cpu_cur.info->latency; ++ ++ if (ftab) ++ return cpufreq_table_validate_and_show(policy, ftab); ++ ++ return 0; + } + + static int __init s3c_cpufreq_initclks(void) +diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c +index c32a833..d300a16 100644 +--- a/drivers/cpufreq/scpi-cpufreq.c ++++ b/drivers/cpufreq/scpi-cpufreq.c +@@ -51,15 +51,23 @@ static unsigned int scpi_cpufreq_get_rate(unsigned int cpu) + static int + scpi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) + { ++ unsigned long freq = policy->freq_table[index].frequency; + struct scpi_data *priv = policy->driver_data; +- u64 rate = policy->freq_table[index].frequency * 1000; ++ u64 rate = freq * 1000; + int ret; + + ret = clk_set_rate(priv->clk, rate); +- if (!ret && (clk_get_rate(priv->clk) != rate)) +- ret = -EIO; + +- return ret; ++ if (ret) ++ return ret; ++ ++ if (clk_get_rate(priv->clk) != rate) ++ return -EIO; ++ ++ arch_set_freq_scale(policy->related_cpus, freq, ++ policy->cpuinfo.max_freq); ++ ++ return 0; + } + + static int +diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c +index 41bc539..4fa5adf 100644 +--- a/drivers/cpufreq/speedstep-centrino.c ++++ b/drivers/cpufreq/speedstep-centrino.c +@@ -37,7 +37,7 @@ struct cpu_id + { + __u8 x86; /* CPU family */ + __u8 x86_model; /* model */ +- __u8 x86_mask; /* stepping */ ++ __u8 x86_stepping; /* stepping */ + }; + + enum { +@@ -277,7 +277,7 @@ static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, + { + if ((c->x86 == x->x86) && + (c->x86_model == x->x86_model) && +- (c->x86_mask == x->x86_mask)) ++ (c->x86_stepping == x->x86_stepping)) + return 1; + return 0; + } +diff --git a/drivers/cpufreq/speedstep-lib.c b/drivers/cpufreq/speedstep-lib.c +index 8085ec9..e3a9962 100644 +--- a/drivers/cpufreq/speedstep-lib.c ++++ b/drivers/cpufreq/speedstep-lib.c +@@ -272,9 +272,9 @@ unsigned int speedstep_detect_processor(void) + ebx = cpuid_ebx(0x00000001); + ebx &= 0x000000FF; + +- pr_debug("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask); ++ pr_debug("ebx value is %x, x86_stepping is %x\n", ebx, c->x86_stepping); + +- switch (c->x86_mask) { ++ switch (c->x86_stepping) { + case 4: + /* + * B-stepping [M-P4-M] +@@ -361,7 +361,7 @@ unsigned int speedstep_detect_processor(void) + msr_lo, msr_hi); + if ((msr_hi & (1<<18)) && + (relaxed_check ? 1 : (msr_hi & (3<<24)))) { +- if (c->x86_mask == 0x01) { ++ if (c->x86_stepping == 0x01) { + pr_debug("early PIII version\n"); + return SPEEDSTEP_CPU_PIII_C_EARLY; + } else +diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c +index 75d280c..e843cf4 100644 +--- a/drivers/crypto/caam/ctrl.c ++++ b/drivers/crypto/caam/ctrl.c +@@ -228,12 +228,16 @@ static int instantiate_rng(struct device *ctrldev, int state_handle_mask, + * without any error (HW optimizations for later + * CAAM eras), then try again. + */ ++ if (ret) ++ break; ++ + rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK; + if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) || +- !(rdsta_val & (1 << sh_idx))) ++ !(rdsta_val & (1 << sh_idx))) { + ret = -EAGAIN; +- if (ret) + break; ++ } ++ + dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx); + /* Clear the contents before recreating the descriptor */ + memset(desc, 0x00, CAAM_CMD_SZ * 7); +diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c +index fcfa5b1..b3afb6c 100644 +--- a/drivers/crypto/ccp/psp-dev.c ++++ b/drivers/crypto/ccp/psp-dev.c +@@ -211,7 +211,7 @@ static int __sev_platform_shutdown_locked(int *error) + { + int ret; + +- ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, 0, error); ++ ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, NULL, error); + if (ret) + return ret; + +@@ -271,7 +271,7 @@ static int sev_ioctl_do_reset(struct sev_issue_cmd *argp) + return rc; + } + +- return __sev_do_cmd_locked(SEV_CMD_FACTORY_RESET, 0, &argp->error); ++ return __sev_do_cmd_locked(SEV_CMD_FACTORY_RESET, NULL, &argp->error); + } + + static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp) +@@ -299,7 +299,7 @@ static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp) + return rc; + } + +- return __sev_do_cmd_locked(cmd, 0, &argp->error); ++ return __sev_do_cmd_locked(cmd, NULL, &argp->error); + } + + static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp) +@@ -624,7 +624,7 @@ EXPORT_SYMBOL_GPL(sev_guest_decommission); + + int sev_guest_df_flush(int *error) + { +- return sev_do_cmd(SEV_CMD_DF_FLUSH, 0, error); ++ return sev_do_cmd(SEV_CMD_DF_FLUSH, NULL, error); + } + EXPORT_SYMBOL_GPL(sev_guest_df_flush); + +diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c +index 4b6642a..1c6cbda 100644 +--- a/drivers/crypto/padlock-aes.c ++++ b/drivers/crypto/padlock-aes.c +@@ -512,7 +512,7 @@ static int __init padlock_init(void) + + printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n"); + +- if (c->x86 == 6 && c->x86_model == 15 && c->x86_mask == 2) { ++ if (c->x86 == 6 && c->x86_model == 15 && c->x86_stepping == 2) { + ecb_fetch_blocks = MAX_ECB_FETCH_BLOCKS; + cbc_fetch_blocks = MAX_CBC_FETCH_BLOCKS; + printk(KERN_NOTICE PFX "VIA Nano stepping 2 detected: enabling workaround.\n"); +diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c +index 188f44b..5d64c08 100644 +--- a/drivers/crypto/s5p-sss.c ++++ b/drivers/crypto/s5p-sss.c +@@ -1922,15 +1922,21 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) + uint32_t aes_control; + unsigned long flags; + int err; ++ u8 *iv; + + aes_control = SSS_AES_KEY_CHANGE_MODE; + if (mode & FLAGS_AES_DECRYPT) + aes_control |= SSS_AES_MODE_DECRYPT; + +- if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) ++ if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) { + aes_control |= SSS_AES_CHAIN_MODE_CBC; +- else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) ++ iv = req->info; ++ } else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) { + aes_control |= SSS_AES_CHAIN_MODE_CTR; ++ iv = req->info; ++ } else { ++ iv = NULL; /* AES_ECB */ ++ } + + if (dev->ctx->keylen == AES_KEYSIZE_192) + aes_control |= SSS_AES_KEY_SIZE_192; +@@ -1961,7 +1967,7 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) + goto outdata_error; + + SSS_AES_WRITE(dev, AES_CONTROL, aes_control); +- s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen); ++ s5p_set_aes(dev, dev->ctx->aes_key, iv, dev->ctx->keylen); + + s5p_set_dma_indata(dev, dev->sg_src); + s5p_set_dma_outdata(dev, dev->sg_dst); +diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-prng.c b/drivers/crypto/sunxi-ss/sun4i-ss-prng.c +index 0d01d16..63d6364 100644 +--- a/drivers/crypto/sunxi-ss/sun4i-ss-prng.c ++++ b/drivers/crypto/sunxi-ss/sun4i-ss-prng.c +@@ -28,7 +28,7 @@ int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src, + algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng); + ss = algt->ss; + +- spin_lock(&ss->slock); ++ spin_lock_bh(&ss->slock); + + writel(mode, ss->base + SS_CTL); + +@@ -51,6 +51,6 @@ int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src, + } + + writel(0, ss->base + SS_CTL); +- spin_unlock(&ss->slock); +- return dlen; ++ spin_unlock_bh(&ss->slock); ++ return 0; + } +diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c +index 9c80e0c..6882fa2 100644 +--- a/drivers/crypto/talitos.c ++++ b/drivers/crypto/talitos.c +@@ -1138,6 +1138,10 @@ static int talitos_sg_map(struct device *dev, struct scatterlist *src, + struct talitos_private *priv = dev_get_drvdata(dev); + bool is_sec1 = has_ftr_sec1(priv); + ++ if (!src) { ++ to_talitos_ptr(ptr, 0, 0, is_sec1); ++ return 1; ++ } + if (sg_count == 1) { + to_talitos_ptr(ptr, sg_dma_address(src) + offset, len, is_sec1); + return sg_count; +diff --git a/drivers/dax/super.c b/drivers/dax/super.c +index 473af69..ecdc292 100644 +--- a/drivers/dax/super.c ++++ b/drivers/dax/super.c +@@ -246,12 +246,6 @@ long dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages, + { + long avail; + +- /* +- * The device driver is allowed to sleep, in order to make the +- * memory directly accessible. +- */ +- might_sleep(); +- + if (!dax_dev) + return -EOPNOTSUPP; + +diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c +index 8b16ec5..329cb96 100644 +--- a/drivers/edac/amd64_edac.c ++++ b/drivers/edac/amd64_edac.c +@@ -3147,7 +3147,7 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt) + struct amd64_family_type *fam_type = NULL; + + pvt->ext_model = boot_cpu_data.x86_model >> 4; +- pvt->stepping = boot_cpu_data.x86_mask; ++ pvt->stepping = boot_cpu_data.x86_stepping; + pvt->model = boot_cpu_data.x86_model; + pvt->fam = boot_cpu_data.x86; + +diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c +index f34430f..8721002 100644 +--- a/drivers/edac/sb_edac.c ++++ b/drivers/edac/sb_edac.c +@@ -279,7 +279,7 @@ static const u32 correrrthrsld[] = { + * sbridge structs + */ + +-#define NUM_CHANNELS 4 /* Max channels per MC */ ++#define NUM_CHANNELS 6 /* Max channels per MC */ + #define MAX_DIMMS 3 /* Max DIMMS per channel */ + #define KNL_MAX_CHAS 38 /* KNL max num. of Cache Home Agents */ + #define KNL_MAX_CHANNELS 6 /* KNL max num. of PCI channels */ +diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c +index 0a44d43..3ec4c71 100644 +--- a/drivers/extcon/extcon-axp288.c ++++ b/drivers/extcon/extcon-axp288.c +@@ -1,7 +1,6 @@ + /* + * extcon-axp288.c - X-Power AXP288 PMIC extcon cable detection driver + * +- * Copyright (C) 2016-2017 Hans de Goede + * Copyright (C) 2015 Intel Corporation + * Author: Ramakrishna Pallala + * +@@ -98,15 +97,13 @@ struct axp288_extcon_info { + struct device *dev; + struct regmap *regmap; + struct regmap_irq_chip_data *regmap_irqc; +- struct delayed_work det_work; + int irq[EXTCON_IRQ_END]; + struct extcon_dev *edev; + unsigned int previous_cable; +- bool first_detect_done; + }; + + /* Power up/down reason string array */ +-static char *axp288_pwr_up_down_info[] = { ++static const char * const axp288_pwr_up_down_info[] = { + "Last wake caused by user pressing the power button", + "Last wake caused by a charger insertion", + "Last wake caused by a battery insertion", +@@ -124,7 +121,7 @@ static char *axp288_pwr_up_down_info[] = { + */ + static void axp288_extcon_log_rsi(struct axp288_extcon_info *info) + { +- char **rsi; ++ const char * const *rsi; + unsigned int val, i, clear_mask = 0; + int ret; + +@@ -140,25 +137,6 @@ static void axp288_extcon_log_rsi(struct axp288_extcon_info *info) + regmap_write(info->regmap, AXP288_PS_BOOT_REASON_REG, clear_mask); + } + +-static void axp288_chrg_detect_complete(struct axp288_extcon_info *info) +-{ +- /* +- * We depend on other drivers to do things like mux the data lines, +- * enable/disable vbus based on the id-pin, etc. Sometimes the BIOS has +- * not set these things up correctly resulting in the initial charger +- * cable type detection giving a wrong result and we end up not charging +- * or charging at only 0.5A. +- * +- * So we schedule a second cable type detection after 2 seconds to +- * give the other drivers time to load and do their thing. +- */ +- if (!info->first_detect_done) { +- queue_delayed_work(system_wq, &info->det_work, +- msecs_to_jiffies(2000)); +- info->first_detect_done = true; +- } +-} +- + static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info) + { + int ret, stat, cfg, pwr_stat; +@@ -223,8 +201,6 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info) + info->previous_cable = cable; + } + +- axp288_chrg_detect_complete(info); +- + return 0; + + dev_det_ret: +@@ -246,11 +222,8 @@ static irqreturn_t axp288_extcon_isr(int irq, void *data) + return IRQ_HANDLED; + } + +-static void axp288_extcon_det_work(struct work_struct *work) ++static void axp288_extcon_enable(struct axp288_extcon_info *info) + { +- struct axp288_extcon_info *info = +- container_of(work, struct axp288_extcon_info, det_work.work); +- + regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG, + BC_GLOBAL_RUN, 0); + /* Enable the charger detection logic */ +@@ -272,7 +245,6 @@ static int axp288_extcon_probe(struct platform_device *pdev) + info->regmap = axp20x->regmap; + info->regmap_irqc = axp20x->regmap_irqc; + info->previous_cable = EXTCON_NONE; +- INIT_DELAYED_WORK(&info->det_work, axp288_extcon_det_work); + + platform_set_drvdata(pdev, info); + +@@ -318,7 +290,7 @@ static int axp288_extcon_probe(struct platform_device *pdev) + } + + /* Start charger cable type detection */ +- queue_delayed_work(system_wq, &info->det_work, 0); ++ axp288_extcon_enable(info); + + return 0; + } +diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c +index c8691b5..191e99f 100644 +--- a/drivers/extcon/extcon-intel-int3496.c ++++ b/drivers/extcon/extcon-intel-int3496.c +@@ -153,8 +153,9 @@ static int int3496_probe(struct platform_device *pdev) + return ret; + } + +- /* queue initial processing of id-pin */ ++ /* process id-pin so that we start with the right status */ + queue_delayed_work(system_wq, &data->work, 0); ++ flush_delayed_work(&data->work); + + platform_set_drvdata(pdev, data); + +diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c +index e76de57..ebaea8b 100644 +--- a/drivers/gpio/gpio-rcar.c ++++ b/drivers/gpio/gpio-rcar.c +@@ -14,7 +14,6 @@ + * GNU General Public License for more details. + */ + +-#include + #include + #include + #include +@@ -37,10 +36,9 @@ struct gpio_rcar_priv { + struct platform_device *pdev; + struct gpio_chip gpio_chip; + struct irq_chip irq_chip; +- struct clk *clk; + unsigned int irq_parent; ++ atomic_t wakeup_path; + bool has_both_edge_trigger; +- bool needs_clk; + }; + + #define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */ +@@ -186,13 +184,10 @@ static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on) + } + } + +- if (!p->clk) +- return 0; +- + if (on) +- clk_enable(p->clk); ++ atomic_inc(&p->wakeup_path); + else +- clk_disable(p->clk); ++ atomic_dec(&p->wakeup_path); + + return 0; + } +@@ -330,17 +325,14 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset, + + struct gpio_rcar_info { + bool has_both_edge_trigger; +- bool needs_clk; + }; + + static const struct gpio_rcar_info gpio_rcar_info_gen1 = { + .has_both_edge_trigger = false, +- .needs_clk = false, + }; + + static const struct gpio_rcar_info gpio_rcar_info_gen2 = { + .has_both_edge_trigger = true, +- .needs_clk = true, + }; + + static const struct of_device_id gpio_rcar_of_table[] = { +@@ -403,7 +395,6 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins) + ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args); + *npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK; + p->has_both_edge_trigger = info->has_both_edge_trigger; +- p->needs_clk = info->needs_clk; + + if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) { + dev_warn(&p->pdev->dev, +@@ -440,16 +431,6 @@ static int gpio_rcar_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, p); + +- p->clk = devm_clk_get(dev, NULL); +- if (IS_ERR(p->clk)) { +- if (p->needs_clk) { +- dev_err(dev, "unable to get clock\n"); +- ret = PTR_ERR(p->clk); +- goto err0; +- } +- p->clk = NULL; +- } +- + pm_runtime_enable(dev); + + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); +@@ -531,11 +512,24 @@ static int gpio_rcar_remove(struct platform_device *pdev) + return 0; + } + ++static int __maybe_unused gpio_rcar_suspend(struct device *dev) ++{ ++ struct gpio_rcar_priv *p = dev_get_drvdata(dev); ++ ++ if (atomic_read(&p->wakeup_path)) ++ device_set_wakeup_path(dev); ++ ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, NULL); ++ + static struct platform_driver gpio_rcar_device_driver = { + .probe = gpio_rcar_probe, + .remove = gpio_rcar_remove, + .driver = { + .name = "gpio_rcar", ++ .pm = &gpio_rcar_pm_ops, + .of_match_table = of_match_ptr(gpio_rcar_of_table), + } + }; +diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c +index 564bb7a..84e5a9d 100644 +--- a/drivers/gpio/gpiolib-of.c ++++ b/drivers/gpio/gpiolib-of.c +@@ -241,6 +241,19 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, + + desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, + &of_flags); ++ /* ++ * -EPROBE_DEFER in our case means that we found a ++ * valid GPIO property, but no controller has been ++ * registered so far. ++ * ++ * This means we don't need to look any further for ++ * alternate name conventions, and we should really ++ * preserve the return code for our user to be able to ++ * retry probing later. ++ */ ++ if (IS_ERR(desc) && PTR_ERR(desc) == -EPROBE_DEFER) ++ return desc; ++ + if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT)) + break; + } +@@ -250,7 +263,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, + desc = of_find_spi_gpio(dev, con_id, &of_flags); + + /* Special handling for regulator GPIOs if used */ +- if (IS_ERR(desc)) ++ if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER) + desc = of_find_regulator_gpio(dev, con_id, &of_flags); + + if (IS_ERR(desc)) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +index d5a2eef..74edba1 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +@@ -1156,7 +1156,7 @@ static inline void amdgpu_set_ib_value(struct amdgpu_cs_parser *p, + /* + * Writeback + */ +-#define AMDGPU_MAX_WB 512 /* Reserve at most 512 WB slots for amdgpu-owned rings. */ ++#define AMDGPU_MAX_WB 128 /* Reserve at most 128 WB slots for amdgpu-owned rings. */ + + struct amdgpu_wb { + struct amdgpu_bo *wb_obj; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +index 57afad7..8fa850a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +@@ -540,6 +540,9 @@ int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev, + size_t size; + u32 retry = 3; + ++ if (amdgpu_acpi_pcie_notify_device_ready(adev)) ++ return -EINVAL; ++ + /* Get the device handle */ + handle = ACPI_HANDLE(&adev->pdev->dev); + if (!handle) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +index e2c3c5e..c53095b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +@@ -568,6 +568,7 @@ static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = { + /* HG _PR3 doesn't seem to work on this A+A weston board */ + { 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX }, + { 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX }, ++ { 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX }, + { 0, 0, 0, 0, 0 }, + }; + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +index 8ca3783..74d2efa 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +@@ -736,9 +736,11 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force) + enum drm_connector_status ret = connector_status_disconnected; + int r; + +- r = pm_runtime_get_sync(connector->dev->dev); +- if (r < 0) +- return connector_status_disconnected; ++ if (!drm_kms_helper_is_poll_worker()) { ++ r = pm_runtime_get_sync(connector->dev->dev); ++ if (r < 0) ++ return connector_status_disconnected; ++ } + + if (encoder) { + struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); +@@ -757,8 +759,12 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force) + /* check acpi lid status ??? */ + + amdgpu_connector_update_scratch_regs(connector, ret); +- pm_runtime_mark_last_busy(connector->dev->dev); +- pm_runtime_put_autosuspend(connector->dev->dev); ++ ++ if (!drm_kms_helper_is_poll_worker()) { ++ pm_runtime_mark_last_busy(connector->dev->dev); ++ pm_runtime_put_autosuspend(connector->dev->dev); ++ } ++ + return ret; + } + +@@ -868,9 +874,11 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force) + enum drm_connector_status ret = connector_status_disconnected; + int r; + +- r = pm_runtime_get_sync(connector->dev->dev); +- if (r < 0) +- return connector_status_disconnected; ++ if (!drm_kms_helper_is_poll_worker()) { ++ r = pm_runtime_get_sync(connector->dev->dev); ++ if (r < 0) ++ return connector_status_disconnected; ++ } + + encoder = amdgpu_connector_best_single_encoder(connector); + if (!encoder) +@@ -924,8 +932,10 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force) + amdgpu_connector_update_scratch_regs(connector, ret); + + out: +- pm_runtime_mark_last_busy(connector->dev->dev); +- pm_runtime_put_autosuspend(connector->dev->dev); ++ if (!drm_kms_helper_is_poll_worker()) { ++ pm_runtime_mark_last_busy(connector->dev->dev); ++ pm_runtime_put_autosuspend(connector->dev->dev); ++ } + + return ret; + } +@@ -988,9 +998,11 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) + enum drm_connector_status ret = connector_status_disconnected; + bool dret = false, broken_edid = false; + +- r = pm_runtime_get_sync(connector->dev->dev); +- if (r < 0) +- return connector_status_disconnected; ++ if (!drm_kms_helper_is_poll_worker()) { ++ r = pm_runtime_get_sync(connector->dev->dev); ++ if (r < 0) ++ return connector_status_disconnected; ++ } + + if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { + ret = connector->status; +@@ -1115,8 +1127,10 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) + amdgpu_connector_update_scratch_regs(connector, ret); + + exit: +- pm_runtime_mark_last_busy(connector->dev->dev); +- pm_runtime_put_autosuspend(connector->dev->dev); ++ if (!drm_kms_helper_is_poll_worker()) { ++ pm_runtime_mark_last_busy(connector->dev->dev); ++ pm_runtime_put_autosuspend(connector->dev->dev); ++ } + + return ret; + } +@@ -1359,9 +1373,11 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) + struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector); + int r; + +- r = pm_runtime_get_sync(connector->dev->dev); +- if (r < 0) +- return connector_status_disconnected; ++ if (!drm_kms_helper_is_poll_worker()) { ++ r = pm_runtime_get_sync(connector->dev->dev); ++ if (r < 0) ++ return connector_status_disconnected; ++ } + + if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { + ret = connector->status; +@@ -1429,8 +1445,10 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) + + amdgpu_connector_update_scratch_regs(connector, ret); + out: +- pm_runtime_mark_last_busy(connector->dev->dev); +- pm_runtime_put_autosuspend(connector->dev->dev); ++ if (!drm_kms_helper_is_poll_worker()) { ++ pm_runtime_mark_last_busy(connector->dev->dev); ++ pm_runtime_put_autosuspend(connector->dev->dev); ++ } + + return ret; + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index 00a50cc..af1b879 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -492,7 +492,7 @@ static int amdgpu_device_wb_init(struct amdgpu_device *adev) + memset(&adev->wb.used, 0, sizeof(adev->wb.used)); + + /* clear wb memory */ +- memset((char *)adev->wb.wb, 0, AMDGPU_MAX_WB * sizeof(uint32_t)); ++ memset((char *)adev->wb.wb, 0, AMDGPU_MAX_WB * sizeof(uint32_t) * 8); + } + + return 0; +@@ -530,8 +530,9 @@ int amdgpu_device_wb_get(struct amdgpu_device *adev, u32 *wb) + */ + void amdgpu_device_wb_free(struct amdgpu_device *adev, u32 wb) + { ++ wb >>= 3; + if (wb < adev->wb.num_wb) +- __clear_bit(wb >> 3, adev->wb.used); ++ __clear_bit(wb, adev->wb.used); + } + + /** +@@ -1455,11 +1456,6 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) + for (i = adev->num_ip_blocks - 1; i >= 0; i--) { + if (!adev->ip_blocks[i].status.hw) + continue; +- if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) { +- amdgpu_free_static_csa(adev); +- amdgpu_device_wb_fini(adev); +- amdgpu_device_vram_scratch_fini(adev); +- } + + if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD && + adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE) { +@@ -1486,6 +1482,13 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) + for (i = adev->num_ip_blocks - 1; i >= 0; i--) { + if (!adev->ip_blocks[i].status.sw) + continue; ++ ++ if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) { ++ amdgpu_free_static_csa(adev); ++ amdgpu_device_wb_fini(adev); ++ amdgpu_device_vram_scratch_fini(adev); ++ } ++ + r = adev->ip_blocks[i].version->funcs->sw_fini((void *)adev); + /* XXX handle errors */ + if (r) { +@@ -2284,14 +2287,6 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon) + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); + } + drm_modeset_unlock_all(dev); +- } else { +- /* +- * There is no equivalent atomic helper to turn on +- * display, so we defined our own function for this, +- * once suspend resume is supported by the atomic +- * framework this will be reworked +- */ +- amdgpu_dm_display_resume(adev); + } + } + +@@ -2726,7 +2721,6 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, + if (amdgpu_device_has_dc_support(adev)) { + if (drm_atomic_helper_resume(adev->ddev, state)) + dev_info(adev->dev, "drm resume failed:%d\n", r); +- amdgpu_dm_display_resume(adev); + } else { + drm_helper_resume_force_mode(adev->ddev); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c +index e14ab34..7c2be32 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c +@@ -75,7 +75,7 @@ static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man, + static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man) + { + struct amdgpu_gtt_mgr *mgr = man->priv; +- ++ spin_lock(&mgr->lock); + drm_mm_takedown(&mgr->mm); + spin_unlock(&mgr->lock); + kfree(mgr); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c +index 56bcd59..36483e0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c +@@ -257,7 +257,8 @@ int amdgpu_irq_init(struct amdgpu_device *adev) + r = drm_irq_install(adev->ddev, adev->ddev->pdev->irq); + if (r) { + adev->irq.installed = false; +- flush_work(&adev->hotplug_work); ++ if (!amdgpu_device_has_dc_support(adev)) ++ flush_work(&adev->hotplug_work); + cancel_work_sync(&adev->reset_work); + return r; + } +@@ -282,7 +283,8 @@ void amdgpu_irq_fini(struct amdgpu_device *adev) + adev->irq.installed = false; + if (adev->irq.msi_enabled) + pci_disable_msi(adev->pdev); +- flush_work(&adev->hotplug_work); ++ if (!amdgpu_device_has_dc_support(adev)) ++ flush_work(&adev->hotplug_work); + cancel_work_sync(&adev->reset_work); + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +index 13044e6..561d331 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +@@ -481,7 +481,7 @@ static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf, + result = 0; + + if (*pos < 12) { +- early[0] = amdgpu_ring_get_rptr(ring); ++ early[0] = amdgpu_ring_get_rptr(ring) & ring->buf_mask; + early[1] = amdgpu_ring_get_wptr(ring) & ring->buf_mask; + early[2] = ring->wptr & ring->buf_mask; + for (i = *pos / 4; i < 3 && size; i++) { +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +index b2eae86..5c26a8e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +@@ -299,12 +299,15 @@ int amdgpu_uvd_suspend(struct amdgpu_device *adev) + + cancel_delayed_work_sync(&adev->uvd.idle_work); + +- for (i = 0; i < adev->uvd.max_handles; ++i) +- if (atomic_read(&adev->uvd.handles[i])) +- break; ++ /* only valid for physical mode */ ++ if (adev->asic_type < CHIP_POLARIS10) { ++ for (i = 0; i < adev->uvd.max_handles; ++i) ++ if (atomic_read(&adev->uvd.handles[i])) ++ break; + +- if (i == AMDGPU_MAX_UVD_HANDLES) +- return 0; ++ if (i == adev->uvd.max_handles) ++ return 0; ++ } + + size = amdgpu_bo_size(adev->uvd.vcpu_bo); + ptr = adev->uvd.cpu_addr; +diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +index bd2c4f7..a712f4b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +@@ -3093,7 +3093,7 @@ static int dce_v6_0_hpd_irq(struct amdgpu_device *adev, + tmp |= DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK; + WREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd], tmp); + schedule_work(&adev->hotplug_work); +- DRM_INFO("IH: HPD%d\n", hpd + 1); ++ DRM_DEBUG("IH: HPD%d\n", hpd + 1); + } + + return 0; +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +index a066c5e..a430969 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +@@ -4384,34 +4384,8 @@ static void gfx_v7_0_gpu_early_init(struct amdgpu_device *adev) + case CHIP_KAVERI: + adev->gfx.config.max_shader_engines = 1; + adev->gfx.config.max_tile_pipes = 4; +- if ((adev->pdev->device == 0x1304) || +- (adev->pdev->device == 0x1305) || +- (adev->pdev->device == 0x130C) || +- (adev->pdev->device == 0x130F) || +- (adev->pdev->device == 0x1310) || +- (adev->pdev->device == 0x1311) || +- (adev->pdev->device == 0x131C)) { +- adev->gfx.config.max_cu_per_sh = 8; +- adev->gfx.config.max_backends_per_se = 2; +- } else if ((adev->pdev->device == 0x1309) || +- (adev->pdev->device == 0x130A) || +- (adev->pdev->device == 0x130D) || +- (adev->pdev->device == 0x1313) || +- (adev->pdev->device == 0x131D)) { +- adev->gfx.config.max_cu_per_sh = 6; +- adev->gfx.config.max_backends_per_se = 2; +- } else if ((adev->pdev->device == 0x1306) || +- (adev->pdev->device == 0x1307) || +- (adev->pdev->device == 0x130B) || +- (adev->pdev->device == 0x130E) || +- (adev->pdev->device == 0x1315) || +- (adev->pdev->device == 0x131B)) { +- adev->gfx.config.max_cu_per_sh = 4; +- adev->gfx.config.max_backends_per_se = 1; +- } else { +- adev->gfx.config.max_cu_per_sh = 3; +- adev->gfx.config.max_backends_per_se = 1; +- } ++ adev->gfx.config.max_cu_per_sh = 8; ++ adev->gfx.config.max_backends_per_se = 2; + adev->gfx.config.max_sh_per_se = 1; + adev->gfx.config.max_texture_channel_caches = 4; + adev->gfx.config.max_gprs = 256; +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +index 2719937..3b7e7af 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +@@ -634,7 +634,7 @@ static int gmc_v9_0_late_init(void *handle) + for(i = 0; i < AMDGPU_MAX_VMHUBS; ++i) + BUG_ON(vm_inv_eng[i] > 16); + +- if (adev->asic_type == CHIP_VEGA10) { ++ if (adev->asic_type == CHIP_VEGA10 && !amdgpu_sriov_vf(adev)) { + r = gmc_v9_0_ecc_available(adev); + if (r == 1) { + DRM_INFO("ECC is active.\n"); +@@ -682,7 +682,10 @@ static int gmc_v9_0_mc_init(struct amdgpu_device *adev) + adev->mc.vram_width = amdgpu_atomfirmware_get_vram_width(adev); + if (!adev->mc.vram_width) { + /* hbm memory channel size */ +- chansize = 128; ++ if (adev->flags & AMD_IS_APU) ++ chansize = 64; ++ else ++ chansize = 128; + + tmp = RREG32_SOC15(DF, 0, mmDF_CS_AON0_DramBaseAddress0); + tmp &= DF_CS_AON0_DramBaseAddress0__IntLvNumChan_MASK; +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +index e92fb37..91cf95a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +@@ -238,31 +238,27 @@ static uint64_t sdma_v4_0_ring_get_rptr(struct amdgpu_ring *ring) + static uint64_t sdma_v4_0_ring_get_wptr(struct amdgpu_ring *ring) + { + struct amdgpu_device *adev = ring->adev; +- u64 *wptr = NULL; +- uint64_t local_wptr = 0; ++ u64 wptr; + + if (ring->use_doorbell) { + /* XXX check if swapping is necessary on BE */ +- wptr = ((u64 *)&adev->wb.wb[ring->wptr_offs]); +- DRM_DEBUG("wptr/doorbell before shift == 0x%016llx\n", *wptr); +- *wptr = (*wptr) >> 2; +- DRM_DEBUG("wptr/doorbell after shift == 0x%016llx\n", *wptr); ++ wptr = READ_ONCE(*((u64 *)&adev->wb.wb[ring->wptr_offs])); ++ DRM_DEBUG("wptr/doorbell before shift == 0x%016llx\n", wptr); + } else { + u32 lowbit, highbit; + int me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1; + +- wptr = &local_wptr; + lowbit = RREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR)) >> 2; + highbit = RREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR_HI)) >> 2; + + DRM_DEBUG("wptr [%i]high== 0x%08x low==0x%08x\n", + me, highbit, lowbit); +- *wptr = highbit; +- *wptr = (*wptr) << 32; +- *wptr |= lowbit; ++ wptr = highbit; ++ wptr = wptr << 32; ++ wptr |= lowbit; + } + +- return *wptr; ++ return wptr >> 2; + } + + /** +diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c +index 543101d..2095173 100644 +--- a/drivers/gpu/drm/amd/amdgpu/si.c ++++ b/drivers/gpu/drm/amd/amdgpu/si.c +@@ -31,6 +31,7 @@ + #include "amdgpu_uvd.h" + #include "amdgpu_vce.h" + #include "atom.h" ++#include "amd_pcie.h" + #include "amdgpu_powerplay.h" + #include "sid.h" + #include "si_ih.h" +@@ -1461,8 +1462,8 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) + { + struct pci_dev *root = adev->pdev->bus->self; + int bridge_pos, gpu_pos; +- u32 speed_cntl, mask, current_data_rate; +- int ret, i; ++ u32 speed_cntl, current_data_rate; ++ int i; + u16 tmp16; + + if (pci_is_root_bus(adev->pdev->bus)) +@@ -1474,23 +1475,20 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) + if (adev->flags & AMD_IS_APU) + return; + +- ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask); +- if (ret != 0) +- return; +- +- if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80))) ++ if (!(adev->pm.pcie_gen_mask & (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 | ++ CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3))) + return; + + speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); + current_data_rate = (speed_cntl & LC_CURRENT_DATA_RATE_MASK) >> + LC_CURRENT_DATA_RATE_SHIFT; +- if (mask & DRM_PCIE_SPEED_80) { ++ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) { + if (current_data_rate == 2) { + DRM_INFO("PCIE gen 3 link speeds already enabled\n"); + return; + } + DRM_INFO("enabling PCIE gen 3 link speeds, disable with amdgpu.pcie_gen2=0\n"); +- } else if (mask & DRM_PCIE_SPEED_50) { ++ } else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) { + if (current_data_rate == 1) { + DRM_INFO("PCIE gen 2 link speeds already enabled\n"); + return; +@@ -1506,7 +1504,7 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) + if (!gpu_pos) + return; + +- if (mask & DRM_PCIE_SPEED_80) { ++ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) { + if (current_data_rate != 2) { + u16 bridge_cfg, gpu_cfg; + u16 bridge_cfg2, gpu_cfg2; +@@ -1589,9 +1587,9 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) + + pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16); + tmp16 &= ~0xf; +- if (mask & DRM_PCIE_SPEED_80) ++ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) + tmp16 |= 3; +- else if (mask & DRM_PCIE_SPEED_50) ++ else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) + tmp16 |= 2; + else + tmp16 |= 1; +diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c +index ce675a7..22f0b7f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c ++++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c +@@ -26,6 +26,7 @@ + #include "amdgpu_pm.h" + #include "amdgpu_dpm.h" + #include "amdgpu_atombios.h" ++#include "amd_pcie.h" + #include "sid.h" + #include "r600_dpm.h" + #include "si_dpm.h" +@@ -3331,29 +3332,6 @@ static void btc_apply_voltage_delta_rules(struct amdgpu_device *adev, + } + } + +-static enum amdgpu_pcie_gen r600_get_pcie_gen_support(struct amdgpu_device *adev, +- u32 sys_mask, +- enum amdgpu_pcie_gen asic_gen, +- enum amdgpu_pcie_gen default_gen) +-{ +- switch (asic_gen) { +- case AMDGPU_PCIE_GEN1: +- return AMDGPU_PCIE_GEN1; +- case AMDGPU_PCIE_GEN2: +- return AMDGPU_PCIE_GEN2; +- case AMDGPU_PCIE_GEN3: +- return AMDGPU_PCIE_GEN3; +- default: +- if ((sys_mask & DRM_PCIE_SPEED_80) && (default_gen == AMDGPU_PCIE_GEN3)) +- return AMDGPU_PCIE_GEN3; +- else if ((sys_mask & DRM_PCIE_SPEED_50) && (default_gen == AMDGPU_PCIE_GEN2)) +- return AMDGPU_PCIE_GEN2; +- else +- return AMDGPU_PCIE_GEN1; +- } +- return AMDGPU_PCIE_GEN1; +-} +- + static void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b, + u32 *p, u32 *u) + { +@@ -5028,10 +5006,11 @@ static int si_populate_smc_acpi_state(struct amdgpu_device *adev, + table->ACPIState.levels[0].vddc.index, + &table->ACPIState.levels[0].std_vddc); + } +- table->ACPIState.levels[0].gen2PCIE = (u8)r600_get_pcie_gen_support(adev, +- si_pi->sys_pcie_mask, +- si_pi->boot_pcie_gen, +- AMDGPU_PCIE_GEN1); ++ table->ACPIState.levels[0].gen2PCIE = ++ (u8)amdgpu_get_pcie_gen_support(adev, ++ si_pi->sys_pcie_mask, ++ si_pi->boot_pcie_gen, ++ AMDGPU_PCIE_GEN1); + + if (si_pi->vddc_phase_shed_control) + si_populate_phase_shedding_value(adev, +@@ -7168,10 +7147,10 @@ static void si_parse_pplib_clock_info(struct amdgpu_device *adev, + pl->vddc = le16_to_cpu(clock_info->si.usVDDC); + pl->vddci = le16_to_cpu(clock_info->si.usVDDCI); + pl->flags = le32_to_cpu(clock_info->si.ulFlags); +- pl->pcie_gen = r600_get_pcie_gen_support(adev, +- si_pi->sys_pcie_mask, +- si_pi->boot_pcie_gen, +- clock_info->si.ucPCIEGen); ++ pl->pcie_gen = amdgpu_get_pcie_gen_support(adev, ++ si_pi->sys_pcie_mask, ++ si_pi->boot_pcie_gen, ++ clock_info->si.ucPCIEGen); + + /* patch up vddc if necessary */ + ret = si_get_leakage_voltage_from_leakage_index(adev, pl->vddc, +@@ -7326,7 +7305,6 @@ static int si_dpm_init(struct amdgpu_device *adev) + struct si_power_info *si_pi; + struct atom_clock_dividers dividers; + int ret; +- u32 mask; + + si_pi = kzalloc(sizeof(struct si_power_info), GFP_KERNEL); + if (si_pi == NULL) +@@ -7336,11 +7314,9 @@ static int si_dpm_init(struct amdgpu_device *adev) + eg_pi = &ni_pi->eg; + pi = &eg_pi->rv7xx; + +- ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask); +- if (ret) +- si_pi->sys_pcie_mask = 0; +- else +- si_pi->sys_pcie_mask = mask; ++ si_pi->sys_pcie_mask = ++ (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK) >> ++ CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT; + si_pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID; + si_pi->boot_pcie_gen = si_get_current_pcie_speed(adev); + +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +index b2bfeda..9bab484 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +@@ -1618,7 +1618,7 @@ static const struct amdgpu_ring_funcs uvd_v6_0_enc_ring_vm_funcs = { + .set_wptr = uvd_v6_0_enc_ring_set_wptr, + .emit_frame_size = + 4 + /* uvd_v6_0_enc_ring_emit_pipeline_sync */ +- 6 + /* uvd_v6_0_enc_ring_emit_vm_flush */ ++ 5 + /* uvd_v6_0_enc_ring_emit_vm_flush */ + 5 + 5 + /* uvd_v6_0_enc_ring_emit_fence x2 vm fence */ + 1, /* uvd_v6_0_enc_ring_insert_end */ + .emit_ib_size = 5, /* uvd_v6_0_enc_ring_emit_ib */ +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 1ce4c98..c345e64 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -629,11 +629,13 @@ static int dm_resume(void *handle) + { + struct amdgpu_device *adev = handle; + struct amdgpu_display_manager *dm = &adev->dm; ++ int ret = 0; + + /* power on hardware */ + dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0); + +- return 0; ++ ret = amdgpu_dm_display_resume(adev); ++ return ret; + } + + int amdgpu_dm_display_resume(struct amdgpu_device *adev) +@@ -1035,6 +1037,10 @@ static void handle_hpd_rx_irq(void *param) + !is_mst_root_connector) { + /* Downstream Port status changed. */ + if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) { ++ ++ if (aconnector->fake_enable) ++ aconnector->fake_enable = false; ++ + amdgpu_dm_update_connector_after_detect(aconnector); + + +@@ -2010,30 +2016,32 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, + dst.width = stream->timing.h_addressable; + dst.height = stream->timing.v_addressable; + +- rmx_type = dm_state->scaling; +- if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) { +- if (src.width * dst.height < +- src.height * dst.width) { +- /* height needs less upscaling/more downscaling */ +- dst.width = src.width * +- dst.height / src.height; +- } else { +- /* width needs less upscaling/more downscaling */ +- dst.height = src.height * +- dst.width / src.width; ++ if (dm_state) { ++ rmx_type = dm_state->scaling; ++ if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) { ++ if (src.width * dst.height < ++ src.height * dst.width) { ++ /* height needs less upscaling/more downscaling */ ++ dst.width = src.width * ++ dst.height / src.height; ++ } else { ++ /* width needs less upscaling/more downscaling */ ++ dst.height = src.height * ++ dst.width / src.width; ++ } ++ } else if (rmx_type == RMX_CENTER) { ++ dst = src; + } +- } else if (rmx_type == RMX_CENTER) { +- dst = src; +- } + +- dst.x = (stream->timing.h_addressable - dst.width) / 2; +- dst.y = (stream->timing.v_addressable - dst.height) / 2; ++ dst.x = (stream->timing.h_addressable - dst.width) / 2; ++ dst.y = (stream->timing.v_addressable - dst.height) / 2; + +- if (dm_state->underscan_enable) { +- dst.x += dm_state->underscan_hborder / 2; +- dst.y += dm_state->underscan_vborder / 2; +- dst.width -= dm_state->underscan_hborder; +- dst.height -= dm_state->underscan_vborder; ++ if (dm_state->underscan_enable) { ++ dst.x += dm_state->underscan_hborder / 2; ++ dst.y += dm_state->underscan_vborder / 2; ++ dst.width -= dm_state->underscan_hborder; ++ dst.height -= dm_state->underscan_vborder; ++ } + } + + stream->src = src; +@@ -2358,12 +2366,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + + if (aconnector == NULL) { + DRM_ERROR("aconnector is NULL!\n"); +- goto drm_connector_null; +- } +- +- if (dm_state == NULL) { +- DRM_ERROR("dm_state is NULL!\n"); +- goto dm_state_null; ++ return stream; + } + + drm_connector = &aconnector->base; +@@ -2375,18 +2378,18 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + */ + if (aconnector->mst_port) { + dm_dp_mst_dc_sink_create(drm_connector); +- goto mst_dc_sink_create_done; ++ return stream; + } + + if (create_fake_sink(aconnector)) +- goto stream_create_fail; ++ return stream; + } + + stream = dc_create_stream_for_sink(aconnector->dc_sink); + + if (stream == NULL) { + DRM_ERROR("Failed to create stream for sink!\n"); +- goto stream_create_fail; ++ return stream; + } + + list_for_each_entry(preferred_mode, &aconnector->base.modes, head) { +@@ -2412,9 +2415,12 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + } else { + decide_crtc_timing_for_drm_display_mode( + &mode, preferred_mode, +- dm_state->scaling != RMX_OFF); ++ dm_state ? (dm_state->scaling != RMX_OFF) : false); + } + ++ if (!dm_state) ++ drm_mode_set_crtcinfo(&mode, 0); ++ + fill_stream_properties_from_drm_display_mode(stream, + &mode, &aconnector->base); + update_stream_scaling_settings(&mode, dm_state, stream); +@@ -2424,10 +2430,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + drm_connector, + aconnector->dc_sink); + +-stream_create_fail: +-dm_state_null: +-drm_connector_null: +-mst_dc_sink_create_done: ++ update_stream_signal(stream); ++ + return stream; + } + +@@ -2495,6 +2499,27 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc) + return &state->base; + } + ++ ++static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable) ++{ ++ enum dc_irq_source irq_source; ++ struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); ++ struct amdgpu_device *adev = crtc->dev->dev_private; ++ ++ irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst; ++ return dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY; ++} ++ ++static int dm_enable_vblank(struct drm_crtc *crtc) ++{ ++ return dm_set_vblank(crtc, true); ++} ++ ++static void dm_disable_vblank(struct drm_crtc *crtc) ++{ ++ dm_set_vblank(crtc, false); ++} ++ + /* Implemented only the options currently availible for the driver */ + static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { + .reset = dm_crtc_reset_state, +@@ -2504,6 +2529,8 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = dm_crtc_duplicate_state, + .atomic_destroy_state = dm_crtc_destroy_state, ++ .enable_vblank = dm_enable_vblank, ++ .disable_vblank = dm_disable_vblank, + }; + + static enum drm_connector_status +@@ -2798,7 +2825,7 @@ int amdgpu_dm_connector_mode_valid(struct drm_connector *connector, + goto fail; + } + +- stream = dc_create_stream_for_sink(dc_sink); ++ stream = create_stream_for_sink(aconnector, mode, NULL); + if (stream == NULL) { + DRM_ERROR("Failed to create stream for sink!\n"); + goto fail; +@@ -3058,6 +3085,9 @@ static int dm_plane_atomic_check(struct drm_plane *plane, + if (!dm_plane_state->dc_state) + return 0; + ++ if (!fill_rects_from_plane_state(state, dm_plane_state->dc_state)) ++ return -EINVAL; ++ + if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK) + return 0; + +@@ -4630,8 +4660,6 @@ static int dm_update_planes_state(struct dc *dc, + bool pflip_needed = !state->allow_modeset; + int ret = 0; + +- if (pflip_needed) +- return ret; + + /* Add new planes */ + for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { +@@ -4646,6 +4674,8 @@ static int dm_update_planes_state(struct dc *dc, + + /* Remove any changed/removed planes */ + if (!enable) { ++ if (pflip_needed) ++ continue; + + if (!old_plane_crtc) + continue; +@@ -4677,6 +4707,7 @@ static int dm_update_planes_state(struct dc *dc, + *lock_and_validation_needed = true; + + } else { /* Add new planes */ ++ struct dc_plane_state *dc_new_plane_state; + + if (drm_atomic_plane_disabling(plane->state, new_plane_state)) + continue; +@@ -4690,38 +4721,50 @@ static int dm_update_planes_state(struct dc *dc, + if (!dm_new_crtc_state->stream) + continue; + ++ if (pflip_needed) ++ continue; + + WARN_ON(dm_new_plane_state->dc_state); + +- dm_new_plane_state->dc_state = dc_create_plane_state(dc); +- +- DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n", +- plane->base.id, new_plane_crtc->base.id); +- +- if (!dm_new_plane_state->dc_state) { ++ dc_new_plane_state = dc_create_plane_state(dc); ++ if (!dc_new_plane_state) { + ret = -EINVAL; + return ret; + } + ++ DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n", ++ plane->base.id, new_plane_crtc->base.id); ++ + ret = fill_plane_attributes( + new_plane_crtc->dev->dev_private, +- dm_new_plane_state->dc_state, ++ dc_new_plane_state, + new_plane_state, + new_crtc_state); +- if (ret) ++ if (ret) { ++ dc_plane_state_release(dc_new_plane_state); + return ret; ++ } + +- ++ /* ++ * Any atomic check errors that occur after this will ++ * not need a release. The plane state will be attached ++ * to the stream, and therefore part of the atomic ++ * state. It'll be released when the atomic state is ++ * cleaned. ++ */ + if (!dc_add_plane_to_context( + dc, + dm_new_crtc_state->stream, +- dm_new_plane_state->dc_state, ++ dc_new_plane_state, + dm_state->context)) { + ++ dc_plane_state_release(dc_new_plane_state); + ret = -EINVAL; + return ret; + } + ++ dm_new_plane_state->dc_state = dc_new_plane_state; ++ + /* Tell DC to do a full surface update every time there + * is a plane change. Inefficient, but works for now. + */ +@@ -4735,6 +4778,30 @@ static int dm_update_planes_state(struct dc *dc, + return ret; + } + ++static int dm_atomic_check_plane_state_fb(struct drm_atomic_state *state, ++ struct drm_crtc *crtc) ++{ ++ struct drm_plane *plane; ++ struct drm_crtc_state *crtc_state; ++ ++ WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc)); ++ ++ drm_for_each_plane_mask(plane, state->dev, crtc->state->plane_mask) { ++ struct drm_plane_state *plane_state = ++ drm_atomic_get_plane_state(state, plane); ++ ++ if (IS_ERR(plane_state)) ++ return -EDEADLK; ++ ++ crtc_state = drm_atomic_get_crtc_state(plane_state->state, crtc); ++ if (crtc->primary == plane && crtc_state->active) { ++ if (!plane_state->fb) ++ return -EINVAL; ++ } ++ } ++ return 0; ++} ++ + static int amdgpu_dm_atomic_check(struct drm_device *dev, + struct drm_atomic_state *state) + { +@@ -4758,6 +4825,10 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, + goto fail; + + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { ++ ret = dm_atomic_check_plane_state_fb(state, crtc); ++ if (ret) ++ goto fail; ++ + if (!drm_atomic_crtc_needs_modeset(new_crtc_state) && + !new_crtc_state->color_mgmt_changed) + continue; +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +index 1874b6c..4220550 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +@@ -683,10 +683,8 @@ static const struct amdgpu_irq_src_funcs dm_hpd_irq_funcs = { + + void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev) + { +- if (adev->mode_info.num_crtc > 0) +- adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_VLINE1 + adev->mode_info.num_crtc; +- else +- adev->crtc_irq.num_types = 0; ++ ++ adev->crtc_irq.num_types = adev->mode_info.num_crtc; + adev->crtc_irq.funcs = &dm_crtc_irq_funcs; + + adev->pageflip_irq.num_types = adev->mode_info.num_crtc; +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 f3d87f4..93421da 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 +@@ -189,6 +189,12 @@ void dm_dp_mst_dc_sink_create(struct drm_connector *connector) + .link = aconnector->dc_link, + .sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST }; + ++ /* ++ * TODO: Need to further figure out why ddc.algo is NULL while MST port exists ++ */ ++ if (!aconnector->port || !aconnector->port->aux.ddc.algo) ++ return; ++ + edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port); + + if (!edid) { +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index 35e84ed..12868c7 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -1358,13 +1358,13 @@ enum dc_irq_source dc_interrupt_to_irq_source( + return dal_irq_service_to_irq_source(dc->res_pool->irqs, src_id, ext_id); + } + +-void dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable) ++bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable) + { + + if (dc == NULL) +- return; ++ return false; + +- dal_irq_service_set(dc->res_pool->irqs, src, enable); ++ return dal_irq_service_set(dc->res_pool->irqs, src, enable); + } + + void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src) +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c +index a374282..be55461 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c +@@ -1749,8 +1749,7 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) + link->link_enc, + pipe_ctx->clock_source->id, + display_color_depth, +- pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A, +- pipe_ctx->stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK, ++ pipe_ctx->stream->signal, + stream->phy_pix_clk); + + if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +index 61e8c3e..639421a 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +@@ -718,7 +718,7 @@ static enum link_training_result perform_channel_equalization_sequence( + uint32_t retries_ch_eq; + enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; + union lane_align_status_updated dpcd_lane_status_updated = {{0}}; +- union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {{{0}}};; ++ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {{{0}}}; + + hw_tr_pattern = get_supported_tp(link); + +@@ -1465,7 +1465,7 @@ void decide_link_settings(struct dc_stream_state *stream, + /* MST doesn't perform link training for now + * TODO: add MST specific link training routine + */ +- if (is_mst_supported(link)) { ++ if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { + *link_setting = link->verified_link_cap; + return; + } +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 95b8dd0..4d07ffe 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -1360,9 +1360,6 @@ bool dc_is_stream_scaling_unchanged( + return true; + } + +-/* Maximum TMDS single link pixel clock 165MHz */ +-#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ 165000 +- + static void update_stream_engine_usage( + struct resource_context *res_ctx, + const struct resource_pool *pool, +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 261811e..cd58197 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +@@ -33,8 +33,7 @@ + /******************************************************************************* + * Private functions + ******************************************************************************/ +-#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST 297000 +-static void update_stream_signal(struct dc_stream_state *stream) ++void update_stream_signal(struct dc_stream_state *stream) + { + + struct dc_sink *dc_sink = stream->sink; +@@ -45,8 +44,9 @@ static void update_stream_signal(struct dc_stream_state *stream) + stream->signal = dc_sink->sink_signal; + + if (dc_is_dvi_signal(stream->signal)) { +- if (stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST && +- stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) ++ if (stream->ctx->dc->caps.dual_link_dvi && ++ stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK && ++ stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) + stream->signal = SIGNAL_TYPE_DVI_DUAL_LINK; + else + stream->signal = SIGNAL_TYPE_DVI_SINGLE_LINK; +@@ -193,44 +193,20 @@ bool dc_stream_set_cursor_attributes( + + core_dc = stream->ctx->dc; + res_ctx = &core_dc->current_state->res_ctx; ++ stream->cursor_attributes = *attributes; + + for (i = 0; i < MAX_PIPES; i++) { + struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; + +- if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp)) ++ if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.xfm && ++ !pipe_ctx->plane_res.dpp) || !pipe_ctx->plane_res.ipp) + continue; + if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) + continue; + + +- if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes != NULL) +- pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes( +- pipe_ctx->plane_res.ipp, attributes); +- +- if (pipe_ctx->plane_res.hubp != NULL && +- pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes != NULL) +- pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( +- pipe_ctx->plane_res.hubp, attributes); +- +- if (pipe_ctx->plane_res.mi != NULL && +- pipe_ctx->plane_res.mi->funcs->set_cursor_attributes != NULL) +- pipe_ctx->plane_res.mi->funcs->set_cursor_attributes( +- pipe_ctx->plane_res.mi, attributes); +- +- +- if (pipe_ctx->plane_res.xfm != NULL && +- pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes != NULL) +- pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes( +- pipe_ctx->plane_res.xfm, attributes); +- +- if (pipe_ctx->plane_res.dpp != NULL && +- pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes != NULL) +- pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( +- pipe_ctx->plane_res.dpp, attributes->color_format); ++ core_dc->hwss.set_cursor_attribute(pipe_ctx); + } +- +- stream->cursor_attributes = *attributes; +- + return true; + } + +@@ -254,55 +230,21 @@ bool dc_stream_set_cursor_position( + + core_dc = stream->ctx->dc; + res_ctx = &core_dc->current_state->res_ctx; ++ stream->cursor_position = *position; + + for (i = 0; i < MAX_PIPES; i++) { + struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; +- struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; +- struct mem_input *mi = pipe_ctx->plane_res.mi; +- struct hubp *hubp = pipe_ctx->plane_res.hubp; +- struct dpp *dpp = pipe_ctx->plane_res.dpp; +- struct dc_cursor_position pos_cpy = *position; +- struct dc_cursor_mi_param param = { +- .pixel_clk_khz = stream->timing.pix_clk_khz, +- .ref_clk_khz = core_dc->res_pool->ref_clock_inKhz, +- .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, +- .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, +- .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz +- }; + + if (pipe_ctx->stream != stream || + (!pipe_ctx->plane_res.mi && !pipe_ctx->plane_res.hubp) || + !pipe_ctx->plane_state || +- (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp)) +- continue; +- +- if (pipe_ctx->plane_state->address.type +- == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) +- pos_cpy.enable = false; +- +- if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) +- pos_cpy.enable = false; +- +- +- if (ipp != NULL && ipp->funcs->ipp_cursor_set_position != NULL) +- ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, ¶m); +- +- if (mi != NULL && mi->funcs->set_cursor_position != NULL) +- mi->funcs->set_cursor_position(mi, &pos_cpy, ¶m); +- +- if (!hubp) ++ (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp) || ++ !pipe_ctx->plane_res.ipp) + continue; + +- if (hubp->funcs->set_cursor_position != NULL) +- hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); +- +- if (dpp != NULL && dpp->funcs->set_cursor_position != NULL) +- dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width); +- ++ core_dc->hwss.set_cursor_position(pipe_ctx); + } + +- stream->cursor_position = *position; +- + return true; + } + +diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h +index e2e3c9d..d6d5661 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc.h ++++ b/drivers/gpu/drm/amd/display/dc/dc.h +@@ -62,6 +62,7 @@ struct dc_caps { + bool dcc_const_color; + bool dynamic_audio; + bool is_apu; ++ bool dual_link_dvi; + }; + + struct dc_dcc_surface_param { +@@ -672,7 +673,7 @@ enum dc_irq_source dc_interrupt_to_irq_source( + struct dc *dc, + uint32_t src_id, + uint32_t ext_id); +-void dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable); ++bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable); + void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src); + enum dc_irq_source dc_get_hpd_irq_source_at_index( + struct dc *dc, uint32_t link_index); +diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h +index 01c60f1..456e4d2 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h +@@ -237,6 +237,8 @@ enum surface_update_type dc_check_update_surfaces_for_stream( + */ + struct dc_stream_state *dc_create_stream_for_sink(struct dc_sink *dc_sink); + ++void update_stream_signal(struct dc_stream_state *stream); ++ + void dc_stream_retain(struct dc_stream_state *dc_stream); + void dc_stream_release(struct dc_stream_state *dc_stream); + +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +index b73db9e..a993279 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +@@ -236,6 +236,7 @@ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ ++ SR(VGA_TEST_CONTROL), \ + SR(DC_IP_REQUEST_CNTL), \ + BL_REG_LIST() + +@@ -337,6 +338,7 @@ struct dce_hwseq_registers { + uint32_t D2VGA_CONTROL; + uint32_t D3VGA_CONTROL; + uint32_t D4VGA_CONTROL; ++ uint32_t VGA_TEST_CONTROL; + /* MMHUB registers. read only. temporary hack */ + uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32; + uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32; +@@ -493,6 +495,9 @@ struct dce_hwseq_registers { + HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ ++ HWS_SF(, D1VGA_CONTROL, D1VGA_MODE_ENABLE, mask_sh),\ ++ HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_ENABLE, mask_sh),\ ++ HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_RENDER_START, mask_sh),\ + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \ + HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) + +@@ -583,7 +588,10 @@ struct dce_hwseq_registers { + type DCFCLK_GATE_DIS; \ + type DCHUBBUB_GLOBAL_TIMER_REFDIV; \ + type DENTIST_DPPCLK_WDIVIDER; \ +- type DENTIST_DISPCLK_WDIVIDER; ++ type DENTIST_DISPCLK_WDIVIDER; \ ++ type VGA_TEST_ENABLE; \ ++ type VGA_TEST_RENDER_START; \ ++ type D1VGA_MODE_ENABLE; + + struct dce_hwseq_shift { + HWSEQ_REG_FIELD_LIST(uint8_t) +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +index a266e3f..e4741f1 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +@@ -82,13 +82,6 @@ + #define DCE110_DIG_FE_SOURCE_SELECT_DIGF 0x20 + #define DCE110_DIG_FE_SOURCE_SELECT_DIGG 0x40 + +-/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */ +-#define TMDS_MIN_PIXEL_CLOCK 25000 +-/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */ +-#define TMDS_MAX_PIXEL_CLOCK 165000 +-/* For current ASICs pixel clock - 600MHz */ +-#define MAX_ENCODER_CLOCK 600000 +- + enum { + DP_MST_UPDATE_MAX_RETRY = 50 + }; +@@ -683,6 +676,7 @@ void dce110_link_encoder_construct( + { + struct bp_encoder_cap_info bp_cap_info = {0}; + const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs; ++ enum bp_result result = BP_RESULT_OK; + + enc110->base.funcs = &dce110_lnk_enc_funcs; + enc110->base.ctx = init_data->ctx; +@@ -757,15 +751,24 @@ void dce110_link_encoder_construct( + enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; + } + ++ /* default to one to mirror Windows behavior */ ++ enc110->base.features.flags.bits.HDMI_6GB_EN = 1; ++ ++ result = bp_funcs->get_encoder_cap_info(enc110->base.ctx->dc_bios, ++ enc110->base.id, &bp_cap_info); ++ + /* Override features with DCE-specific values */ +- if (BP_RESULT_OK == bp_funcs->get_encoder_cap_info( +- enc110->base.ctx->dc_bios, enc110->base.id, +- &bp_cap_info)) { ++ if (BP_RESULT_OK == result) { + enc110->base.features.flags.bits.IS_HBR2_CAPABLE = + bp_cap_info.DP_HBR2_EN; + enc110->base.features.flags.bits.IS_HBR3_CAPABLE = + bp_cap_info.DP_HBR3_EN; + enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN; ++ } else { ++ dm_logger_write(enc110->base.ctx->logger, LOG_WARNING, ++ "%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", ++ __func__, ++ result); + } + } + +@@ -904,8 +907,7 @@ void dce110_link_encoder_enable_tmds_output( + struct link_encoder *enc, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, +- bool hdmi, +- bool dual_link, ++ enum signal_type signal, + uint32_t pixel_clock) + { + struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); +@@ -919,16 +921,12 @@ void dce110_link_encoder_enable_tmds_output( + cntl.engine_id = enc->preferred_engine; + cntl.transmitter = enc110->base.transmitter; + cntl.pll_id = clock_source; +- if (hdmi) { +- cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A; +- cntl.lanes_number = 4; +- } else if (dual_link) { +- cntl.signal = SIGNAL_TYPE_DVI_DUAL_LINK; ++ cntl.signal = signal; ++ if (cntl.signal == SIGNAL_TYPE_DVI_DUAL_LINK) + cntl.lanes_number = 8; +- } else { +- cntl.signal = SIGNAL_TYPE_DVI_SINGLE_LINK; ++ else + cntl.lanes_number = 4; +- } ++ + cntl.hpd_sel = enc110->base.hpd_source; + + cntl.pixel_clock = pixel_clock; +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h +index 8ca9afe..0ec3433 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h +@@ -210,8 +210,7 @@ void dce110_link_encoder_enable_tmds_output( + struct link_encoder *enc, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, +- bool hdmi, +- bool dual_link, ++ enum signal_type signal, + uint32_t pixel_clock); + + /* enables DP PHY output */ +diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +index 3ea43e2..442dd2d 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +@@ -852,6 +852,7 @@ static bool construct( + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 40; + dc->caps.max_cursor_size = 128; ++ dc->caps.dual_link_dvi = true; + + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.timing_generators[i] = +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 86cdd7b4..6f382a3 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 +@@ -688,15 +688,22 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) + struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; + struct dc_link *link = pipe_ctx->stream->sink->link; + +- /* 1. update AVI info frame (HDMI, DP) +- * we always need to update info frame +- */ ++ + uint32_t active_total_with_borders; + uint32_t early_control = 0; + struct timing_generator *tg = pipe_ctx->stream_res.tg; + +- /* TODOFPGA may change to hwss.update_info_frame */ ++ /* For MST, there are multiply stream go to only one link. ++ * connect DIG back_end to front_end while enable_stream and ++ * disconnect them during disable_stream ++ * BY this, it is logic clean to separate stream and link */ ++ link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, ++ pipe_ctx->stream_res.stream_enc->id, true); ++ ++ /* update AVI info frame (HDMI, DP)*/ ++ /* TODO: FPGA may change to hwss.update_info_frame */ + dce110_update_info_frame(pipe_ctx); ++ + /* enable early control to avoid corruption on DP monitor*/ + active_total_with_borders = + timing->h_addressable +@@ -717,12 +724,8 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) + pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc); + } + +- /* For MST, there are multiply stream go to only one link. +- * connect DIG back_end to front_end while enable_stream and +- * disconnect them during disable_stream +- * BY this, it is logic clean to separate stream and link */ +- link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, +- pipe_ctx->stream_res.stream_enc->id, true); ++ ++ + + } + +@@ -1690,9 +1693,13 @@ static void apply_min_clocks( + * Check if FBC can be enabled + */ + static bool should_enable_fbc(struct dc *dc, +- struct dc_state *context) ++ struct dc_state *context, ++ uint32_t *pipe_idx) + { +- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[0]; ++ uint32_t i; ++ struct pipe_ctx *pipe_ctx = NULL; ++ struct resource_context *res_ctx = &context->res_ctx; ++ + + ASSERT(dc->fbc_compressor); + +@@ -1704,6 +1711,14 @@ static bool should_enable_fbc(struct dc *dc, + if (context->stream_count != 1) + return false; + ++ for (i = 0; i < dc->res_pool->pipe_count; i++) { ++ if (res_ctx->pipe_ctx[i].stream) { ++ pipe_ctx = &res_ctx->pipe_ctx[i]; ++ *pipe_idx = i; ++ break; ++ } ++ } ++ + /* Only supports eDP */ + if (pipe_ctx->stream->sink->link->connector_signal != SIGNAL_TYPE_EDP) + return false; +@@ -1729,11 +1744,14 @@ static bool should_enable_fbc(struct dc *dc, + static void enable_fbc(struct dc *dc, + struct dc_state *context) + { +- if (should_enable_fbc(dc, context)) { ++ uint32_t pipe_idx = 0; ++ ++ if (should_enable_fbc(dc, context, &pipe_idx)) { + /* Program GRPH COMPRESSED ADDRESS and PITCH */ + struct compr_addr_and_pitch_params params = {0, 0, 0}; + struct compressor *compr = dc->fbc_compressor; +- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[0]; ++ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx]; ++ + + params.source_view_width = pipe_ctx->stream->timing.h_addressable; + params.source_view_height = pipe_ctx->stream->timing.v_addressable; +@@ -2915,6 +2933,49 @@ static void program_csc_matrix(struct pipe_ctx *pipe_ctx, + } + } + ++void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx) ++{ ++ struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; ++ struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; ++ struct mem_input *mi = pipe_ctx->plane_res.mi; ++ struct dc_cursor_mi_param param = { ++ .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, ++ .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, ++ .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, ++ .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, ++ .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz ++ }; ++ ++ if (pipe_ctx->plane_state->address.type ++ == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) ++ pos_cpy.enable = false; ++ ++ if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) ++ pos_cpy.enable = false; ++ ++ if (ipp->funcs->ipp_cursor_set_position) ++ ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, ¶m); ++ if (mi->funcs->set_cursor_position) ++ mi->funcs->set_cursor_position(mi, &pos_cpy, ¶m); ++} ++ ++void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx) ++{ ++ struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; ++ ++ if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes) ++ pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes( ++ pipe_ctx->plane_res.ipp, attributes); ++ ++ if (pipe_ctx->plane_res.mi->funcs->set_cursor_attributes) ++ pipe_ctx->plane_res.mi->funcs->set_cursor_attributes( ++ pipe_ctx->plane_res.mi, attributes); ++ ++ if (pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes) ++ pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes( ++ pipe_ctx->plane_res.xfm, attributes); ++} ++ + static void ready_shared_resources(struct dc *dc, struct dc_state *context) {} + + static void optimize_shared_resources(struct dc *dc) {} +@@ -2957,6 +3018,8 @@ static const struct hw_sequencer_funcs dce110_funcs = { + .edp_backlight_control = hwss_edp_backlight_control, + .edp_power_control = hwss_edp_power_control, + .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, ++ .set_cursor_position = dce110_set_cursor_position, ++ .set_cursor_attribute = dce110_set_cursor_attribute + }; + + void dce110_hw_sequencer_construct(struct dc *dc) +diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +index 7c47795..00f18c4 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +@@ -846,6 +846,16 @@ static bool dce110_validate_bandwidth( + return result; + } + ++enum dc_status dce110_validate_plane(const struct dc_plane_state *plane_state, ++ struct dc_caps *caps) ++{ ++ if (((plane_state->dst_rect.width * 2) < plane_state->src_rect.width) || ++ ((plane_state->dst_rect.height * 2) < plane_state->src_rect.height)) ++ return DC_FAIL_SURFACE_VALIDATE; ++ ++ return DC_OK; ++} ++ + static bool dce110_validate_surface_sets( + struct dc_state *context) + { +@@ -869,6 +879,13 @@ static bool dce110_validate_surface_sets( + plane->src_rect.height > 1080)) + return false; + ++ /* we don't have the logic to support underlay ++ * only yet so block the use case where we get ++ * NV12 plane as top layer ++ */ ++ if (j == 0) ++ return false; ++ + /* irrespective of plane format, + * stream should be RGB encoded + */ +@@ -1021,6 +1038,7 @@ static const struct resource_funcs dce110_res_pool_funcs = { + .link_enc_create = dce110_link_encoder_create, + .validate_guaranteed = dce110_validate_guaranteed, + .validate_bandwidth = dce110_validate_bandwidth, ++ .validate_plane = dce110_validate_plane, + .acquire_idle_pipe_for_layer = dce110_acquire_underlay, + .add_stream_to_ctx = dce110_add_stream_to_ctx, + .validate_global = dce110_validate_global +diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +index 663e0a0..98d9cd0 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +@@ -1103,6 +1103,8 @@ static bool construct( + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.max_cursor_size = 128; ++ dc->caps.dual_link_dvi = true; ++ + + /************************************************* + * Create resources * +diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +index 57cd673..5aab01d 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +@@ -835,6 +835,8 @@ static bool construct( + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.max_cursor_size = 128; ++ dc->caps.dual_link_dvi = true; ++ + dc->debug = debug_defaults; + + /************************************************* +diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +index 8f2bd56..25d7eb1 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +@@ -793,6 +793,7 @@ static bool dce80_construct( + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 40; + dc->caps.max_cursor_size = 128; ++ dc->caps.dual_link_dvi = true; + + /************************************************* + * Create resources * +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 8257286..072e448 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 +@@ -238,10 +238,24 @@ static void enable_power_gating_plane( + static void disable_vga( + struct dce_hwseq *hws) + { ++ unsigned int in_vga_mode = 0; ++ ++ REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga_mode); ++ ++ if (in_vga_mode == 0) ++ return; ++ + REG_WRITE(D1VGA_CONTROL, 0); +- REG_WRITE(D2VGA_CONTROL, 0); +- REG_WRITE(D3VGA_CONTROL, 0); +- REG_WRITE(D4VGA_CONTROL, 0); ++ ++ /* HW Engineer's Notes: ++ * During switch from vga->extended, if we set the VGA_TEST_ENABLE and ++ * then hit the VGA_TEST_RENDER_START, then the DCHUBP timing gets updated correctly. ++ * ++ * Then vBIOS will have it poll for the VGA_TEST_RENDER_DONE and unset ++ * VGA_TEST_ENABLE, to leave it in the same state as before. ++ */ ++ REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_ENABLE, 1); ++ REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1); + } + + static void dpp_pg_control( +@@ -1761,6 +1775,11 @@ static void update_dchubp_dpp( + &pipe_ctx->plane_res.scl_data.viewport_c); + } + ++ if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { ++ dc->hwss.set_cursor_position(pipe_ctx); ++ dc->hwss.set_cursor_attribute(pipe_ctx); ++ } ++ + if (plane_state->update_flags.bits.full_update) { + /*gamut remap*/ + program_gamut_remap(pipe_ctx); +@@ -2296,7 +2315,7 @@ static bool dcn10_dummy_display_power_gating( + return true; + } + +-void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) ++static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) + { + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + struct timing_generator *tg = pipe_ctx->stream_res.tg; +@@ -2316,12 +2335,46 @@ void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) + } + } + +-void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) ++static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) + { + if (hws->ctx->dc->res_pool->hubbub != NULL) + hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data); + } + ++static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) ++{ ++ struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; ++ struct hubp *hubp = pipe_ctx->plane_res.hubp; ++ struct dpp *dpp = pipe_ctx->plane_res.dpp; ++ struct dc_cursor_mi_param param = { ++ .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, ++ .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, ++ .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, ++ .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, ++ .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz ++ }; ++ ++ if (pipe_ctx->plane_state->address.type ++ == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) ++ pos_cpy.enable = false; ++ ++ if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) ++ pos_cpy.enable = false; ++ ++ hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); ++ dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width); ++} ++ ++static void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) ++{ ++ struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; ++ ++ pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( ++ pipe_ctx->plane_res.hubp, attributes); ++ pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( ++ pipe_ctx->plane_res.dpp, attributes->color_format); ++} ++ + static const struct hw_sequencer_funcs dcn10_funcs = { + .program_gamut_remap = program_gamut_remap, + .program_csc_matrix = program_csc_matrix, +@@ -2362,6 +2415,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = { + .edp_backlight_control = hwss_edp_backlight_control, + .edp_power_control = hwss_edp_power_control, + .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, ++ .set_cursor_position = dcn10_set_cursor_position, ++ .set_cursor_attribute = dcn10_set_cursor_attribute + }; + + +diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +index 0fd329d..54d8a13 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +@@ -123,8 +123,7 @@ struct link_encoder_funcs { + void (*enable_tmds_output)(struct link_encoder *enc, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, +- bool hdmi, +- bool dual_link, ++ enum signal_type signal, + uint32_t pixel_clock); + void (*enable_dp_output)(struct link_encoder *enc, + const struct dc_link_settings *link_settings, +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 4c0aa56..379c6ec 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +@@ -198,6 +198,9 @@ struct hw_sequencer_funcs { + bool enable); + void (*edp_wait_for_hpd_ready)(struct dc_link *link, bool power_up); + ++ void (*set_cursor_position)(struct pipe_ctx *pipe); ++ void (*set_cursor_attribute)(struct pipe_ctx *pipe); ++ + }; + + void color_space_to_black_color( +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 f7e40b2..d3e1923 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 +@@ -217,7 +217,7 @@ bool dce110_vblank_set( + core_dc->current_state->res_ctx.pipe_ctx[pipe_offset].stream_res.tg; + + if (enable) { +- if (!tg->funcs->arm_vert_intr(tg, 2)) { ++ if (!tg || !tg->funcs->arm_vert_intr(tg, 2)) { + DC_ERROR("Failed to get VBLANK!\n"); + return false; + } +diff --git a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c +index 57a54a7..1c079ba 100644 +--- a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c +@@ -42,8 +42,7 @@ static void virtual_link_encoder_enable_tmds_output( + struct link_encoder *enc, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, +- bool hdmi, +- bool dual_link, ++ enum signal_type signal, + uint32_t pixel_clock) {} + + static void virtual_link_encoder_enable_dp_output( +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 7a9b43f..36bbad5 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 +@@ -419,11 +419,6 @@ struct bios_event_info { + bool backlight_changed; + }; + +-enum { +- HDMI_PIXEL_CLOCK_IN_KHZ_297 = 297000, +- TMDS_PIXEL_CLOCK_IN_KHZ_165 = 165000 +-}; +- + /* + * DFS-bypass flag + */ +diff --git a/drivers/gpu/drm/amd/display/include/signal_types.h b/drivers/gpu/drm/amd/display/include/signal_types.h +index b5ebde6..199c5db 100644 +--- a/drivers/gpu/drm/amd/display/include/signal_types.h ++++ b/drivers/gpu/drm/amd/display/include/signal_types.h +@@ -26,6 +26,11 @@ + #ifndef __DC_SIGNAL_TYPES_H__ + #define __DC_SIGNAL_TYPES_H__ + ++/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */ ++#define TMDS_MIN_PIXEL_CLOCK 25000 ++/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */ ++#define TMDS_MAX_PIXEL_CLOCK 165000 ++ + enum signal_type { + SIGNAL_TYPE_NONE = 0L, /* no signal */ + SIGNAL_TYPE_DVI_SINGLE_LINK = (1 << 0), +diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +index 4c3223a..adb6e7b 100644 +--- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c ++++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +@@ -162,7 +162,7 @@ static int pp_hw_init(void *handle) + if(hwmgr->smumgr_funcs->start_smu(pp_handle->hwmgr)) { + pr_err("smc start failed\n"); + hwmgr->smumgr_funcs->smu_fini(pp_handle->hwmgr); +- return -EINVAL;; ++ return -EINVAL; + } + if (ret == PP_DPM_DISABLED) + goto exit; +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +index 41e42be..08e8a79 100644 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +@@ -2756,10 +2756,13 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, + PHM_PlatformCaps_DisableMclkSwitchingForFrameLock); + + +- disable_mclk_switching = ((1 < info.display_count) || +- disable_mclk_switching_for_frame_lock || +- smu7_vblank_too_short(hwmgr, mode_info.vblank_time_us) || +- (mode_info.refresh_rate > 120)); ++ if (info.display_count == 0) ++ disable_mclk_switching = false; ++ else ++ disable_mclk_switching = ((1 < info.display_count) || ++ disable_mclk_switching_for_frame_lock || ++ smu7_vblank_too_short(hwmgr, mode_info.vblank_time_us) || ++ (mode_info.refresh_rate > 120)); + + sclk = smu7_ps->performance_levels[0].engine_clock; + mclk = smu7_ps->performance_levels[0].memory_clock; +@@ -4534,13 +4537,6 @@ static int smu7_set_power_profile_state(struct pp_hwmgr *hwmgr, + int tmp_result, result = 0; + uint32_t sclk_mask = 0, mclk_mask = 0; + +- if (hwmgr->chip_id == CHIP_FIJI) { +- if (request->type == AMD_PP_GFX_PROFILE) +- smu7_enable_power_containment(hwmgr); +- else if (request->type == AMD_PP_COMPUTE_PROFILE) +- smu7_disable_power_containment(hwmgr); +- } +- + if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_AUTO) + return -EINVAL; + +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +index 2d55dab..5f9c3ef 100644 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +@@ -3168,10 +3168,13 @@ static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, + disable_mclk_switching_for_vr = PP_CAP(PHM_PlatformCaps_DisableMclkSwitchForVR); + force_mclk_high = PP_CAP(PHM_PlatformCaps_ForceMclkHigh); + +- disable_mclk_switching = (info.display_count > 1) || +- disable_mclk_switching_for_frame_lock || +- disable_mclk_switching_for_vr || +- force_mclk_high; ++ if (info.display_count == 0) ++ disable_mclk_switching = false; ++ else ++ disable_mclk_switching = (info.display_count > 1) || ++ disable_mclk_switching_for_frame_lock || ++ disable_mclk_switching_for_vr || ++ force_mclk_high; + + sclk = vega10_ps->performance_levels[0].gfx_clock; + mclk = vega10_ps->performance_levels[0].mem_clock; +diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c +index cd23b1b..c91b9b0 100644 +--- a/drivers/gpu/drm/cirrus/cirrus_mode.c ++++ b/drivers/gpu/drm/cirrus/cirrus_mode.c +@@ -294,22 +294,7 @@ static void cirrus_crtc_prepare(struct drm_crtc *crtc) + { + } + +-/* +- * This is called after a mode is programmed. It should reverse anything done +- * by the prepare function +- */ +-static void cirrus_crtc_commit(struct drm_crtc *crtc) +-{ +-} +- +-/* +- * The core can pass us a set of gamma values to program. We actually only +- * use this for 8-bit mode so can't perform smooth fades on deeper modes, +- * but it's a requirement that we provide the function +- */ +-static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, +- u16 *blue, uint32_t size, +- struct drm_modeset_acquire_ctx *ctx) ++static void cirrus_crtc_load_lut(struct drm_crtc *crtc) + { + struct drm_device *dev = crtc->dev; + struct cirrus_device *cdev = dev->dev_private; +@@ -317,7 +302,7 @@ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, + int i; + + if (!crtc->enabled) +- return 0; ++ return; + + r = crtc->gamma_store; + g = r + crtc->gamma_size; +@@ -330,6 +315,27 @@ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, + WREG8(PALETTE_DATA, *g++ >> 8); + WREG8(PALETTE_DATA, *b++ >> 8); + } ++} ++ ++/* ++ * This is called after a mode is programmed. It should reverse anything done ++ * by the prepare function ++ */ ++static void cirrus_crtc_commit(struct drm_crtc *crtc) ++{ ++ cirrus_crtc_load_lut(crtc); ++} ++ ++/* ++ * The core can pass us a set of gamma values to program. We actually only ++ * use this for 8-bit mode so can't perform smooth fades on deeper modes, ++ * but it's a requirement that we provide the function ++ */ ++static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, ++ u16 *blue, uint32_t size, ++ struct drm_modeset_acquire_ctx *ctx) ++{ ++ cirrus_crtc_load_lut(crtc); + + return 0; + } +diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c +index ab40321..ae3cbfe 100644 +--- a/drivers/gpu/drm/drm_atomic_helper.c ++++ b/drivers/gpu/drm/drm_atomic_helper.c +@@ -1878,6 +1878,8 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, + new_crtc_state->event->base.completion = &commit->flip_done; + new_crtc_state->event->base.completion_release = release_crtc_commit; + drm_crtc_commit_get(commit); ++ ++ commit->abort_completion = true; + } + + for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) { +@@ -3421,8 +3423,21 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); + void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state) + { + if (state->commit) { ++ /* ++ * In the event that a non-blocking commit returns ++ * -ERESTARTSYS before the commit_tail work is queued, we will ++ * have an extra reference to the commit object. Release it, if ++ * the event has not been consumed by the worker. ++ * ++ * state->event may be freed, so we can't directly look at ++ * state->event->base.completion. ++ */ ++ if (state->event && state->commit->abort_completion) ++ drm_crtc_commit_put(state->commit); ++ + kfree(state->commit->event); + state->commit->event = NULL; ++ + drm_crtc_commit_put(state->commit); + } + +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index ddd5379..4f751a9 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -113,6 +113,9 @@ static const struct edid_quirk { + /* AEO model 0 reports 8 bpc, but is a 6 bpc panel */ + { "AEO", 0, EDID_QUIRK_FORCE_6BPC }, + ++ /* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */ ++ { "CPT", 0x17df, EDID_QUIRK_FORCE_6BPC }, ++ + /* Belinea 10 15 55 */ + { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 }, + { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 }, +@@ -162,6 +165,24 @@ static const struct edid_quirk { + + /* HTC Vive VR Headset */ + { "HVR", 0xaa01, EDID_QUIRK_NON_DESKTOP }, ++ ++ /* Oculus Rift DK1, DK2, and CV1 VR Headsets */ ++ { "OVR", 0x0001, EDID_QUIRK_NON_DESKTOP }, ++ { "OVR", 0x0003, EDID_QUIRK_NON_DESKTOP }, ++ { "OVR", 0x0004, EDID_QUIRK_NON_DESKTOP }, ++ ++ /* Windows Mixed Reality Headsets */ ++ { "ACR", 0x7fce, EDID_QUIRK_NON_DESKTOP }, ++ { "HPN", 0x3515, EDID_QUIRK_NON_DESKTOP }, ++ { "LEN", 0x0408, EDID_QUIRK_NON_DESKTOP }, ++ { "LEN", 0xb800, EDID_QUIRK_NON_DESKTOP }, ++ { "FUJ", 0x1970, EDID_QUIRK_NON_DESKTOP }, ++ { "DEL", 0x7fce, EDID_QUIRK_NON_DESKTOP }, ++ { "SEC", 0x144a, EDID_QUIRK_NON_DESKTOP }, ++ { "AUS", 0xc102, EDID_QUIRK_NON_DESKTOP }, ++ ++ /* Sony PlayStation VR Headset */ ++ { "SNY", 0x0704, EDID_QUIRK_NON_DESKTOP }, + }; + + /* +diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c +index 5a13ff2..c0530a1 100644 +--- a/drivers/gpu/drm/drm_framebuffer.c ++++ b/drivers/gpu/drm/drm_framebuffer.c +@@ -121,6 +121,10 @@ int drm_mode_addfb(struct drm_device *dev, + r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); + r.handles[0] = or->handle; + ++ if (r.pixel_format == DRM_FORMAT_XRGB2101010 && ++ dev->driver->driver_features & DRIVER_PREFER_XBGR_30BPP) ++ r.pixel_format = DRM_FORMAT_XBGR2101010; ++ + ret = drm_mode_addfb2(dev, &r, file_priv); + if (ret) + return ret; +diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c +index 186c4e9..89eef1b 100644 +--- a/drivers/gpu/drm/drm_mm.c ++++ b/drivers/gpu/drm/drm_mm.c +@@ -836,9 +836,24 @@ struct drm_mm_node *drm_mm_scan_color_evict(struct drm_mm_scan *scan) + if (!mm->color_adjust) + return NULL; + +- hole = list_first_entry(&mm->hole_stack, typeof(*hole), hole_stack); +- hole_start = __drm_mm_hole_node_start(hole); +- hole_end = hole_start + hole->hole_size; ++ /* ++ * The hole found during scanning should ideally be the first element ++ * in the hole_stack list, but due to side-effects in the driver it ++ * may not be. ++ */ ++ list_for_each_entry(hole, &mm->hole_stack, hole_stack) { ++ hole_start = __drm_mm_hole_node_start(hole); ++ hole_end = hole_start + hole->hole_size; ++ ++ if (hole_start <= scan->hit_start && ++ hole_end >= scan->hit_end) ++ break; ++ } ++ ++ /* We should only be called after we found the hole previously */ ++ DRM_MM_BUG_ON(&hole->hole_stack == &mm->hole_stack); ++ if (unlikely(&hole->hole_stack == &mm->hole_stack)) ++ return NULL; + + DRM_MM_BUG_ON(hole_start > scan->hit_start); + DRM_MM_BUG_ON(hole_end < scan->hit_end); +diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c +index 555fbe5..00b8445b 100644 +--- a/drivers/gpu/drm/drm_probe_helper.c ++++ b/drivers/gpu/drm/drm_probe_helper.c +@@ -654,6 +654,26 @@ static void output_poll_execute(struct work_struct *work) + } + + /** ++ * drm_kms_helper_is_poll_worker - is %current task an output poll worker? ++ * ++ * Determine if %current task is an output poll worker. This can be used ++ * to select distinct code paths for output polling versus other contexts. ++ * ++ * One use case is to avoid a deadlock between the output poll worker and ++ * the autosuspend worker wherein the latter waits for polling to finish ++ * upon calling drm_kms_helper_poll_disable(), while the former waits for ++ * runtime suspend to finish upon calling pm_runtime_get_sync() in a ++ * connector ->detect hook. ++ */ ++bool drm_kms_helper_is_poll_worker(void) ++{ ++ struct work_struct *work = current_work(); ++ ++ return work && work->func == output_poll_execute; ++} ++EXPORT_SYMBOL(drm_kms_helper_is_poll_worker); ++ ++/** + * drm_kms_helper_poll_disable - disable output polling + * @dev: drm_device + * +diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c +index 2b8bf2d..f68ef1b 100644 +--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c ++++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c +@@ -286,7 +286,6 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) + + node = kcalloc(G2D_CMDLIST_NUM, sizeof(*node), GFP_KERNEL); + if (!node) { +- dev_err(dev, "failed to allocate memory\n"); + ret = -ENOMEM; + goto err; + } +@@ -926,7 +925,7 @@ static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no) + struct drm_device *drm_dev = g2d->subdrv.drm_dev; + struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node; + struct drm_exynos_pending_g2d_event *e; +- struct timeval now; ++ struct timespec64 now; + + if (list_empty(&runqueue_node->event_list)) + return; +@@ -934,9 +933,9 @@ static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no) + e = list_first_entry(&runqueue_node->event_list, + struct drm_exynos_pending_g2d_event, base.link); + +- do_gettimeofday(&now); ++ ktime_get_ts64(&now); + e->event.tv_sec = now.tv_sec; +- e->event.tv_usec = now.tv_usec; ++ e->event.tv_usec = now.tv_nsec / NSEC_PER_USEC; + e->event.cmdlist_no = cmdlist_no; + + drm_send_event(drm_dev, &e->base); +@@ -1358,10 +1357,9 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data, + return -EFAULT; + + runqueue_node = kmem_cache_alloc(g2d->runqueue_slab, GFP_KERNEL); +- if (!runqueue_node) { +- dev_err(dev, "failed to allocate memory\n"); ++ if (!runqueue_node) + return -ENOMEM; +- } ++ + run_cmdlist = &runqueue_node->run_cmdlist; + event_list = &runqueue_node->event_list; + INIT_LIST_HEAD(run_cmdlist); +diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.h b/drivers/gpu/drm/exynos/exynos_drm_rotator.h +deleted file mode 100644 +index 71a0b4c..0000000 +--- a/drivers/gpu/drm/exynos/exynos_drm_rotator.h ++++ /dev/null +@@ -1,19 +0,0 @@ +-/* +- * Copyright (c) 2012 Samsung Electronics Co., Ltd. +- * +- * Authors: +- * YoungJun Cho +- * Eunchul Kim +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License as published by the +- * Free Software Foundation; either version 2 of the License, or (at your +- * option) any later version. +- */ +- +-#ifndef _EXYNOS_DRM_ROTATOR_H_ +-#define _EXYNOS_DRM_ROTATOR_H_ +- +-/* TODO */ +- +-#endif +diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c +index a4b75a4..abd84cb 100644 +--- a/drivers/gpu/drm/exynos/exynos_hdmi.c ++++ b/drivers/gpu/drm/exynos/exynos_hdmi.c +@@ -1068,10 +1068,13 @@ static void hdmi_audio_config(struct hdmi_context *hdata) + /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */ + hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5) + | HDMI_I2S_SEL_LRCK(6)); +- hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1) +- | HDMI_I2S_SEL_SDATA2(4)); ++ ++ hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(3) ++ | HDMI_I2S_SEL_SDATA0(4)); ++ + hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1) + | HDMI_I2S_SEL_SDATA2(2)); ++ + hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0)); + + /* I2S_CON_1 & 2 */ +diff --git a/drivers/gpu/drm/exynos/regs-fimc.h b/drivers/gpu/drm/exynos/regs-fimc.h +index 3049613..d7cbe53 100644 +--- a/drivers/gpu/drm/exynos/regs-fimc.h ++++ b/drivers/gpu/drm/exynos/regs-fimc.h +@@ -569,7 +569,7 @@ + #define EXYNOS_CIIMGEFF_FIN_EMBOSSING (4 << 26) + #define EXYNOS_CIIMGEFF_FIN_SILHOUETTE (5 << 26) + #define EXYNOS_CIIMGEFF_FIN_MASK (7 << 26) +-#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK ((0xff < 13) | (0xff < 0)) ++#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK ((0xff << 13) | (0xff << 0)) + + /* Real input DMA size register */ + #define EXYNOS_CIREAL_ISIZE_AUTOLOAD_ENABLE (1 << 31) +diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h +index 04be0f7e..4420c20 100644 +--- a/drivers/gpu/drm/exynos/regs-hdmi.h ++++ b/drivers/gpu/drm/exynos/regs-hdmi.h +@@ -464,7 +464,7 @@ + + /* I2S_PIN_SEL_1 */ + #define HDMI_I2S_SEL_SDATA1(x) (((x) & 0x7) << 4) +-#define HDMI_I2S_SEL_SDATA2(x) ((x) & 0x7) ++#define HDMI_I2S_SEL_SDATA0(x) ((x) & 0x7) + + /* I2S_PIN_SEL_2 */ + #define HDMI_I2S_SEL_SDATA3(x) (((x) & 0x7) << 4) +diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c +index 909499b..021f722 100644 +--- a/drivers/gpu/drm/i915/gvt/kvmgt.c ++++ b/drivers/gpu/drm/i915/gvt/kvmgt.c +@@ -733,6 +733,25 @@ static ssize_t intel_vgpu_rw(struct mdev_device *mdev, char *buf, + return ret == 0 ? count : ret; + } + ++static bool gtt_entry(struct mdev_device *mdev, loff_t *ppos) ++{ ++ struct intel_vgpu *vgpu = mdev_get_drvdata(mdev); ++ unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); ++ struct intel_gvt *gvt = vgpu->gvt; ++ int offset; ++ ++ /* Only allow MMIO GGTT entry access */ ++ if (index != PCI_BASE_ADDRESS_0) ++ return false; ++ ++ offset = (u64)(*ppos & VFIO_PCI_OFFSET_MASK) - ++ intel_vgpu_get_bar_gpa(vgpu, PCI_BASE_ADDRESS_0); ++ ++ return (offset >= gvt->device_info.gtt_start_offset && ++ offset < gvt->device_info.gtt_start_offset + gvt_ggtt_sz(gvt)) ? ++ true : false; ++} ++ + static ssize_t intel_vgpu_read(struct mdev_device *mdev, char __user *buf, + size_t count, loff_t *ppos) + { +@@ -742,7 +761,21 @@ static ssize_t intel_vgpu_read(struct mdev_device *mdev, char __user *buf, + while (count) { + size_t filled; + +- if (count >= 4 && !(*ppos % 4)) { ++ /* Only support GGTT entry 8 bytes read */ ++ if (count >= 8 && !(*ppos % 8) && ++ gtt_entry(mdev, ppos)) { ++ u64 val; ++ ++ ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val), ++ ppos, false); ++ if (ret <= 0) ++ goto read_err; ++ ++ if (copy_to_user(buf, &val, sizeof(val))) ++ goto read_err; ++ ++ filled = 8; ++ } else if (count >= 4 && !(*ppos % 4)) { + u32 val; + + ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val), +@@ -802,7 +835,21 @@ static ssize_t intel_vgpu_write(struct mdev_device *mdev, + while (count) { + size_t filled; + +- if (count >= 4 && !(*ppos % 4)) { ++ /* Only support GGTT entry 8 bytes write */ ++ if (count >= 8 && !(*ppos % 8) && ++ gtt_entry(mdev, ppos)) { ++ u64 val; ++ ++ if (copy_from_user(&val, buf, sizeof(val))) ++ goto write_err; ++ ++ ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val), ++ ppos, true); ++ if (ret <= 0) ++ goto write_err; ++ ++ filled = 8; ++ } else if (count >= 4 && !(*ppos % 4)) { + u32 val; + + if (copy_from_user(&val, buf, sizeof(val))) +diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c +index 73ad6e90..256f1bb5 100644 +--- a/drivers/gpu/drm/i915/gvt/mmio_context.c ++++ b/drivers/gpu/drm/i915/gvt/mmio_context.c +@@ -118,6 +118,7 @@ static struct engine_mmio gen9_engine_mmio_list[] __cacheline_aligned = { + {RCS, HALF_SLICE_CHICKEN3, 0xffff, true}, /* 0xe184 */ + {RCS, GEN9_HALF_SLICE_CHICKEN5, 0xffff, true}, /* 0xe188 */ + {RCS, GEN9_HALF_SLICE_CHICKEN7, 0xffff, true}, /* 0xe194 */ ++ {RCS, GEN8_ROW_CHICKEN, 0xffff, true}, /* 0xe4f0 */ + {RCS, TRVATTL3PTRDW(0), 0, false}, /* 0x4de0 */ + {RCS, TRVATTL3PTRDW(1), 0, false}, /* 0x4de4 */ + {RCS, TRNULLDETCT, 0, false}, /* 0x4de8 */ +diff --git a/drivers/gpu/drm/i915/gvt/trace.h b/drivers/gpu/drm/i915/gvt/trace.h +index 7a25115..736bd2b 100644 +--- a/drivers/gpu/drm/i915/gvt/trace.h ++++ b/drivers/gpu/drm/i915/gvt/trace.h +@@ -333,7 +333,7 @@ TRACE_EVENT(render_mmio, + TP_PROTO(int old_id, int new_id, char *action, unsigned int reg, + unsigned int old_val, unsigned int new_val), + +- TP_ARGS(old_id, new_id, action, reg, new_val, old_val), ++ TP_ARGS(old_id, new_id, action, reg, old_val, new_val), + + TP_STRUCT__entry( + __field(int, old_id) +diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c +index 173d009..2f5209d 100644 +--- a/drivers/gpu/drm/i915/i915_drv.c ++++ b/drivers/gpu/drm/i915/i915_drv.c +@@ -1433,19 +1433,7 @@ void i915_driver_unload(struct drm_device *dev) + + intel_modeset_cleanup(dev); + +- /* +- * free the memory space allocated for the child device +- * config parsed from VBT +- */ +- if (dev_priv->vbt.child_dev && dev_priv->vbt.child_dev_num) { +- kfree(dev_priv->vbt.child_dev); +- dev_priv->vbt.child_dev = NULL; +- dev_priv->vbt.child_dev_num = 0; +- } +- kfree(dev_priv->vbt.sdvo_lvds_vbt_mode); +- dev_priv->vbt.sdvo_lvds_vbt_mode = NULL; +- kfree(dev_priv->vbt.lfp_lvds_vbt_mode); +- dev_priv->vbt.lfp_lvds_vbt_mode = NULL; ++ intel_bios_cleanup(dev_priv); + + vga_switcheroo_unregister_client(pdev); + vga_client_register(pdev, NULL, NULL, NULL); +diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h +index a42deeb..d307429 100644 +--- a/drivers/gpu/drm/i915/i915_drv.h ++++ b/drivers/gpu/drm/i915/i915_drv.h +@@ -1349,6 +1349,7 @@ struct intel_vbt_data { + u32 size; + u8 *data; + const u8 *sequence[MIPI_SEQ_MAX]; ++ u8 *deassert_seq; /* Used by fixup_mipi_sequences() */ + } dsi; + + int crt_ddc_pin; +@@ -3657,6 +3658,7 @@ extern void intel_i2c_reset(struct drm_i915_private *dev_priv); + + /* intel_bios.c */ + void intel_bios_init(struct drm_i915_private *dev_priv); ++void intel_bios_cleanup(struct drm_i915_private *dev_priv); + bool intel_bios_is_valid_vbt(const void *buf, size_t size); + bool intel_bios_is_tv_present(struct drm_i915_private *dev_priv); + bool intel_bios_is_lvds_present(struct drm_i915_private *dev_priv, u8 *i2c_pin); +diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c +index dd89abd..66ee9d8 100644 +--- a/drivers/gpu/drm/i915/i915_gem.c ++++ b/drivers/gpu/drm/i915/i915_gem.c +@@ -3205,8 +3205,10 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) + * rolling the global seqno forward (since this would complete requests + * for which we haven't set the fence error to EIO yet). + */ +- for_each_engine(engine, i915, id) ++ for_each_engine(engine, i915, id) { ++ i915_gem_reset_prepare_engine(engine); + engine->submit_request = nop_submit_request; ++ } + + /* + * Make sure no one is running the old callback before we proceed with +@@ -3244,6 +3246,8 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) + intel_engine_init_global_seqno(engine, + intel_engine_last_submit(engine)); + spin_unlock_irqrestore(&engine->timeline->lock, flags); ++ ++ i915_gem_reset_finish_engine(engine); + } + + set_bit(I915_WEDGED, &i915->gpu_error.flags); +diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c +index 648e753..0c963fc 100644 +--- a/drivers/gpu/drm/i915/i915_gem_context.c ++++ b/drivers/gpu/drm/i915/i915_gem_context.c +@@ -803,7 +803,7 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data, + + case I915_CONTEXT_PARAM_PRIORITY: + { +- int priority = args->value; ++ s64 priority = args->value; + + if (args->size) + ret = -EINVAL; +diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c +index 4401068..3ab1ace 100644 +--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c ++++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c +@@ -505,6 +505,8 @@ eb_add_vma(struct i915_execbuffer *eb, unsigned int i, struct i915_vma *vma) + list_add_tail(&vma->exec_link, &eb->unbound); + if (drm_mm_node_allocated(&vma->node)) + err = i915_vma_unbind(vma); ++ if (unlikely(err)) ++ vma->exec_flags = NULL; + } + return err; + } +@@ -2410,7 +2412,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, + if (out_fence) { + if (err == 0) { + fd_install(out_fence_fd, out_fence->file); +- args->rsvd2 &= GENMASK_ULL(0, 31); /* keep in-fence */ ++ args->rsvd2 &= GENMASK_ULL(31, 0); /* keep in-fence */ + args->rsvd2 |= (u64)out_fence_fd << 32; + out_fence_fd = -1; + } else { +diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c +index e09d18d..a3e93d4 100644 +--- a/drivers/gpu/drm/i915/i915_gem_request.c ++++ b/drivers/gpu/drm/i915/i915_gem_request.c +@@ -476,8 +476,6 @@ void __i915_gem_request_submit(struct drm_i915_gem_request *request) + GEM_BUG_ON(!irqs_disabled()); + lockdep_assert_held(&engine->timeline->lock); + +- trace_i915_gem_request_execute(request); +- + /* Transfer from per-context onto the global per-engine timeline */ + timeline = engine->timeline; + GEM_BUG_ON(timeline == request->timeline); +@@ -501,6 +499,8 @@ void __i915_gem_request_submit(struct drm_i915_gem_request *request) + list_move_tail(&request->link, &timeline->requests); + spin_unlock(&request->timeline->lock); + ++ trace_i915_gem_request_execute(request); ++ + wake_up_all(&request->execute); + } + +diff --git a/drivers/gpu/drm/i915/i915_oa_cflgt3.c b/drivers/gpu/drm/i915/i915_oa_cflgt3.c +index 42ff06f..792facd 100644 +--- a/drivers/gpu/drm/i915/i915_oa_cflgt3.c ++++ b/drivers/gpu/drm/i915/i915_oa_cflgt3.c +@@ -84,9 +84,9 @@ show_test_oa_id(struct device *kdev, struct device_attribute *attr, char *buf) + void + i915_perf_load_test_config_cflgt3(struct drm_i915_private *dev_priv) + { +- strncpy(dev_priv->perf.oa.test_config.uuid, ++ strlcpy(dev_priv->perf.oa.test_config.uuid, + "577e8e2c-3fa0-4875-8743-3538d585e3b0", +- UUID_STRING_LEN); ++ sizeof(dev_priv->perf.oa.test_config.uuid)); + dev_priv->perf.oa.test_config.id = 1; + + dev_priv->perf.oa.test_config.mux_regs = mux_config_test_oa; +diff --git a/drivers/gpu/drm/i915/i915_oa_cnl.c b/drivers/gpu/drm/i915/i915_oa_cnl.c +index ff0ac36..ba9140c 100644 +--- a/drivers/gpu/drm/i915/i915_oa_cnl.c ++++ b/drivers/gpu/drm/i915/i915_oa_cnl.c +@@ -96,9 +96,9 @@ show_test_oa_id(struct device *kdev, struct device_attribute *attr, char *buf) + void + i915_perf_load_test_config_cnl(struct drm_i915_private *dev_priv) + { +- strncpy(dev_priv->perf.oa.test_config.uuid, ++ strlcpy(dev_priv->perf.oa.test_config.uuid, + "db41edd4-d8e7-4730-ad11-b9a2d6833503", +- UUID_STRING_LEN); ++ sizeof(dev_priv->perf.oa.test_config.uuid)); + dev_priv->perf.oa.test_config.id = 1; + + dev_priv->perf.oa.test_config.mux_regs = mux_config_test_oa; +diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c +index 0be50e4..f8fe5ff 100644 +--- a/drivers/gpu/drm/i915/i915_perf.c ++++ b/drivers/gpu/drm/i915/i915_perf.c +@@ -1303,9 +1303,8 @@ static void i915_oa_stream_destroy(struct i915_perf_stream *stream) + */ + mutex_lock(&dev_priv->drm.struct_mutex); + dev_priv->perf.oa.exclusive_stream = NULL; +- mutex_unlock(&dev_priv->drm.struct_mutex); +- + dev_priv->perf.oa.ops.disable_metric_set(dev_priv); ++ mutex_unlock(&dev_priv->drm.struct_mutex); + + free_oa_buffer(dev_priv); + +@@ -1756,22 +1755,13 @@ static int gen8_switch_to_updated_kernel_context(struct drm_i915_private *dev_pr + * Note: it's only the RCS/Render context that has any OA state. + */ + static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv, +- const struct i915_oa_config *oa_config, +- bool interruptible) ++ const struct i915_oa_config *oa_config) + { + struct i915_gem_context *ctx; + int ret; + unsigned int wait_flags = I915_WAIT_LOCKED; + +- if (interruptible) { +- ret = i915_mutex_lock_interruptible(&dev_priv->drm); +- if (ret) +- return ret; +- +- wait_flags |= I915_WAIT_INTERRUPTIBLE; +- } else { +- mutex_lock(&dev_priv->drm.struct_mutex); +- } ++ lockdep_assert_held(&dev_priv->drm.struct_mutex); + + /* Switch away from any user context. */ + ret = gen8_switch_to_updated_kernel_context(dev_priv, oa_config); +@@ -1819,8 +1809,6 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv, + } + + out: +- mutex_unlock(&dev_priv->drm.struct_mutex); +- + return ret; + } + +@@ -1863,7 +1851,7 @@ static int gen8_enable_metric_set(struct drm_i915_private *dev_priv, + * to make sure all slices/subslices are ON before writing to NOA + * registers. + */ +- ret = gen8_configure_all_contexts(dev_priv, oa_config, true); ++ ret = gen8_configure_all_contexts(dev_priv, oa_config); + if (ret) + return ret; + +@@ -1878,7 +1866,7 @@ static int gen8_enable_metric_set(struct drm_i915_private *dev_priv, + static void gen8_disable_metric_set(struct drm_i915_private *dev_priv) + { + /* Reset all contexts' slices/subslices configurations. */ +- gen8_configure_all_contexts(dev_priv, NULL, false); ++ gen8_configure_all_contexts(dev_priv, NULL); + + I915_WRITE(GDT_CHICKEN_BITS, (I915_READ(GDT_CHICKEN_BITS) & + ~GT_NOA_ENABLE)); +@@ -1888,7 +1876,7 @@ static void gen8_disable_metric_set(struct drm_i915_private *dev_priv) + static void gen10_disable_metric_set(struct drm_i915_private *dev_priv) + { + /* Reset all contexts' slices/subslices configurations. */ +- gen8_configure_all_contexts(dev_priv, NULL, false); ++ gen8_configure_all_contexts(dev_priv, NULL); + + /* Make sure we disable noa to save power. */ + I915_WRITE(RPM_CONFIG1, +@@ -2138,6 +2126,10 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, + if (ret) + goto err_oa_buf_alloc; + ++ ret = i915_mutex_lock_interruptible(&dev_priv->drm); ++ if (ret) ++ goto err_lock; ++ + ret = dev_priv->perf.oa.ops.enable_metric_set(dev_priv, + stream->oa_config); + if (ret) +@@ -2145,23 +2137,17 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, + + stream->ops = &i915_oa_stream_ops; + +- /* Lock device for exclusive_stream access late because +- * enable_metric_set() might lock as well on gen8+. +- */ +- ret = i915_mutex_lock_interruptible(&dev_priv->drm); +- if (ret) +- goto err_lock; +- + dev_priv->perf.oa.exclusive_stream = stream; + + mutex_unlock(&dev_priv->drm.struct_mutex); + + return 0; + +-err_lock: ++err_enable: + dev_priv->perf.oa.ops.disable_metric_set(dev_priv); ++ mutex_unlock(&dev_priv->drm.struct_mutex); + +-err_enable: ++err_lock: + free_oa_buffer(dev_priv); + + err_oa_buf_alloc: +diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c +index 55a8a1e..0e9b98c 100644 +--- a/drivers/gpu/drm/i915/i915_pmu.c ++++ b/drivers/gpu/drm/i915/i915_pmu.c +@@ -285,26 +285,41 @@ static u64 count_interrupts(struct drm_i915_private *i915) + return sum; + } + +-static void i915_pmu_event_destroy(struct perf_event *event) ++static void engine_event_destroy(struct perf_event *event) + { +- WARN_ON(event->parent); ++ struct drm_i915_private *i915 = ++ container_of(event->pmu, typeof(*i915), pmu.base); ++ struct intel_engine_cs *engine; ++ ++ engine = intel_engine_lookup_user(i915, ++ engine_event_class(event), ++ engine_event_instance(event)); ++ if (WARN_ON_ONCE(!engine)) ++ return; ++ ++ if (engine_event_sample(event) == I915_SAMPLE_BUSY && ++ intel_engine_supports_stats(engine)) ++ intel_disable_engine_stats(engine); + } + +-static int engine_event_init(struct perf_event *event) ++static void i915_pmu_event_destroy(struct perf_event *event) + { +- struct drm_i915_private *i915 = +- container_of(event->pmu, typeof(*i915), pmu.base); ++ WARN_ON(event->parent); + +- if (!intel_engine_lookup_user(i915, engine_event_class(event), +- engine_event_instance(event))) +- return -ENODEV; ++ if (is_engine_event(event)) ++ engine_event_destroy(event); ++} + +- switch (engine_event_sample(event)) { ++static int ++engine_event_status(struct intel_engine_cs *engine, ++ enum drm_i915_pmu_engine_sample sample) ++{ ++ switch (sample) { + case I915_SAMPLE_BUSY: + case I915_SAMPLE_WAIT: + break; + case I915_SAMPLE_SEMA: +- if (INTEL_GEN(i915) < 6) ++ if (INTEL_GEN(engine->i915) < 6) + return -ENODEV; + break; + default: +@@ -314,6 +329,30 @@ static int engine_event_init(struct perf_event *event) + return 0; + } + ++static int engine_event_init(struct perf_event *event) ++{ ++ struct drm_i915_private *i915 = ++ container_of(event->pmu, typeof(*i915), pmu.base); ++ struct intel_engine_cs *engine; ++ u8 sample; ++ int ret; ++ ++ engine = intel_engine_lookup_user(i915, engine_event_class(event), ++ engine_event_instance(event)); ++ if (!engine) ++ return -ENODEV; ++ ++ sample = engine_event_sample(event); ++ ret = engine_event_status(engine, sample); ++ if (ret) ++ return ret; ++ ++ if (sample == I915_SAMPLE_BUSY && intel_engine_supports_stats(engine)) ++ ret = intel_enable_engine_stats(engine); ++ ++ return ret; ++} ++ + static int i915_pmu_event_init(struct perf_event *event) + { + struct drm_i915_private *i915 = +@@ -370,7 +409,94 @@ static int i915_pmu_event_init(struct perf_event *event) + return 0; + } + +-static u64 __i915_pmu_event_read(struct perf_event *event) ++static u64 __get_rc6(struct drm_i915_private *i915) ++{ ++ u64 val; ++ ++ val = intel_rc6_residency_ns(i915, ++ IS_VALLEYVIEW(i915) ? ++ VLV_GT_RENDER_RC6 : ++ GEN6_GT_GFX_RC6); ++ ++ if (HAS_RC6p(i915)) ++ val += intel_rc6_residency_ns(i915, GEN6_GT_GFX_RC6p); ++ ++ if (HAS_RC6pp(i915)) ++ val += intel_rc6_residency_ns(i915, GEN6_GT_GFX_RC6pp); ++ ++ return val; ++} ++ ++static u64 get_rc6(struct drm_i915_private *i915, bool locked) ++{ ++#if IS_ENABLED(CONFIG_PM) ++ unsigned long flags; ++ u64 val; ++ ++ if (intel_runtime_pm_get_if_in_use(i915)) { ++ val = __get_rc6(i915); ++ intel_runtime_pm_put(i915); ++ ++ /* ++ * If we are coming back from being runtime suspended we must ++ * be careful not to report a larger value than returned ++ * previously. ++ */ ++ ++ if (!locked) ++ spin_lock_irqsave(&i915->pmu.lock, flags); ++ ++ if (val >= i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur) { ++ i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur = 0; ++ i915->pmu.sample[__I915_SAMPLE_RC6].cur = val; ++ } else { ++ val = i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur; ++ } ++ ++ if (!locked) ++ spin_unlock_irqrestore(&i915->pmu.lock, flags); ++ } else { ++ struct pci_dev *pdev = i915->drm.pdev; ++ struct device *kdev = &pdev->dev; ++ unsigned long flags2; ++ ++ /* ++ * We are runtime suspended. ++ * ++ * Report the delta from when the device was suspended to now, ++ * on top of the last known real value, as the approximated RC6 ++ * counter value. ++ */ ++ if (!locked) ++ spin_lock_irqsave(&i915->pmu.lock, flags); ++ ++ spin_lock_irqsave(&kdev->power.lock, flags2); ++ ++ if (!i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur) ++ i915->pmu.suspended_jiffies_last = ++ kdev->power.suspended_jiffies; ++ ++ val = kdev->power.suspended_jiffies - ++ i915->pmu.suspended_jiffies_last; ++ val += jiffies - kdev->power.accounting_timestamp; ++ ++ spin_unlock_irqrestore(&kdev->power.lock, flags2); ++ ++ val = jiffies_to_nsecs(val); ++ val += i915->pmu.sample[__I915_SAMPLE_RC6].cur; ++ i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur = val; ++ ++ if (!locked) ++ spin_unlock_irqrestore(&i915->pmu.lock, flags); ++ } ++ ++ return val; ++#else ++ return __get_rc6(i915); ++#endif ++} ++ ++static u64 __i915_pmu_event_read(struct perf_event *event, bool locked) + { + struct drm_i915_private *i915 = + container_of(event->pmu, typeof(*i915), pmu.base); +@@ -387,7 +513,7 @@ static u64 __i915_pmu_event_read(struct perf_event *event) + if (WARN_ON_ONCE(!engine)) { + /* Do nothing */ + } else if (sample == I915_SAMPLE_BUSY && +- engine->pmu.busy_stats) { ++ intel_engine_supports_stats(engine)) { + val = ktime_to_ns(intel_engine_get_busy_time(engine)); + } else { + val = engine->pmu.sample[sample].cur; +@@ -408,18 +534,7 @@ static u64 __i915_pmu_event_read(struct perf_event *event) + val = count_interrupts(i915); + break; + case I915_PMU_RC6_RESIDENCY: +- intel_runtime_pm_get(i915); +- val = intel_rc6_residency_ns(i915, +- IS_VALLEYVIEW(i915) ? +- VLV_GT_RENDER_RC6 : +- GEN6_GT_GFX_RC6); +- if (HAS_RC6p(i915)) +- val += intel_rc6_residency_ns(i915, +- GEN6_GT_GFX_RC6p); +- if (HAS_RC6pp(i915)) +- val += intel_rc6_residency_ns(i915, +- GEN6_GT_GFX_RC6pp); +- intel_runtime_pm_put(i915); ++ val = get_rc6(i915, locked); + break; + } + } +@@ -434,7 +549,7 @@ static void i915_pmu_event_read(struct perf_event *event) + + again: + prev = local64_read(&hwc->prev_count); +- new = __i915_pmu_event_read(event); ++ new = __i915_pmu_event_read(event, false); + + if (local64_cmpxchg(&hwc->prev_count, prev, new) != prev) + goto again; +@@ -442,12 +557,6 @@ static void i915_pmu_event_read(struct perf_event *event) + local64_add(new - prev, &event->count); + } + +-static bool engine_needs_busy_stats(struct intel_engine_cs *engine) +-{ +- return intel_engine_supports_stats(engine) && +- (engine->pmu.enable & BIT(I915_SAMPLE_BUSY)); +-} +- + static void i915_pmu_enable(struct perf_event *event) + { + struct drm_i915_private *i915 = +@@ -487,21 +596,7 @@ static void i915_pmu_enable(struct perf_event *event) + + GEM_BUG_ON(sample >= I915_PMU_SAMPLE_BITS); + GEM_BUG_ON(engine->pmu.enable_count[sample] == ~0); +- if (engine->pmu.enable_count[sample]++ == 0) { +- /* +- * Enable engine busy stats tracking if needed or +- * alternatively cancel the scheduled disable. +- * +- * If the delayed disable was pending, cancel it and +- * in this case do not enable since it already is. +- */ +- if (engine_needs_busy_stats(engine) && +- !engine->pmu.busy_stats) { +- engine->pmu.busy_stats = true; +- if (!cancel_delayed_work(&engine->pmu.disable_busy_stats)) +- intel_enable_engine_stats(engine); +- } +- } ++ engine->pmu.enable_count[sample]++; + } + + /* +@@ -509,19 +604,11 @@ static void i915_pmu_enable(struct perf_event *event) + * for all listeners. Even when the event was already enabled and has + * an existing non-zero value. + */ +- local64_set(&event->hw.prev_count, __i915_pmu_event_read(event)); ++ local64_set(&event->hw.prev_count, __i915_pmu_event_read(event, true)); + + spin_unlock_irqrestore(&i915->pmu.lock, flags); + } + +-static void __disable_busy_stats(struct work_struct *work) +-{ +- struct intel_engine_cs *engine = +- container_of(work, typeof(*engine), pmu.disable_busy_stats.work); +- +- intel_disable_engine_stats(engine); +-} +- + static void i915_pmu_disable(struct perf_event *event) + { + struct drm_i915_private *i915 = +@@ -545,26 +632,8 @@ static void i915_pmu_disable(struct perf_event *event) + * Decrement the reference count and clear the enabled + * bitmask when the last listener on an event goes away. + */ +- if (--engine->pmu.enable_count[sample] == 0) { ++ if (--engine->pmu.enable_count[sample] == 0) + engine->pmu.enable &= ~BIT(sample); +- if (!engine_needs_busy_stats(engine) && +- engine->pmu.busy_stats) { +- engine->pmu.busy_stats = false; +- /* +- * We request a delayed disable to handle the +- * rapid on/off cycles on events, which can +- * happen when tools like perf stat start, in a +- * nicer way. +- * +- * In addition, this also helps with busy stats +- * accuracy with background CPU offline/online +- * migration events. +- */ +- queue_delayed_work(system_wq, +- &engine->pmu.disable_busy_stats, +- round_jiffies_up_relative(HZ)); +- } +- } + } + + GEM_BUG_ON(bit >= I915_PMU_MASK_BITS); +@@ -797,8 +866,6 @@ static void i915_pmu_unregister_cpuhp_state(struct drm_i915_private *i915) + + void i915_pmu_register(struct drm_i915_private *i915) + { +- struct intel_engine_cs *engine; +- enum intel_engine_id id; + int ret; + + if (INTEL_GEN(i915) <= 2) { +@@ -820,10 +887,6 @@ void i915_pmu_register(struct drm_i915_private *i915) + hrtimer_init(&i915->pmu.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + i915->pmu.timer.function = i915_sample; + +- for_each_engine(engine, i915, id) +- INIT_DELAYED_WORK(&engine->pmu.disable_busy_stats, +- __disable_busy_stats); +- + ret = perf_pmu_register(&i915->pmu.base, "i915", -1); + if (ret) + goto err; +@@ -843,9 +906,6 @@ void i915_pmu_register(struct drm_i915_private *i915) + + void i915_pmu_unregister(struct drm_i915_private *i915) + { +- struct intel_engine_cs *engine; +- enum intel_engine_id id; +- + if (!i915->pmu.base.event_init) + return; + +@@ -853,11 +913,6 @@ void i915_pmu_unregister(struct drm_i915_private *i915) + + hrtimer_cancel(&i915->pmu.timer); + +- for_each_engine(engine, i915, id) { +- GEM_BUG_ON(engine->pmu.busy_stats); +- flush_delayed_work(&engine->pmu.disable_busy_stats); +- } +- + i915_pmu_unregister_cpuhp_state(i915); + + perf_pmu_unregister(&i915->pmu.base); +diff --git a/drivers/gpu/drm/i915/i915_pmu.h b/drivers/gpu/drm/i915/i915_pmu.h +index 40c154d..bb62df1 100644 +--- a/drivers/gpu/drm/i915/i915_pmu.h ++++ b/drivers/gpu/drm/i915/i915_pmu.h +@@ -27,6 +27,8 @@ + enum { + __I915_SAMPLE_FREQ_ACT = 0, + __I915_SAMPLE_FREQ_REQ, ++ __I915_SAMPLE_RC6, ++ __I915_SAMPLE_RC6_ESTIMATED, + __I915_NUM_PMU_SAMPLERS + }; + +@@ -94,6 +96,10 @@ struct i915_pmu { + * struct intel_engine_cs. + */ + struct i915_pmu_sample sample[__I915_NUM_PMU_SAMPLERS]; ++ /** ++ * @suspended_jiffies_last: Cached suspend time from PM core. ++ */ ++ unsigned long suspended_jiffies_last; + }; + + #ifdef CONFIG_PERF_EVENTS +diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h +index a2108e3..33eb0c5 100644 +--- a/drivers/gpu/drm/i915/i915_reg.h ++++ b/drivers/gpu/drm/i915/i915_reg.h +@@ -2027,7 +2027,7 @@ enum i915_power_well_id { + #define _CNL_PORT_TX_DW5_LN0_AE 0x162454 + #define _CNL_PORT_TX_DW5_LN0_B 0x162654 + #define _CNL_PORT_TX_DW5_LN0_C 0x162C54 +-#define _CNL_PORT_TX_DW5_LN0_D 0x162ED4 ++#define _CNL_PORT_TX_DW5_LN0_D 0x162E54 + #define _CNL_PORT_TX_DW5_LN0_F 0x162854 + #define CNL_PORT_TX_DW5_GRP(port) _MMIO_PORT6(port, \ + _CNL_PORT_TX_DW5_GRP_AE, \ +@@ -2058,7 +2058,7 @@ enum i915_power_well_id { + #define _CNL_PORT_TX_DW7_LN0_AE 0x16245C + #define _CNL_PORT_TX_DW7_LN0_B 0x16265C + #define _CNL_PORT_TX_DW7_LN0_C 0x162C5C +-#define _CNL_PORT_TX_DW7_LN0_D 0x162EDC ++#define _CNL_PORT_TX_DW7_LN0_D 0x162E5C + #define _CNL_PORT_TX_DW7_LN0_F 0x16285C + #define CNL_PORT_TX_DW7_GRP(port) _MMIO_PORT6(port, \ + _CNL_PORT_TX_DW7_GRP_AE, \ +diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c +index 522d54f..4a01f62 100644 +--- a/drivers/gpu/drm/i915/intel_audio.c ++++ b/drivers/gpu/drm/i915/intel_audio.c +@@ -779,11 +779,11 @@ static struct intel_encoder *get_saved_enc(struct drm_i915_private *dev_priv, + { + struct intel_encoder *encoder; + +- if (WARN_ON(pipe >= ARRAY_SIZE(dev_priv->av_enc_map))) +- return NULL; +- + /* MST */ + if (pipe >= 0) { ++ if (WARN_ON(pipe >= ARRAY_SIZE(dev_priv->av_enc_map))) ++ return NULL; ++ + encoder = dev_priv->av_enc_map[pipe]; + /* + * when bootup, audio driver may not know it is +diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c +index f7f7717..b49a2df 100644 +--- a/drivers/gpu/drm/i915/intel_bios.c ++++ b/drivers/gpu/drm/i915/intel_bios.c +@@ -947,6 +947,86 @@ static int goto_next_sequence_v3(const u8 *data, int index, int total) + return 0; + } + ++/* ++ * Get len of pre-fixed deassert fragment from a v1 init OTP sequence, ++ * skip all delay + gpio operands and stop at the first DSI packet op. ++ */ ++static int get_init_otp_deassert_fragment_len(struct drm_i915_private *dev_priv) ++{ ++ const u8 *data = dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP]; ++ int index, len; ++ ++ if (WARN_ON(!data || dev_priv->vbt.dsi.seq_version != 1)) ++ return 0; ++ ++ /* index = 1 to skip sequence byte */ ++ for (index = 1; data[index] != MIPI_SEQ_ELEM_END; index += len) { ++ switch (data[index]) { ++ case MIPI_SEQ_ELEM_SEND_PKT: ++ return index == 1 ? 0 : index; ++ case MIPI_SEQ_ELEM_DELAY: ++ len = 5; /* 1 byte for operand + uint32 */ ++ break; ++ case MIPI_SEQ_ELEM_GPIO: ++ len = 3; /* 1 byte for op, 1 for gpio_nr, 1 for value */ ++ break; ++ default: ++ return 0; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * Some v1 VBT MIPI sequences do the deassert in the init OTP sequence. ++ * The deassert must be done before calling intel_dsi_device_ready, so for ++ * 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 *dev_priv) ++{ ++ u8 *init_otp; ++ int len; ++ ++ /* Limit this to VLV for now. */ ++ if (!IS_VALLEYVIEW(dev_priv)) ++ return; ++ ++ /* Limit this to v1 vid-mode sequences */ ++ if (dev_priv->vbt.dsi.config->is_cmd_mode || ++ dev_priv->vbt.dsi.seq_version != 1) ++ return; ++ ++ /* Only do this if there are otp and assert seqs and no deassert seq */ ++ if (!dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] || ++ !dev_priv->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET] || ++ dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET]) ++ return; ++ ++ /* The deassert-sequence ends at the first DSI packet */ ++ len = get_init_otp_deassert_fragment_len(dev_priv); ++ if (!len) ++ return; ++ ++ DRM_DEBUG_KMS("Using init OTP fragment to deassert reset\n"); ++ ++ /* Copy the fragment, update seq byte and terminate it */ ++ init_otp = (u8 *)dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP]; ++ dev_priv->vbt.dsi.deassert_seq = kmemdup(init_otp, len + 1, GFP_KERNEL); ++ if (!dev_priv->vbt.dsi.deassert_seq) ++ return; ++ dev_priv->vbt.dsi.deassert_seq[0] = MIPI_SEQ_DEASSERT_RESET; ++ dev_priv->vbt.dsi.deassert_seq[len] = MIPI_SEQ_ELEM_END; ++ /* Use the copy for deassert */ ++ dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET] = ++ dev_priv->vbt.dsi.deassert_seq; ++ /* Replace the last byte of the fragment with init OTP seq byte */ ++ init_otp[len - 1] = MIPI_SEQ_INIT_OTP; ++ /* And make MIPI_MIPI_SEQ_INIT_OTP point to it */ ++ dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] = init_otp + len - 1; ++} ++ + static void + parse_mipi_sequence(struct drm_i915_private *dev_priv, + const struct bdb_header *bdb) +@@ -1016,6 +1096,8 @@ parse_mipi_sequence(struct drm_i915_private *dev_priv, + dev_priv->vbt.dsi.size = seq_size; + dev_priv->vbt.dsi.seq_version = sequence->version; + ++ fixup_mipi_sequences(dev_priv); ++ + DRM_DEBUG_DRIVER("MIPI related VBT parsing complete\n"); + return; + +@@ -1589,6 +1671,29 @@ void intel_bios_init(struct drm_i915_private *dev_priv) + } + + /** ++ * intel_bios_cleanup - Free any resources allocated by intel_bios_init() ++ * @dev_priv: i915 device instance ++ */ ++void intel_bios_cleanup(struct drm_i915_private *dev_priv) ++{ ++ kfree(dev_priv->vbt.child_dev); ++ dev_priv->vbt.child_dev = NULL; ++ dev_priv->vbt.child_dev_num = 0; ++ kfree(dev_priv->vbt.sdvo_lvds_vbt_mode); ++ dev_priv->vbt.sdvo_lvds_vbt_mode = NULL; ++ kfree(dev_priv->vbt.lfp_lvds_vbt_mode); ++ dev_priv->vbt.lfp_lvds_vbt_mode = NULL; ++ kfree(dev_priv->vbt.dsi.data); ++ dev_priv->vbt.dsi.data = NULL; ++ kfree(dev_priv->vbt.dsi.pps); ++ dev_priv->vbt.dsi.pps = NULL; ++ kfree(dev_priv->vbt.dsi.config); ++ dev_priv->vbt.dsi.config = NULL; ++ kfree(dev_priv->vbt.dsi.deassert_seq); ++ dev_priv->vbt.dsi.deassert_seq = NULL; ++} ++ ++/** + * intel_bios_is_tv_present - is integrated TV present in VBT + * @dev_priv: i915 device instance + * +diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c +index bd40fea..f54ddda 100644 +--- a/drivers/gpu/drm/i915/intel_breadcrumbs.c ++++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c +@@ -594,29 +594,16 @@ void intel_engine_remove_wait(struct intel_engine_cs *engine, + spin_unlock_irq(&b->rb_lock); + } + +-static bool signal_valid(const struct drm_i915_gem_request *request) +-{ +- return intel_wait_check_request(&request->signaling.wait, request); +-} +- + static bool signal_complete(const struct drm_i915_gem_request *request) + { + if (!request) + return false; + +- /* If another process served as the bottom-half it may have already +- * signalled that this wait is already completed. +- */ +- if (intel_wait_complete(&request->signaling.wait)) +- return signal_valid(request); +- +- /* Carefully check if the request is complete, giving time for the ++ /* ++ * Carefully check if the request is complete, giving time for the + * seqno to be visible or if the GPU hung. + */ +- if (__i915_request_irq_complete(request)) +- return true; +- +- return false; ++ return __i915_request_irq_complete(request); + } + + static struct drm_i915_gem_request *to_signaler(struct rb_node *rb) +@@ -659,9 +646,13 @@ static int intel_breadcrumbs_signaler(void *arg) + request = i915_gem_request_get_rcu(request); + rcu_read_unlock(); + if (signal_complete(request)) { +- local_bh_disable(); +- dma_fence_signal(&request->fence); +- local_bh_enable(); /* kick start the tasklets */ ++ if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, ++ &request->fence.flags)) { ++ local_bh_disable(); ++ dma_fence_signal(&request->fence); ++ GEM_BUG_ON(!i915_gem_request_completed(request)); ++ local_bh_enable(); /* kick start the tasklets */ ++ } + + spin_lock_irq(&b->rb_lock); + +diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c +index 5dc118f..1704c88 100644 +--- a/drivers/gpu/drm/i915/intel_cdclk.c ++++ b/drivers/gpu/drm/i915/intel_cdclk.c +@@ -1952,6 +1952,14 @@ int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state) + if (crtc_state->has_audio && INTEL_GEN(dev_priv) >= 9) + min_cdclk = max(2 * 96000, min_cdclk); + ++ /* ++ * On Valleyview some DSI panels lose (v|h)sync when the clock is lower ++ * than 320000KHz. ++ */ ++ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI) && ++ IS_VALLEYVIEW(dev_priv)) ++ min_cdclk = max(320000, min_cdclk); ++ + if (min_cdclk > dev_priv->max_cdclk_freq) { + DRM_DEBUG_KMS("required cdclk (%d kHz) exceeds max (%d kHz)\n", + min_cdclk, dev_priv->max_cdclk_freq); +diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c +index d790bdc..fa960cf 100644 +--- a/drivers/gpu/drm/i915/intel_engine_cs.c ++++ b/drivers/gpu/drm/i915/intel_engine_cs.c +@@ -1458,7 +1458,9 @@ static bool ring_is_idle(struct intel_engine_cs *engine) + struct drm_i915_private *dev_priv = engine->i915; + bool idle = true; + +- intel_runtime_pm_get(dev_priv); ++ /* If the whole device is asleep, the engine must be idle */ ++ if (!intel_runtime_pm_get_if_in_use(dev_priv)) ++ return true; + + /* First check that no commands are left in the ring */ + if ((I915_READ_HEAD(engine) & HEAD_ADDR) != +@@ -1943,16 +1945,22 @@ intel_engine_lookup_user(struct drm_i915_private *i915, u8 class, u8 instance) + */ + int intel_enable_engine_stats(struct intel_engine_cs *engine) + { ++ struct intel_engine_execlists *execlists = &engine->execlists; + unsigned long flags; ++ int err = 0; + + if (!intel_engine_supports_stats(engine)) + return -ENODEV; + ++ tasklet_disable(&execlists->tasklet); + spin_lock_irqsave(&engine->stats.lock, flags); +- if (engine->stats.enabled == ~0) +- goto busy; ++ ++ if (unlikely(engine->stats.enabled == ~0)) { ++ err = -EBUSY; ++ goto unlock; ++ } ++ + if (engine->stats.enabled++ == 0) { +- struct intel_engine_execlists *execlists = &engine->execlists; + const struct execlist_port *port = execlists->port; + unsigned int num_ports = execlists_num_ports(execlists); + +@@ -1967,14 +1975,12 @@ int intel_enable_engine_stats(struct intel_engine_cs *engine) + if (engine->stats.active) + engine->stats.start = engine->stats.enabled_at; + } +- spin_unlock_irqrestore(&engine->stats.lock, flags); +- +- return 0; + +-busy: ++unlock: + spin_unlock_irqrestore(&engine->stats.lock, flags); ++ tasklet_enable(&execlists->tasklet); + +- return -EBUSY; ++ return err; + } + + static ktime_t __intel_engine_get_busy_time(struct intel_engine_cs *engine) +diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c +index 7ece2f0..e0fca03 100644 +--- a/drivers/gpu/drm/i915/intel_lrc.c ++++ b/drivers/gpu/drm/i915/intel_lrc.c +@@ -719,6 +719,8 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) + struct rb_node *rb; + unsigned long flags; + ++ GEM_TRACE("%s\n", engine->name); ++ + spin_lock_irqsave(&engine->timeline->lock, flags); + + /* Cancel the requests on the HW and clear the ELSP tracker. */ +@@ -765,6 +767,9 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) + */ + clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); + ++ /* Mark all CS interrupts as complete */ ++ execlists->active = 0; ++ + spin_unlock_irqrestore(&engine->timeline->lock, flags); + } + +diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h +index c5ff203..a0e7a6c 100644 +--- a/drivers/gpu/drm/i915/intel_ringbuffer.h ++++ b/drivers/gpu/drm/i915/intel_ringbuffer.h +@@ -366,20 +366,6 @@ struct intel_engine_cs { + */ + #define I915_ENGINE_SAMPLE_MAX (I915_SAMPLE_SEMA + 1) + struct i915_pmu_sample sample[I915_ENGINE_SAMPLE_MAX]; +- /** +- * @busy_stats: Has enablement of engine stats tracking been +- * requested. +- */ +- bool busy_stats; +- /** +- * @disable_busy_stats: Work item for busy stats disabling. +- * +- * Same as with @enable_busy_stats action, with the difference +- * that we delay it in case there are rapid enable-disable +- * actions, which can happen during tool startup (like perf +- * stat). +- */ +- struct delayed_work disable_busy_stats; + } pmu; + + /* +diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c +index 5155f01..0552020 100644 +--- a/drivers/gpu/drm/meson/meson_crtc.c ++++ b/drivers/gpu/drm/meson/meson_crtc.c +@@ -36,6 +36,7 @@ + #include "meson_venc.h" + #include "meson_vpp.h" + #include "meson_viu.h" ++#include "meson_canvas.h" + #include "meson_registers.h" + + /* CRTC definition */ +@@ -192,6 +193,11 @@ void meson_crtc_irq(struct meson_drm *priv) + } else + meson_vpp_disable_interlace_vscaler_osd1(priv); + ++ meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, ++ priv->viu.osd1_addr, priv->viu.osd1_stride, ++ priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, ++ MESON_CANVAS_BLKMODE_LINEAR); ++ + /* Enable OSD1 */ + writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, + priv->io_base + _REG(VPP_MISC)); +diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h +index 5e8b392..8450d6ac 100644 +--- a/drivers/gpu/drm/meson/meson_drv.h ++++ b/drivers/gpu/drm/meson/meson_drv.h +@@ -43,6 +43,9 @@ struct meson_drm { + bool osd1_commit; + uint32_t osd1_ctrl_stat; + uint32_t osd1_blk0_cfg[5]; ++ uint32_t osd1_addr; ++ uint32_t osd1_stride; ++ uint32_t osd1_height; + } viu; + + struct { +diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c +index d0a6ac8..27bd350 100644 +--- a/drivers/gpu/drm/meson/meson_plane.c ++++ b/drivers/gpu/drm/meson/meson_plane.c +@@ -164,10 +164,9 @@ static void meson_plane_atomic_update(struct drm_plane *plane, + /* Update Canvas with buffer address */ + gem = drm_fb_cma_get_gem_obj(fb, 0); + +- meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, +- gem->paddr, fb->pitches[0], +- fb->height, MESON_CANVAS_WRAP_NONE, +- MESON_CANVAS_BLKMODE_LINEAR); ++ priv->viu.osd1_addr = gem->paddr; ++ priv->viu.osd1_stride = fb->pitches[0]; ++ priv->viu.osd1_height = fb->height; + + spin_unlock_irqrestore(&priv->drm->event_lock, flags); + } +diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +index 3e9bba4..6d8e3a9 100644 +--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c ++++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +@@ -680,7 +680,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) + } else { + dev_info(&pdev->dev, + "no iommu, fallback to phys contig buffers for scanout\n"); +- aspace = NULL;; ++ aspace = NULL; + } + + pm_runtime_put_sync(&pdev->dev); +diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c +index 69d6e61..6ed9cb0 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_connector.c ++++ b/drivers/gpu/drm/nouveau/nouveau_connector.c +@@ -570,9 +570,15 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) + nv_connector->edid = NULL; + } + +- ret = pm_runtime_get_sync(connector->dev->dev); +- if (ret < 0 && ret != -EACCES) +- return conn_status; ++ /* Outputs are only polled while runtime active, so acquiring a ++ * runtime PM ref here is unnecessary (and would deadlock upon ++ * runtime suspend because it waits for polling to finish). ++ */ ++ if (!drm_kms_helper_is_poll_worker()) { ++ ret = pm_runtime_get_sync(connector->dev->dev); ++ if (ret < 0 && ret != -EACCES) ++ return conn_status; ++ } + + nv_encoder = nouveau_connector_ddc_detect(connector); + if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) { +@@ -647,8 +653,10 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) + + out: + +- pm_runtime_mark_last_busy(connector->dev->dev); +- pm_runtime_put_autosuspend(connector->dev->dev); ++ if (!drm_kms_helper_is_poll_worker()) { ++ pm_runtime_mark_last_busy(connector->dev->dev); ++ pm_runtime_put_autosuspend(connector->dev->dev); ++ } + + return conn_status; + } +diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c +index dd8d435..caddce8 100644 +--- a/drivers/gpu/drm/nouveau/nv50_display.c ++++ b/drivers/gpu/drm/nouveau/nv50_display.c +@@ -4477,6 +4477,7 @@ nv50_display_create(struct drm_device *dev) + nouveau_display(dev)->fini = nv50_display_fini; + disp->disp = &nouveau_display(dev)->disp; + dev->mode_config.funcs = &nv50_disp_func; ++ dev->driver->driver_features |= DRIVER_PREFER_XBGR_30BPP; + if (nouveau_atomic) + dev->driver->driver_features |= DRIVER_ATOMIC; + +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c +index bf62303..3695cde 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c +@@ -301,7 +301,7 @@ nvkm_therm_attr_set(struct nvkm_therm *therm, + void + nvkm_therm_clkgate_enable(struct nvkm_therm *therm) + { +- if (!therm->func->clkgate_enable || !therm->clkgating_enabled) ++ if (!therm || !therm->func->clkgate_enable || !therm->clkgating_enabled) + return; + + nvkm_debug(&therm->subdev, +@@ -312,7 +312,7 @@ nvkm_therm_clkgate_enable(struct nvkm_therm *therm) + void + nvkm_therm_clkgate_fini(struct nvkm_therm *therm, bool suspend) + { +- if (!therm->func->clkgate_fini || !therm->clkgating_enabled) ++ if (!therm || !therm->func->clkgate_fini || !therm->clkgating_enabled) + return; + + nvkm_debug(&therm->subdev, +@@ -395,7 +395,7 @@ void + nvkm_therm_clkgate_init(struct nvkm_therm *therm, + const struct nvkm_therm_clkgate_pack *p) + { +- if (!therm->func->clkgate_init || !therm->clkgating_enabled) ++ if (!therm || !therm->func->clkgate_init || !therm->clkgating_enabled) + return; + + therm->func->clkgate_init(therm, p); +diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c +index d3045a3..7c73bc7 100644 +--- a/drivers/gpu/drm/radeon/cik.c ++++ b/drivers/gpu/drm/radeon/cik.c +@@ -3221,35 +3221,8 @@ static void cik_gpu_init(struct radeon_device *rdev) + case CHIP_KAVERI: + rdev->config.cik.max_shader_engines = 1; + rdev->config.cik.max_tile_pipes = 4; +- if ((rdev->pdev->device == 0x1304) || +- (rdev->pdev->device == 0x1305) || +- (rdev->pdev->device == 0x130C) || +- (rdev->pdev->device == 0x130F) || +- (rdev->pdev->device == 0x1310) || +- (rdev->pdev->device == 0x1311) || +- (rdev->pdev->device == 0x131C)) { +- rdev->config.cik.max_cu_per_sh = 8; +- rdev->config.cik.max_backends_per_se = 2; +- } else if ((rdev->pdev->device == 0x1309) || +- (rdev->pdev->device == 0x130A) || +- (rdev->pdev->device == 0x130D) || +- (rdev->pdev->device == 0x1313) || +- (rdev->pdev->device == 0x131D)) { +- rdev->config.cik.max_cu_per_sh = 6; +- rdev->config.cik.max_backends_per_se = 2; +- } else if ((rdev->pdev->device == 0x1306) || +- (rdev->pdev->device == 0x1307) || +- (rdev->pdev->device == 0x130B) || +- (rdev->pdev->device == 0x130E) || +- (rdev->pdev->device == 0x1315) || +- (rdev->pdev->device == 0x1318) || +- (rdev->pdev->device == 0x131B)) { +- rdev->config.cik.max_cu_per_sh = 4; +- rdev->config.cik.max_backends_per_se = 1; +- } else { +- rdev->config.cik.max_cu_per_sh = 3; +- rdev->config.cik.max_backends_per_se = 1; +- } ++ rdev->config.cik.max_cu_per_sh = 8; ++ rdev->config.cik.max_backends_per_se = 2; + rdev->config.cik.max_sh_per_se = 1; + rdev->config.cik.max_texture_channel_caches = 4; + rdev->config.cik.max_gprs = 256; +diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c +index 5012f5e..2e2ca3c 100644 +--- a/drivers/gpu/drm/radeon/radeon_connectors.c ++++ b/drivers/gpu/drm/radeon/radeon_connectors.c +@@ -899,9 +899,11 @@ radeon_lvds_detect(struct drm_connector *connector, bool force) + enum drm_connector_status ret = connector_status_disconnected; + int r; + +- r = pm_runtime_get_sync(connector->dev->dev); +- if (r < 0) +- return connector_status_disconnected; ++ if (!drm_kms_helper_is_poll_worker()) { ++ r = pm_runtime_get_sync(connector->dev->dev); ++ if (r < 0) ++ return connector_status_disconnected; ++ } + + if (encoder) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); +@@ -924,8 +926,12 @@ radeon_lvds_detect(struct drm_connector *connector, bool force) + /* check acpi lid status ??? */ + + radeon_connector_update_scratch_regs(connector, ret); +- pm_runtime_mark_last_busy(connector->dev->dev); +- pm_runtime_put_autosuspend(connector->dev->dev); ++ ++ if (!drm_kms_helper_is_poll_worker()) { ++ pm_runtime_mark_last_busy(connector->dev->dev); ++ pm_runtime_put_autosuspend(connector->dev->dev); ++ } ++ + return ret; + } + +@@ -1039,9 +1045,11 @@ radeon_vga_detect(struct drm_connector *connector, bool force) + enum drm_connector_status ret = connector_status_disconnected; + int r; + +- r = pm_runtime_get_sync(connector->dev->dev); +- if (r < 0) +- return connector_status_disconnected; ++ if (!drm_kms_helper_is_poll_worker()) { ++ r = pm_runtime_get_sync(connector->dev->dev); ++ if (r < 0) ++ return connector_status_disconnected; ++ } + + encoder = radeon_best_single_encoder(connector); + if (!encoder) +@@ -1108,8 +1116,10 @@ radeon_vga_detect(struct drm_connector *connector, bool force) + radeon_connector_update_scratch_regs(connector, ret); + + out: +- pm_runtime_mark_last_busy(connector->dev->dev); +- pm_runtime_put_autosuspend(connector->dev->dev); ++ if (!drm_kms_helper_is_poll_worker()) { ++ pm_runtime_mark_last_busy(connector->dev->dev); ++ pm_runtime_put_autosuspend(connector->dev->dev); ++ } + + return ret; + } +@@ -1173,9 +1183,11 @@ radeon_tv_detect(struct drm_connector *connector, bool force) + if (!radeon_connector->dac_load_detect) + return ret; + +- r = pm_runtime_get_sync(connector->dev->dev); +- if (r < 0) +- return connector_status_disconnected; ++ if (!drm_kms_helper_is_poll_worker()) { ++ r = pm_runtime_get_sync(connector->dev->dev); ++ if (r < 0) ++ return connector_status_disconnected; ++ } + + encoder = radeon_best_single_encoder(connector); + if (!encoder) +@@ -1187,8 +1199,12 @@ radeon_tv_detect(struct drm_connector *connector, bool force) + if (ret == connector_status_connected) + ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false); + radeon_connector_update_scratch_regs(connector, ret); +- pm_runtime_mark_last_busy(connector->dev->dev); +- pm_runtime_put_autosuspend(connector->dev->dev); ++ ++ if (!drm_kms_helper_is_poll_worker()) { ++ pm_runtime_mark_last_busy(connector->dev->dev); ++ pm_runtime_put_autosuspend(connector->dev->dev); ++ } ++ + return ret; + } + +@@ -1251,9 +1267,11 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) + enum drm_connector_status ret = connector_status_disconnected; + bool dret = false, broken_edid = false; + +- r = pm_runtime_get_sync(connector->dev->dev); +- if (r < 0) +- return connector_status_disconnected; ++ if (!drm_kms_helper_is_poll_worker()) { ++ r = pm_runtime_get_sync(connector->dev->dev); ++ if (r < 0) ++ return connector_status_disconnected; ++ } + + if (radeon_connector->detected_hpd_without_ddc) { + force = true; +@@ -1436,8 +1454,10 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) + } + + exit: +- pm_runtime_mark_last_busy(connector->dev->dev); +- pm_runtime_put_autosuspend(connector->dev->dev); ++ if (!drm_kms_helper_is_poll_worker()) { ++ pm_runtime_mark_last_busy(connector->dev->dev); ++ pm_runtime_put_autosuspend(connector->dev->dev); ++ } + + return ret; + } +@@ -1688,9 +1708,11 @@ radeon_dp_detect(struct drm_connector *connector, bool force) + if (radeon_dig_connector->is_mst) + return connector_status_disconnected; + +- r = pm_runtime_get_sync(connector->dev->dev); +- if (r < 0) +- return connector_status_disconnected; ++ if (!drm_kms_helper_is_poll_worker()) { ++ r = pm_runtime_get_sync(connector->dev->dev); ++ if (r < 0) ++ return connector_status_disconnected; ++ } + + if (!force && radeon_check_hpd_status_unchanged(connector)) { + ret = connector->status; +@@ -1777,8 +1799,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force) + } + + out: +- pm_runtime_mark_last_busy(connector->dev->dev); +- pm_runtime_put_autosuspend(connector->dev->dev); ++ if (!drm_kms_helper_is_poll_worker()) { ++ pm_runtime_mark_last_busy(connector->dev->dev); ++ pm_runtime_put_autosuspend(connector->dev->dev); ++ } + + return ret; + } +diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c +index 8d3e3d2..7828a5e 100644 +--- a/drivers/gpu/drm/radeon/radeon_device.c ++++ b/drivers/gpu/drm/radeon/radeon_device.c +@@ -1365,6 +1365,10 @@ int radeon_device_init(struct radeon_device *rdev, + if ((rdev->flags & RADEON_IS_PCI) && + (rdev->family <= CHIP_RS740)) + rdev->need_dma32 = true; ++#ifdef CONFIG_PPC64 ++ if (rdev->family == CHIP_CEDAR) ++ rdev->need_dma32 = true; ++#endif + + dma_bits = rdev->need_dma32 ? 32 : 40; + r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits)); +diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c +index 326ad06..4b65425 100644 +--- a/drivers/gpu/drm/radeon/radeon_pm.c ++++ b/drivers/gpu/drm/radeon/radeon_pm.c +@@ -47,7 +47,6 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev); + static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); + static void radeon_pm_update_profile(struct radeon_device *rdev); + static void radeon_pm_set_clocks(struct radeon_device *rdev); +-static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev); + + int radeon_pm_get_type_index(struct radeon_device *rdev, + enum radeon_pm_state_type ps_type, +@@ -80,8 +79,6 @@ void radeon_pm_acpi_event_handler(struct radeon_device *rdev) + radeon_dpm_enable_bapm(rdev, rdev->pm.dpm.ac_power); + } + mutex_unlock(&rdev->pm.mutex); +- /* allow new DPM state to be picked */ +- radeon_pm_compute_clocks_dpm(rdev); + } else if (rdev->pm.pm_method == PM_METHOD_PROFILE) { + if (rdev->pm.profile == PM_PROFILE_AUTO) { + mutex_lock(&rdev->pm.mutex); +@@ -885,8 +882,7 @@ static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev, + dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF; + /* balanced states don't exist at the moment */ + if (dpm_state == POWER_STATE_TYPE_BALANCED) +- dpm_state = rdev->pm.dpm.ac_power ? +- POWER_STATE_TYPE_PERFORMANCE : POWER_STATE_TYPE_BATTERY; ++ dpm_state = POWER_STATE_TYPE_PERFORMANCE; + + restart_search: + /* Pick the best power state based on current conditions */ +diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c +index 2c18996..0d95888 100644 +--- a/drivers/gpu/drm/scheduler/gpu_scheduler.c ++++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c +@@ -461,7 +461,7 @@ void drm_sched_hw_job_reset(struct drm_gpu_scheduler *sched, struct drm_sched_jo + { + struct drm_sched_job *s_job; + struct drm_sched_entity *entity, *tmp; +- int i;; ++ int i; + + spin_lock(&sched->job_list_lock); + list_for_each_entry_reverse(s_job, &sched->ring_mirror_list, node) { +diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c +index 5decae0..78cbc31 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c ++++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c +@@ -93,6 +93,8 @@ static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc, + + DRM_DEBUG_DRIVER("Disabling the CRTC\n"); + ++ drm_crtc_vblank_off(crtc); ++ + sun4i_tcon_set_status(scrtc->tcon, encoder, false); + + if (crtc->state->event && !crtc->state->active) { +@@ -113,6 +115,8 @@ static void sun4i_crtc_atomic_enable(struct drm_crtc *crtc, + DRM_DEBUG_DRIVER("Enabling the CRTC\n"); + + sun4i_tcon_set_status(scrtc->tcon, encoder, true); ++ ++ drm_crtc_vblank_on(crtc); + } + + static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc) +diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c +index 023f39b..e36004f 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c ++++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c +@@ -132,10 +132,13 @@ static int sun4i_dclk_get_phase(struct clk_hw *hw) + static int sun4i_dclk_set_phase(struct clk_hw *hw, int degrees) + { + struct sun4i_dclk *dclk = hw_to_dclk(hw); ++ u32 val = degrees / 120; ++ ++ val <<= 28; + + regmap_update_bits(dclk->regmap, SUN4I_TCON0_IO_POL_REG, + GENMASK(29, 28), +- degrees / 120); ++ val); + + return 0; + } +diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c +index 832f8f9..b8da5a5 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c ++++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c +@@ -92,6 +92,8 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector, + + DRM_DEBUG_DRIVER("Vertical parameters OK\n"); + ++ tcon->dclk_min_div = 6; ++ tcon->dclk_max_div = 127; + rounded_rate = clk_round_rate(tcon->dclk, rate); + if (rounded_rate < rate) + return MODE_CLOCK_LOW; +diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c +index 3c15cf2..2de586b 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c ++++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c +@@ -101,10 +101,12 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel, + return; + } + +- if (enabled) ++ if (enabled) { + clk_prepare_enable(clk); +- else ++ } else { ++ clk_rate_exclusive_put(clk); + clk_disable_unprepare(clk); ++ } + } + + static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon, +@@ -260,7 +262,7 @@ static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon, + const struct drm_display_mode *mode) + { + /* Configure the dot clock */ +- clk_set_rate(tcon->dclk, mode->crtc_clock * 1000); ++ clk_set_rate_exclusive(tcon->dclk, mode->crtc_clock * 1000); + + /* Set the resolution */ + regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG, +@@ -335,6 +337,9 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon, + regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, + SUN4I_TCON_GCTL_IOMAP_MASK, + SUN4I_TCON_GCTL_IOMAP_TCON0); ++ ++ /* Enable the output on the pins */ ++ regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0xe0000000); + } + + static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, +@@ -418,7 +423,7 @@ static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon, + WARN_ON(!tcon->quirks->has_channel_1); + + /* Configure the dot clock */ +- clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000); ++ clk_set_rate_exclusive(tcon->sclk1, mode->crtc_clock * 1000); + + /* Adjust clock delay */ + clk_delay = sun4i_tcon_get_clk_delay(mode, 1); +@@ -870,52 +875,56 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, + return ret; + } + +- /* +- * This can only be made optional since we've had DT nodes +- * without the LVDS reset properties. +- * +- * If the property is missing, just disable LVDS, and print a +- * warning. +- */ +- tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds"); +- if (IS_ERR(tcon->lvds_rst)) { +- dev_err(dev, "Couldn't get our reset line\n"); +- return PTR_ERR(tcon->lvds_rst); +- } else if (tcon->lvds_rst) { +- has_lvds_rst = true; +- reset_control_reset(tcon->lvds_rst); +- } else { +- has_lvds_rst = false; +- } ++ if (tcon->quirks->supports_lvds) { ++ /* ++ * This can only be made optional since we've had DT ++ * nodes without the LVDS reset properties. ++ * ++ * If the property is missing, just disable LVDS, and ++ * print a warning. ++ */ ++ tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds"); ++ if (IS_ERR(tcon->lvds_rst)) { ++ dev_err(dev, "Couldn't get our reset line\n"); ++ return PTR_ERR(tcon->lvds_rst); ++ } else if (tcon->lvds_rst) { ++ has_lvds_rst = true; ++ reset_control_reset(tcon->lvds_rst); ++ } else { ++ has_lvds_rst = false; ++ } + +- /* +- * This can only be made optional since we've had DT nodes +- * without the LVDS reset properties. +- * +- * If the property is missing, just disable LVDS, and print a +- * warning. +- */ +- if (tcon->quirks->has_lvds_alt) { +- tcon->lvds_pll = devm_clk_get(dev, "lvds-alt"); +- if (IS_ERR(tcon->lvds_pll)) { +- if (PTR_ERR(tcon->lvds_pll) == -ENOENT) { +- has_lvds_alt = false; ++ /* ++ * This can only be made optional since we've had DT ++ * nodes without the LVDS reset properties. ++ * ++ * If the property is missing, just disable LVDS, and ++ * print a warning. ++ */ ++ if (tcon->quirks->has_lvds_alt) { ++ tcon->lvds_pll = devm_clk_get(dev, "lvds-alt"); ++ if (IS_ERR(tcon->lvds_pll)) { ++ if (PTR_ERR(tcon->lvds_pll) == -ENOENT) { ++ has_lvds_alt = false; ++ } else { ++ dev_err(dev, "Couldn't get the LVDS PLL\n"); ++ return PTR_ERR(tcon->lvds_pll); ++ } + } else { +- dev_err(dev, "Couldn't get the LVDS PLL\n"); +- return PTR_ERR(tcon->lvds_pll); ++ has_lvds_alt = true; + } +- } else { +- has_lvds_alt = true; + } +- } + +- if (!has_lvds_rst || (tcon->quirks->has_lvds_alt && !has_lvds_alt)) { +- dev_warn(dev, +- "Missing LVDS properties, Please upgrade your DT\n"); +- dev_warn(dev, "LVDS output disabled\n"); +- can_lvds = false; ++ if (!has_lvds_rst || ++ (tcon->quirks->has_lvds_alt && !has_lvds_alt)) { ++ dev_warn(dev, "Missing LVDS properties, Please upgrade your DT\n"); ++ dev_warn(dev, "LVDS output disabled\n"); ++ can_lvds = false; ++ } else { ++ can_lvds = true; ++ } + } else { +- can_lvds = true; ++ can_lvds = false; + } + + ret = sun4i_tcon_init_clocks(dev, tcon); +@@ -1134,7 +1143,7 @@ static const struct sun4i_tcon_quirks sun8i_a33_quirks = { + }; + + static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = { +- /* nothing is supported */ ++ .supports_lvds = true, + }; + + static const struct sun4i_tcon_quirks sun8i_v3s_quirks = { +diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h +index b761c7b..278700c 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h ++++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h +@@ -175,6 +175,7 @@ struct sun4i_tcon_quirks { + bool has_channel_1; /* a33 does not have channel 1 */ + bool has_lvds_alt; /* Does the LVDS clock have a parent other than the TCON clock? */ + bool needs_de_be_mux; /* sun6i needs mux to select backend */ ++ bool supports_lvds; /* Does the TCON support an LVDS output? */ + + /* callback to handle tcon muxing options */ + int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *); +diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c +index 5720a0d..677ac16 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c ++++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c +@@ -197,6 +197,9 @@ static int virtio_gpu_getparam_ioctl(struct drm_device *dev, void *data, + case VIRTGPU_PARAM_3D_FEATURES: + value = vgdev->has_virgl_3d == true ? 1 : 0; + break; ++ case VIRTGPU_PARAM_CAPSET_QUERY_FIX: ++ value = 1; ++ break; + default: + return -EINVAL; + } +@@ -472,7 +475,7 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, + { + struct virtio_gpu_device *vgdev = dev->dev_private; + struct drm_virtgpu_get_caps *args = data; +- int size; ++ unsigned size, host_caps_size; + int i; + int found_valid = -1; + int ret; +@@ -481,6 +484,10 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, + if (vgdev->num_capsets == 0) + return -ENOSYS; + ++ /* don't allow userspace to pass 0 */ ++ if (args->size == 0) ++ return -EINVAL; ++ + spin_lock(&vgdev->display_info_lock); + for (i = 0; i < vgdev->num_capsets; i++) { + if (vgdev->capsets[i].id == args->cap_set_id) { +@@ -496,11 +503,9 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev, + return -EINVAL; + } + +- size = vgdev->capsets[found_valid].max_size; +- if (args->size > size) { +- spin_unlock(&vgdev->display_info_lock); +- return -EINVAL; +- } ++ host_caps_size = vgdev->capsets[found_valid].max_size; ++ /* only copy to user the minimum of the host caps size or the guest caps size */ ++ size = min(args->size, host_caps_size); + + list_for_each_entry(cache_ent, &vgdev->cap_cache, head) { + if (cache_ent->id == args->cap_set_id && +diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c +index 658fa2d..48685cd 100644 +--- a/drivers/gpu/ipu-v3/ipu-common.c ++++ b/drivers/gpu/ipu-v3/ipu-common.c +@@ -1089,7 +1089,7 @@ static void ipu_irq_handler(struct irq_desc *desc) + { + struct ipu_soc *ipu = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); +- const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14}; ++ static const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14}; + + chained_irq_enter(chip, desc); + +@@ -1102,7 +1102,7 @@ static void ipu_err_irq_handler(struct irq_desc *desc) + { + struct ipu_soc *ipu = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); +- const int int_reg[] = { 4, 5, 8, 9}; ++ static const int int_reg[] = { 4, 5, 8, 9}; + + chained_irq_enter(chip, desc); + +diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c +index bb9c087..9f2d9ec 100644 +--- a/drivers/gpu/ipu-v3/ipu-cpmem.c ++++ b/drivers/gpu/ipu-v3/ipu-cpmem.c +@@ -788,12 +788,14 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: ++ case V4L2_PIX_FMT_GREY: + offset = image->rect.left + image->rect.top * pix->bytesperline; + break; + case V4L2_PIX_FMT_SBGGR16: + case V4L2_PIX_FMT_SGBRG16: + case V4L2_PIX_FMT_SGRBG16: + case V4L2_PIX_FMT_SRGGB16: ++ case V4L2_PIX_FMT_Y16: + offset = image->rect.left * 2 + + image->rect.top * pix->bytesperline; + break; +diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c +index 24e12b8..caa05b0 100644 +--- a/drivers/gpu/ipu-v3/ipu-csi.c ++++ b/drivers/gpu/ipu-v3/ipu-csi.c +@@ -288,6 +288,7 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code) + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: ++ case MEDIA_BUS_FMT_Y10_1X10: + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; + cfg->mipi_dt = MIPI_DT_RAW10; + cfg->data_width = IPU_CSI_DATA_WIDTH_10; +@@ -296,6 +297,7 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code) + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: ++ case MEDIA_BUS_FMT_Y12_1X12: + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; + cfg->mipi_dt = MIPI_DT_RAW12; + cfg->data_width = IPU_CSI_DATA_WIDTH_12; +diff --git a/drivers/gpu/ipu-v3/ipu-pre.c b/drivers/gpu/ipu-v3/ipu-pre.c +index f1cec3d..0f70e88 100644 +--- a/drivers/gpu/ipu-v3/ipu-pre.c ++++ b/drivers/gpu/ipu-v3/ipu-pre.c +@@ -129,11 +129,14 @@ ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index) + if (pre_node == pre->dev->of_node) { + mutex_unlock(&ipu_pre_list_mutex); + device_link_add(dev, pre->dev, DL_FLAG_AUTOREMOVE); ++ of_node_put(pre_node); + return pre; + } + } + mutex_unlock(&ipu_pre_list_mutex); + ++ of_node_put(pre_node); ++ + return NULL; + } + +diff --git a/drivers/gpu/ipu-v3/ipu-prg.c b/drivers/gpu/ipu-v3/ipu-prg.c +index 067365c..97b9950 100644 +--- a/drivers/gpu/ipu-v3/ipu-prg.c ++++ b/drivers/gpu/ipu-v3/ipu-prg.c +@@ -102,11 +102,14 @@ ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id) + mutex_unlock(&ipu_prg_list_mutex); + device_link_add(dev, prg->dev, DL_FLAG_AUTOREMOVE); + prg->id = ipu_id; ++ of_node_put(prg_node); + return prg; + } + } + mutex_unlock(&ipu_prg_list_mutex); + ++ of_node_put(prg_node); ++ + return NULL; + } + +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index 43ddcdf..9454ac1 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -645,6 +645,9 @@ + #define USB_DEVICE_ID_LD_MICROCASSYTIME 0x1033 + #define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE 0x1035 + #define USB_DEVICE_ID_LD_MICROCASSYPH 0x1038 ++#define USB_DEVICE_ID_LD_POWERANALYSERCASSY 0x1040 ++#define USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY 0x1042 ++#define USB_DEVICE_ID_LD_MACHINETESTCASSY 0x1043 + #define USB_DEVICE_ID_LD_JWM 0x1080 + #define USB_DEVICE_ID_LD_DMMP 0x1081 + #define USB_DEVICE_ID_LD_UMIP 0x1090 +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index 5f6035a..e92b77f 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -809,6 +809,9 @@ static const struct hid_device_id hid_ignore_list[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERANALYSERCASSY) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETESTCASSY) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) }, +diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c +index 4bdbf77..72c338e 100644 +--- a/drivers/hwmon/coretemp.c ++++ b/drivers/hwmon/coretemp.c +@@ -269,13 +269,13 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) + for (i = 0; i < ARRAY_SIZE(tjmax_model_table); i++) { + const struct tjmax_model *tm = &tjmax_model_table[i]; + if (c->x86_model == tm->model && +- (tm->mask == ANY || c->x86_mask == tm->mask)) ++ (tm->mask == ANY || c->x86_stepping == tm->mask)) + return tm->tjmax; + } + + /* Early chips have no MSR for TjMax */ + +- if (c->x86_model == 0xf && c->x86_mask < 4) ++ if (c->x86_model == 0xf && c->x86_stepping < 4) + usemsr_ee = 0; + + if (c->x86_model > 0xe && usemsr_ee) { +@@ -426,7 +426,7 @@ static int chk_ucode_version(unsigned int cpu) + * Readings might stop update when processor visited too deep sleep, + * fixed for stepping D0 (6EC). + */ +- if (c->x86_model == 0xe && c->x86_mask < 0xc && c->microcode < 0x39) { ++ if (c->x86_model == 0xe && c->x86_stepping < 0xc && c->microcode < 0x39) { + pr_err("Errata AE18 not fixed, update BIOS or microcode of the CPU!\n"); + return -ENODEV; + } +diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c +index ef91b8a..84e9128 100644 +--- a/drivers/hwmon/hwmon-vid.c ++++ b/drivers/hwmon/hwmon-vid.c +@@ -293,7 +293,7 @@ u8 vid_which_vrm(void) + if (c->x86 < 6) /* Any CPU with family lower than 6 */ + return 0; /* doesn't have VID */ + +- vrm_ret = find_vrm(c->x86, c->x86_model, c->x86_mask, c->x86_vendor); ++ vrm_ret = find_vrm(c->x86, c->x86_model, c->x86_stepping, c->x86_vendor); + if (vrm_ret == 134) + vrm_ret = get_via_model_d_vrm(); + if (vrm_ret == 0) +diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c +index 06b4e1c..051a72e 100644 +--- a/drivers/hwmon/k10temp.c ++++ b/drivers/hwmon/k10temp.c +@@ -129,7 +129,10 @@ static ssize_t temp1_input_show(struct device *dev, + + data->read_tempreg(data->pdev, ®val); + temp = (regval >> 21) * 125; +- temp -= data->temp_offset; ++ if (temp > data->temp_offset) ++ temp -= data->temp_offset; ++ else ++ temp = 0; + + return sprintf(buf, "%u\n", temp); + } +@@ -227,7 +230,7 @@ static bool has_erratum_319(struct pci_dev *pdev) + * and AM3 formats, but that's the best we can do. + */ + return boot_cpu_data.x86_model < 4 || +- (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_mask <= 2); ++ (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_stepping <= 2); + } + + static int k10temp_probe(struct pci_dev *pdev, +diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c +index 5a632bc..e59f911 100644 +--- a/drivers/hwmon/k8temp.c ++++ b/drivers/hwmon/k8temp.c +@@ -187,7 +187,7 @@ static int k8temp_probe(struct pci_dev *pdev, + return -ENOMEM; + + model = boot_cpu_data.x86_model; +- stepping = boot_cpu_data.x86_mask; ++ stepping = boot_cpu_data.x86_stepping; + + /* feature available since SH-C0, exclude older revisions */ + if ((model == 4 && stepping == 0) || +diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +index a9805c7..e2954fb 100644 +--- a/drivers/i2c/busses/Kconfig ++++ b/drivers/i2c/busses/Kconfig +@@ -123,8 +123,10 @@ config I2C_I801 + Wildcat Point (PCH) + Wildcat Point-LP (PCH) + BayTrail (SOC) ++ Braswell (SOC) + Sunrise Point-H (PCH) + Sunrise Point-LP (PCH) ++ Kaby Lake-H (PCH) + DNV (SOC) + Broxton (SOC) + Lewisburg (PCH) +diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c +index cd07a69..44deae7 100644 +--- a/drivers/i2c/busses/i2c-bcm2835.c ++++ b/drivers/i2c/busses/i2c-bcm2835.c +@@ -50,6 +50,9 @@ + #define BCM2835_I2C_S_CLKT BIT(9) + #define BCM2835_I2C_S_LEN BIT(10) /* Fake bit for SW error reporting */ + ++#define BCM2835_I2C_FEDL_SHIFT 16 ++#define BCM2835_I2C_REDL_SHIFT 0 ++ + #define BCM2835_I2C_CDIV_MIN 0x0002 + #define BCM2835_I2C_CDIV_MAX 0xFFFE + +@@ -81,7 +84,7 @@ static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg) + + static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev) + { +- u32 divider; ++ u32 divider, redl, fedl; + + divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk), + i2c_dev->bus_clk_rate); +@@ -100,6 +103,22 @@ static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev) + + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider); + ++ /* ++ * Number of core clocks to wait after falling edge before ++ * outputting the next data bit. Note that both FEDL and REDL ++ * can't be greater than CDIV/2. ++ */ ++ fedl = max(divider / 16, 1u); ++ ++ /* ++ * Number of core clocks to wait after rising edge before ++ * sampling the next incoming data bit. ++ */ ++ redl = max(divider / 4, 1u); ++ ++ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DEL, ++ (fedl << BCM2835_I2C_FEDL_SHIFT) | ++ (redl << BCM2835_I2C_REDL_SHIFT)); + return 0; + } + +diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c +index ae69188..0573253 100644 +--- a/drivers/i2c/busses/i2c-designware-master.c ++++ b/drivers/i2c/busses/i2c-designware-master.c +@@ -209,7 +209,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) + i2c_dw_disable_int(dev); + + /* Enable the adapter */ +- __i2c_dw_enable(dev, true); ++ __i2c_dw_enable_and_wait(dev, true); + + /* Clear and enable interrupts */ + dw_readl(dev, DW_IC_CLR_INTR); +@@ -644,7 +644,7 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev) + gpio = devm_gpiod_get(dev->dev, "scl", GPIOD_OUT_HIGH); + if (IS_ERR(gpio)) { + r = PTR_ERR(gpio); +- if (r == -ENOENT) ++ if (r == -ENOENT || r == -ENOSYS) + return 0; + return r; + } +diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c +index 8eac00e..692b341 100644 +--- a/drivers/i2c/busses/i2c-i801.c ++++ b/drivers/i2c/busses/i2c-i801.c +@@ -58,6 +58,7 @@ + * Wildcat Point (PCH) 0x8ca2 32 hard yes yes yes + * Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes + * BayTrail (SOC) 0x0f12 32 hard yes yes yes ++ * Braswell (SOC) 0x2292 32 hard yes yes yes + * Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes + * Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes + * DNV (SOC) 0x19df 32 hard yes yes yes +diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c +index 1d8775799..d960790 100644 +--- a/drivers/i2c/busses/i2c-octeon-core.c ++++ b/drivers/i2c/busses/i2c-octeon-core.c +@@ -233,6 +233,7 @@ static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read) + return -EOPNOTSUPP; + + case STAT_TXDATA_NAK: ++ case STAT_BUS_ERROR: + return -EIO; + case STAT_TXADDR_NAK: + case STAT_RXADDR_NAK: +diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h +index a7ef198..9bb9f64 100644 +--- a/drivers/i2c/busses/i2c-octeon-core.h ++++ b/drivers/i2c/busses/i2c-octeon-core.h +@@ -43,7 +43,7 @@ + #define TWSI_CTL_AAK 0x04 /* Assert ACK */ + + /* Status values */ +-#define STAT_ERROR 0x00 ++#define STAT_BUS_ERROR 0x00 + #define STAT_START 0x08 + #define STAT_REP_START 0x10 + #define STAT_TXADDR_ACK 0x18 +diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c +index 2fd8b6d..87197ec 100644 +--- a/drivers/i2c/busses/i2c-sirf.c ++++ b/drivers/i2c/busses/i2c-sirf.c +@@ -341,7 +341,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev) + platform_set_drvdata(pdev, adap); + init_completion(&siic->done); + +- /* Controller Initalisation */ ++ /* Controller initialisation */ + + writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL); + while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET) +@@ -369,7 +369,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev) + * but they start to affect the speed when clock is set to faster + * frequencies. + * Through the actual tests, use the different user_div value(which +- * in the divider formular 'Fio / (Fi2c * user_div)') to adapt ++ * in the divider formula 'Fio / (Fi2c * user_div)') to adapt + * the different ranges of i2c bus clock frequency, to make the SCL + * more accurate. + */ +diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c +index 17fd55a..caa20eb 100644 +--- a/drivers/ide/ide-probe.c ++++ b/drivers/ide/ide-probe.c +@@ -928,7 +928,7 @@ static int exact_lock(dev_t dev, void *data) + { + struct gendisk *p = data; + +- if (!get_disk(p)) ++ if (!get_disk_and_module(p)) + return -1; + return 0; + } +diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c +index 327a49b..9515ca1 100644 +--- a/drivers/iio/adc/aspeed_adc.c ++++ b/drivers/iio/adc/aspeed_adc.c +@@ -243,7 +243,7 @@ static int aspeed_adc_probe(struct platform_device *pdev) + ASPEED_ADC_INIT_POLLING_TIME, + ASPEED_ADC_INIT_TIMEOUT); + if (ret) +- goto scaler_error; ++ goto poll_timeout_error; + } + + /* Start all channels in normal mode. */ +@@ -274,9 +274,10 @@ static int aspeed_adc_probe(struct platform_device *pdev) + writel(ASPEED_OPERATION_MODE_POWER_DOWN, + data->base + ASPEED_REG_ENGINE_CONTROL); + clk_disable_unprepare(data->clk_scaler->clk); +-reset_error: +- reset_control_assert(data->rst); + clk_enable_error: ++poll_timeout_error: ++ reset_control_assert(data->rst); ++reset_error: + clk_hw_unregister_divider(data->clk_scaler); + scaler_error: + clk_hw_unregister_divider(data->clk_prescaler); +diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c +index 7f5def4..9a2583ca 100644 +--- a/drivers/iio/adc/stm32-adc.c ++++ b/drivers/iio/adc/stm32-adc.c +@@ -722,8 +722,6 @@ static int stm32h7_adc_enable(struct stm32_adc *adc) + int ret; + u32 val; + +- /* Clear ADRDY by writing one, then enable ADC */ +- stm32_adc_set_bits(adc, STM32H7_ADC_ISR, STM32H7_ADRDY); + stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADEN); + + /* Poll for ADRDY to be set (after adc startup time) */ +@@ -731,8 +729,11 @@ static int stm32h7_adc_enable(struct stm32_adc *adc) + val & STM32H7_ADRDY, + 100, STM32_ADC_TIMEOUT_US); + if (ret) { +- stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_ADEN); ++ stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADDIS); + dev_err(&indio_dev->dev, "Failed to enable ADC\n"); ++ } else { ++ /* Clear ADRDY by writing one */ ++ stm32_adc_set_bits(adc, STM32H7_ADC_ISR, STM32H7_ADRDY); + } + + return ret; +diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c +index 0dd5a38..457372f 100644 +--- a/drivers/iio/imu/adis_trigger.c ++++ b/drivers/iio/imu/adis_trigger.c +@@ -46,6 +46,10 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) + if (adis->trig == NULL) + return -ENOMEM; + ++ adis->trig->dev.parent = &adis->spi->dev; ++ adis->trig->ops = &adis_trigger_ops; ++ iio_trigger_set_drvdata(adis->trig, adis); ++ + ret = request_irq(adis->spi->irq, + &iio_trigger_generic_data_rdy_poll, + IRQF_TRIGGER_RISING, +@@ -54,9 +58,6 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) + if (ret) + goto error_free_trig; + +- adis->trig->dev.parent = &adis->spi->dev; +- adis->trig->ops = &adis_trigger_ops; +- iio_trigger_set_drvdata(adis->trig, adis); + ret = iio_trigger_register(adis->trig); + + indio_dev->trig = iio_trigger_get(adis->trig); +diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c +index 79abf70..cd5bfe3 100644 +--- a/drivers/iio/industrialio-buffer.c ++++ b/drivers/iio/industrialio-buffer.c +@@ -175,7 +175,7 @@ __poll_t iio_buffer_poll(struct file *filp, + struct iio_dev *indio_dev = filp->private_data; + struct iio_buffer *rb = indio_dev->buffer; + +- if (!indio_dev->info) ++ if (!indio_dev->info || rb == NULL) + return 0; + + poll_wait(filp, &rb->pollq, wait); +diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig +index fcb1c4b..f726f94 100644 +--- a/drivers/iio/proximity/Kconfig ++++ b/drivers/iio/proximity/Kconfig +@@ -68,6 +68,8 @@ config SX9500 + + config SRF08 + tristate "Devantech SRF02/SRF08/SRF10 ultrasonic ranger sensor" ++ select IIO_BUFFER ++ select IIO_TRIGGERED_BUFFER + depends on I2C + help + Say Y here to build a driver for Devantech SRF02/SRF08/SRF10 +diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c +index a5b4cf0..9183d148d 100644 +--- a/drivers/infiniband/core/addr.c ++++ b/drivers/infiniband/core/addr.c +@@ -550,18 +550,13 @@ static int addr_resolve(struct sockaddr *src_in, + dst_release(dst); + } + +- if (ndev->flags & IFF_LOOPBACK) { +- ret = rdma_translate_ip(dst_in, addr); +- /* +- * Put the loopback device and get the translated +- * device instead. +- */ ++ if (ndev) { ++ if (ndev->flags & IFF_LOOPBACK) ++ ret = rdma_translate_ip(dst_in, addr); ++ else ++ addr->bound_dev_if = ndev->ifindex; + dev_put(ndev); +- ndev = dev_get_by_index(addr->net, addr->bound_dev_if); +- } else { +- addr->bound_dev_if = ndev->ifindex; + } +- dev_put(ndev); + + return ret; + } +diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h +index c4560d8..25bb178 100644 +--- a/drivers/infiniband/core/core_priv.h ++++ b/drivers/infiniband/core/core_priv.h +@@ -305,16 +305,21 @@ void nldev_exit(void); + static inline struct ib_qp *_ib_create_qp(struct ib_device *dev, + struct ib_pd *pd, + struct ib_qp_init_attr *attr, +- struct ib_udata *udata) ++ struct ib_udata *udata, ++ struct ib_uobject *uobj) + { + struct ib_qp *qp; + ++ if (!dev->create_qp) ++ return ERR_PTR(-EOPNOTSUPP); ++ + qp = dev->create_qp(pd, attr, udata); + if (IS_ERR(qp)) + return qp; + + qp->device = dev; + qp->pd = pd; ++ qp->uobject = uobj; + /* + * We don't track XRC QPs for now, because they don't have PD + * and more importantly they are created internaly by driver, +diff --git a/drivers/infiniband/core/cq.c b/drivers/infiniband/core/cq.c +index bc79ca8..af5ad6a 100644 +--- a/drivers/infiniband/core/cq.c ++++ b/drivers/infiniband/core/cq.c +@@ -17,6 +17,7 @@ + + /* # of WCs to poll for with a single call to ib_poll_cq */ + #define IB_POLL_BATCH 16 ++#define IB_POLL_BATCH_DIRECT 8 + + /* # of WCs to iterate over before yielding */ + #define IB_POLL_BUDGET_IRQ 256 +@@ -25,18 +26,18 @@ + #define IB_POLL_FLAGS \ + (IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS) + +-static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) ++static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *wcs, ++ int batch) + { + int i, n, completed = 0; +- struct ib_wc *wcs = poll_wc ? : cq->wc; + + /* + * budget might be (-1) if the caller does not + * want to bound this call, thus we need unsigned + * minimum here. + */ +- while ((n = ib_poll_cq(cq, min_t(u32, IB_POLL_BATCH, +- budget - completed), wcs)) > 0) { ++ while ((n = ib_poll_cq(cq, min_t(u32, batch, ++ budget - completed), wcs)) > 0) { + for (i = 0; i < n; i++) { + struct ib_wc *wc = &wcs[i]; + +@@ -48,8 +49,7 @@ static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) + + completed += n; + +- if (n != IB_POLL_BATCH || +- (budget != -1 && completed >= budget)) ++ if (n != batch || (budget != -1 && completed >= budget)) + break; + } + +@@ -72,9 +72,9 @@ static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) + */ + int ib_process_cq_direct(struct ib_cq *cq, int budget) + { +- struct ib_wc wcs[IB_POLL_BATCH]; ++ struct ib_wc wcs[IB_POLL_BATCH_DIRECT]; + +- return __ib_process_cq(cq, budget, wcs); ++ return __ib_process_cq(cq, budget, wcs, IB_POLL_BATCH_DIRECT); + } + EXPORT_SYMBOL(ib_process_cq_direct); + +@@ -88,7 +88,7 @@ static int ib_poll_handler(struct irq_poll *iop, int budget) + struct ib_cq *cq = container_of(iop, struct ib_cq, iop); + int completed; + +- completed = __ib_process_cq(cq, budget, NULL); ++ completed = __ib_process_cq(cq, budget, cq->wc, IB_POLL_BATCH); + if (completed < budget) { + irq_poll_complete(&cq->iop); + if (ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0) +@@ -108,7 +108,8 @@ static void ib_cq_poll_work(struct work_struct *work) + struct ib_cq *cq = container_of(work, struct ib_cq, work); + int completed; + +- completed = __ib_process_cq(cq, IB_POLL_BUDGET_WORKQUEUE, NULL); ++ completed = __ib_process_cq(cq, IB_POLL_BUDGET_WORKQUEUE, cq->wc, ++ IB_POLL_BATCH); + if (completed >= IB_POLL_BUDGET_WORKQUEUE || + ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0) + queue_work(ib_comp_wq, &cq->work); +diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c +index e8010e7..bb065c9 100644 +--- a/drivers/infiniband/core/device.c ++++ b/drivers/infiniband/core/device.c +@@ -536,14 +536,14 @@ int ib_register_device(struct ib_device *device, + ret = device->query_device(device, &device->attrs, &uhw); + if (ret) { + pr_warn("Couldn't query the device attributes\n"); +- goto cache_cleanup; ++ goto cg_cleanup; + } + + ret = ib_device_register_sysfs(device, port_callback); + if (ret) { + pr_warn("Couldn't register device %s with driver model\n", + device->name); +- goto cache_cleanup; ++ goto cg_cleanup; + } + + device->reg_state = IB_DEV_REGISTERED; +@@ -559,6 +559,8 @@ int ib_register_device(struct ib_device *device, + mutex_unlock(&device_mutex); + return 0; + ++cg_cleanup: ++ ib_device_unregister_rdmacg(device); + cache_cleanup: + ib_cache_cleanup_one(device); + ib_cache_release_one(device); +diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c +index 85b5ee4..d8eead5 100644 +--- a/drivers/infiniband/core/rdma_core.c ++++ b/drivers/infiniband/core/rdma_core.c +@@ -141,7 +141,12 @@ static struct ib_uobject *alloc_uobj(struct ib_ucontext *context, + */ + uobj->context = context; + uobj->type = type; +- atomic_set(&uobj->usecnt, 0); ++ /* ++ * Allocated objects start out as write locked to deny any other ++ * syscalls from accessing them until they are committed. See ++ * rdma_alloc_commit_uobject ++ */ ++ atomic_set(&uobj->usecnt, -1); + kref_init(&uobj->ref); + + return uobj; +@@ -196,7 +201,15 @@ static struct ib_uobject *lookup_get_idr_uobject(const struct uverbs_obj_type *t + goto free; + } + +- uverbs_uobject_get(uobj); ++ /* ++ * The idr_find is guaranteed to return a pointer to something that ++ * isn't freed yet, or NULL, as the free after idr_remove goes through ++ * kfree_rcu(). However the object may still have been released and ++ * kfree() could be called at any time. ++ */ ++ if (!kref_get_unless_zero(&uobj->ref)) ++ uobj = ERR_PTR(-ENOENT); ++ + free: + rcu_read_unlock(); + return uobj; +@@ -399,13 +412,13 @@ static int __must_check remove_commit_fd_uobject(struct ib_uobject *uobj, + return ret; + } + +-static void lockdep_check(struct ib_uobject *uobj, bool exclusive) ++static void assert_uverbs_usecnt(struct ib_uobject *uobj, bool exclusive) + { + #ifdef CONFIG_LOCKDEP + if (exclusive) +- WARN_ON(atomic_read(&uobj->usecnt) > 0); ++ WARN_ON(atomic_read(&uobj->usecnt) != -1); + else +- WARN_ON(atomic_read(&uobj->usecnt) == -1); ++ WARN_ON(atomic_read(&uobj->usecnt) <= 0); + #endif + } + +@@ -444,7 +457,7 @@ int __must_check rdma_remove_commit_uobject(struct ib_uobject *uobj) + WARN(true, "ib_uverbs: Cleanup is running while removing an uobject\n"); + return 0; + } +- lockdep_check(uobj, true); ++ assert_uverbs_usecnt(uobj, true); + ret = _rdma_remove_commit_uobject(uobj, RDMA_REMOVE_DESTROY); + + up_read(&ucontext->cleanup_rwsem); +@@ -474,16 +487,17 @@ int rdma_explicit_destroy(struct ib_uobject *uobject) + WARN(true, "ib_uverbs: Cleanup is running while removing an uobject\n"); + return 0; + } +- lockdep_check(uobject, true); ++ assert_uverbs_usecnt(uobject, true); + ret = uobject->type->type_class->remove_commit(uobject, + RDMA_REMOVE_DESTROY); + if (ret) +- return ret; ++ goto out; + + uobject->type = &null_obj_type; + ++out: + up_read(&ucontext->cleanup_rwsem); +- return 0; ++ return ret; + } + + static void alloc_commit_idr_uobject(struct ib_uobject *uobj) +@@ -527,6 +541,10 @@ int rdma_alloc_commit_uobject(struct ib_uobject *uobj) + return ret; + } + ++ /* matches atomic_set(-1) in alloc_uobj */ ++ assert_uverbs_usecnt(uobj, true); ++ atomic_set(&uobj->usecnt, 0); ++ + uobj->type->type_class->alloc_commit(uobj); + up_read(&uobj->context->cleanup_rwsem); + +@@ -561,7 +579,7 @@ static void lookup_put_fd_uobject(struct ib_uobject *uobj, bool exclusive) + + void rdma_lookup_put_uobject(struct ib_uobject *uobj, bool exclusive) + { +- lockdep_check(uobj, exclusive); ++ assert_uverbs_usecnt(uobj, exclusive); + uobj->type->type_class->lookup_put(uobj, exclusive); + /* + * In order to unlock an object, either decrease its usecnt for +diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c +index 857637b..3dbc4e4 100644 +--- a/drivers/infiniband/core/restrack.c ++++ b/drivers/infiniband/core/restrack.c +@@ -7,7 +7,6 @@ + #include + #include + #include +-#include + #include + + void rdma_restrack_init(struct rdma_restrack_root *res) +@@ -63,7 +62,6 @@ static struct ib_device *res_to_dev(struct rdma_restrack_entry *res) + { + enum rdma_restrack_type type = res->type; + struct ib_device *dev; +- struct ib_xrcd *xrcd; + struct ib_pd *pd; + struct ib_cq *cq; + struct ib_qp *qp; +@@ -81,10 +79,6 @@ static struct ib_device *res_to_dev(struct rdma_restrack_entry *res) + qp = container_of(res, struct ib_qp, res); + dev = qp->device; + break; +- case RDMA_RESTRACK_XRCD: +- xrcd = container_of(res, struct ib_xrcd, res); +- dev = xrcd->device; +- break; + default: + WARN_ONCE(true, "Wrong resource tracking type %u\n", type); + return NULL; +@@ -93,6 +87,21 @@ static struct ib_device *res_to_dev(struct rdma_restrack_entry *res) + return dev; + } + ++static bool res_is_user(struct rdma_restrack_entry *res) ++{ ++ switch (res->type) { ++ case RDMA_RESTRACK_PD: ++ return container_of(res, struct ib_pd, res)->uobject; ++ case RDMA_RESTRACK_CQ: ++ return container_of(res, struct ib_cq, res)->uobject; ++ case RDMA_RESTRACK_QP: ++ return container_of(res, struct ib_qp, res)->uobject; ++ default: ++ WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type); ++ return false; ++ } ++} ++ + void rdma_restrack_add(struct rdma_restrack_entry *res) + { + struct ib_device *dev = res_to_dev(res); +@@ -100,7 +109,7 @@ void rdma_restrack_add(struct rdma_restrack_entry *res) + if (!dev) + return; + +- if (!uaccess_kernel()) { ++ if (res_is_user(res)) { + get_task_struct(current); + res->task = current; + res->kern_name = NULL; +diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c +index 8cf15d4..9f029a1 100644 +--- a/drivers/infiniband/core/sa_query.c ++++ b/drivers/infiniband/core/sa_query.c +@@ -1291,10 +1291,9 @@ int ib_init_ah_attr_from_path(struct ib_device *device, u8 port_num, + + resolved_dev = dev_get_by_index(dev_addr.net, + dev_addr.bound_dev_if); +- if (resolved_dev->flags & IFF_LOOPBACK) { +- dev_put(resolved_dev); +- resolved_dev = idev; +- dev_hold(resolved_dev); ++ if (!resolved_dev) { ++ dev_put(idev); ++ return -ENODEV; + } + ndev = ib_get_ndev_from_path(rec); + rcu_read_lock(); +diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c +index f015f1b..3a9d0f5 100644 +--- a/drivers/infiniband/core/ucma.c ++++ b/drivers/infiniband/core/ucma.c +@@ -1149,6 +1149,9 @@ static ssize_t ucma_init_qp_attr(struct ucma_file *file, + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + ++ if (cmd.qp_state > IB_QPS_ERR) ++ return -EINVAL; ++ + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); +@@ -1294,6 +1297,9 @@ static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf, + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + ++ if (unlikely(cmd.optval > KMALLOC_MAX_SIZE)) ++ return -EINVAL; ++ + optval = memdup_user((void __user *) (unsigned long) cmd.optval, + cmd.optlen); + if (IS_ERR(optval)) { +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index 256934d..a148de3 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -562,9 +562,10 @@ ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file, + if (f.file) + fdput(f); + ++ mutex_unlock(&file->device->xrcd_tree_mutex); ++ + uobj_alloc_commit(&obj->uobject); + +- mutex_unlock(&file->device->xrcd_tree_mutex); + return in_len; + + err_copy: +@@ -603,10 +604,8 @@ ssize_t ib_uverbs_close_xrcd(struct ib_uverbs_file *file, + + uobj = uobj_get_write(uobj_get_type(xrcd), cmd.xrcd_handle, + file->ucontext); +- if (IS_ERR(uobj)) { +- mutex_unlock(&file->device->xrcd_tree_mutex); ++ if (IS_ERR(uobj)) + return PTR_ERR(uobj); +- } + + ret = uobj_remove_commit(uobj); + return ret ?: in_len; +@@ -979,6 +978,9 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file, + struct ib_uverbs_ex_create_cq_resp resp; + struct ib_cq_init_attr attr = {}; + ++ if (!ib_dev->create_cq) ++ return ERR_PTR(-EOPNOTSUPP); ++ + if (cmd->comp_vector >= file->device->num_comp_vectors) + return ERR_PTR(-EINVAL); + +@@ -1030,14 +1032,14 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file, + resp.response_length = offsetof(typeof(resp), response_length) + + sizeof(resp.response_length); + ++ cq->res.type = RDMA_RESTRACK_CQ; ++ rdma_restrack_add(&cq->res); ++ + ret = cb(file, obj, &resp, ucore, context); + if (ret) + goto err_cb; + + uobj_alloc_commit(&obj->uobject); +- cq->res.type = RDMA_RESTRACK_CQ; +- rdma_restrack_add(&cq->res); +- + return obj; + + err_cb: +@@ -1518,7 +1520,8 @@ static int create_qp(struct ib_uverbs_file *file, + if (cmd->qp_type == IB_QPT_XRC_TGT) + qp = ib_create_qp(pd, &attr); + else +- qp = _ib_create_qp(device, pd, &attr, uhw); ++ qp = _ib_create_qp(device, pd, &attr, uhw, ++ &obj->uevent.uobject); + + if (IS_ERR(qp)) { + ret = PTR_ERR(qp); +@@ -1550,8 +1553,10 @@ static int create_qp(struct ib_uverbs_file *file, + atomic_inc(&attr.srq->usecnt); + if (ind_tbl) + atomic_inc(&ind_tbl->usecnt); ++ } else { ++ /* It is done in _ib_create_qp for other QP types */ ++ qp->uobject = &obj->uevent.uobject; + } +- qp->uobject = &obj->uevent.uobject; + + obj->uevent.uobject.object = qp; + +@@ -1971,8 +1976,15 @@ static int modify_qp(struct ib_uverbs_file *file, + goto release_qp; + } + ++ if ((cmd->base.attr_mask & IB_QP_AV) && ++ !rdma_is_port_valid(qp->device, cmd->base.dest.port_num)) { ++ ret = -EINVAL; ++ goto release_qp; ++ } ++ + if ((cmd->base.attr_mask & IB_QP_ALT_PATH) && +- !rdma_is_port_valid(qp->device, cmd->base.alt_port_num)) { ++ (!rdma_is_port_valid(qp->device, cmd->base.alt_port_num) || ++ !rdma_is_port_valid(qp->device, cmd->base.alt_dest.port_num))) { + ret = -EINVAL; + goto release_qp; + } +@@ -2941,6 +2953,11 @@ int ib_uverbs_ex_create_wq(struct ib_uverbs_file *file, + wq_init_attr.create_flags = cmd.create_flags; + obj->uevent.events_reported = 0; + INIT_LIST_HEAD(&obj->uevent.event_list); ++ ++ if (!pd->device->create_wq) { ++ err = -EOPNOTSUPP; ++ goto err_put_cq; ++ } + wq = pd->device->create_wq(pd, &wq_init_attr, uhw); + if (IS_ERR(wq)) { + err = PTR_ERR(wq); +@@ -3084,7 +3101,12 @@ int ib_uverbs_ex_modify_wq(struct ib_uverbs_file *file, + wq_attr.flags = cmd.flags; + wq_attr.flags_mask = cmd.flags_mask; + } ++ if (!wq->device->modify_wq) { ++ ret = -EOPNOTSUPP; ++ goto out; ++ } + ret = wq->device->modify_wq(wq, &wq_attr, cmd.attr_mask, uhw); ++out: + uobj_put_obj_read(wq); + return ret; + } +@@ -3181,6 +3203,11 @@ int ib_uverbs_ex_create_rwq_ind_table(struct ib_uverbs_file *file, + + init_attr.log_ind_tbl_size = cmd.log_ind_tbl_size; + init_attr.ind_tbl = wqs; ++ ++ if (!ib_dev->create_rwq_ind_table) { ++ err = -EOPNOTSUPP; ++ goto err_uobj; ++ } + rwq_ind_tbl = ib_dev->create_rwq_ind_table(ib_dev, &init_attr, uhw); + + if (IS_ERR(rwq_ind_tbl)) { +@@ -3770,6 +3797,9 @@ int ib_uverbs_ex_query_device(struct ib_uverbs_file *file, + struct ib_device_attr attr = {0}; + int err; + ++ if (!ib_dev->query_device) ++ return -EOPNOTSUPP; ++ + if (ucore->inlen < sizeof(cmd)) + return -EINVAL; + +diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c +index d96dc1d..339b851 100644 +--- a/drivers/infiniband/core/uverbs_ioctl.c ++++ b/drivers/infiniband/core/uverbs_ioctl.c +@@ -59,6 +59,9 @@ static int uverbs_process_attr(struct ib_device *ibdev, + return 0; + } + ++ if (test_bit(attr_id, attr_bundle_h->valid_bitmap)) ++ return -EINVAL; ++ + spec = &attr_spec_bucket->attrs[attr_id]; + e = &elements[attr_id]; + e->uattr = uattr_ptr; +diff --git a/drivers/infiniband/core/uverbs_ioctl_merge.c b/drivers/infiniband/core/uverbs_ioctl_merge.c +index 062485f..62e1eb1 100644 +--- a/drivers/infiniband/core/uverbs_ioctl_merge.c ++++ b/drivers/infiniband/core/uverbs_ioctl_merge.c +@@ -114,6 +114,7 @@ static size_t get_elements_above_id(const void **iters, + short min = SHRT_MAX; + const void *elem; + int i, j, last_stored = -1; ++ unsigned int equal_min = 0; + + for_each_element(elem, i, j, elements, num_elements, num_offset, + data_offset) { +@@ -136,6 +137,10 @@ static size_t get_elements_above_id(const void **iters, + */ + iters[last_stored == i ? num_iters - 1 : num_iters++] = elem; + last_stored = i; ++ if (min == GET_ID(id)) ++ equal_min++; ++ else ++ equal_min = 1; + min = GET_ID(id); + } + +@@ -146,15 +151,10 @@ static size_t get_elements_above_id(const void **iters, + * Therefore, we need to clean the beginning of the array to make sure + * all ids of final elements are equal to min. + */ +- for (i = num_iters - 1; i >= 0 && +- GET_ID(*(u16 *)(iters[i] + id_offset)) == min; i--) +- ; +- +- num_iters -= i + 1; +- memmove(iters, iters + i + 1, sizeof(*iters) * num_iters); ++ memmove(iters, iters + num_iters - equal_min, sizeof(*iters) * equal_min); + + *min_id = min; +- return num_iters; ++ return equal_min; + } + + #define find_max_element_entry_id(num_elements, elements, num_objects_fld, \ +@@ -322,7 +322,7 @@ static struct uverbs_method_spec *build_method_with_attrs(const struct uverbs_me + hash = kzalloc(sizeof(*hash) + + ALIGN(sizeof(*hash->attrs) * (attr_max_bucket + 1), + sizeof(long)) + +- BITS_TO_LONGS(attr_max_bucket) * sizeof(long), ++ BITS_TO_LONGS(attr_max_bucket + 1) * sizeof(long), + GFP_KERNEL); + if (!hash) { + res = -ENOMEM; +@@ -509,7 +509,7 @@ static struct uverbs_object_spec *build_object_with_methods(const struct uverbs_ + * first handler which != NULL. This also defines the + * set of flags used for this handler. + */ +- for (i = num_object_defs - 1; ++ for (i = num_method_defs - 1; + i >= 0 && !method_defs[i]->handler; i--) + ; + hash->methods[min_id++] = method; +diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c +index 395a3b0..b1ca223 100644 +--- a/drivers/infiniband/core/uverbs_main.c ++++ b/drivers/infiniband/core/uverbs_main.c +@@ -650,12 +650,21 @@ static int verify_command_mask(struct ib_device *ib_dev, __u32 command) + return -1; + } + ++static bool verify_command_idx(u32 command, bool extended) ++{ ++ if (extended) ++ return command < ARRAY_SIZE(uverbs_ex_cmd_table); ++ ++ return command < ARRAY_SIZE(uverbs_cmd_table); ++} ++ + static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, + size_t count, loff_t *pos) + { + struct ib_uverbs_file *file = filp->private_data; + struct ib_device *ib_dev; + struct ib_uverbs_cmd_hdr hdr; ++ bool extended_command; + __u32 command; + __u32 flags; + int srcu_key; +@@ -688,6 +697,15 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, + } + + command = hdr.command & IB_USER_VERBS_CMD_COMMAND_MASK; ++ flags = (hdr.command & ++ IB_USER_VERBS_CMD_FLAGS_MASK) >> IB_USER_VERBS_CMD_FLAGS_SHIFT; ++ ++ extended_command = flags & IB_USER_VERBS_CMD_FLAG_EXTENDED; ++ if (!verify_command_idx(command, extended_command)) { ++ ret = -EINVAL; ++ goto out; ++ } ++ + if (verify_command_mask(ib_dev, command)) { + ret = -EOPNOTSUPP; + goto out; +@@ -699,12 +717,8 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, + goto out; + } + +- flags = (hdr.command & +- IB_USER_VERBS_CMD_FLAGS_MASK) >> IB_USER_VERBS_CMD_FLAGS_SHIFT; +- + if (!flags) { +- if (command >= ARRAY_SIZE(uverbs_cmd_table) || +- !uverbs_cmd_table[command]) { ++ if (!uverbs_cmd_table[command]) { + ret = -EINVAL; + goto out; + } +@@ -725,8 +739,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, + struct ib_udata uhw; + size_t written_count = count; + +- if (command >= ARRAY_SIZE(uverbs_ex_cmd_table) || +- !uverbs_ex_cmd_table[command]) { ++ if (!uverbs_ex_cmd_table[command]) { + ret = -ENOSYS; + goto out; + } +@@ -942,6 +955,7 @@ static const struct file_operations uverbs_fops = { + .llseek = no_llseek, + #if IS_ENABLED(CONFIG_INFINIBAND_EXP_USER_ACCESS) + .unlocked_ioctl = ib_uverbs_ioctl, ++ .compat_ioctl = ib_uverbs_ioctl, + #endif + }; + +@@ -954,6 +968,7 @@ static const struct file_operations uverbs_mmap_fops = { + .llseek = no_llseek, + #if IS_ENABLED(CONFIG_INFINIBAND_EXP_USER_ACCESS) + .unlocked_ioctl = ib_uverbs_ioctl, ++ .compat_ioctl = ib_uverbs_ioctl, + #endif + }; + +diff --git a/drivers/infiniband/core/uverbs_std_types.c b/drivers/infiniband/core/uverbs_std_types.c +index cab0ac3..df1360e 100644 +--- a/drivers/infiniband/core/uverbs_std_types.c ++++ b/drivers/infiniband/core/uverbs_std_types.c +@@ -234,15 +234,18 @@ static void create_udata(struct uverbs_attr_bundle *ctx, + uverbs_attr_get(ctx, UVERBS_UHW_OUT); + + if (!IS_ERR(uhw_in)) { +- udata->inbuf = uhw_in->ptr_attr.ptr; + udata->inlen = uhw_in->ptr_attr.len; ++ if (uverbs_attr_ptr_is_inline(uhw_in)) ++ udata->inbuf = &uhw_in->uattr->data; ++ else ++ udata->inbuf = u64_to_user_ptr(uhw_in->ptr_attr.data); + } else { + udata->inbuf = NULL; + udata->inlen = 0; + } + + if (!IS_ERR(uhw_out)) { +- udata->outbuf = uhw_out->ptr_attr.ptr; ++ udata->outbuf = u64_to_user_ptr(uhw_out->ptr_attr.data); + udata->outlen = uhw_out->ptr_attr.len; + } else { + udata->outbuf = NULL; +@@ -323,7 +326,8 @@ static int uverbs_create_cq_handler(struct ib_device *ib_dev, + cq->res.type = RDMA_RESTRACK_CQ; + rdma_restrack_add(&cq->res); + +- ret = uverbs_copy_to(attrs, CREATE_CQ_RESP_CQE, &cq->cqe); ++ ret = uverbs_copy_to(attrs, CREATE_CQ_RESP_CQE, &cq->cqe, ++ sizeof(cq->cqe)); + if (ret) + goto err_cq; + +@@ -375,7 +379,7 @@ static int uverbs_destroy_cq_handler(struct ib_device *ib_dev, + resp.comp_events_reported = obj->comp_events_reported; + resp.async_events_reported = obj->async_events_reported; + +- return uverbs_copy_to(attrs, DESTROY_CQ_RESP, &resp); ++ return uverbs_copy_to(attrs, DESTROY_CQ_RESP, &resp, sizeof(resp)); + } + + static DECLARE_UVERBS_METHOD( +diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c +index 16ebc63..93025d2 100644 +--- a/drivers/infiniband/core/verbs.c ++++ b/drivers/infiniband/core/verbs.c +@@ -887,7 +887,7 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd, + if (qp_init_attr->cap.max_rdma_ctxs) + rdma_rw_init_qp(device, qp_init_attr); + +- qp = _ib_create_qp(device, pd, qp_init_attr, NULL); ++ qp = _ib_create_qp(device, pd, qp_init_attr, NULL, NULL); + if (IS_ERR(qp)) + return qp; + +@@ -898,7 +898,6 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd, + } + + qp->real_qp = qp; +- qp->uobject = NULL; + qp->qp_type = qp_init_attr->qp_type; + qp->rwq_ind_tbl = qp_init_attr->rwq_ind_tbl; + +diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h +index ca32057..3eb7a83 100644 +--- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h ++++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h +@@ -120,7 +120,6 @@ struct bnxt_re_dev { + #define BNXT_RE_FLAG_HAVE_L2_REF 3 + #define BNXT_RE_FLAG_RCFW_CHANNEL_EN 4 + #define BNXT_RE_FLAG_QOS_WORK_REG 5 +-#define BNXT_RE_FLAG_TASK_IN_PROG 6 + #define BNXT_RE_FLAG_ISSUE_ROCE_STATS 29 + struct net_device *netdev; + unsigned int version, major, minor; +@@ -158,6 +157,7 @@ struct bnxt_re_dev { + atomic_t srq_count; + atomic_t mr_count; + atomic_t mw_count; ++ atomic_t sched_count; + /* Max of 2 lossless traffic class supported per port */ + u16 cosq[2]; + +diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +index ae9e9ff..0dd75f4 100644 +--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c ++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +@@ -174,10 +174,8 @@ int bnxt_re_query_device(struct ib_device *ibdev, + ib_attr->max_pd = dev_attr->max_pd; + ib_attr->max_qp_rd_atom = dev_attr->max_qp_rd_atom; + ib_attr->max_qp_init_rd_atom = dev_attr->max_qp_init_rd_atom; +- if (dev_attr->is_atomic) { +- ib_attr->atomic_cap = IB_ATOMIC_HCA; +- ib_attr->masked_atomic_cap = IB_ATOMIC_HCA; +- } ++ ib_attr->atomic_cap = IB_ATOMIC_NONE; ++ ib_attr->masked_atomic_cap = IB_ATOMIC_NONE; + + ib_attr->max_ee_rd_atom = 0; + ib_attr->max_res_rd_atom = 0; +@@ -787,20 +785,51 @@ int bnxt_re_query_ah(struct ib_ah *ib_ah, struct rdma_ah_attr *ah_attr) + return 0; + } + ++unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp) ++ __acquires(&qp->scq->cq_lock) __acquires(&qp->rcq->cq_lock) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&qp->scq->cq_lock, flags); ++ if (qp->rcq != qp->scq) ++ spin_lock(&qp->rcq->cq_lock); ++ else ++ __acquire(&qp->rcq->cq_lock); ++ ++ return flags; ++} ++ ++void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp, ++ unsigned long flags) ++ __releases(&qp->scq->cq_lock) __releases(&qp->rcq->cq_lock) ++{ ++ if (qp->rcq != qp->scq) ++ spin_unlock(&qp->rcq->cq_lock); ++ else ++ __release(&qp->rcq->cq_lock); ++ spin_unlock_irqrestore(&qp->scq->cq_lock, flags); ++} ++ + /* Queue Pairs */ + int bnxt_re_destroy_qp(struct ib_qp *ib_qp) + { + struct bnxt_re_qp *qp = container_of(ib_qp, struct bnxt_re_qp, ib_qp); + struct bnxt_re_dev *rdev = qp->rdev; + int rc; ++ unsigned int flags; + + bnxt_qplib_flush_cqn_wq(&qp->qplib_qp); +- bnxt_qplib_del_flush_qp(&qp->qplib_qp); + rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp); + if (rc) { + dev_err(rdev_to_dev(rdev), "Failed to destroy HW QP"); + return rc; + } ++ ++ flags = bnxt_re_lock_cqs(qp); ++ bnxt_qplib_clean_qp(&qp->qplib_qp); ++ bnxt_re_unlock_cqs(qp, flags); ++ bnxt_qplib_free_qp_res(&rdev->qplib_res, &qp->qplib_qp); ++ + if (ib_qp->qp_type == IB_QPT_GSI && rdev->qp1_sqp) { + rc = bnxt_qplib_destroy_ah(&rdev->qplib_res, + &rdev->sqp_ah->qplib_ah); +@@ -810,7 +839,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp) + return rc; + } + +- bnxt_qplib_del_flush_qp(&qp->qplib_qp); ++ bnxt_qplib_clean_qp(&qp->qplib_qp); + rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, + &rdev->qp1_sqp->qplib_qp); + if (rc) { +@@ -1069,6 +1098,7 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd, + goto fail; + } + qp->qplib_qp.scq = &cq->qplib_cq; ++ qp->scq = cq; + } + + if (qp_init_attr->recv_cq) { +@@ -1080,6 +1110,7 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd, + goto fail; + } + qp->qplib_qp.rcq = &cq->qplib_cq; ++ qp->rcq = cq; + } + + if (qp_init_attr->srq) { +@@ -1185,7 +1216,7 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd, + rc = bnxt_qplib_create_qp(&rdev->qplib_res, &qp->qplib_qp); + if (rc) { + dev_err(rdev_to_dev(rdev), "Failed to create HW QP"); +- goto fail; ++ goto free_umem; + } + } + +@@ -1213,6 +1244,13 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd, + return &qp->ib_qp; + qp_destroy: + bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp); ++free_umem: ++ if (udata) { ++ if (qp->rumem) ++ ib_umem_release(qp->rumem); ++ if (qp->sumem) ++ ib_umem_release(qp->sumem); ++ } + fail: + kfree(qp); + return ERR_PTR(rc); +@@ -1568,6 +1606,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, + int status; + union ib_gid sgid; + struct ib_gid_attr sgid_attr; ++ unsigned int flags; + u8 nw_type; + + qp->qplib_qp.modify_flags = 0; +@@ -1596,14 +1635,18 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, + dev_dbg(rdev_to_dev(rdev), + "Move QP = %p to flush list\n", + qp); ++ flags = bnxt_re_lock_cqs(qp); + bnxt_qplib_add_flush_qp(&qp->qplib_qp); ++ bnxt_re_unlock_cqs(qp, flags); + } + if (!qp->sumem && + qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_RESET) { + dev_dbg(rdev_to_dev(rdev), + "Move QP = %p out of flush list\n", + qp); +- bnxt_qplib_del_flush_qp(&qp->qplib_qp); ++ flags = bnxt_re_lock_cqs(qp); ++ bnxt_qplib_clean_qp(&qp->qplib_qp); ++ bnxt_re_unlock_cqs(qp, flags); + } + } + if (qp_attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) { +@@ -2189,10 +2232,13 @@ static int bnxt_re_build_inv_wqe(struct ib_send_wr *wr, + wqe->type = BNXT_QPLIB_SWQE_TYPE_LOCAL_INV; + wqe->local_inv.inv_l_key = wr->ex.invalidate_rkey; + ++ /* Need unconditional fence for local invalidate ++ * opcode to work as expected. ++ */ ++ wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; ++ + if (wr->send_flags & IB_SEND_SIGNALED) + wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP; +- if (wr->send_flags & IB_SEND_FENCE) +- wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; + if (wr->send_flags & IB_SEND_SOLICITED) + wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SOLICIT_EVENT; + +@@ -2213,8 +2259,12 @@ static int bnxt_re_build_reg_wqe(struct ib_reg_wr *wr, + wqe->frmr.levels = qplib_frpl->hwq.level + 1; + wqe->type = BNXT_QPLIB_SWQE_TYPE_REG_MR; + +- if (wr->wr.send_flags & IB_SEND_FENCE) +- wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; ++ /* Need unconditional fence for reg_mr ++ * opcode to function as expected. ++ */ ++ ++ wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; ++ + if (wr->wr.send_flags & IB_SEND_SIGNALED) + wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP; + +diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h +index 423ebe0..e62b7c2 100644 +--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h ++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h +@@ -89,6 +89,8 @@ struct bnxt_re_qp { + /* QP1 */ + u32 send_psn; + struct ib_ud_header qp1_hdr; ++ struct bnxt_re_cq *scq; ++ struct bnxt_re_cq *rcq; + }; + + struct bnxt_re_cq { +@@ -220,4 +222,7 @@ struct ib_ucontext *bnxt_re_alloc_ucontext(struct ib_device *ibdev, + struct ib_udata *udata); + int bnxt_re_dealloc_ucontext(struct ib_ucontext *context); + int bnxt_re_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); ++ ++unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp); ++void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp, unsigned long flags); + #endif /* __BNXT_RE_IB_VERBS_H__ */ +diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c +index 508d00a..f6e3617 100644 +--- a/drivers/infiniband/hw/bnxt_re/main.c ++++ b/drivers/infiniband/hw/bnxt_re/main.c +@@ -656,7 +656,6 @@ static void bnxt_re_dev_remove(struct bnxt_re_dev *rdev) + mutex_unlock(&bnxt_re_dev_lock); + + synchronize_rcu(); +- flush_workqueue(bnxt_re_wq); + + ib_dealloc_device(&rdev->ibdev); + /* rdev is gone */ +@@ -731,6 +730,13 @@ static int bnxt_re_handle_qp_async_event(struct creq_qp_event *qp_event, + struct bnxt_re_qp *qp) + { + struct ib_event event; ++ unsigned int flags; ++ ++ if (qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR) { ++ flags = bnxt_re_lock_cqs(qp); ++ bnxt_qplib_add_flush_qp(&qp->qplib_qp); ++ bnxt_re_unlock_cqs(qp, flags); ++ } + + memset(&event, 0, sizeof(event)); + if (qp->qplib_qp.srq) { +@@ -1417,9 +1423,12 @@ static void bnxt_re_task(struct work_struct *work) + switch (re_work->event) { + case NETDEV_REGISTER: + rc = bnxt_re_ib_reg(rdev); +- if (rc) ++ if (rc) { + dev_err(rdev_to_dev(rdev), + "Failed to register with IB: %#x", rc); ++ bnxt_re_remove_one(rdev); ++ bnxt_re_dev_unreg(rdev); ++ } + break; + case NETDEV_UP: + bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1, +@@ -1441,7 +1450,7 @@ static void bnxt_re_task(struct work_struct *work) + break; + } + smp_mb__before_atomic(); +- clear_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags); ++ atomic_dec(&rdev->sched_count); + kfree(re_work); + } + +@@ -1503,7 +1512,7 @@ static int bnxt_re_netdev_event(struct notifier_block *notifier, + /* netdev notifier will call NETDEV_UNREGISTER again later since + * we are still holding the reference to the netdev + */ +- if (test_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags)) ++ if (atomic_read(&rdev->sched_count) > 0) + goto exit; + bnxt_re_ib_unreg(rdev, false); + bnxt_re_remove_one(rdev); +@@ -1523,7 +1532,7 @@ static int bnxt_re_netdev_event(struct notifier_block *notifier, + re_work->vlan_dev = (real_dev == netdev ? + NULL : netdev); + INIT_WORK(&re_work->work, bnxt_re_task); +- set_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags); ++ atomic_inc(&rdev->sched_count); + queue_work(bnxt_re_wq, &re_work->work); + } + } +@@ -1578,6 +1587,11 @@ static void __exit bnxt_re_mod_exit(void) + */ + list_for_each_entry_safe_reverse(rdev, next, &to_be_deleted, list) { + dev_info(rdev_to_dev(rdev), "Unregistering Device"); ++ /* ++ * Flush out any scheduled tasks before destroying the ++ * resources ++ */ ++ flush_workqueue(bnxt_re_wq); + bnxt_re_dev_stop(rdev); + bnxt_re_ib_unreg(rdev, true); + bnxt_re_remove_one(rdev); +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c +index 1b0e946..06b42c8 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c +@@ -88,75 +88,35 @@ static void __bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp) + } + } + +-void bnxt_qplib_acquire_cq_locks(struct bnxt_qplib_qp *qp, +- unsigned long *flags) +- __acquires(&qp->scq->hwq.lock) __acquires(&qp->rcq->hwq.lock) ++static void bnxt_qplib_acquire_cq_flush_locks(struct bnxt_qplib_qp *qp, ++ unsigned long *flags) ++ __acquires(&qp->scq->flush_lock) __acquires(&qp->rcq->flush_lock) + { +- spin_lock_irqsave(&qp->scq->hwq.lock, *flags); ++ spin_lock_irqsave(&qp->scq->flush_lock, *flags); + if (qp->scq == qp->rcq) +- __acquire(&qp->rcq->hwq.lock); ++ __acquire(&qp->rcq->flush_lock); + else +- spin_lock(&qp->rcq->hwq.lock); ++ spin_lock(&qp->rcq->flush_lock); + } + +-void bnxt_qplib_release_cq_locks(struct bnxt_qplib_qp *qp, +- unsigned long *flags) +- __releases(&qp->scq->hwq.lock) __releases(&qp->rcq->hwq.lock) ++static void bnxt_qplib_release_cq_flush_locks(struct bnxt_qplib_qp *qp, ++ unsigned long *flags) ++ __releases(&qp->scq->flush_lock) __releases(&qp->rcq->flush_lock) + { + if (qp->scq == qp->rcq) +- __release(&qp->rcq->hwq.lock); ++ __release(&qp->rcq->flush_lock); + else +- spin_unlock(&qp->rcq->hwq.lock); +- spin_unlock_irqrestore(&qp->scq->hwq.lock, *flags); +-} +- +-static struct bnxt_qplib_cq *bnxt_qplib_find_buddy_cq(struct bnxt_qplib_qp *qp, +- struct bnxt_qplib_cq *cq) +-{ +- struct bnxt_qplib_cq *buddy_cq = NULL; +- +- if (qp->scq == qp->rcq) +- buddy_cq = NULL; +- else if (qp->scq == cq) +- buddy_cq = qp->rcq; +- else +- buddy_cq = qp->scq; +- return buddy_cq; +-} +- +-static void bnxt_qplib_lock_buddy_cq(struct bnxt_qplib_qp *qp, +- struct bnxt_qplib_cq *cq) +- __acquires(&buddy_cq->hwq.lock) +-{ +- struct bnxt_qplib_cq *buddy_cq = NULL; +- +- buddy_cq = bnxt_qplib_find_buddy_cq(qp, cq); +- if (!buddy_cq) +- __acquire(&cq->hwq.lock); +- else +- spin_lock(&buddy_cq->hwq.lock); +-} +- +-static void bnxt_qplib_unlock_buddy_cq(struct bnxt_qplib_qp *qp, +- struct bnxt_qplib_cq *cq) +- __releases(&buddy_cq->hwq.lock) +-{ +- struct bnxt_qplib_cq *buddy_cq = NULL; +- +- buddy_cq = bnxt_qplib_find_buddy_cq(qp, cq); +- if (!buddy_cq) +- __release(&cq->hwq.lock); +- else +- spin_unlock(&buddy_cq->hwq.lock); ++ spin_unlock(&qp->rcq->flush_lock); ++ spin_unlock_irqrestore(&qp->scq->flush_lock, *flags); + } + + void bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp) + { + unsigned long flags; + +- bnxt_qplib_acquire_cq_locks(qp, &flags); ++ bnxt_qplib_acquire_cq_flush_locks(qp, &flags); + __bnxt_qplib_add_flush_qp(qp); +- bnxt_qplib_release_cq_locks(qp, &flags); ++ bnxt_qplib_release_cq_flush_locks(qp, &flags); + } + + static void __bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp) +@@ -173,11 +133,11 @@ static void __bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp) + } + } + +-void bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp) ++void bnxt_qplib_clean_qp(struct bnxt_qplib_qp *qp) + { + unsigned long flags; + +- bnxt_qplib_acquire_cq_locks(qp, &flags); ++ bnxt_qplib_acquire_cq_flush_locks(qp, &flags); + __clean_cq(qp->scq, (u64)(unsigned long)qp); + qp->sq.hwq.prod = 0; + qp->sq.hwq.cons = 0; +@@ -186,7 +146,7 @@ void bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp) + qp->rq.hwq.cons = 0; + + __bnxt_qplib_del_flush_qp(qp); +- bnxt_qplib_release_cq_locks(qp, &flags); ++ bnxt_qplib_release_cq_flush_locks(qp, &flags); + } + + static void bnxt_qpn_cqn_sched_task(struct work_struct *work) +@@ -1419,7 +1379,6 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res, + struct bnxt_qplib_rcfw *rcfw = res->rcfw; + struct cmdq_destroy_qp req; + struct creq_destroy_qp_resp resp; +- unsigned long flags; + u16 cmd_flags = 0; + int rc; + +@@ -1437,19 +1396,12 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res, + return rc; + } + +- /* Must walk the associated CQs to nullified the QP ptr */ +- spin_lock_irqsave(&qp->scq->hwq.lock, flags); +- +- __clean_cq(qp->scq, (u64)(unsigned long)qp); +- +- if (qp->rcq && qp->rcq != qp->scq) { +- spin_lock(&qp->rcq->hwq.lock); +- __clean_cq(qp->rcq, (u64)(unsigned long)qp); +- spin_unlock(&qp->rcq->hwq.lock); +- } +- +- spin_unlock_irqrestore(&qp->scq->hwq.lock, flags); ++ return 0; ++} + ++void bnxt_qplib_free_qp_res(struct bnxt_qplib_res *res, ++ struct bnxt_qplib_qp *qp) ++{ + bnxt_qplib_free_qp_hdr_buf(res, qp); + bnxt_qplib_free_hwq(res->pdev, &qp->sq.hwq); + kfree(qp->sq.swq); +@@ -1462,7 +1414,6 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res, + if (qp->orrq.max_elements) + bnxt_qplib_free_hwq(res->pdev, &qp->orrq); + +- return 0; + } + + void *bnxt_qplib_get_qp1_sq_buf(struct bnxt_qplib_qp *qp, +@@ -2116,9 +2067,6 @@ void bnxt_qplib_mark_qp_error(void *qp_handle) + /* Must block new posting of SQ and RQ */ + qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; + bnxt_qplib_cancel_phantom_processing(qp); +- +- /* Add qp to flush list of the CQ */ +- __bnxt_qplib_add_flush_qp(qp); + } + + /* Note: SQE is valid from sw_sq_cons up to cqe_sq_cons (exclusive) +@@ -2294,9 +2242,9 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq, + sw_sq_cons, cqe->wr_id, cqe->status); + cqe++; + (*budget)--; +- bnxt_qplib_lock_buddy_cq(qp, cq); + bnxt_qplib_mark_qp_error(qp); +- bnxt_qplib_unlock_buddy_cq(qp, cq); ++ /* Add qp to flush list of the CQ */ ++ bnxt_qplib_add_flush_qp(qp); + } else { + if (swq->flags & SQ_SEND_FLAGS_SIGNAL_COMP) { + /* Before we complete, do WA 9060 */ +@@ -2412,9 +2360,7 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq, + if (hwcqe->status != CQ_RES_RC_STATUS_OK) { + qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; + /* Add qp to flush list of the CQ */ +- bnxt_qplib_lock_buddy_cq(qp, cq); +- __bnxt_qplib_add_flush_qp(qp); +- bnxt_qplib_unlock_buddy_cq(qp, cq); ++ bnxt_qplib_add_flush_qp(qp); + } + } + +@@ -2498,9 +2444,7 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq, + if (hwcqe->status != CQ_RES_RC_STATUS_OK) { + qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; + /* Add qp to flush list of the CQ */ +- bnxt_qplib_lock_buddy_cq(qp, cq); +- __bnxt_qplib_add_flush_qp(qp); +- bnxt_qplib_unlock_buddy_cq(qp, cq); ++ bnxt_qplib_add_flush_qp(qp); + } + } + done: +@@ -2510,11 +2454,9 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq, + bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq) + { + struct cq_base *hw_cqe, **hw_cqe_ptr; +- unsigned long flags; + u32 sw_cons, raw_cons; + bool rc = true; + +- spin_lock_irqsave(&cq->hwq.lock, flags); + raw_cons = cq->hwq.cons; + sw_cons = HWQ_CMP(raw_cons, &cq->hwq); + hw_cqe_ptr = (struct cq_base **)cq->hwq.pbl_ptr; +@@ -2522,7 +2464,6 @@ bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq) + + /* Check for Valid bit. If the CQE is valid, return false */ + rc = !CQE_CMP_VALID(hw_cqe, raw_cons, cq->hwq.max_elements); +- spin_unlock_irqrestore(&cq->hwq.lock, flags); + return rc; + } + +@@ -2611,9 +2552,7 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq, + if (hwcqe->status != CQ_RES_RC_STATUS_OK) { + qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; + /* Add qp to flush list of the CQ */ +- bnxt_qplib_lock_buddy_cq(qp, cq); +- __bnxt_qplib_add_flush_qp(qp); +- bnxt_qplib_unlock_buddy_cq(qp, cq); ++ bnxt_qplib_add_flush_qp(qp); + } + } + +@@ -2728,9 +2667,7 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq, + */ + + /* Add qp to flush list of the CQ */ +- bnxt_qplib_lock_buddy_cq(qp, cq); +- __bnxt_qplib_add_flush_qp(qp); +- bnxt_qplib_unlock_buddy_cq(qp, cq); ++ bnxt_qplib_add_flush_qp(qp); + done: + return rc; + } +@@ -2759,7 +2696,7 @@ int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq, + u32 budget = num_cqes; + unsigned long flags; + +- spin_lock_irqsave(&cq->hwq.lock, flags); ++ spin_lock_irqsave(&cq->flush_lock, flags); + list_for_each_entry(qp, &cq->sqf_head, sq_flush) { + dev_dbg(&cq->hwq.pdev->dev, + "QPLIB: FP: Flushing SQ QP= %p", +@@ -2773,7 +2710,7 @@ int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq, + qp); + __flush_rq(&qp->rq, qp, &cqe, &budget); + } +- spin_unlock_irqrestore(&cq->hwq.lock, flags); ++ spin_unlock_irqrestore(&cq->flush_lock, flags); + + return num_cqes - budget; + } +@@ -2782,11 +2719,9 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, + int num_cqes, struct bnxt_qplib_qp **lib_qp) + { + struct cq_base *hw_cqe, **hw_cqe_ptr; +- unsigned long flags; + u32 sw_cons, raw_cons; + int budget, rc = 0; + +- spin_lock_irqsave(&cq->hwq.lock, flags); + raw_cons = cq->hwq.cons; + budget = num_cqes; + +@@ -2862,20 +2797,15 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, + bnxt_qplib_arm_cq(cq, DBR_DBR_TYPE_CQ); + } + exit: +- spin_unlock_irqrestore(&cq->hwq.lock, flags); + return num_cqes - budget; + } + + void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type) + { +- unsigned long flags; +- +- spin_lock_irqsave(&cq->hwq.lock, flags); + if (arm_type) + bnxt_qplib_arm_cq(cq, arm_type); + /* Using cq->arm_state variable to track whether to issue cq handler */ + atomic_set(&cq->arm_state, 1); +- spin_unlock_irqrestore(&cq->hwq.lock, flags); + } + + void bnxt_qplib_flush_cqn_wq(struct bnxt_qplib_qp *qp) +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h +index 211b27a..ade9f13 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h ++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h +@@ -389,6 +389,18 @@ struct bnxt_qplib_cq { + struct list_head sqf_head, rqf_head; + atomic_t arm_state; + spinlock_t compl_lock; /* synch CQ handlers */ ++/* Locking Notes: ++ * QP can move to error state from modify_qp, async error event or error ++ * CQE as part of poll_cq. When QP is moved to error state, it gets added ++ * to two flush lists, one each for SQ and RQ. ++ * Each flush list is protected by qplib_cq->flush_lock. Both scq and rcq ++ * flush_locks should be acquired when QP is moved to error. The control path ++ * operations(modify_qp and async error events) are synchronized with poll_cq ++ * using upper level CQ locks (bnxt_re_cq->cq_lock) of both SCQ and RCQ. ++ * The qplib_cq->flush_lock is required to synchronize two instances of poll_cq ++ * of the same QP while manipulating the flush list. ++ */ ++ spinlock_t flush_lock; /* QP flush management */ + }; + + #define BNXT_QPLIB_MAX_IRRQE_ENTRY_SIZE sizeof(struct xrrq_irrq) +@@ -478,6 +490,9 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp); + int bnxt_qplib_modify_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp); + int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp); + int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp); ++void bnxt_qplib_clean_qp(struct bnxt_qplib_qp *qp); ++void bnxt_qplib_free_qp_res(struct bnxt_qplib_res *res, ++ struct bnxt_qplib_qp *qp); + void *bnxt_qplib_get_qp1_sq_buf(struct bnxt_qplib_qp *qp, + struct bnxt_qplib_sge *sge); + void *bnxt_qplib_get_qp1_rq_buf(struct bnxt_qplib_qp *qp, +@@ -500,7 +515,6 @@ void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type); + void bnxt_qplib_free_nq(struct bnxt_qplib_nq *nq); + int bnxt_qplib_alloc_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq); + void bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp); +-void bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp); + void bnxt_qplib_acquire_cq_locks(struct bnxt_qplib_qp *qp, + unsigned long *flags); + void bnxt_qplib_release_cq_locks(struct bnxt_qplib_qp *qp, +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +index 8329ec6..80027a4 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +@@ -305,9 +305,8 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw, + err_event->res_err_state_reason); + if (!qp) + break; +- bnxt_qplib_acquire_cq_locks(qp, &flags); + bnxt_qplib_mark_qp_error(qp); +- bnxt_qplib_release_cq_locks(qp, &flags); ++ rcfw->aeq_handler(rcfw, qp_event, qp); + break; + default: + /* Command Response */ +@@ -460,7 +459,11 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, + int rc; + + RCFW_CMD_PREP(req, INITIALIZE_FW, cmd_flags); +- ++ /* Supply (log-base-2-of-host-page-size - base-page-shift) ++ * to bono to adjust the doorbell page sizes. ++ */ ++ req.log2_dbr_pg_size = cpu_to_le16(PAGE_SHIFT - ++ RCFW_DBR_BASE_PAGE_SHIFT); + /* + * VFs need not setup the HW context area, PF + * shall setup this area for VF. Skipping the +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +index 6bee6e3..c7cce2e 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h ++++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +@@ -49,6 +49,7 @@ + #define RCFW_COMM_SIZE 0x104 + + #define RCFW_DBR_PCI_BAR_REGION 2 ++#define RCFW_DBR_BASE_PAGE_SHIFT 12 + + #define RCFW_CMD_PREP(req, CMD, cmd_flags) \ + do { \ +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c +index c015c18..ee98e5e 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c +@@ -52,18 +52,6 @@ const struct bnxt_qplib_gid bnxt_qplib_gid_zero = {{ 0, 0, 0, 0, 0, 0, 0, 0, + + /* Device */ + +-static bool bnxt_qplib_is_atomic_cap(struct bnxt_qplib_rcfw *rcfw) +-{ +- int rc; +- u16 pcie_ctl2; +- +- rc = pcie_capability_read_word(rcfw->pdev, PCI_EXP_DEVCTL2, +- &pcie_ctl2); +- if (rc) +- return false; +- return !!(pcie_ctl2 & PCI_EXP_DEVCTL2_ATOMIC_REQ); +-} +- + static void bnxt_qplib_query_version(struct bnxt_qplib_rcfw *rcfw, + char *fw_ver) + { +@@ -151,7 +139,8 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, + attr->max_pkey = le32_to_cpu(sb->max_pkeys); + + attr->max_inline_data = le32_to_cpu(sb->max_inline_data); +- attr->l2_db_size = (sb->l2_db_space_size + 1) * PAGE_SIZE; ++ attr->l2_db_size = (sb->l2_db_space_size + 1) * ++ (0x01 << RCFW_DBR_BASE_PAGE_SHIFT); + attr->max_sgid = le32_to_cpu(sb->max_gid); + + bnxt_qplib_query_version(rcfw, attr->fw_ver); +@@ -165,7 +154,7 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, + attr->tqm_alloc_reqs[i * 4 + 3] = *(++tqm_alloc); + } + +- attr->is_atomic = bnxt_qplib_is_atomic_cap(rcfw); ++ attr->is_atomic = 0; + bail: + bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf); + return rc; +diff --git a/drivers/infiniband/hw/bnxt_re/roce_hsi.h b/drivers/infiniband/hw/bnxt_re/roce_hsi.h +index 2d7ea09..3e5a4f7 100644 +--- a/drivers/infiniband/hw/bnxt_re/roce_hsi.h ++++ b/drivers/infiniband/hw/bnxt_re/roce_hsi.h +@@ -1761,7 +1761,30 @@ struct cmdq_initialize_fw { + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_2M (0x3UL << 4) + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_8M (0x4UL << 4) + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_1G (0x5UL << 4) +- __le16 reserved16; ++ /* This value is (log-base-2-of-DBR-page-size - 12). ++ * 0 for 4KB. HW supported values are enumerated below. ++ */ ++ __le16 log2_dbr_pg_size; ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_MASK 0xfUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_SFT 0 ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4K 0x0UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8K 0x1UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16K 0x2UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32K 0x3UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64K 0x4UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128K 0x5UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_256K 0x6UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_512K 0x7UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_1M 0x8UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_2M 0x9UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4M 0xaUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8M 0xbUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16M 0xcUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32M 0xdUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64M 0xeUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M 0xfUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_LAST \ ++ CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M + __le64 qpc_page_dir; + __le64 mrw_page_dir; + __le64 srq_page_dir; +diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c +index 9a566ee..82adc0d 100644 +--- a/drivers/infiniband/hw/mlx4/cq.c ++++ b/drivers/infiniband/hw/mlx4/cq.c +@@ -601,6 +601,7 @@ static void use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct + wc->dlid_path_bits = 0; + + if (is_eth) { ++ wc->slid = 0; + wc->vlan_id = be16_to_cpu(hdr->tun.sl_vid); + memcpy(&(wc->smac[0]), (char *)&hdr->tun.mac_31_0, 4); + memcpy(&(wc->smac[4]), (char *)&hdr->tun.slid_mac_47_32, 2); +@@ -851,7 +852,6 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, + } + } + +- wc->slid = be16_to_cpu(cqe->rlid); + g_mlpath_rqpn = be32_to_cpu(cqe->g_mlpath_rqpn); + wc->src_qp = g_mlpath_rqpn & 0xffffff; + wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f; +@@ -860,6 +860,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, + wc->wc_flags |= mlx4_ib_ipoib_csum_ok(cqe->status, + cqe->checksum) ? IB_WC_IP_CSUM_OK : 0; + if (is_eth) { ++ wc->slid = 0; + wc->sl = be16_to_cpu(cqe->sl_vid) >> 13; + if (be32_to_cpu(cqe->vlan_my_qpn) & + MLX4_CQE_CVLAN_PRESENT_MASK) { +@@ -871,6 +872,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, + memcpy(wc->smac, cqe->smac, ETH_ALEN); + wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC); + } else { ++ wc->slid = be16_to_cpu(cqe->rlid); + wc->sl = be16_to_cpu(cqe->sl_vid) >> 12; + wc->vlan_id = 0xffff; + } +diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c +index 8d2ee93..5a0e4fc 100644 +--- a/drivers/infiniband/hw/mlx4/main.c ++++ b/drivers/infiniband/hw/mlx4/main.c +@@ -219,8 +219,6 @@ static int mlx4_ib_update_gids_v1_v2(struct gid_entry *gids, + gid_tbl[i].version = 2; + if (!ipv6_addr_v4mapped((struct in6_addr *)&gids[i].gid)) + gid_tbl[i].type = 1; +- else +- memset(&gid_tbl[i].gid, 0, 12); + } + } + +@@ -366,8 +364,13 @@ static int mlx4_ib_del_gid(struct ib_device *device, + if (!gids) { + ret = -ENOMEM; + } else { +- for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) +- memcpy(&gids[i].gid, &port_gid_table->gids[i].gid, sizeof(union ib_gid)); ++ for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) { ++ memcpy(&gids[i].gid, ++ &port_gid_table->gids[i].gid, ++ sizeof(union ib_gid)); ++ gids[i].gid_type = ++ port_gid_table->gids[i].gid_type; ++ } + } + } + spin_unlock_bh(&iboe->lock); +diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c +index 5b974fb..15457c9 100644 +--- a/drivers/infiniband/hw/mlx5/cq.c ++++ b/drivers/infiniband/hw/mlx5/cq.c +@@ -226,7 +226,6 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, + wc->ex.invalidate_rkey = be32_to_cpu(cqe->imm_inval_pkey); + break; + } +- wc->slid = be16_to_cpu(cqe->slid); + wc->src_qp = be32_to_cpu(cqe->flags_rqpn) & 0xffffff; + wc->dlid_path_bits = cqe->ml_path; + g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3; +@@ -241,10 +240,12 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, + } + + if (ll != IB_LINK_LAYER_ETHERNET) { ++ wc->slid = be16_to_cpu(cqe->slid); + wc->sl = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0xf; + return; + } + ++ wc->slid = 0; + vlan_present = cqe->l4_l3_hdr_type & 0x1; + roce_packet_type = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0x3; + if (vlan_present) { +@@ -1177,7 +1178,12 @@ static int resize_user(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, + if (ucmd.reserved0 || ucmd.reserved1) + return -EINVAL; + +- umem = ib_umem_get(context, ucmd.buf_addr, entries * ucmd.cqe_size, ++ /* check multiplication overflow */ ++ if (ucmd.cqe_size && SIZE_MAX / ucmd.cqe_size <= entries - 1) ++ return -EINVAL; ++ ++ umem = ib_umem_get(context, ucmd.buf_addr, ++ (size_t)ucmd.cqe_size * entries, + IB_ACCESS_LOCAL_WRITE, 1); + if (IS_ERR(umem)) { + err = PTR_ERR(umem); +diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c +index 4236c80..033b6af 100644 +--- a/drivers/infiniband/hw/mlx5/main.c ++++ b/drivers/infiniband/hw/mlx5/main.c +@@ -245,12 +245,16 @@ struct mlx5_core_dev *mlx5_ib_get_native_port_mdev(struct mlx5_ib_dev *ibdev, + struct mlx5_ib_multiport_info *mpi; + struct mlx5_ib_port *port; + ++ if (!mlx5_core_mp_enabled(ibdev->mdev) || ++ ll != IB_LINK_LAYER_ETHERNET) { ++ if (native_port_num) ++ *native_port_num = ib_port_num; ++ return ibdev->mdev; ++ } ++ + if (native_port_num) + *native_port_num = 1; + +- if (!mlx5_core_mp_enabled(ibdev->mdev) || ll != IB_LINK_LAYER_ETHERNET) +- return ibdev->mdev; +- + port = &ibdev->port[ib_port_num - 1]; + if (!port) + return NULL; +@@ -3263,7 +3267,7 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + struct mlx5_ib_dev *ibdev; + struct ib_event ibev; + bool fatal = false; +- u8 port = 0; ++ u8 port = (u8)work->param; + + if (mlx5_core_is_mp_slave(work->dev)) { + ibdev = mlx5_ib_get_ibdev_from_mpi(work->context); +@@ -3283,8 +3287,6 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + case MLX5_DEV_EVENT_PORT_UP: + case MLX5_DEV_EVENT_PORT_DOWN: + case MLX5_DEV_EVENT_PORT_INITIALIZED: +- port = (u8)work->param; +- + /* In RoCE, port up/down events are handled in + * mlx5_netdev_event(). + */ +@@ -3298,24 +3300,19 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + + case MLX5_DEV_EVENT_LID_CHANGE: + ibev.event = IB_EVENT_LID_CHANGE; +- port = (u8)work->param; + break; + + case MLX5_DEV_EVENT_PKEY_CHANGE: + ibev.event = IB_EVENT_PKEY_CHANGE; +- port = (u8)work->param; +- + schedule_work(&ibdev->devr.ports[port - 1].pkey_change_work); + break; + + case MLX5_DEV_EVENT_GUID_CHANGE: + ibev.event = IB_EVENT_GID_CHANGE; +- port = (u8)work->param; + break; + + case MLX5_DEV_EVENT_CLIENT_REREG: + ibev.event = IB_EVENT_CLIENT_REREGISTER; +- port = (u8)work->param; + break; + case MLX5_DEV_EVENT_DELAY_DROP_TIMEOUT: + schedule_work(&ibdev->delay_drop.delay_drop_work); +@@ -3327,7 +3324,7 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + ibev.device = &ibdev->ib_dev; + ibev.element.port_num = port; + +- if (port < 1 || port > ibdev->num_ports) { ++ if (!rdma_is_port_valid(&ibdev->ib_dev, port)) { + mlx5_ib_warn(ibdev, "warning: event on port %d\n", port); + goto out; + } +diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c +index 556e015..1961c6a 100644 +--- a/drivers/infiniband/hw/mlx5/mr.c ++++ b/drivers/infiniband/hw/mlx5/mr.c +@@ -1816,7 +1816,6 @@ mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr, + + mr->ibmr.iova = sg_dma_address(sg) + sg_offset; + mr->ibmr.length = 0; +- mr->ndescs = sg_nents; + + for_each_sg(sgl, sg, sg_nents, i) { + if (unlikely(i >= mr->max_descs)) +@@ -1828,6 +1827,7 @@ mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr, + + sg_offset = 0; + } ++ mr->ndescs = i; + + if (sg_offset_p) + *sg_offset_p = sg_offset; +diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c +index 39d24bf..36197fb 100644 +--- a/drivers/infiniband/hw/mlx5/qp.c ++++ b/drivers/infiniband/hw/mlx5/qp.c +@@ -1584,6 +1584,7 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, + u32 uidx = MLX5_IB_DEFAULT_UIDX; + struct mlx5_ib_create_qp ucmd; + struct mlx5_ib_qp_base *base; ++ int mlx5_st; + void *qpc; + u32 *in; + int err; +@@ -1592,6 +1593,10 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, + spin_lock_init(&qp->sq.lock); + spin_lock_init(&qp->rq.lock); + ++ mlx5_st = to_mlx5_st(init_attr->qp_type); ++ if (mlx5_st < 0) ++ return -EINVAL; ++ + if (init_attr->rwq_ind_tbl) { + if (!udata) + return -ENOSYS; +@@ -1753,7 +1758,7 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, + + qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); + +- MLX5_SET(qpc, qpc, st, to_mlx5_st(init_attr->qp_type)); ++ MLX5_SET(qpc, qpc, st, mlx5_st); + MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); + + if (init_attr->qp_type != MLX5_IB_QPT_REG_UMR) +@@ -3095,8 +3100,10 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, + goto out; + + if (mlx5_cur >= MLX5_QP_NUM_STATE || mlx5_new >= MLX5_QP_NUM_STATE || +- !optab[mlx5_cur][mlx5_new]) ++ !optab[mlx5_cur][mlx5_new]) { ++ err = -EINVAL; + goto out; ++ } + + op = optab[mlx5_cur][mlx5_new]; + optpar = ib_mask_to_mlx5_opt(attr_mask); +diff --git a/drivers/infiniband/hw/qedr/qedr_iw_cm.c b/drivers/infiniband/hw/qedr/qedr_iw_cm.c +index 478b731..26dc374 100644 +--- a/drivers/infiniband/hw/qedr/qedr_iw_cm.c ++++ b/drivers/infiniband/hw/qedr/qedr_iw_cm.c +@@ -458,8 +458,7 @@ qedr_addr6_resolve(struct qedr_dev *dev, + } + return -EINVAL; + } +- neigh = dst_neigh_lookup(dst, &dst_in); +- ++ neigh = dst_neigh_lookup(dst, &fl6.daddr); + if (neigh) { + rcu_read_lock(); + if (neigh->nud_state & NUD_VALID) { +@@ -494,10 +493,14 @@ int qedr_iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) + + qp = idr_find(&dev->qpidr, conn_param->qpn); + +- laddr = (struct sockaddr_in *)&cm_id->local_addr; +- raddr = (struct sockaddr_in *)&cm_id->remote_addr; +- laddr6 = (struct sockaddr_in6 *)&cm_id->local_addr; +- raddr6 = (struct sockaddr_in6 *)&cm_id->remote_addr; ++ laddr = (struct sockaddr_in *)&cm_id->m_local_addr; ++ raddr = (struct sockaddr_in *)&cm_id->m_remote_addr; ++ laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr; ++ raddr6 = (struct sockaddr_in6 *)&cm_id->m_remote_addr; ++ ++ DP_DEBUG(dev, QEDR_MSG_IWARP, "MAPPED %d %d\n", ++ ntohs(((struct sockaddr_in *)&cm_id->remote_addr)->sin_port), ++ ntohs(raddr->sin_port)); + + DP_DEBUG(dev, QEDR_MSG_IWARP, + "Connect source address: %pISpc, remote address: %pISpc\n", +@@ -599,8 +602,8 @@ int qedr_iw_create_listen(struct iw_cm_id *cm_id, int backlog) + int rc; + int i; + +- laddr = (struct sockaddr_in *)&cm_id->local_addr; +- laddr6 = (struct sockaddr_in6 *)&cm_id->local_addr; ++ laddr = (struct sockaddr_in *)&cm_id->m_local_addr; ++ laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr; + + DP_DEBUG(dev, QEDR_MSG_IWARP, + "Create Listener address: %pISpc\n", &cm_id->local_addr); +diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c +index 53f00db..875b172 100644 +--- a/drivers/infiniband/hw/qedr/verbs.c ++++ b/drivers/infiniband/hw/qedr/verbs.c +@@ -3034,6 +3034,11 @@ static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + + switch (wr->opcode) { + case IB_WR_SEND_WITH_IMM: ++ if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) { ++ rc = -EINVAL; ++ *bad_wr = wr; ++ break; ++ } + wqe->req_type = RDMA_SQ_REQ_TYPE_SEND_WITH_IMM; + swqe = (struct rdma_sq_send_wqe_1st *)wqe; + swqe->wqe_size = 2; +@@ -3075,6 +3080,11 @@ static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + break; + + case IB_WR_RDMA_WRITE_WITH_IMM: ++ if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) { ++ rc = -EINVAL; ++ *bad_wr = wr; ++ break; ++ } + wqe->req_type = RDMA_SQ_REQ_TYPE_RDMA_WR_WITH_IMM; + rwqe = (struct rdma_sq_rdma_wqe_1st *)wqe; + +@@ -3724,7 +3734,7 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) + { + struct qedr_dev *dev = get_qedr_dev(ibcq->device); + struct qedr_cq *cq = get_qedr_cq(ibcq); +- union rdma_cqe *cqe = cq->latest_cqe; ++ union rdma_cqe *cqe; + u32 old_cons, new_cons; + unsigned long flags; + int update = 0; +@@ -3741,6 +3751,7 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) + return qedr_gsi_poll_cq(ibcq, num_entries, wc); + + spin_lock_irqsave(&cq->cq_lock, flags); ++ cqe = cq->latest_cqe; + old_cons = qed_chain_get_cons_idx_u32(&cq->pbl); + while (num_entries && is_valid_cqe(cq, cqe)) { + struct qedr_qp *qp; +diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c +index faa9478..f95b976 100644 +--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c ++++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c +@@ -114,6 +114,7 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev, + union pvrdma_cmd_resp rsp; + struct pvrdma_cmd_create_cq *cmd = &req.create_cq; + struct pvrdma_cmd_create_cq_resp *resp = &rsp.create_cq_resp; ++ struct pvrdma_create_cq_resp cq_resp = {0}; + struct pvrdma_create_cq ucmd; + + BUILD_BUG_ON(sizeof(struct pvrdma_cqe) != 64); +@@ -197,6 +198,7 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev, + + cq->ibcq.cqe = resp->cqe; + cq->cq_handle = resp->cq_handle; ++ cq_resp.cqn = resp->cq_handle; + spin_lock_irqsave(&dev->cq_tbl_lock, flags); + dev->cq_tbl[cq->cq_handle % dev->dsr->caps.max_cq] = cq; + spin_unlock_irqrestore(&dev->cq_tbl_lock, flags); +@@ -205,7 +207,7 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev, + cq->uar = &(to_vucontext(context)->uar); + + /* Copy udata back. */ +- if (ib_copy_to_udata(udata, &cq->cq_handle, sizeof(__u32))) { ++ if (ib_copy_to_udata(udata, &cq_resp, sizeof(cq_resp))) { + dev_warn(&dev->pdev->dev, + "failed to copy back udata\n"); + pvrdma_destroy_cq(&cq->ibcq); +diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c +index 5acebb1..af23596 100644 +--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c ++++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c +@@ -113,6 +113,7 @@ struct ib_srq *pvrdma_create_srq(struct ib_pd *pd, + union pvrdma_cmd_resp rsp; + struct pvrdma_cmd_create_srq *cmd = &req.create_srq; + struct pvrdma_cmd_create_srq_resp *resp = &rsp.create_srq_resp; ++ struct pvrdma_create_srq_resp srq_resp = {0}; + struct pvrdma_create_srq ucmd; + unsigned long flags; + int ret; +@@ -204,12 +205,13 @@ struct ib_srq *pvrdma_create_srq(struct ib_pd *pd, + } + + srq->srq_handle = resp->srqn; ++ srq_resp.srqn = resp->srqn; + spin_lock_irqsave(&dev->srq_tbl_lock, flags); + dev->srq_tbl[srq->srq_handle % dev->dsr->caps.max_srq] = srq; + spin_unlock_irqrestore(&dev->srq_tbl_lock, flags); + + /* Copy udata back. */ +- if (ib_copy_to_udata(udata, &srq->srq_handle, sizeof(__u32))) { ++ if (ib_copy_to_udata(udata, &srq_resp, sizeof(srq_resp))) { + dev_warn(&dev->pdev->dev, "failed to copy back udata\n"); + pvrdma_destroy_srq(&srq->ibsrq); + return ERR_PTR(-EINVAL); +diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c +index 16b9661..a51463c 100644 +--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c ++++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c +@@ -447,6 +447,7 @@ struct ib_pd *pvrdma_alloc_pd(struct ib_device *ibdev, + union pvrdma_cmd_resp rsp; + struct pvrdma_cmd_create_pd *cmd = &req.create_pd; + struct pvrdma_cmd_create_pd_resp *resp = &rsp.create_pd_resp; ++ struct pvrdma_alloc_pd_resp pd_resp = {0}; + int ret; + void *ptr; + +@@ -475,9 +476,10 @@ struct ib_pd *pvrdma_alloc_pd(struct ib_device *ibdev, + pd->privileged = !context; + pd->pd_handle = resp->pd_handle; + pd->pdn = resp->pd_handle; ++ pd_resp.pdn = resp->pd_handle; + + if (context) { +- if (ib_copy_to_udata(udata, &pd->pdn, sizeof(__u32))) { ++ if (ib_copy_to_udata(udata, &pd_resp, sizeof(pd_resp))) { + dev_warn(&dev->pdev->dev, + "failed to copy back protection domain\n"); + pvrdma_dealloc_pd(&pd->ibpd); +diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c +index 11f74cb..ea302b0 100644 +--- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c ++++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c +@@ -281,8 +281,6 @@ void ipoib_delete_debug_files(struct net_device *dev) + { + struct ipoib_dev_priv *priv = ipoib_priv(dev); + +- WARN_ONCE(!priv->mcg_dentry, "null mcg debug file\n"); +- WARN_ONCE(!priv->path_dentry, "null path debug file\n"); + debugfs_remove(priv->mcg_dentry); + debugfs_remove(priv->path_dentry); + priv->mcg_dentry = priv->path_dentry = NULL; +diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c +index 1f316d6..41614c1 100644 +--- a/drivers/input/keyboard/matrix_keypad.c ++++ b/drivers/input/keyboard/matrix_keypad.c +@@ -218,8 +218,10 @@ static void matrix_keypad_stop(struct input_dev *dev) + { + struct matrix_keypad *keypad = input_get_drvdata(dev); + ++ spin_lock_irq(&keypad->lock); + keypad->stopped = true; +- mb(); ++ spin_unlock_irq(&keypad->lock); ++ + flush_work(&keypad->work.work); + /* + * matrix_keypad_scan() will leave IRQs enabled; +diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c +index 3d2e23a..a246fc6 100644 +--- a/drivers/input/mouse/synaptics.c ++++ b/drivers/input/mouse/synaptics.c +@@ -173,7 +173,6 @@ static const char * const smbus_pnp_ids[] = { + "LEN0046", /* X250 */ + "LEN004a", /* W541 */ + "LEN200f", /* T450s */ +- "LEN2018", /* T460p */ + NULL + }; + +diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c +index db4f6bb..a5ab774 100644 +--- a/drivers/input/touchscreen/mms114.c ++++ b/drivers/input/touchscreen/mms114.c +@@ -1,11 +1,8 @@ +-/* +- * Copyright (C) 2012 Samsung Electronics Co.Ltd +- * Author: Joonyoung Shim +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ ++// SPDX-License-Identifier: GPL-2.0 ++// Melfas MMS114/MMS152 touchscreen device driver ++// ++// Copyright (c) 2012 Samsung Electronics Co., Ltd. ++// Author: Joonyoung Shim + + #include + #include +@@ -624,4 +621,4 @@ module_i2c_driver(mms114_driver); + /* Module information */ + MODULE_AUTHOR("Joonyoung Shim "); + MODULE_DESCRIPTION("MELFAS mms114 Touchscreen driver"); +-MODULE_LICENSE("GPL"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c +index 35a408d..99bc9bd 100644 +--- a/drivers/iommu/intel-svm.c ++++ b/drivers/iommu/intel-svm.c +@@ -205,7 +205,7 @@ static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_d + * for example, an "address" value of 0x12345f000 will + * flush from 0x123440000 to 0x12347ffff (256KiB). */ + unsigned long last = address + ((unsigned long)(pages - 1) << VTD_PAGE_SHIFT); +- unsigned long mask = __rounddown_pow_of_two(address ^ last);; ++ unsigned long mask = __rounddown_pow_of_two(address ^ last); + + desc.high = QI_DEV_EIOTLB_ADDR((address & ~mask) | (mask - 1)) | QI_DEV_EIOTLB_SIZE; + } else { +diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c +index 55cfb98..faf734f 100644 +--- a/drivers/irqchip/irq-bcm7038-l1.c ++++ b/drivers/irqchip/irq-bcm7038-l1.c +@@ -339,9 +339,6 @@ int __init bcm7038_l1_of_init(struct device_node *dn, + goto out_unmap; + } + +- pr_info("registered BCM7038 L1 intc (mem: 0x%p, IRQs: %d)\n", +- intc->cpus[0]->map_base, IRQS_PER_WORD * intc->n_words); +- + return 0; + + out_unmap: +diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c +index 983640e..8968e5e 100644 +--- a/drivers/irqchip/irq-bcm7120-l2.c ++++ b/drivers/irqchip/irq-bcm7120-l2.c +@@ -318,9 +318,6 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn, + } + } + +- pr_info("registered %s intc (mem: 0x%p, parent IRQ(s): %d)\n", +- intc_name, data->map_base[0], data->num_parent_irqs); +- + return 0; + + out_free_domain: +diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c +index 691d20e..0e65f60 100644 +--- a/drivers/irqchip/irq-brcmstb-l2.c ++++ b/drivers/irqchip/irq-brcmstb-l2.c +@@ -262,9 +262,6 @@ static int __init brcmstb_l2_intc_of_init(struct device_node *np, + ct->chip.irq_set_wake = irq_gc_set_wake; + } + +- pr_info("registered L2 intc (mem: 0x%p, parent irq: %d)\n", +- base, parent_irq); +- + return 0; + + out_free_domain: +diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c +index 993a842..1ff38af 100644 +--- a/drivers/irqchip/irq-gic-v2m.c ++++ b/drivers/irqchip/irq-gic-v2m.c +@@ -94,7 +94,7 @@ static struct irq_chip gicv2m_msi_irq_chip = { + + static struct msi_domain_info gicv2m_msi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | +- MSI_FLAG_PCI_MSIX), ++ MSI_FLAG_PCI_MSIX | MSI_FLAG_MULTI_PCI_MSI), + .chip = &gicv2m_msi_irq_chip, + }; + +@@ -155,18 +155,12 @@ static int gicv2m_irq_gic_domain_alloc(struct irq_domain *domain, + return 0; + } + +-static void gicv2m_unalloc_msi(struct v2m_data *v2m, unsigned int hwirq) ++static void gicv2m_unalloc_msi(struct v2m_data *v2m, unsigned int hwirq, ++ int nr_irqs) + { +- int pos; +- +- pos = hwirq - v2m->spi_start; +- if (pos < 0 || pos >= v2m->nr_spis) { +- pr_err("Failed to teardown msi. Invalid hwirq %d\n", hwirq); +- return; +- } +- + spin_lock(&v2m_lock); +- __clear_bit(pos, v2m->bm); ++ bitmap_release_region(v2m->bm, hwirq - v2m->spi_start, ++ get_count_order(nr_irqs)); + spin_unlock(&v2m_lock); + } + +@@ -174,13 +168,13 @@ static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs, void *args) + { + struct v2m_data *v2m = NULL, *tmp; +- int hwirq, offset, err = 0; ++ int hwirq, offset, i, err = 0; + + spin_lock(&v2m_lock); + list_for_each_entry(tmp, &v2m_nodes, entry) { +- offset = find_first_zero_bit(tmp->bm, tmp->nr_spis); +- if (offset < tmp->nr_spis) { +- __set_bit(offset, tmp->bm); ++ offset = bitmap_find_free_region(tmp->bm, tmp->nr_spis, ++ get_count_order(nr_irqs)); ++ if (offset >= 0) { + v2m = tmp; + break; + } +@@ -192,16 +186,21 @@ static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, + + hwirq = v2m->spi_start + offset; + +- err = gicv2m_irq_gic_domain_alloc(domain, virq, hwirq); +- if (err) { +- gicv2m_unalloc_msi(v2m, hwirq); +- return err; +- } ++ for (i = 0; i < nr_irqs; i++) { ++ err = gicv2m_irq_gic_domain_alloc(domain, virq + i, hwirq + i); ++ if (err) ++ goto fail; + +- irq_domain_set_hwirq_and_chip(domain, virq, hwirq, +- &gicv2m_irq_chip, v2m); ++ irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, ++ &gicv2m_irq_chip, v2m); ++ } + + return 0; ++ ++fail: ++ irq_domain_free_irqs_parent(domain, virq, nr_irqs); ++ gicv2m_unalloc_msi(v2m, hwirq, get_count_order(nr_irqs)); ++ return err; + } + + static void gicv2m_irq_domain_free(struct irq_domain *domain, +@@ -210,8 +209,7 @@ static void gicv2m_irq_domain_free(struct irq_domain *domain, + struct irq_data *d = irq_domain_get_irq_data(domain, virq); + struct v2m_data *v2m = irq_data_get_irq_chip_data(d); + +- BUG_ON(nr_irqs != 1); +- gicv2m_unalloc_msi(v2m, d->hwirq); ++ gicv2m_unalloc_msi(v2m, d->hwirq, nr_irqs); + irq_domain_free_irqs_parent(domain, virq, nr_irqs); + } + +diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c +index 14a8c0a..25a98de 100644 +--- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c ++++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c +@@ -132,6 +132,8 @@ static int __init its_pci_of_msi_init(void) + + for (np = of_find_matching_node(NULL, its_device_id); np; + np = of_find_matching_node(np, its_device_id)) { ++ if (!of_device_is_available(np)) ++ continue; + if (!of_property_read_bool(np, "msi-controller")) + continue; + +diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c +index 833a90f..8881a05 100644 +--- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c ++++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c +@@ -154,6 +154,8 @@ static void __init its_pmsi_of_init(void) + + for (np = of_find_matching_node(NULL, its_device_id); np; + np = of_find_matching_node(np, its_device_id)) { ++ if (!of_device_is_available(np)) ++ continue; + if (!of_property_read_bool(np, "msi-controller")) + continue; + +diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c +index 06f025f..1d3056f 100644 +--- a/drivers/irqchip/irq-gic-v3-its.c ++++ b/drivers/irqchip/irq-gic-v3-its.c +@@ -3314,6 +3314,8 @@ static int __init its_of_probe(struct device_node *node) + + for (np = of_find_matching_node(node, its_device_id); np; + np = of_find_matching_node(np, its_device_id)) { ++ if (!of_device_is_available(np)) ++ continue; + if (!of_property_read_bool(np, "msi-controller")) { + pr_warn("%pOF: no msi-controller property, ITS ignored\n", + np); +diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c +index a57c0fb..d99cc07 100644 +--- a/drivers/irqchip/irq-gic-v3.c ++++ b/drivers/irqchip/irq-gic-v3.c +@@ -673,7 +673,7 @@ static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq) + MPIDR_TO_SGI_RS(cluster_id) | + tlist << ICC_SGI1R_TARGET_LIST_SHIFT); + +- pr_debug("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val); ++ pr_devel("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val); + gic_write_sgi1r(val); + } + +@@ -688,7 +688,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) + * Ensure that stores to Normal memory are visible to the + * other CPUs before issuing the IPI. + */ +- smp_wmb(); ++ wmb(); + + for_each_cpu(cpu, mask) { + u64 cluster_id = MPIDR_TO_SGI_CLUSTER_ID(cpu_logical_map(cpu)); +diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c +index ef92a4d..d32268c 100644 +--- a/drivers/irqchip/irq-mips-gic.c ++++ b/drivers/irqchip/irq-mips-gic.c +@@ -424,8 +424,6 @@ static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq, + spin_lock_irqsave(&gic_lock, flags); + write_gic_map_pin(intr, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin); + write_gic_map_vp(intr, BIT(mips_cm_vp_id(cpu))); +- gic_clear_pcpu_masks(intr); +- set_bit(intr, per_cpu_ptr(pcpu_masks, cpu)); + irq_data_update_effective_affinity(data, cpumask_of(cpu)); + spin_unlock_irqrestore(&gic_lock, flags); + +diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c +index 62f541f..0707482 100644 +--- a/drivers/macintosh/macio_asic.c ++++ b/drivers/macintosh/macio_asic.c +@@ -375,6 +375,7 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, + dev->ofdev.dev.of_node = np; + dev->ofdev.archdata.dma_mask = 0xffffffffUL; + dev->ofdev.dev.dma_mask = &dev->ofdev.archdata.dma_mask; ++ dev->ofdev.dev.coherent_dma_mask = dev->ofdev.archdata.dma_mask; + dev->ofdev.dev.parent = parent; + dev->ofdev.dev.bus = &macio_bus_type; + dev->ofdev.dev.release = macio_release_dev; +diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c +index 1a46b41..6422846 100644 +--- a/drivers/md/bcache/request.c ++++ b/drivers/md/bcache/request.c +@@ -659,11 +659,11 @@ static void do_bio_hook(struct search *s, struct bio *orig_bio) + static void search_free(struct closure *cl) + { + struct search *s = container_of(cl, struct search, cl); +- bio_complete(s); + + if (s->iop.bio) + bio_put(s->iop.bio); + ++ bio_complete(s); + closure_debug_destroy(cl); + mempool_free(s, s->d->c->search); + } +diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c +index 3128957..f227314 100644 +--- a/drivers/md/bcache/super.c ++++ b/drivers/md/bcache/super.c +@@ -963,6 +963,7 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, + uint32_t rtime = cpu_to_le32(get_seconds()); + struct uuid_entry *u; + char buf[BDEVNAME_SIZE]; ++ struct cached_dev *exist_dc, *t; + + bdevname(dc->bdev, buf); + +@@ -987,6 +988,16 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, + return -EINVAL; + } + ++ /* Check whether already attached */ ++ list_for_each_entry_safe(exist_dc, t, &c->cached_devs, list) { ++ if (!memcmp(dc->sb.uuid, exist_dc->sb.uuid, 16)) { ++ pr_err("Tried to attach %s but duplicate UUID already attached", ++ buf); ++ ++ return -EINVAL; ++ } ++ } ++ + u = uuid_find(c, dc->sb.uuid); + + if (u && +@@ -1204,7 +1215,7 @@ static void register_bdev(struct cache_sb *sb, struct page *sb_page, + + return; + err: +- pr_notice("error opening %s: %s", bdevname(bdev, name), err); ++ pr_notice("error %s: %s", bdevname(bdev, name), err); + bcache_device_stop(&dc->disk); + } + +@@ -1274,7 +1285,7 @@ static int flash_devs_run(struct cache_set *c) + struct uuid_entry *u; + + for (u = c->uuids; +- u < c->uuids + c->devices_max_used && !ret; ++ u < c->uuids + c->nr_uuids && !ret; + u++) + if (UUID_FLASH_ONLY(u)) + ret = flash_dev_run(c, u); +@@ -1883,6 +1894,8 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page, + const char *err = NULL; /* must be set for any error case */ + int ret = 0; + ++ bdevname(bdev, name); ++ + memcpy(&ca->sb, sb, sizeof(struct cache_sb)); + ca->bdev = bdev; + ca->bdev->bd_holder = ca; +@@ -1891,11 +1904,12 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page, + bio_first_bvec_all(&ca->sb_bio)->bv_page = sb_page; + get_page(sb_page); + +- if (blk_queue_discard(bdev_get_queue(ca->bdev))) ++ if (blk_queue_discard(bdev_get_queue(bdev))) + ca->discard = CACHE_DISCARD(&ca->sb); + + ret = cache_alloc(ca); + if (ret != 0) { ++ blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); + if (ret == -ENOMEM) + err = "cache_alloc(): -ENOMEM"; + else +@@ -1918,14 +1932,14 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page, + goto out; + } + +- pr_info("registered cache device %s", bdevname(bdev, name)); ++ pr_info("registered cache device %s", name); + + out: + kobject_put(&ca->kobj); + + err: + if (err) +- pr_notice("error opening %s: %s", bdevname(bdev, name), err); ++ pr_notice("error %s: %s", name, err); + + return ret; + } +@@ -2014,6 +2028,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, + if (err) + goto err_close; + ++ err = "failed to register device"; + if (SB_IS_BDEV(sb)) { + struct cached_dev *dc = kzalloc(sizeof(*dc), GFP_KERNEL); + if (!dc) +@@ -2028,7 +2043,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, + goto err_close; + + if (register_cache(sb, sb_page, bdev, ca) != 0) +- goto err_close; ++ goto err; + } + out: + if (sb_page) +@@ -2041,7 +2056,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, + err_close: + blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); + err: +- pr_info("error opening %s: %s", path, err); ++ pr_info("error %s: %s", path, err); + ret = -EINVAL; + goto out; + } +diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c +index 414c9af..aa2032f 100644 +--- a/drivers/md/dm-bufio.c ++++ b/drivers/md/dm-bufio.c +@@ -386,9 +386,6 @@ static void __cache_size_refresh(void) + static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, + enum data_mode *data_mode) + { +- unsigned noio_flag; +- void *ptr; +- + if (c->block_size <= DM_BUFIO_BLOCK_SIZE_SLAB_LIMIT) { + *data_mode = DATA_MODE_SLAB; + return kmem_cache_alloc(DM_BUFIO_CACHE(c), gfp_mask); +@@ -412,16 +409,15 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, + * all allocations done by this process (including pagetables) are done + * as if GFP_NOIO was specified. + */ ++ if (gfp_mask & __GFP_NORETRY) { ++ unsigned noio_flag = memalloc_noio_save(); ++ void *ptr = __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL); + +- if (gfp_mask & __GFP_NORETRY) +- noio_flag = memalloc_noio_save(); +- +- ptr = __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL); +- +- if (gfp_mask & __GFP_NORETRY) + memalloc_noio_restore(noio_flag); ++ return ptr; ++ } + +- return ptr; ++ return __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL); + } + + /* +diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c +index 7d3e572..3fde9e9 100644 +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -211,25 +212,13 @@ static int alloc_multipath_stage2(struct dm_target *ti, struct multipath *m) + else + m->queue_mode = DM_TYPE_REQUEST_BASED; + +- } else if (m->queue_mode == DM_TYPE_BIO_BASED || +- m->queue_mode == DM_TYPE_NVME_BIO_BASED) { ++ } else if (m->queue_mode == DM_TYPE_BIO_BASED) { + INIT_WORK(&m->process_queued_bios, process_queued_bios); +- +- if (m->queue_mode == DM_TYPE_BIO_BASED) { +- /* +- * bio-based doesn't support any direct scsi_dh management; +- * it just discovers if a scsi_dh is attached. +- */ +- set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags); +- } +- } +- +- if (m->queue_mode != DM_TYPE_NVME_BIO_BASED) { +- set_bit(MPATHF_QUEUE_IO, &m->flags); +- atomic_set(&m->pg_init_in_progress, 0); +- atomic_set(&m->pg_init_count, 0); +- m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT; +- init_waitqueue_head(&m->pg_init_wait); ++ /* ++ * bio-based doesn't support any direct scsi_dh management; ++ * it just discovers if a scsi_dh is attached. ++ */ ++ set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags); + } + + dm_table_set_type(ti->table, m->queue_mode); +@@ -337,14 +326,12 @@ static void __switch_pg(struct multipath *m, struct priority_group *pg) + { + m->current_pg = pg; + +- if (m->queue_mode == DM_TYPE_NVME_BIO_BASED) +- return; +- + /* Must we initialise the PG first, and queue I/O till it's ready? */ + if (m->hw_handler_name) { + set_bit(MPATHF_PG_INIT_REQUIRED, &m->flags); + set_bit(MPATHF_QUEUE_IO, &m->flags); + } else { ++ /* FIXME: not needed if no scsi_dh is attached */ + clear_bit(MPATHF_PG_INIT_REQUIRED, &m->flags); + clear_bit(MPATHF_QUEUE_IO, &m->flags); + } +@@ -385,8 +372,7 @@ static struct pgpath *choose_pgpath(struct multipath *m, size_t nr_bytes) + unsigned bypassed = 1; + + if (!atomic_read(&m->nr_valid_paths)) { +- if (m->queue_mode != DM_TYPE_NVME_BIO_BASED) +- clear_bit(MPATHF_QUEUE_IO, &m->flags); ++ clear_bit(MPATHF_QUEUE_IO, &m->flags); + goto failed; + } + +@@ -599,7 +585,7 @@ static struct pgpath *__map_bio(struct multipath *m, struct bio *bio) + return pgpath; + } + +-static struct pgpath *__map_bio_nvme(struct multipath *m, struct bio *bio) ++static struct pgpath *__map_bio_fast(struct multipath *m, struct bio *bio) + { + struct pgpath *pgpath; + unsigned long flags; +@@ -634,8 +620,8 @@ static int __multipath_map_bio(struct multipath *m, struct bio *bio, + { + struct pgpath *pgpath; + +- if (m->queue_mode == DM_TYPE_NVME_BIO_BASED) +- pgpath = __map_bio_nvme(m, bio); ++ if (!m->hw_handler_name) ++ pgpath = __map_bio_fast(m, bio); + else + pgpath = __map_bio(m, bio); + +@@ -675,8 +661,7 @@ static void process_queued_io_list(struct multipath *m) + { + if (m->queue_mode == DM_TYPE_MQ_REQUEST_BASED) + dm_mq_kick_requeue_list(dm_table_get_md(m->ti->table)); +- else if (m->queue_mode == DM_TYPE_BIO_BASED || +- m->queue_mode == DM_TYPE_NVME_BIO_BASED) ++ else if (m->queue_mode == DM_TYPE_BIO_BASED) + queue_work(kmultipathd, &m->process_queued_bios); + } + +@@ -838,6 +823,16 @@ static int setup_scsi_dh(struct block_device *bdev, struct multipath *m, char ** + */ + kfree(m->hw_handler_name); + m->hw_handler_name = attached_handler_name; ++ ++ /* ++ * Init fields that are only used when a scsi_dh is attached ++ */ ++ if (!test_and_set_bit(MPATHF_QUEUE_IO, &m->flags)) { ++ atomic_set(&m->pg_init_in_progress, 0); ++ atomic_set(&m->pg_init_count, 0); ++ m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT; ++ init_waitqueue_head(&m->pg_init_wait); ++ } + } + } + +@@ -873,6 +868,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps + int r; + struct pgpath *p; + struct multipath *m = ti->private; ++ struct scsi_device *sdev; + + /* we need at least a path arg */ + if (as->argc < 1) { +@@ -891,7 +887,9 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps + goto bad; + } + +- if (m->queue_mode != DM_TYPE_NVME_BIO_BASED) { ++ sdev = scsi_device_from_queue(bdev_get_queue(p->path.dev->bdev)); ++ if (sdev) { ++ put_device(&sdev->sdev_gendev); + INIT_DELAYED_WORK(&p->activate_path, activate_path_work); + r = setup_scsi_dh(p->path.dev->bdev, m, &ti->error); + if (r) { +@@ -1001,8 +999,7 @@ static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m) + if (!hw_argc) + return 0; + +- if (m->queue_mode == DM_TYPE_BIO_BASED || +- m->queue_mode == DM_TYPE_NVME_BIO_BASED) { ++ if (m->queue_mode == DM_TYPE_BIO_BASED) { + dm_consume_args(as, hw_argc); + DMERR("bio-based multipath doesn't allow hardware handler args"); + return 0; +@@ -1091,8 +1088,6 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) + + if (!strcasecmp(queue_mode_name, "bio")) + m->queue_mode = DM_TYPE_BIO_BASED; +- else if (!strcasecmp(queue_mode_name, "nvme")) +- m->queue_mode = DM_TYPE_NVME_BIO_BASED; + else if (!strcasecmp(queue_mode_name, "rq")) + m->queue_mode = DM_TYPE_REQUEST_BASED; + else if (!strcasecmp(queue_mode_name, "mq")) +@@ -1193,7 +1188,7 @@ static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv) + ti->num_discard_bios = 1; + ti->num_write_same_bios = 1; + ti->num_write_zeroes_bios = 1; +- if (m->queue_mode == DM_TYPE_BIO_BASED || m->queue_mode == DM_TYPE_NVME_BIO_BASED) ++ if (m->queue_mode == DM_TYPE_BIO_BASED) + ti->per_io_data_size = multipath_per_bio_data_size(); + else + ti->per_io_data_size = sizeof(struct dm_mpath_io); +@@ -1730,9 +1725,6 @@ static void multipath_status(struct dm_target *ti, status_type_t type, + case DM_TYPE_BIO_BASED: + DMEMIT("queue_mode bio "); + break; +- case DM_TYPE_NVME_BIO_BASED: +- DMEMIT("queue_mode nvme "); +- break; + case DM_TYPE_MQ_REQUEST_BASED: + DMEMIT("queue_mode mq "); + break; +diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c +index 7ef469e..c1d1034 100644 +--- a/drivers/md/dm-raid.c ++++ b/drivers/md/dm-raid.c +@@ -3408,9 +3408,10 @@ static sector_t rs_get_progress(struct raid_set *rs, unsigned long recovery, + set_bit(RT_FLAG_RS_IN_SYNC, &rs->runtime_flags); + + } else { +- if (test_bit(MD_RECOVERY_NEEDED, &recovery) || +- test_bit(MD_RECOVERY_RESHAPE, &recovery) || +- test_bit(MD_RECOVERY_RUNNING, &recovery)) ++ if (!test_bit(MD_RECOVERY_INTR, &recovery) && ++ (test_bit(MD_RECOVERY_NEEDED, &recovery) || ++ test_bit(MD_RECOVERY_RESHAPE, &recovery) || ++ test_bit(MD_RECOVERY_RUNNING, &recovery))) + r = mddev->curr_resync_completed; + else + r = mddev->recovery_cp; +diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c +index 5fe7ec3..7eb3e2a 100644 +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -942,17 +942,12 @@ static int dm_table_determine_type(struct dm_table *t) + + if (t->type != DM_TYPE_NONE) { + /* target already set the table's type */ +- if (t->type == DM_TYPE_BIO_BASED) +- return 0; +- else if (t->type == DM_TYPE_NVME_BIO_BASED) { +- if (!dm_table_does_not_support_partial_completion(t)) { +- DMERR("nvme bio-based is only possible with devices" +- " that don't support partial completion"); +- return -EINVAL; +- } +- /* Fallthru, also verify all devices are blk-mq */ ++ if (t->type == DM_TYPE_BIO_BASED) { ++ /* possibly upgrade to a variant of bio-based */ ++ goto verify_bio_based; + } + BUG_ON(t->type == DM_TYPE_DAX_BIO_BASED); ++ BUG_ON(t->type == DM_TYPE_NVME_BIO_BASED); + goto verify_rq_based; + } + +@@ -985,6 +980,7 @@ static int dm_table_determine_type(struct dm_table *t) + } + + if (bio_based) { ++verify_bio_based: + /* We must use this table as bio-based */ + t->type = DM_TYPE_BIO_BASED; + if (dm_table_supports_dax(t) || +@@ -1755,7 +1751,7 @@ static int device_no_partial_completion(struct dm_target *ti, struct dm_dev *dev + char b[BDEVNAME_SIZE]; + + /* For now, NVMe devices are the only devices of this class */ +- return (strncmp(bdevname(dev->bdev, b), "nvme", 3) == 0); ++ return (strncmp(bdevname(dev->bdev, b), "nvme", 4) == 0); + } + + static bool dm_table_does_not_support_partial_completion(struct dm_table *t) +diff --git a/drivers/md/dm.c b/drivers/md/dm.c +index d6de00f..45328d8 100644 +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -458,9 +458,11 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) + return dm_get_geometry(md, geo); + } + +-static int dm_grab_bdev_for_ioctl(struct mapped_device *md, +- struct block_device **bdev, +- fmode_t *mode) ++static char *_dm_claim_ptr = "I belong to device-mapper"; ++ ++static int dm_get_bdev_for_ioctl(struct mapped_device *md, ++ struct block_device **bdev, ++ fmode_t *mode) + { + struct dm_target *tgt; + struct dm_table *map; +@@ -490,6 +492,10 @@ static int dm_grab_bdev_for_ioctl(struct mapped_device *md, + goto out; + + bdgrab(*bdev); ++ r = blkdev_get(*bdev, *mode, _dm_claim_ptr); ++ if (r < 0) ++ goto out; ++ + dm_put_live_table(md, srcu_idx); + return r; + +@@ -508,7 +514,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, + struct mapped_device *md = bdev->bd_disk->private_data; + int r; + +- r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); ++ r = dm_get_bdev_for_ioctl(md, &bdev, &mode); + if (r < 0) + return r; + +@@ -528,7 +534,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, + + r = __blkdev_driver_ioctl(bdev, mode, cmd, arg); + out: +- bdput(bdev); ++ blkdev_put(bdev, mode); + return r; + } + +@@ -708,14 +714,13 @@ static void dm_put_live_table_fast(struct mapped_device *md) __releases(RCU) + static int open_table_device(struct table_device *td, dev_t dev, + struct mapped_device *md) + { +- static char *_claim_ptr = "I belong to device-mapper"; + struct block_device *bdev; + + int r; + + BUG_ON(td->dm_dev.bdev); + +- bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _claim_ptr); ++ bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _dm_claim_ptr); + if (IS_ERR(bdev)) + return PTR_ERR(bdev); + +@@ -903,7 +908,8 @@ static void dec_pending(struct dm_io *io, blk_status_t error) + queue_io(md, bio); + } else { + /* done with normal IO or empty flush */ +- bio->bi_status = io_error; ++ if (io_error) ++ bio->bi_status = io_error; + bio_endio(bio); + } + } +@@ -3010,7 +3016,7 @@ static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type, + fmode_t mode; + int r; + +- r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); ++ r = dm_get_bdev_for_ioctl(md, &bdev, &mode); + if (r < 0) + return r; + +@@ -3020,7 +3026,7 @@ static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type, + else + r = -EOPNOTSUPP; + +- bdput(bdev); ++ blkdev_put(bdev, mode); + return r; + } + +@@ -3031,7 +3037,7 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type) + fmode_t mode; + int r; + +- r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); ++ r = dm_get_bdev_for_ioctl(md, &bdev, &mode); + if (r < 0) + return r; + +@@ -3041,7 +3047,7 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type) + else + r = -EOPNOTSUPP; + +- bdput(bdev); ++ blkdev_put(bdev, mode); + return r; + } + +@@ -3053,7 +3059,7 @@ static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key, + fmode_t mode; + int r; + +- r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); ++ r = dm_get_bdev_for_ioctl(md, &bdev, &mode); + if (r < 0) + return r; + +@@ -3063,7 +3069,7 @@ static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key, + else + r = -EOPNOTSUPP; + +- bdput(bdev); ++ blkdev_put(bdev, mode); + return r; + } + +@@ -3074,7 +3080,7 @@ static int dm_pr_clear(struct block_device *bdev, u64 key) + fmode_t mode; + int r; + +- r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); ++ r = dm_get_bdev_for_ioctl(md, &bdev, &mode); + if (r < 0) + return r; + +@@ -3084,7 +3090,7 @@ static int dm_pr_clear(struct block_device *bdev, u64 key) + else + r = -EOPNOTSUPP; + +- bdput(bdev); ++ blkdev_put(bdev, mode); + return r; + } + +diff --git a/drivers/md/md-multipath.c b/drivers/md/md-multipath.c +index e40065b..0a7e99d 100644 +--- a/drivers/md/md-multipath.c ++++ b/drivers/md/md-multipath.c +@@ -157,7 +157,7 @@ static void multipath_status(struct seq_file *seq, struct mddev *mddev) + seq_printf (seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_"); + } + rcu_read_unlock(); +- seq_printf (seq, "]"); ++ seq_putc(seq, ']'); + } + + static int multipath_congested(struct mddev *mddev, int bits) +diff --git a/drivers/md/md.c b/drivers/md/md.c +index bc67ab6..254e44e 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -801,6 +801,9 @@ void md_super_write(struct mddev *mddev, struct md_rdev *rdev, + struct bio *bio; + int ff = 0; + ++ if (!page) ++ return; ++ + if (test_bit(Faulty, &rdev->flags)) + return; + +@@ -5452,6 +5455,7 @@ int md_run(struct mddev *mddev) + * the only valid external interface is through the md + * device. + */ ++ mddev->has_superblocks = false; + rdev_for_each(rdev, mddev) { + if (test_bit(Faulty, &rdev->flags)) + continue; +@@ -5465,6 +5469,9 @@ int md_run(struct mddev *mddev) + set_disk_ro(mddev->gendisk, 1); + } + ++ if (rdev->sb_page) ++ mddev->has_superblocks = true; ++ + /* perform some consistency tests on the device. + * We don't want the data to overlap the metadata, + * Internal Bitmap issues have been handled elsewhere. +@@ -5497,8 +5504,10 @@ int md_run(struct mddev *mddev) + } + if (mddev->sync_set == NULL) { + mddev->sync_set = bioset_create(BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); +- if (!mddev->sync_set) +- return -ENOMEM; ++ if (!mddev->sync_set) { ++ err = -ENOMEM; ++ goto abort; ++ } + } + + spin_lock(&pers_lock); +@@ -5511,7 +5520,8 @@ int md_run(struct mddev *mddev) + else + pr_warn("md: personality for level %s is not loaded!\n", + mddev->clevel); +- return -EINVAL; ++ err = -EINVAL; ++ goto abort; + } + spin_unlock(&pers_lock); + if (mddev->level != pers->level) { +@@ -5524,7 +5534,8 @@ int md_run(struct mddev *mddev) + pers->start_reshape == NULL) { + /* This personality cannot handle reshaping... */ + module_put(pers->owner); +- return -EINVAL; ++ err = -EINVAL; ++ goto abort; + } + + if (pers->sync_request) { +@@ -5593,7 +5604,7 @@ int md_run(struct mddev *mddev) + mddev->private = NULL; + module_put(pers->owner); + bitmap_destroy(mddev); +- return err; ++ goto abort; + } + if (mddev->queue) { + bool nonrot = true; +@@ -5655,6 +5666,18 @@ int md_run(struct mddev *mddev) + sysfs_notify_dirent_safe(mddev->sysfs_action); + sysfs_notify(&mddev->kobj, NULL, "degraded"); + return 0; ++ ++abort: ++ if (mddev->bio_set) { ++ bioset_free(mddev->bio_set); ++ mddev->bio_set = NULL; ++ } ++ if (mddev->sync_set) { ++ bioset_free(mddev->sync_set); ++ mddev->sync_set = NULL; ++ } ++ ++ return err; + } + EXPORT_SYMBOL_GPL(md_run); + +@@ -8049,6 +8072,7 @@ EXPORT_SYMBOL(md_done_sync); + bool md_write_start(struct mddev *mddev, struct bio *bi) + { + int did_change = 0; ++ + if (bio_data_dir(bi) != WRITE) + return true; + +@@ -8081,6 +8105,8 @@ bool md_write_start(struct mddev *mddev, struct bio *bi) + rcu_read_unlock(); + if (did_change) + sysfs_notify_dirent_safe(mddev->sysfs_state); ++ if (!mddev->has_superblocks) ++ return true; + wait_event(mddev->sb_wait, + !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags) || + mddev->suspended); +@@ -8543,6 +8569,19 @@ void md_do_sync(struct md_thread *thread) + set_mask_bits(&mddev->sb_flags, 0, + BIT(MD_SB_CHANGE_PENDING) | BIT(MD_SB_CHANGE_DEVS)); + ++ if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && ++ !test_bit(MD_RECOVERY_INTR, &mddev->recovery) && ++ mddev->delta_disks > 0 && ++ mddev->pers->finish_reshape && ++ mddev->pers->size && ++ mddev->queue) { ++ mddev_lock_nointr(mddev); ++ md_set_array_sectors(mddev, mddev->pers->size(mddev, 0, 0)); ++ mddev_unlock(mddev); ++ set_capacity(mddev->gendisk, mddev->array_sectors); ++ revalidate_disk(mddev->gendisk); ++ } ++ + spin_lock(&mddev->lock); + if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { + /* We completed so min/max setting can be forgotten if used. */ +@@ -8569,6 +8608,10 @@ static int remove_and_add_spares(struct mddev *mddev, + int removed = 0; + bool remove_some = false; + ++ if (this && test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) ++ /* Mustn't remove devices when resync thread is running */ ++ return 0; ++ + rdev_for_each(rdev, mddev) { + if ((this == NULL || rdev == this) && + rdev->raid_disk >= 0 && +diff --git a/drivers/md/md.h b/drivers/md/md.h +index 58cd20a..fbc925c 100644 +--- a/drivers/md/md.h ++++ b/drivers/md/md.h +@@ -468,6 +468,8 @@ struct mddev { + void (*sync_super)(struct mddev *mddev, struct md_rdev *rdev); + struct md_cluster_info *cluster_info; + unsigned int good_device_nr; /* good device num within cluster raid */ ++ ++ bool has_superblocks:1; + }; + + enum recovery_flags { +diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c +index b2eae33..fe872dc 100644 +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -1108,7 +1108,7 @@ static void alloc_behind_master_bio(struct r1bio *r1_bio, + + bio_copy_data(behind_bio, bio); + skip_copy: +- r1_bio->behind_master_bio = behind_bio;; ++ r1_bio->behind_master_bio = behind_bio; + set_bit(R1BIO_BehindIO, &r1_bio->state); + + return; +@@ -1809,6 +1809,17 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev) + struct md_rdev *repl = + conf->mirrors[conf->raid_disks + number].rdev; + freeze_array(conf, 0); ++ if (atomic_read(&repl->nr_pending)) { ++ /* It means that some queued IO of retry_list ++ * hold repl. Thus, we cannot set replacement ++ * as NULL, avoiding rdev NULL pointer ++ * dereference in sync_request_write and ++ * handle_write_finished. ++ */ ++ err = -EBUSY; ++ unfreeze_array(conf); ++ goto abort; ++ } + clear_bit(Replacement, &repl->flags); + p->rdev = repl; + conf->mirrors[conf->raid_disks + number].rdev = NULL; +diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h +index c7294e7..eb84bc6 100644 +--- a/drivers/md/raid1.h ++++ b/drivers/md/raid1.h +@@ -26,6 +26,18 @@ + #define BARRIER_BUCKETS_NR_BITS (PAGE_SHIFT - ilog2(sizeof(atomic_t))) + #define BARRIER_BUCKETS_NR (1<reconfig_mutex ++ * 2/ when resync/recovery is known to be happening - i.e. in code that is ++ * called as part of performing resync/recovery. ++ * 3/ while holding rcu_read_lock(), use rcu_dereference to get the pointer ++ * and if it is non-NULL, increment rdev->nr_pending before dropping the ++ * RCU lock. ++ * When .rdev is set to NULL, the nr_pending count checked again and if it has ++ * been incremented, the pointer is put back in .rdev. ++ */ ++ + struct raid1_info { + struct md_rdev *rdev; + sector_t head_position; +diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c +index 99c9207..c5e6c60 100644 +--- a/drivers/md/raid10.c ++++ b/drivers/md/raid10.c +@@ -141,7 +141,7 @@ static void r10bio_pool_free(void *r10_bio, void *data) + #define RESYNC_WINDOW (1024*1024) + /* maximum number of concurrent requests, memory permitting */ + #define RESYNC_DEPTH (32*1024*1024/RESYNC_BLOCK_SIZE) +-#define CLUSTER_RESYNC_WINDOW (16 * RESYNC_WINDOW) ++#define CLUSTER_RESYNC_WINDOW (32 * RESYNC_WINDOW) + #define CLUSTER_RESYNC_WINDOW_SECTORS (CLUSTER_RESYNC_WINDOW >> 9) + + /* +@@ -2655,7 +2655,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) + for (m = 0; m < conf->copies; m++) { + int dev = r10_bio->devs[m].devnum; + rdev = conf->mirrors[dev].rdev; +- if (r10_bio->devs[m].bio == NULL) ++ if (r10_bio->devs[m].bio == NULL || ++ r10_bio->devs[m].bio->bi_end_io == NULL) + continue; + if (!r10_bio->devs[m].bio->bi_status) { + rdev_clear_badblocks( +@@ -2670,7 +2671,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) + md_error(conf->mddev, rdev); + } + rdev = conf->mirrors[dev].replacement; +- if (r10_bio->devs[m].repl_bio == NULL) ++ if (r10_bio->devs[m].repl_bio == NULL || ++ r10_bio->devs[m].repl_bio->bi_end_io == NULL) + continue; + + if (!r10_bio->devs[m].repl_bio->bi_status) { +@@ -3782,7 +3784,7 @@ static int raid10_run(struct mddev *mddev) + if (fc > 1 || fo > 0) { + pr_err("only near layout is supported by clustered" + " raid10\n"); +- goto out; ++ goto out_free_conf; + } + } + +@@ -4830,17 +4832,11 @@ static void raid10_finish_reshape(struct mddev *mddev) + return; + + if (mddev->delta_disks > 0) { +- sector_t size = raid10_size(mddev, 0, 0); +- md_set_array_sectors(mddev, size); + if (mddev->recovery_cp > mddev->resync_max_sectors) { + mddev->recovery_cp = mddev->resync_max_sectors; + set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); + } +- mddev->resync_max_sectors = size; +- if (mddev->queue) { +- set_capacity(mddev->gendisk, mddev->array_sectors); +- revalidate_disk(mddev->gendisk); +- } ++ mddev->resync_max_sectors = mddev->array_sectors; + } else { + int d; + rcu_read_lock(); +diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h +index db2ac22..e2e8840 100644 +--- a/drivers/md/raid10.h ++++ b/drivers/md/raid10.h +@@ -2,6 +2,19 @@ + #ifndef _RAID10_H + #define _RAID10_H + ++/* Note: raid10_info.rdev can be set to NULL asynchronously by ++ * raid10_remove_disk. ++ * There are three safe ways to access raid10_info.rdev. ++ * 1/ when holding mddev->reconfig_mutex ++ * 2/ when resync/recovery/reshape is known to be happening - i.e. in code ++ * that is called as part of performing resync/recovery/reshape. ++ * 3/ while holding rcu_read_lock(), use rcu_dereference to get the pointer ++ * and if it is non-NULL, increment rdev->nr_pending before dropping the ++ * RCU lock. ++ * When .rdev is set to NULL, the nr_pending count checked again and if it has ++ * been incremented, the pointer is put back in .rdev. ++ */ ++ + struct raid10_info { + struct md_rdev *rdev, *replacement; + sector_t head_position; +diff --git a/drivers/md/raid5-log.h b/drivers/md/raid5-log.h +index 0c76bce..a001808 100644 +--- a/drivers/md/raid5-log.h ++++ b/drivers/md/raid5-log.h +@@ -44,6 +44,7 @@ extern void ppl_write_stripe_run(struct r5conf *conf); + extern void ppl_stripe_write_finished(struct stripe_head *sh); + extern int ppl_modify_log(struct r5conf *conf, struct md_rdev *rdev, bool add); + extern void ppl_quiesce(struct r5conf *conf, int quiesce); ++extern int ppl_handle_flush_request(struct r5l_log *log, struct bio *bio); + + static inline bool raid5_has_ppl(struct r5conf *conf) + { +@@ -104,7 +105,7 @@ static inline int log_handle_flush_request(struct r5conf *conf, struct bio *bio) + if (conf->log) + ret = r5l_handle_flush_request(conf->log, bio); + else if (raid5_has_ppl(conf)) +- ret = 0; ++ ret = ppl_handle_flush_request(conf->log, bio); + + return ret; + } +diff --git a/drivers/md/raid5-ppl.c b/drivers/md/raid5-ppl.c +index 2764c22..42890a08 100644 +--- a/drivers/md/raid5-ppl.c ++++ b/drivers/md/raid5-ppl.c +@@ -693,6 +693,16 @@ void ppl_quiesce(struct r5conf *conf, int quiesce) + } + } + ++int ppl_handle_flush_request(struct r5l_log *log, struct bio *bio) ++{ ++ if (bio->bi_iter.bi_size == 0) { ++ bio_endio(bio); ++ return 0; ++ } ++ bio->bi_opf &= ~REQ_PREFLUSH; ++ return -EAGAIN; ++} ++ + void ppl_stripe_write_finished(struct stripe_head *sh) + { + struct ppl_io_unit *io; +diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c +index 50d0114..b5d2601 100644 +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -2196,15 +2196,16 @@ static int grow_one_stripe(struct r5conf *conf, gfp_t gfp) + static int grow_stripes(struct r5conf *conf, int num) + { + struct kmem_cache *sc; ++ size_t namelen = sizeof(conf->cache_name[0]); + int devs = max(conf->raid_disks, conf->previous_raid_disks); + + if (conf->mddev->gendisk) +- sprintf(conf->cache_name[0], ++ snprintf(conf->cache_name[0], namelen, + "raid%d-%s", conf->level, mdname(conf->mddev)); + else +- sprintf(conf->cache_name[0], ++ snprintf(conf->cache_name[0], namelen, + "raid%d-%p", conf->level, conf->mddev); +- sprintf(conf->cache_name[1], "%s-alt", conf->cache_name[0]); ++ snprintf(conf->cache_name[1], namelen, "%.27s-alt", conf->cache_name[0]); + + conf->active_name = 0; + sc = kmem_cache_create(conf->cache_name[conf->active_name], +@@ -6764,9 +6765,7 @@ static void free_conf(struct r5conf *conf) + + log_exit(conf); + +- if (conf->shrinker.nr_deferred) +- unregister_shrinker(&conf->shrinker); +- ++ unregister_shrinker(&conf->shrinker); + free_thread_groups(conf); + shrink_stripes(conf); + raid5_free_percpu(conf); +@@ -8001,13 +8000,7 @@ static void raid5_finish_reshape(struct mddev *mddev) + + if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { + +- if (mddev->delta_disks > 0) { +- md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); +- if (mddev->queue) { +- set_capacity(mddev->gendisk, mddev->array_sectors); +- revalidate_disk(mddev->gendisk); +- } +- } else { ++ if (mddev->delta_disks <= 0) { + int d; + spin_lock_irq(&conf->device_lock); + mddev->degraded = raid5_calc_degraded(conf); +diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h +index 2e61238..3f8da26 100644 +--- a/drivers/md/raid5.h ++++ b/drivers/md/raid5.h +@@ -450,6 +450,18 @@ enum { + * HANDLE gets cleared if stripe_handle leaves nothing locked. + */ + ++/* Note: disk_info.rdev can be set to NULL asynchronously by raid5_remove_disk. ++ * There are three safe ways to access disk_info.rdev. ++ * 1/ when holding mddev->reconfig_mutex ++ * 2/ when resync/recovery/reshape is known to be happening - i.e. in code that ++ * is called as part of performing resync/recovery/reshape. ++ * 3/ while holding rcu_read_lock(), use rcu_dereference to get the pointer ++ * and if it is non-NULL, increment rdev->nr_pending before dropping the RCU ++ * lock. ++ * When .rdev is set to NULL, the nr_pending count checked again and if ++ * it has been incremented, the pointer is put back in .rdev. ++ */ ++ + struct disk_info { + struct md_rdev *rdev, *replacement; + struct page *extra_page; /* extra page to use in prexor */ +diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig +index 145e12b..372c074 100644 +--- a/drivers/media/Kconfig ++++ b/drivers/media/Kconfig +@@ -147,6 +147,8 @@ config DVB_CORE + config DVB_MMAP + bool "Enable DVB memory-mapped API (EXPERIMENTAL)" + depends on DVB_CORE ++ depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_CORE ++ select VIDEOBUF2_VMALLOC + default n + help + This option enables DVB experimental memory-mapped API, with +diff --git a/drivers/media/common/videobuf2/Kconfig b/drivers/media/common/videobuf2/Kconfig +index 5df0525..17c32ea 100644 +--- a/drivers/media/common/videobuf2/Kconfig ++++ b/drivers/media/common/videobuf2/Kconfig +@@ -3,6 +3,9 @@ config VIDEOBUF2_CORE + select DMA_SHARED_BUFFER + tristate + ++config VIDEOBUF2_V4L2 ++ tristate ++ + config VIDEOBUF2_MEMOPS + tristate + select FRAME_VECTOR +diff --git a/drivers/media/common/videobuf2/Makefile b/drivers/media/common/videobuf2/Makefile +index 19de5cc..77bebe8b 100644 +--- a/drivers/media/common/videobuf2/Makefile ++++ b/drivers/media/common/videobuf2/Makefile +@@ -1,5 +1,12 @@ ++# SPDX-License-Identifier: GPL-2.0 ++videobuf2-common-objs := videobuf2-core.o + +-obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o videobuf2-v4l2.o ++ifeq ($(CONFIG_TRACEPOINTS),y) ++ videobuf2-common-objs += vb2-trace.o ++endif ++ ++obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-common.o ++obj-$(CONFIG_VIDEOBUF2_V4L2) += videobuf2-v4l2.o + obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o + obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o + obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o +diff --git a/drivers/media/common/videobuf2/vb2-trace.c b/drivers/media/common/videobuf2/vb2-trace.c +new file mode 100644 +index 0000000..4c0f39d +--- /dev/null ++++ b/drivers/media/common/videobuf2/vb2-trace.c +@@ -0,0 +1,10 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include ++ ++#define CREATE_TRACE_POINTS ++#include ++ ++EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_buf_done); ++EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_buf_queue); ++EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_dqbuf); ++EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_qbuf); +diff --git a/drivers/media/dvb-core/Makefile b/drivers/media/dvb-core/Makefile +index 3a105d8..62b028d 100644 +--- a/drivers/media/dvb-core/Makefile ++++ b/drivers/media/dvb-core/Makefile +@@ -4,7 +4,7 @@ + # + + dvb-net-$(CONFIG_DVB_NET) := dvb_net.o +-dvb-vb2-$(CONFIG_DVB_MMSP) := dvb_vb2.o ++dvb-vb2-$(CONFIG_DVB_MMAP) := dvb_vb2.o + + dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o \ + dvb_ca_en50221.o dvb_frontend.o \ +diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c +index 6d53af0..61a750f 100644 +--- a/drivers/media/dvb-core/dmxdev.c ++++ b/drivers/media/dvb-core/dmxdev.c +@@ -128,11 +128,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + struct dmx_frontend *front; +-#ifndef DVB_MMAP + bool need_ringbuffer = false; +-#else +- const bool need_ringbuffer = true; +-#endif + + dprintk("%s\n", __func__); + +@@ -144,17 +140,31 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) + return -ENODEV; + } + +-#ifndef DVB_MMAP ++ dmxdev->may_do_mmap = 0; ++ ++ /* ++ * The logic here is a little tricky due to the ifdef. ++ * ++ * The ringbuffer is used for both read and mmap. ++ * ++ * It is not needed, however, on two situations: ++ * - Write devices (access with O_WRONLY); ++ * - For duplex device nodes, opened with O_RDWR. ++ */ ++ + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + need_ringbuffer = true; +-#else +- if ((file->f_flags & O_ACCMODE) == O_RDWR) { ++ else if ((file->f_flags & O_ACCMODE) == O_RDWR) { + if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { ++#ifdef CONFIG_DVB_MMAP ++ dmxdev->may_do_mmap = 1; ++ need_ringbuffer = true; ++#else + mutex_unlock(&dmxdev->mutex); + return -EOPNOTSUPP; ++#endif + } + } +-#endif + + if (need_ringbuffer) { + void *mem; +@@ -169,8 +179,9 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) + return -ENOMEM; + } + dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); +- dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr", +- file->f_flags & O_NONBLOCK); ++ if (dmxdev->may_do_mmap) ++ dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr", ++ file->f_flags & O_NONBLOCK); + dvbdev->readers--; + } + +@@ -200,11 +211,6 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) + { + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; +-#ifndef DVB_MMAP +- bool need_ringbuffer = false; +-#else +- const bool need_ringbuffer = true; +-#endif + + mutex_lock(&dmxdev->mutex); + +@@ -213,15 +219,14 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) + dmxdev->demux->connect_frontend(dmxdev->demux, + dmxdev->dvr_orig_fe); + } +-#ifndef DVB_MMAP +- if ((file->f_flags & O_ACCMODE) == O_RDONLY) +- need_ringbuffer = true; +-#endif + +- if (need_ringbuffer) { +- if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) +- dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx); +- dvb_vb2_release(&dmxdev->dvr_vb2_ctx); ++ if (((file->f_flags & O_ACCMODE) == O_RDONLY) || ++ dmxdev->may_do_mmap) { ++ if (dmxdev->may_do_mmap) { ++ if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) ++ dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx); ++ dvb_vb2_release(&dmxdev->dvr_vb2_ctx); ++ } + dvbdev->readers++; + if (dmxdev->dvr_buffer.data) { + void *mem = dmxdev->dvr_buffer.data; +@@ -380,7 +385,8 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) + + static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, + const u8 *buffer2, size_t buffer2_len, +- struct dmx_section_filter *filter) ++ struct dmx_section_filter *filter, ++ u32 *buffer_flags) + { + struct dmxdev_filter *dmxdevfilter = filter->priv; + int ret; +@@ -399,10 +405,12 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, + dprintk("section callback %*ph\n", 6, buffer1); + if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) { + ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx, +- buffer1, buffer1_len); ++ buffer1, buffer1_len, ++ buffer_flags); + if (ret == buffer1_len) + ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx, +- buffer2, buffer2_len); ++ buffer2, buffer2_len, ++ buffer_flags); + } else { + ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, + buffer1, buffer1_len); +@@ -422,11 +430,12 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, + + static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, + const u8 *buffer2, size_t buffer2_len, +- struct dmx_ts_feed *feed) ++ struct dmx_ts_feed *feed, ++ u32 *buffer_flags) + { + struct dmxdev_filter *dmxdevfilter = feed->priv; + struct dvb_ringbuffer *buffer; +-#ifdef DVB_MMAP ++#ifdef CONFIG_DVB_MMAP + struct dvb_vb2_ctx *ctx; + #endif + int ret; +@@ -440,20 +449,22 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, + if (dmxdevfilter->params.pes.output == DMX_OUT_TAP || + dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) { + buffer = &dmxdevfilter->buffer; +-#ifdef DVB_MMAP ++#ifdef CONFIG_DVB_MMAP + ctx = &dmxdevfilter->vb2_ctx; + #endif + } else { + buffer = &dmxdevfilter->dev->dvr_buffer; +-#ifdef DVB_MMAP ++#ifdef CONFIG_DVB_MMAP + ctx = &dmxdevfilter->dev->dvr_vb2_ctx; + #endif + } + + if (dvb_vb2_is_streaming(ctx)) { +- ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len); ++ ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len, ++ buffer_flags); + if (ret == buffer1_len) +- ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len); ++ ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len, ++ buffer_flags); + } else { + if (buffer->error) { + spin_unlock(&dmxdevfilter->dev->lock); +@@ -802,6 +813,12 @@ static int dvb_demux_open(struct inode *inode, struct file *file) + mutex_init(&dmxdevfilter->mutex); + file->private_data = dmxdevfilter; + ++#ifdef CONFIG_DVB_MMAP ++ dmxdev->may_do_mmap = 1; ++#else ++ dmxdev->may_do_mmap = 0; ++#endif ++ + dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); + dvb_vb2_init(&dmxdevfilter->vb2_ctx, "demux_filter", + file->f_flags & O_NONBLOCK); +@@ -1111,7 +1128,7 @@ static int dvb_demux_do_ioctl(struct file *file, + mutex_unlock(&dmxdevfilter->mutex); + break; + +-#ifdef DVB_MMAP ++#ifdef CONFIG_DVB_MMAP + case DMX_REQBUFS: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); +@@ -1160,7 +1177,7 @@ static int dvb_demux_do_ioctl(struct file *file, + break; + #endif + default: +- ret = -EINVAL; ++ ret = -ENOTTY; + break; + } + mutex_unlock(&dmxdev->mutex); +@@ -1199,13 +1216,16 @@ static __poll_t dvb_demux_poll(struct file *file, poll_table *wait) + return mask; + } + +-#ifdef DVB_MMAP ++#ifdef CONFIG_DVB_MMAP + static int dvb_demux_mmap(struct file *file, struct vm_area_struct *vma) + { + struct dmxdev_filter *dmxdevfilter = file->private_data; + struct dmxdev *dmxdev = dmxdevfilter->dev; + int ret; + ++ if (!dmxdev->may_do_mmap) ++ return -ENOTTY; ++ + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + +@@ -1249,7 +1269,7 @@ static const struct file_operations dvb_demux_fops = { + .release = dvb_demux_release, + .poll = dvb_demux_poll, + .llseek = default_llseek, +-#ifdef DVB_MMAP ++#ifdef CONFIG_DVB_MMAP + .mmap = dvb_demux_mmap, + #endif + }; +@@ -1280,7 +1300,7 @@ static int dvb_dvr_do_ioctl(struct file *file, + ret = dvb_dvr_set_buffer_size(dmxdev, arg); + break; + +-#ifdef DVB_MMAP ++#ifdef CONFIG_DVB_MMAP + case DMX_REQBUFS: + ret = dvb_vb2_reqbufs(&dmxdev->dvr_vb2_ctx, parg); + break; +@@ -1304,7 +1324,7 @@ static int dvb_dvr_do_ioctl(struct file *file, + break; + #endif + default: +- ret = -EINVAL; ++ ret = -ENOTTY; + break; + } + mutex_unlock(&dmxdev->mutex); +@@ -1322,11 +1342,6 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait) + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + __poll_t mask = 0; +-#ifndef DVB_MMAP +- bool need_ringbuffer = false; +-#else +- const bool need_ringbuffer = true; +-#endif + + dprintk("%s\n", __func__); + +@@ -1337,11 +1352,8 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait) + + poll_wait(file, &dmxdev->dvr_buffer.queue, wait); + +-#ifndef DVB_MMAP +- if ((file->f_flags & O_ACCMODE) == O_RDONLY) +- need_ringbuffer = true; +-#endif +- if (need_ringbuffer) { ++ if (((file->f_flags & O_ACCMODE) == O_RDONLY) || ++ dmxdev->may_do_mmap) { + if (dmxdev->dvr_buffer.error) + mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR); + +@@ -1353,13 +1365,16 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait) + return mask; + } + +-#ifdef DVB_MMAP ++#ifdef CONFIG_DVB_MMAP + static int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma) + { + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + int ret; + ++ if (!dmxdev->may_do_mmap) ++ return -ENOTTY; ++ + if (dmxdev->exit) + return -ENODEV; + +@@ -1381,7 +1396,7 @@ static const struct file_operations dvb_dvr_fops = { + .release = dvb_dvr_release, + .poll = dvb_dvr_poll, + .llseek = default_llseek, +-#ifdef DVB_MMAP ++#ifdef CONFIG_DVB_MMAP + .mmap = dvb_dvr_mmap, + #endif + }; +diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c +index 210eed0..f450912 100644 +--- a/drivers/media/dvb-core/dvb_demux.c ++++ b/drivers/media/dvb-core/dvb_demux.c +@@ -55,6 +55,17 @@ MODULE_PARM_DESC(dvb_demux_feed_err_pkts, + dprintk(x); \ + } while (0) + ++#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG ++# define dprintk_sect_loss(x...) dprintk(x) ++#else ++# define dprintk_sect_loss(x...) ++#endif ++ ++#define set_buf_flags(__feed, __flag) \ ++ do { \ ++ (__feed)->buffer_flags |= (__flag); \ ++ } while (0) ++ + /****************************************************************************** + * static inlined helper functions + ******************************************************************************/ +@@ -104,31 +115,30 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, + { + int count = payload(buf); + int p; +-#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG + int ccok; + u8 cc; +-#endif + + if (count == 0) + return -1; + + p = 188 - count; + +-#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG + cc = buf[3] & 0x0f; + ccok = ((feed->cc + 1) & 0x0f) == cc; + feed->cc = cc; +- if (!ccok) +- dprintk("missed packet: %d instead of %d!\n", +- cc, (feed->cc + 1) & 0x0f); +-#endif ++ if (!ccok) { ++ set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); ++ dprintk_sect_loss("missed packet: %d instead of %d!\n", ++ cc, (feed->cc + 1) & 0x0f); ++ } + + if (buf[1] & 0x40) // PUSI ? + feed->peslen = 0xfffa; + + feed->peslen += count; + +- return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts); ++ return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, ++ &feed->buffer_flags); + } + + static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, +@@ -150,7 +160,7 @@ static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, + return 0; + + return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen, +- NULL, 0, &f->filter); ++ NULL, 0, &f->filter, &feed->buffer_flags); + } + + static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) +@@ -169,8 +179,10 @@ static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) + if (sec->check_crc) { + section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0); + if (section_syntax_indicator && +- demux->check_crc32(feed, sec->secbuf, sec->seclen)) ++ demux->check_crc32(feed, sec->secbuf, sec->seclen)) { ++ set_buf_flags(feed, DMX_BUFFER_FLAG_HAD_CRC32_DISCARD); + return -1; ++ } + } + + do { +@@ -187,7 +199,6 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) + { + struct dmx_section_feed *sec = &feed->feed.sec; + +-#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG + if (sec->secbufp < sec->tsfeedp) { + int n = sec->tsfeedp - sec->secbufp; + +@@ -197,12 +208,13 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) + * but just first and last. + */ + if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) { +- dprintk("section ts padding loss: %d/%d\n", +- n, sec->tsfeedp); +- dprintk("pad data: %*ph\n", n, sec->secbuf); ++ set_buf_flags(feed, ++ DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); ++ dprintk_sect_loss("section ts padding loss: %d/%d\n", ++ n, sec->tsfeedp); ++ dprintk_sect_loss("pad data: %*ph\n", n, sec->secbuf); + } + } +-#endif + + sec->tsfeedp = sec->secbufp = sec->seclen = 0; + sec->secbuf = sec->secbuf_base; +@@ -237,11 +249,10 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, + return 0; + + if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) { +-#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG +- dprintk("section buffer full loss: %d/%d\n", +- sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, +- DMX_MAX_SECFEED_SIZE); +-#endif ++ set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); ++ dprintk_sect_loss("section buffer full loss: %d/%d\n", ++ sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, ++ DMX_MAX_SECFEED_SIZE); + len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp; + } + +@@ -269,12 +280,13 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, + sec->seclen = seclen; + sec->crc_val = ~0; + /* dump [secbuf .. secbuf+seclen) */ +- if (feed->pusi_seen) ++ if (feed->pusi_seen) { + dvb_dmx_swfilter_section_feed(feed); +-#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG +- else +- dprintk("pusi not seen, discarding section data\n"); +-#endif ++ } else { ++ set_buf_flags(feed, ++ DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); ++ dprintk_sect_loss("pusi not seen, discarding section data\n"); ++ } + sec->secbufp += seclen; /* secbufp and secbuf moving together is */ + sec->secbuf += seclen; /* redundant but saves pointer arithmetic */ + } +@@ -307,18 +319,22 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, + } + + if (!ccok || dc_i) { +-#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG +- if (dc_i) +- dprintk("%d frame with disconnect indicator\n", ++ if (dc_i) { ++ set_buf_flags(feed, ++ DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR); ++ dprintk_sect_loss("%d frame with disconnect indicator\n", + cc); +- else +- dprintk("discontinuity: %d instead of %d. %d bytes lost\n", ++ } else { ++ set_buf_flags(feed, ++ DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); ++ dprintk_sect_loss("discontinuity: %d instead of %d. %d bytes lost\n", + cc, (feed->cc + 1) & 0x0f, count + 4); ++ } + /* +- * those bytes under sume circumstances will again be reported ++ * those bytes under some circumstances will again be reported + * in the following dvb_dmx_swfilter_section_new + */ +-#endif ++ + /* + * Discontinuity detected. Reset pusi_seen to + * stop feeding of suspicious data until next PUSI=1 arrives +@@ -326,6 +342,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, + * FIXME: does it make sense if the MPEG-TS is the one + * reporting discontinuity? + */ ++ + feed->pusi_seen = false; + dvb_dmx_swfilter_section_new(feed); + } +@@ -345,11 +362,11 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, + dvb_dmx_swfilter_section_new(feed); + dvb_dmx_swfilter_section_copy_dump(feed, after, + after_len); ++ } else if (count > 0) { ++ set_buf_flags(feed, ++ DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); ++ dprintk_sect_loss("PUSI=1 but %d bytes lost\n", count); + } +-#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG +- else if (count > 0) +- dprintk("PUSI=1 but %d bytes lost\n", count); +-#endif + } else { + /* PUSI=0 (is not set), no section boundary */ + dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count); +@@ -369,7 +386,8 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, + if (feed->ts_type & TS_PAYLOAD_ONLY) + dvb_dmx_swfilter_payload(feed, buf); + else +- feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); ++ feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, ++ &feed->buffer_flags); + } + /* Used only on full-featured devices */ + if (feed->ts_type & TS_DECODER) +@@ -430,6 +448,11 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) + } + + if (buf[1] & 0x80) { ++ list_for_each_entry(feed, &demux->feed_list, list_head) { ++ if ((feed->pid != pid) && (feed->pid != 0x2000)) ++ continue; ++ set_buf_flags(feed, DMX_BUFFER_FLAG_TEI); ++ } + dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n", + pid, buf[1]); + /* data in this packet can't be trusted - drop it unless +@@ -445,6 +468,13 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) + (demux->cnt_storage[pid] + 1) & 0xf; + + if ((buf[3] & 0xf) != demux->cnt_storage[pid]) { ++ list_for_each_entry(feed, &demux->feed_list, list_head) { ++ if ((feed->pid != pid) && (feed->pid != 0x2000)) ++ continue; ++ set_buf_flags(feed, ++ DMX_BUFFER_PKT_COUNTER_MISMATCH); ++ } ++ + dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n", + pid, demux->cnt_storage[pid], + buf[3] & 0xf); +@@ -466,7 +496,8 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) + if (feed->pid == pid) + dvb_dmx_swfilter_packet_type(feed, buf); + else if (feed->pid == 0x2000) +- feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); ++ feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, ++ &feed->buffer_flags); + } + } + +@@ -585,7 +616,8 @@ void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count) + + spin_lock_irqsave(&demux->lock, flags); + +- demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts); ++ demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, ++ &demux->feed->buffer_flags); + + spin_unlock_irqrestore(&demux->lock, flags); + } +@@ -785,6 +817,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, + feed->demux = demux; + feed->pid = 0xffff; + feed->peslen = 0xfffa; ++ feed->buffer_flags = 0; + + (*ts_feed) = &feed->feed.ts; + (*ts_feed)->parent = dmx; +@@ -1042,6 +1075,7 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, + dvbdmxfeed->cb.sec = callback; + dvbdmxfeed->demux = dvbdmx; + dvbdmxfeed->pid = 0xffff; ++ dvbdmxfeed->buffer_flags = 0; + dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; + dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0; + dvbdmxfeed->feed.sec.tsfeedp = 0; +diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c +index b6c7eec..ba39f99 100644 +--- a/drivers/media/dvb-core/dvb_net.c ++++ b/drivers/media/dvb-core/dvb_net.c +@@ -883,7 +883,8 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len) + + static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len, + const u8 *buffer2, size_t buffer2_len, +- struct dmx_ts_feed *feed) ++ struct dmx_ts_feed *feed, ++ u32 *buffer_flags) + { + struct net_device *dev = feed->priv; + +@@ -992,7 +993,7 @@ static void dvb_net_sec(struct net_device *dev, + + static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len, + const u8 *buffer2, size_t buffer2_len, +- struct dmx_section_filter *filter) ++ struct dmx_section_filter *filter, u32 *buffer_flags) + { + struct net_device *dev = filter->priv; + +diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c +index 763145d..b811adf 100644 +--- a/drivers/media/dvb-core/dvb_vb2.c ++++ b/drivers/media/dvb-core/dvb_vb2.c +@@ -256,7 +256,8 @@ int dvb_vb2_is_streaming(struct dvb_vb2_ctx *ctx) + } + + int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx, +- const unsigned char *src, int len) ++ const unsigned char *src, int len, ++ enum dmx_buffer_flags *buffer_flags) + { + unsigned long flags = 0; + void *vbuf = NULL; +@@ -264,15 +265,17 @@ int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx, + unsigned char *psrc = (unsigned char *)src; + int ll = 0; + +- dprintk(3, "[%s] %d bytes are rcvd\n", ctx->name, len); +- if (!src) { +- dprintk(3, "[%s]:NULL pointer src\n", ctx->name); +- /**normal case: This func is called twice from demux driver +- * once with valid src pointer, second time with NULL pointer +- */ ++ /* ++ * normal case: This func is called twice from demux driver ++ * one with valid src pointer, second time with NULL pointer ++ */ ++ if (!src || !len) + return 0; +- } + spin_lock_irqsave(&ctx->slock, flags); ++ if (buffer_flags && *buffer_flags) { ++ ctx->flags |= *buffer_flags; ++ *buffer_flags = 0; ++ } + while (todo) { + if (!ctx->buf) { + if (list_empty(&ctx->dvb_q)) { +@@ -395,6 +398,7 @@ int dvb_vb2_qbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b) + + int dvb_vb2_dqbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b) + { ++ unsigned long flags; + int ret; + + ret = vb2_core_dqbuf(&ctx->vb_q, &b->index, b, ctx->nonblocking); +@@ -402,7 +406,16 @@ int dvb_vb2_dqbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b) + dprintk(1, "[%s] errno=%d\n", ctx->name, ret); + return ret; + } +- dprintk(5, "[%s] index=%d\n", ctx->name, b->index); ++ ++ spin_lock_irqsave(&ctx->slock, flags); ++ b->count = ctx->count++; ++ b->flags = ctx->flags; ++ ctx->flags = 0; ++ spin_unlock_irqrestore(&ctx->slock, flags); ++ ++ dprintk(5, "[%s] index=%d, count=%d, flags=%d\n", ++ ctx->name, b->index, ctx->count, b->flags); ++ + + return 0; + } +diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c +index 50bce68..65d157f 100644 +--- a/drivers/media/dvb-frontends/m88ds3103.c ++++ b/drivers/media/dvb-frontends/m88ds3103.c +@@ -1262,11 +1262,12 @@ static int m88ds3103_select(struct i2c_mux_core *muxc, u32 chan) + * New users must use I2C client binding directly! + */ + struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg, +- struct i2c_adapter *i2c, struct i2c_adapter **tuner_i2c_adapter) ++ struct i2c_adapter *i2c, ++ struct i2c_adapter **tuner_i2c_adapter) + { + struct i2c_client *client; + struct i2c_board_info board_info; +- struct m88ds3103_platform_data pdata; ++ struct m88ds3103_platform_data pdata = {}; + + pdata.clk = cfg->clock; + pdata.i2c_wr_max = cfg->i2c_wr_max; +@@ -1409,6 +1410,8 @@ static int m88ds3103_probe(struct i2c_client *client, + case M88DS3103_CHIP_ID: + break; + default: ++ ret = -ENODEV; ++ dev_err(&client->dev, "Unknown device. Chip_id=%02x\n", dev->chip_id); + goto err_kfree; + } + +diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c +index 3c18519..2476d81 100644 +--- a/drivers/media/i2c/tvp5150.c ++++ b/drivers/media/i2c/tvp5150.c +@@ -505,80 +505,77 @@ static struct i2c_vbi_ram_value vbi_ram_default[] = + /* FIXME: Current api doesn't handle all VBI types, those not + yet supported are placed under #if 0 */ + #if 0 +- {0x010, /* Teletext, SECAM, WST System A */ ++ [0] = {0x010, /* Teletext, SECAM, WST System A */ + {V4L2_SLICED_TELETEXT_SECAM,6,23,1}, + { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26, + 0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 } + }, + #endif +- {0x030, /* Teletext, PAL, WST System B */ ++ [1] = {0x030, /* Teletext, PAL, WST System B */ + {V4L2_SLICED_TELETEXT_B,6,22,1}, + { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b, + 0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 } + }, + #if 0 +- {0x050, /* Teletext, PAL, WST System C */ ++ [2] = {0x050, /* Teletext, PAL, WST System C */ + {V4L2_SLICED_TELETEXT_PAL_C,6,22,1}, + { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, + 0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } + }, +- {0x070, /* Teletext, NTSC, WST System B */ ++ [3] = {0x070, /* Teletext, NTSC, WST System B */ + {V4L2_SLICED_TELETEXT_NTSC_B,10,21,1}, + { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23, + 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } + }, +- {0x090, /* Tetetext, NTSC NABTS System C */ ++ [4] = {0x090, /* Tetetext, NTSC NABTS System C */ + {V4L2_SLICED_TELETEXT_NTSC_C,10,21,1}, + { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, + 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 } + }, +- {0x0b0, /* Teletext, NTSC-J, NABTS System D */ ++ [5] = {0x0b0, /* Teletext, NTSC-J, NABTS System D */ + {V4L2_SLICED_TELETEXT_NTSC_D,10,21,1}, + { 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23, + 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } + }, +- {0x0d0, /* Closed Caption, PAL/SECAM */ ++ [6] = {0x0d0, /* Closed Caption, PAL/SECAM */ + {V4L2_SLICED_CAPTION_625,22,22,1}, + { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, + 0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } + }, + #endif +- {0x0f0, /* Closed Caption, NTSC */ ++ [7] = {0x0f0, /* Closed Caption, NTSC */ + {V4L2_SLICED_CAPTION_525,21,21,1}, + { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, + 0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } + }, +- {0x110, /* Wide Screen Signal, PAL/SECAM */ ++ [8] = {0x110, /* Wide Screen Signal, PAL/SECAM */ + {V4L2_SLICED_WSS_625,23,23,1}, + { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42, + 0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 } + }, + #if 0 +- {0x130, /* Wide Screen Signal, NTSC C */ ++ [9] = {0x130, /* Wide Screen Signal, NTSC C */ + {V4L2_SLICED_WSS_525,20,20,1}, + { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43, + 0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 } + }, +- {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */ ++ [10] = {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */ + {V4l2_SLICED_VITC_625,6,22,0}, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, + 0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } + }, +- {0x170, /* Vertical Interval Timecode (VITC), NTSC */ ++ [11] = {0x170, /* Vertical Interval Timecode (VITC), NTSC */ + {V4l2_SLICED_VITC_525,10,20,0}, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, + 0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } + }, + #endif +- {0x190, /* Video Program System (VPS), PAL */ ++ [12] = {0x190, /* Video Program System (VPS), PAL */ + {V4L2_SLICED_VPS,16,16,0}, + { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d, + 0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 } + }, + /* 0x1d0 User programmable */ +- +- /* End of struct */ +- { (u16)-1 } + }; + + static int tvp5150_write_inittab(struct v4l2_subdev *sd, +@@ -591,10 +588,10 @@ static int tvp5150_write_inittab(struct v4l2_subdev *sd, + return 0; + } + +-static int tvp5150_vdp_init(struct v4l2_subdev *sd, +- const struct i2c_vbi_ram_value *regs) ++static int tvp5150_vdp_init(struct v4l2_subdev *sd) + { + unsigned int i; ++ int j; + + /* Disable Full Field */ + tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0); +@@ -604,14 +601,17 @@ static int tvp5150_vdp_init(struct v4l2_subdev *sd, + tvp5150_write(sd, i, 0xff); + + /* Load Ram Table */ +- while (regs->reg != (u16)-1) { ++ for (j = 0; j < ARRAY_SIZE(vbi_ram_default); j++) { ++ const struct i2c_vbi_ram_value *regs = &vbi_ram_default[j]; ++ ++ if (!regs->type.vbi_type) ++ continue; ++ + tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8); + tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_LOW, regs->reg); + + for (i = 0; i < 16; i++) + tvp5150_write(sd, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]); +- +- regs++; + } + return 0; + } +@@ -620,19 +620,23 @@ static int tvp5150_vdp_init(struct v4l2_subdev *sd, + static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, + struct v4l2_sliced_vbi_cap *cap) + { +- const struct i2c_vbi_ram_value *regs = vbi_ram_default; +- int line; ++ int line, i; + + dev_dbg_lvl(sd->dev, 1, debug, "g_sliced_vbi_cap\n"); + memset(cap, 0, sizeof *cap); + +- while (regs->reg != (u16)-1 ) { +- for (line=regs->type.ini_line;line<=regs->type.end_line;line++) { ++ for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) { ++ const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i]; ++ ++ if (!regs->type.vbi_type) ++ continue; ++ ++ for (line = regs->type.ini_line; ++ line <= regs->type.end_line; ++ line++) { + cap->service_lines[0][line] |= regs->type.vbi_type; + } + cap->service_set |= regs->type.vbi_type; +- +- regs++; + } + return 0; + } +@@ -651,14 +655,13 @@ static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, + * MSB = field2 + */ + static int tvp5150_set_vbi(struct v4l2_subdev *sd, +- const struct i2c_vbi_ram_value *regs, + unsigned int type,u8 flags, int line, + const int fields) + { + struct tvp5150 *decoder = to_tvp5150(sd); + v4l2_std_id std = decoder->norm; + u8 reg; +- int pos = 0; ++ int i, pos = 0; + + if (std == V4L2_STD_ALL) { + dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n"); +@@ -671,19 +674,19 @@ static int tvp5150_set_vbi(struct v4l2_subdev *sd, + if (line < 6 || line > 27) + return 0; + +- while (regs->reg != (u16)-1) { ++ for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) { ++ const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i]; ++ ++ if (!regs->type.vbi_type) ++ continue; ++ + if ((type & regs->type.vbi_type) && + (line >= regs->type.ini_line) && + (line <= regs->type.end_line)) + break; +- +- regs++; + pos++; + } + +- if (regs->reg == (u16)-1) +- return 0; +- + type = pos | (flags & 0xf0); + reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI; + +@@ -696,8 +699,7 @@ static int tvp5150_set_vbi(struct v4l2_subdev *sd, + return type; + } + +-static int tvp5150_get_vbi(struct v4l2_subdev *sd, +- const struct i2c_vbi_ram_value *regs, int line) ++static int tvp5150_get_vbi(struct v4l2_subdev *sd, int line) + { + struct tvp5150 *decoder = to_tvp5150(sd); + v4l2_std_id std = decoder->norm; +@@ -726,8 +728,8 @@ static int tvp5150_get_vbi(struct v4l2_subdev *sd, + return 0; + } + pos = ret & 0x0f; +- if (pos < 0x0f) +- type |= regs[pos].type.vbi_type; ++ if (pos < ARRAY_SIZE(vbi_ram_default)) ++ type |= vbi_ram_default[pos].type.vbi_type; + } + + return type; +@@ -788,7 +790,7 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val) + tvp5150_write_inittab(sd, tvp5150_init_default); + + /* Initializes VDP registers */ +- tvp5150_vdp_init(sd, vbi_ram_default); ++ tvp5150_vdp_init(sd); + + /* Selects decoder input */ + tvp5150_selmux(sd); +@@ -1121,8 +1123,8 @@ static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f + for (i = 0; i <= 23; i++) { + svbi->service_lines[1][i] = 0; + svbi->service_lines[0][i] = +- tvp5150_set_vbi(sd, vbi_ram_default, +- svbi->service_lines[0][i], 0xf0, i, 3); ++ tvp5150_set_vbi(sd, svbi->service_lines[0][i], ++ 0xf0, i, 3); + } + /* Enables FIFO */ + tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 1); +@@ -1148,7 +1150,7 @@ static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f + + for (i = 0; i <= 23; i++) { + svbi->service_lines[0][i] = +- tvp5150_get_vbi(sd, vbi_ram_default, i); ++ tvp5150_get_vbi(sd, i); + mask |= svbi->service_lines[0][i]; + } + svbi->service_set = mask; +diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c +index dc8e577..d6816ef 100644 +--- a/drivers/media/pci/ttpci/av7110.c ++++ b/drivers/media/pci/ttpci/av7110.c +@@ -324,14 +324,15 @@ static int DvbDmxFilterCallback(u8 *buffer1, size_t buffer1_len, + } + return dvbdmxfilter->feed->cb.sec(buffer1, buffer1_len, + buffer2, buffer2_len, +- &dvbdmxfilter->filter); ++ &dvbdmxfilter->filter, NULL); + case DMX_TYPE_TS: + if (!(dvbdmxfilter->feed->ts_type & TS_PACKET)) + return 0; + if (dvbdmxfilter->feed->ts_type & TS_PAYLOAD_ONLY) + return dvbdmxfilter->feed->cb.ts(buffer1, buffer1_len, + buffer2, buffer2_len, +- &dvbdmxfilter->feed->feed.ts); ++ &dvbdmxfilter->feed->feed.ts, ++ NULL); + else + av7110_p2t_write(buffer1, buffer1_len, + dvbdmxfilter->feed->pid, +diff --git a/drivers/media/pci/ttpci/av7110_av.c b/drivers/media/pci/ttpci/av7110_av.c +index 4daba76..ef1bc17 100644 +--- a/drivers/media/pci/ttpci/av7110_av.c ++++ b/drivers/media/pci/ttpci/av7110_av.c +@@ -99,7 +99,7 @@ int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len) + buf[4] = buf[5] = 0; + if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) + return dvbdmxfeed->cb.ts(buf, len, NULL, 0, +- &dvbdmxfeed->feed.ts); ++ &dvbdmxfeed->feed.ts, NULL); + else + return dvb_filter_pes2ts(p2t, buf, len, 1); + } +@@ -109,7 +109,7 @@ static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data) + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv; + + dvbdmxfeed->cb.ts(data, 188, NULL, 0, +- &dvbdmxfeed->feed.ts); ++ &dvbdmxfeed->feed.ts, NULL); + return 0; + } + +@@ -814,7 +814,7 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, + memcpy(obuf + l, buf + c, TS_SIZE - l); + c = length; + } +- feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts); ++ feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts, NULL); + pes_start = 0; + } + } +diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig +index 70521e0..bfaa806 100644 +--- a/drivers/media/usb/au0828/Kconfig ++++ b/drivers/media/usb/au0828/Kconfig +@@ -1,7 +1,7 @@ + + config VIDEO_AU0828 + tristate "Auvitek AU0828 support" +- depends on I2C && INPUT && DVB_CORE && USB ++ depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2 + select I2C_ALGOBIT + select VIDEO_TVEEPROM + select VIDEOBUF2_VMALLOC +diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c +index a8900f5..44ca66c 100644 +--- a/drivers/media/usb/ttusb-dec/ttusb_dec.c ++++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c +@@ -428,7 +428,7 @@ static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data) + struct ttusb_dec *dec = priv; + + dec->audio_filter->feed->cb.ts(data, 188, NULL, 0, +- &dec->audio_filter->feed->feed.ts); ++ &dec->audio_filter->feed->feed.ts, NULL); + + return 0; + } +@@ -438,7 +438,7 @@ static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data) + struct ttusb_dec *dec = priv; + + dec->video_filter->feed->cb.ts(data, 188, NULL, 0, +- &dec->video_filter->feed->feed.ts); ++ &dec->video_filter->feed->feed.ts, NULL); + + return 0; + } +@@ -490,7 +490,7 @@ static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length) + + if (output_pva) { + dec->video_filter->feed->cb.ts(pva, length, NULL, 0, +- &dec->video_filter->feed->feed.ts); ++ &dec->video_filter->feed->feed.ts, NULL); + return; + } + +@@ -551,7 +551,7 @@ static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length) + case 0x02: /* MainAudioStream */ + if (output_pva) { + dec->audio_filter->feed->cb.ts(pva, length, NULL, 0, +- &dec->audio_filter->feed->feed.ts); ++ &dec->audio_filter->feed->feed.ts, NULL); + return; + } + +@@ -589,7 +589,7 @@ static void ttusb_dec_process_filter(struct ttusb_dec *dec, u8 *packet, + + if (filter) + filter->feed->cb.sec(&packet[2], length - 2, NULL, 0, +- &filter->filter); ++ &filter->filter, NULL); + } + + static void ttusb_dec_process_packet(struct ttusb_dec *dec) +diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig +index bf52fbd..8e37e7c 100644 +--- a/drivers/media/v4l2-core/Kconfig ++++ b/drivers/media/v4l2-core/Kconfig +@@ -7,6 +7,7 @@ config VIDEO_V4L2 + tristate + depends on (I2C || I2C=n) && VIDEO_DEV + select RATIONAL ++ select VIDEOBUF2_V4L2 if VIDEOBUF2_CORE + default (I2C || I2C=n) && VIDEO_DEV + + config VIDEO_ADV_DEBUG +diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile +index 80de2cb..7df5458 100644 +--- a/drivers/media/v4l2-core/Makefile ++++ b/drivers/media/v4l2-core/Makefile +@@ -13,7 +13,7 @@ ifeq ($(CONFIG_COMPAT),y) + endif + obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o + ifeq ($(CONFIG_TRACEPOINTS),y) +- videodev-objs += vb2-trace.o v4l2-trace.o ++ videodev-objs += v4l2-trace.o + endif + videodev-$(CONFIG_MEDIA_CONTROLLER) += v4l2-mc.o + +@@ -35,4 +35,3 @@ obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o + + ccflags-y += -I$(srctree)/drivers/media/dvb-frontends + ccflags-y += -I$(srctree)/drivers/media/tuners +- +diff --git a/drivers/media/v4l2-core/vb2-trace.c b/drivers/media/v4l2-core/vb2-trace.c +deleted file mode 100644 +index 4c0f39d..0000000 +--- a/drivers/media/v4l2-core/vb2-trace.c ++++ /dev/null +@@ -1,10 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-#include +- +-#define CREATE_TRACE_POINTS +-#include +- +-EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_buf_done); +-EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_buf_queue); +-EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_dqbuf); +-EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_qbuf); +diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c +index 0a7bdbe..e9c1485 100644 +--- a/drivers/memory/brcmstb_dpfe.c ++++ b/drivers/memory/brcmstb_dpfe.c +@@ -45,8 +45,16 @@ + #define REG_TO_DCPU_MBOX 0x10 + #define REG_TO_HOST_MBOX 0x14 + ++/* Macros to process offsets returned by the DCPU */ ++#define DRAM_MSG_ADDR_OFFSET 0x0 ++#define DRAM_MSG_TYPE_OFFSET 0x1c ++#define DRAM_MSG_ADDR_MASK ((1UL << DRAM_MSG_TYPE_OFFSET) - 1) ++#define DRAM_MSG_TYPE_MASK ((1UL << \ ++ (BITS_PER_LONG - DRAM_MSG_TYPE_OFFSET)) - 1) ++ + /* Message RAM */ +-#define DCPU_MSG_RAM(x) (0x100 + (x) * sizeof(u32)) ++#define DCPU_MSG_RAM_START 0x100 ++#define DCPU_MSG_RAM(x) (DCPU_MSG_RAM_START + (x) * sizeof(u32)) + + /* DRAM Info Offsets & Masks */ + #define DRAM_INFO_INTERVAL 0x0 +@@ -255,6 +263,40 @@ static unsigned int get_msg_chksum(const u32 msg[]) + return sum; + } + ++static void __iomem *get_msg_ptr(struct private_data *priv, u32 response, ++ char *buf, ssize_t *size) ++{ ++ unsigned int msg_type; ++ unsigned int offset; ++ void __iomem *ptr = NULL; ++ ++ msg_type = (response >> DRAM_MSG_TYPE_OFFSET) & DRAM_MSG_TYPE_MASK; ++ offset = (response >> DRAM_MSG_ADDR_OFFSET) & DRAM_MSG_ADDR_MASK; ++ ++ /* ++ * msg_type == 1: the offset is relative to the message RAM ++ * msg_type == 0: the offset is relative to the data RAM (this is the ++ * previous way of passing data) ++ * msg_type is anything else: there's critical hardware problem ++ */ ++ switch (msg_type) { ++ case 1: ++ ptr = priv->regs + DCPU_MSG_RAM_START + offset; ++ break; ++ case 0: ++ ptr = priv->dmem + offset; ++ break; ++ default: ++ dev_emerg(priv->dev, "invalid message reply from DCPU: %#x\n", ++ response); ++ if (buf && size) ++ *size = sprintf(buf, ++ "FATAL: communication error with DCPU\n"); ++ } ++ ++ return ptr; ++} ++ + static int __send_command(struct private_data *priv, unsigned int cmd, + u32 result[]) + { +@@ -507,7 +549,7 @@ static ssize_t show_info(struct device *dev, struct device_attribute *devattr, + { + u32 response[MSG_FIELD_MAX]; + unsigned int info; +- int ret; ++ ssize_t ret; + + ret = generic_show(DPFE_CMD_GET_INFO, response, dev, buf); + if (ret) +@@ -528,18 +570,19 @@ static ssize_t show_refresh(struct device *dev, + u32 response[MSG_FIELD_MAX]; + void __iomem *info; + struct private_data *priv; +- unsigned int offset; + u8 refresh, sr_abort, ppre, thermal_offs, tuf; + u32 mr4; +- int ret; ++ ssize_t ret; + + ret = generic_show(DPFE_CMD_GET_REFRESH, response, dev, buf); + if (ret) + return ret; + + priv = dev_get_drvdata(dev); +- offset = response[MSG_ARG0]; +- info = priv->dmem + offset; ++ ++ info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret); ++ if (!info) ++ return ret; + + mr4 = readl_relaxed(info + DRAM_INFO_MR4) & DRAM_INFO_MR4_MASK; + +@@ -561,7 +604,6 @@ static ssize_t store_refresh(struct device *dev, struct device_attribute *attr, + u32 response[MSG_FIELD_MAX]; + struct private_data *priv; + void __iomem *info; +- unsigned int offset; + unsigned long val; + int ret; + +@@ -574,8 +616,10 @@ static ssize_t store_refresh(struct device *dev, struct device_attribute *attr, + if (ret) + return ret; + +- offset = response[MSG_ARG0]; +- info = priv->dmem + offset; ++ info = get_msg_ptr(priv, response[MSG_ARG0], NULL, NULL); ++ if (!info) ++ return -EIO; ++ + writel_relaxed(val, info + DRAM_INFO_INTERVAL); + + return count; +@@ -587,23 +631,25 @@ static ssize_t show_vendor(struct device *dev, struct device_attribute *devattr, + u32 response[MSG_FIELD_MAX]; + struct private_data *priv; + void __iomem *info; +- unsigned int offset; +- int ret; ++ ssize_t ret; + + ret = generic_show(DPFE_CMD_GET_VENDOR, response, dev, buf); + if (ret) + return ret; + +- offset = response[MSG_ARG0]; + priv = dev_get_drvdata(dev); +- info = priv->dmem + offset; ++ ++ info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret); ++ if (!info) ++ return ret; + + return sprintf(buf, "%#x %#x %#x %#x %#x\n", + readl_relaxed(info + DRAM_VENDOR_MR5) & DRAM_VENDOR_MASK, + readl_relaxed(info + DRAM_VENDOR_MR6) & DRAM_VENDOR_MASK, + readl_relaxed(info + DRAM_VENDOR_MR7) & DRAM_VENDOR_MASK, + readl_relaxed(info + DRAM_VENDOR_MR8) & DRAM_VENDOR_MASK, +- readl_relaxed(info + DRAM_VENDOR_ERROR)); ++ readl_relaxed(info + DRAM_VENDOR_ERROR) & ++ DRAM_VENDOR_MASK); + } + + static int brcmstb_dpfe_resume(struct platform_device *pdev) +diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c +index 8d12017..4470630 100644 +--- a/drivers/message/fusion/mptctl.c ++++ b/drivers/message/fusion/mptctl.c +@@ -2687,6 +2687,8 @@ mptctl_hp_targetinfo(unsigned long arg) + __FILE__, __LINE__, iocnum); + return -ENODEV; + } ++ if (karg.hdr.id >= MPT_MAX_FC_DEVICES) ++ return -EINVAL; + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n", + ioc->name)); + +diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c +index 3e5eabd..772d029 100644 +--- a/drivers/misc/mei/bus.c ++++ b/drivers/misc/mei/bus.c +@@ -548,12 +548,6 @@ int mei_cldev_disable(struct mei_cl_device *cldev) + goto out; + } + +- if (bus->dev_state == MEI_DEV_POWER_DOWN) { +- dev_dbg(bus->dev, "Device is powering down, don't bother with disconnection\n"); +- err = 0; +- goto out; +- } +- + err = mei_cl_disconnect(cl); + if (err < 0) + dev_err(bus->dev, "Could not disconnect from the ME client\n"); +diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c +index be64969..7e60c18 100644 +--- a/drivers/misc/mei/client.c ++++ b/drivers/misc/mei/client.c +@@ -945,6 +945,12 @@ int mei_cl_disconnect(struct mei_cl *cl) + return 0; + } + ++ if (dev->dev_state == MEI_DEV_POWER_DOWN) { ++ cl_dbg(dev, cl, "Device is powering down, don't bother with disconnection\n"); ++ mei_cl_set_disconnected(cl); ++ return 0; ++ } ++ + rets = pm_runtime_get(dev->dev); + if (rets < 0 && rets != -EINPROGRESS) { + pm_runtime_put_noidle(dev->dev); +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index 0ccccba..e4b10b2 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -132,6 +132,11 @@ + #define MEI_DEV_ID_KBP 0xA2BA /* Kaby Point */ + #define MEI_DEV_ID_KBP_2 0xA2BB /* Kaby Point 2 */ + ++#define MEI_DEV_ID_CNP_LP 0x9DE0 /* Cannon Point LP */ ++#define MEI_DEV_ID_CNP_LP_4 0x9DE4 /* Cannon Point LP 4 (iTouch) */ ++#define MEI_DEV_ID_CNP_H 0xA360 /* Cannon Point H */ ++#define MEI_DEV_ID_CNP_H_4 0xA364 /* Cannon Point H 4 (iTouch) */ ++ + /* + * MEI HW Section + */ +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 4a0ccda..ea4e152 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -98,6 +98,11 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_KBP, MEI_ME_PCH8_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_KBP_2, MEI_ME_PCH8_CFG)}, + ++ {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_LP, MEI_ME_PCH8_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_LP_4, MEI_ME_PCH8_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_H, MEI_ME_PCH8_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_H_4, MEI_ME_PCH8_CFG)}, ++ + /* required last entry */ + {0, } + }; +diff --git a/drivers/misc/ocxl/file.c b/drivers/misc/ocxl/file.c +index d9aa407..038509e 100644 +--- a/drivers/misc/ocxl/file.c ++++ b/drivers/misc/ocxl/file.c +@@ -102,10 +102,32 @@ static long afu_ioctl_attach(struct ocxl_context *ctx, + return rc; + } + ++static long afu_ioctl_get_metadata(struct ocxl_context *ctx, ++ struct ocxl_ioctl_metadata __user *uarg) ++{ ++ struct ocxl_ioctl_metadata arg; ++ ++ memset(&arg, 0, sizeof(arg)); ++ ++ arg.version = 0; ++ ++ arg.afu_version_major = ctx->afu->config.version_major; ++ arg.afu_version_minor = ctx->afu->config.version_minor; ++ arg.pasid = ctx->pasid; ++ arg.pp_mmio_size = ctx->afu->config.pp_mmio_stride; ++ arg.global_mmio_size = ctx->afu->config.global_mmio_size; ++ ++ if (copy_to_user(uarg, &arg, sizeof(arg))) ++ return -EFAULT; ++ ++ return 0; ++} ++ + #define CMD_STR(x) (x == OCXL_IOCTL_ATTACH ? "ATTACH" : \ + x == OCXL_IOCTL_IRQ_ALLOC ? "IRQ_ALLOC" : \ + x == OCXL_IOCTL_IRQ_FREE ? "IRQ_FREE" : \ + x == OCXL_IOCTL_IRQ_SET_FD ? "IRQ_SET_FD" : \ ++ x == OCXL_IOCTL_GET_METADATA ? "GET_METADATA" : \ + "UNKNOWN") + + static long afu_ioctl(struct file *file, unsigned int cmd, +@@ -133,8 +155,10 @@ static long afu_ioctl(struct file *file, unsigned int cmd, + if (!rc) { + rc = copy_to_user((u64 __user *) args, &irq_offset, + sizeof(irq_offset)); +- if (rc) ++ if (rc) { + ocxl_afu_irq_free(ctx, irq_offset); ++ return -EFAULT; ++ } + } + break; + +@@ -157,6 +181,11 @@ static long afu_ioctl(struct file *file, unsigned int cmd, + irq_fd.eventfd); + break; + ++ case OCXL_IOCTL_GET_METADATA: ++ rc = afu_ioctl_get_metadata(ctx, ++ (struct ocxl_ioctl_metadata __user *) args); ++ break; ++ + default: + rc = -EINVAL; + } +@@ -277,7 +306,7 @@ static ssize_t afu_read(struct file *file, char __user *buf, size_t count, + struct ocxl_context *ctx = file->private_data; + struct ocxl_kernel_event_header header; + ssize_t rc; +- size_t used = 0; ++ ssize_t used = 0; + DEFINE_WAIT(event_wait); + + memset(&header, 0, sizeof(header)); +@@ -329,7 +358,7 @@ static ssize_t afu_read(struct file *file, char __user *buf, size_t count, + + used += sizeof(header); + +- rc = (ssize_t) used; ++ rc = used; + return rc; + } + +diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c +index 908e4db..42d6aa8 100644 +--- a/drivers/mmc/core/mmc_ops.c ++++ b/drivers/mmc/core/mmc_ops.c +@@ -848,7 +848,6 @@ int mmc_interrupt_hpi(struct mmc_card *card) + return 1; + } + +- mmc_claim_host(card->host); + err = mmc_send_status(card, &status); + if (err) { + pr_err("%s: Get card status fail\n", mmc_hostname(card->host)); +@@ -890,7 +889,6 @@ int mmc_interrupt_hpi(struct mmc_card *card) + } while (!err); + + out: +- mmc_release_host(card->host); + return err; + } + +@@ -932,9 +930,7 @@ static int mmc_read_bkops_status(struct mmc_card *card) + int err; + u8 *ext_csd; + +- mmc_claim_host(card->host); + err = mmc_get_ext_csd(card, &ext_csd); +- mmc_release_host(card->host); + if (err) + return err; + +diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c +index 229dc18..768972a 100644 +--- a/drivers/mmc/host/bcm2835.c ++++ b/drivers/mmc/host/bcm2835.c +@@ -1265,7 +1265,8 @@ static int bcm2835_add_host(struct bcm2835_host *host) + char pio_limit_string[20]; + int ret; + +- mmc->f_max = host->max_clk; ++ if (!mmc->f_max || mmc->f_max > host->max_clk) ++ mmc->f_max = host->max_clk; + mmc->f_min = host->max_clk / SDCDIV_MAX_CDIV; + + mmc->max_busy_timeout = ~0 / (mmc->f_max / 1000); +diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c +index 3502679..fa41d94 100644 +--- a/drivers/mmc/host/dw_mmc-exynos.c ++++ b/drivers/mmc/host/dw_mmc-exynos.c +@@ -487,6 +487,7 @@ static unsigned long exynos_dwmmc_caps[4] = { + + static const struct dw_mci_drv_data exynos_drv_data = { + .caps = exynos_dwmmc_caps, ++ .num_caps = ARRAY_SIZE(exynos_dwmmc_caps), + .init = dw_mci_exynos_priv_init, + .set_ios = dw_mci_exynos_set_ios, + .parse_dt = dw_mci_exynos_parse_dt, +diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c +index 73fd75c..89cdb3d 100644 +--- a/drivers/mmc/host/dw_mmc-k3.c ++++ b/drivers/mmc/host/dw_mmc-k3.c +@@ -135,6 +135,9 @@ static int dw_mci_hi6220_parse_dt(struct dw_mci *host) + if (priv->ctrl_id < 0) + priv->ctrl_id = 0; + ++ if (priv->ctrl_id >= TIMING_MODE) ++ return -EINVAL; ++ + host->priv = priv; + return 0; + } +@@ -207,6 +210,7 @@ static int dw_mci_hi6220_execute_tuning(struct dw_mci_slot *slot, u32 opcode) + + static const struct dw_mci_drv_data hi6220_data = { + .caps = dw_mci_hi6220_caps, ++ .num_caps = ARRAY_SIZE(dw_mci_hi6220_caps), + .switch_voltage = dw_mci_hi6220_switch_voltage, + .set_ios = dw_mci_hi6220_set_ios, + .parse_dt = dw_mci_hi6220_parse_dt, +diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c +index a3f1c2b..3392952 100644 +--- a/drivers/mmc/host/dw_mmc-rockchip.c ++++ b/drivers/mmc/host/dw_mmc-rockchip.c +@@ -319,6 +319,7 @@ static const struct dw_mci_drv_data rk2928_drv_data = { + + static const struct dw_mci_drv_data rk3288_drv_data = { + .caps = dw_mci_rk3288_dwmmc_caps, ++ .num_caps = ARRAY_SIZE(dw_mci_rk3288_dwmmc_caps), + .set_ios = dw_mci_rk3288_set_ios, + .execute_tuning = dw_mci_rk3288_execute_tuning, + .parse_dt = dw_mci_rk3288_parse_dt, +diff --git a/drivers/mmc/host/dw_mmc-zx.c b/drivers/mmc/host/dw_mmc-zx.c +index d38e94a..c06b539 100644 +--- a/drivers/mmc/host/dw_mmc-zx.c ++++ b/drivers/mmc/host/dw_mmc-zx.c +@@ -195,6 +195,7 @@ static unsigned long zx_dwmmc_caps[3] = { + + static const struct dw_mci_drv_data zx_drv_data = { + .caps = zx_dwmmc_caps, ++ .num_caps = ARRAY_SIZE(zx_dwmmc_caps), + .execute_tuning = dw_mci_zx_execute_tuning, + .prepare_hs400_tuning = dw_mci_zx_prepare_hs400_tuning, + .parse_dt = dw_mci_zx_parse_dt, +diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c +index 0aa3997..d9b4ace 100644 +--- a/drivers/mmc/host/dw_mmc.c ++++ b/drivers/mmc/host/dw_mmc.c +@@ -165,6 +165,8 @@ static int dw_mci_regs_show(struct seq_file *s, void *v) + { + struct dw_mci *host = s->private; + ++ pm_runtime_get_sync(host->dev); ++ + seq_printf(s, "STATUS:\t0x%08x\n", mci_readl(host, STATUS)); + seq_printf(s, "RINTSTS:\t0x%08x\n", mci_readl(host, RINTSTS)); + seq_printf(s, "CMD:\t0x%08x\n", mci_readl(host, CMD)); +@@ -172,6 +174,8 @@ static int dw_mci_regs_show(struct seq_file *s, void *v) + seq_printf(s, "INTMASK:\t0x%08x\n", mci_readl(host, INTMASK)); + seq_printf(s, "CLKENA:\t0x%08x\n", mci_readl(host, CLKENA)); + ++ pm_runtime_put_autosuspend(host->dev); ++ + return 0; + } + +@@ -2778,12 +2782,57 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) + return IRQ_HANDLED; + } + ++static int dw_mci_init_slot_caps(struct dw_mci_slot *slot) ++{ ++ struct dw_mci *host = slot->host; ++ const struct dw_mci_drv_data *drv_data = host->drv_data; ++ struct mmc_host *mmc = slot->mmc; ++ int ctrl_id; ++ ++ if (host->pdata->caps) ++ mmc->caps = host->pdata->caps; ++ ++ /* ++ * Support MMC_CAP_ERASE by default. ++ * It needs to use trim/discard/erase commands. ++ */ ++ mmc->caps |= MMC_CAP_ERASE; ++ ++ if (host->pdata->pm_caps) ++ mmc->pm_caps = host->pdata->pm_caps; ++ ++ if (host->dev->of_node) { ++ ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); ++ if (ctrl_id < 0) ++ ctrl_id = 0; ++ } else { ++ ctrl_id = to_platform_device(host->dev)->id; ++ } ++ ++ if (drv_data && drv_data->caps) { ++ if (ctrl_id >= drv_data->num_caps) { ++ dev_err(host->dev, "invalid controller id %d\n", ++ ctrl_id); ++ return -EINVAL; ++ } ++ mmc->caps |= drv_data->caps[ctrl_id]; ++ } ++ ++ if (host->pdata->caps2) ++ mmc->caps2 = host->pdata->caps2; ++ ++ /* Process SDIO IRQs through the sdio_irq_work. */ ++ if (mmc->caps & MMC_CAP_SDIO_IRQ) ++ mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; ++ ++ return 0; ++} ++ + static int dw_mci_init_slot(struct dw_mci *host) + { + struct mmc_host *mmc; + struct dw_mci_slot *slot; +- const struct dw_mci_drv_data *drv_data = host->drv_data; +- int ctrl_id, ret; ++ int ret; + u32 freq[2]; + + mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); +@@ -2817,38 +2866,13 @@ static int dw_mci_init_slot(struct dw_mci *host) + if (!mmc->ocr_avail) + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + +- if (host->pdata->caps) +- mmc->caps = host->pdata->caps; +- +- /* +- * Support MMC_CAP_ERASE by default. +- * It needs to use trim/discard/erase commands. +- */ +- mmc->caps |= MMC_CAP_ERASE; +- +- if (host->pdata->pm_caps) +- mmc->pm_caps = host->pdata->pm_caps; +- +- if (host->dev->of_node) { +- ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); +- if (ctrl_id < 0) +- ctrl_id = 0; +- } else { +- ctrl_id = to_platform_device(host->dev)->id; +- } +- if (drv_data && drv_data->caps) +- mmc->caps |= drv_data->caps[ctrl_id]; +- +- if (host->pdata->caps2) +- mmc->caps2 = host->pdata->caps2; +- + ret = mmc_of_parse(mmc); + if (ret) + goto err_host_allocated; + +- /* Process SDIO IRQs through the sdio_irq_work. */ +- if (mmc->caps & MMC_CAP_SDIO_IRQ) +- mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; ++ ret = dw_mci_init_slot_caps(slot); ++ if (ret) ++ goto err_host_allocated; + + /* Useful defaults if platform data is unset. */ + if (host->use_dma == TRANS_MODE_IDMAC) { +diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h +index e3124f0..1424bd4 100644 +--- a/drivers/mmc/host/dw_mmc.h ++++ b/drivers/mmc/host/dw_mmc.h +@@ -543,6 +543,7 @@ struct dw_mci_slot { + /** + * dw_mci driver data - dw-mshc implementation specific driver data. + * @caps: mmc subsystem specified capabilities of the controller(s). ++ * @num_caps: number of capabilities specified by @caps. + * @init: early implementation specific initialization. + * @set_ios: handle bus specific extensions. + * @parse_dt: parse implementation specific device tree properties. +@@ -554,6 +555,7 @@ struct dw_mci_slot { + */ + struct dw_mci_drv_data { + unsigned long *caps; ++ u32 num_caps; + int (*init)(struct dw_mci *host); + void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); + int (*parse_dt)(struct dw_mci *host); +diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c +index 22438ebf..4f972b8 100644 +--- a/drivers/mmc/host/meson-gx-mmc.c ++++ b/drivers/mmc/host/meson-gx-mmc.c +@@ -717,22 +717,6 @@ static int meson_mmc_clk_phase_tuning(struct mmc_host *mmc, u32 opcode, + static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode) + { + struct meson_host *host = mmc_priv(mmc); +- int ret; +- +- /* +- * If this is the initial tuning, try to get a sane Rx starting +- * phase before doing the actual tuning. +- */ +- if (!mmc->doing_retune) { +- ret = meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); +- +- if (ret) +- return ret; +- } +- +- ret = meson_mmc_clk_phase_tuning(mmc, opcode, host->tx_clk); +- if (ret) +- return ret; + + return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); + } +@@ -763,9 +747,8 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + if (!IS_ERR(mmc->supply.vmmc)) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); + +- /* Reset phases */ ++ /* Reset rx phase */ + clk_set_phase(host->rx_clk, 0); +- clk_set_phase(host->tx_clk, 270); + + break; + +diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c +index 6d1a983..82c4f05 100644 +--- a/drivers/mmc/host/sdhci-pci-core.c ++++ b/drivers/mmc/host/sdhci-pci-core.c +@@ -654,9 +654,36 @@ static void byt_read_dsm(struct sdhci_pci_slot *slot) + slot->chip->rpm_retune = intel_host->d3_retune; + } + +-static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) ++static int intel_execute_tuning(struct mmc_host *mmc, u32 opcode) ++{ ++ int err = sdhci_execute_tuning(mmc, opcode); ++ struct sdhci_host *host = mmc_priv(mmc); ++ ++ if (err) ++ return err; ++ ++ /* ++ * Tuning can leave the IP in an active state (Buffer Read Enable bit ++ * set) which prevents the entry to low power states (i.e. S0i3). Data ++ * reset will clear it. ++ */ ++ sdhci_reset(host, SDHCI_RESET_DATA); ++ ++ return 0; ++} ++ ++static void byt_probe_slot(struct sdhci_pci_slot *slot) + { ++ struct mmc_host_ops *ops = &slot->host->mmc_host_ops; ++ + byt_read_dsm(slot); ++ ++ ops->execute_tuning = intel_execute_tuning; ++} ++ ++static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) ++{ ++ byt_probe_slot(slot); + slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | + MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR | + MMC_CAP_CMD_DURING_TFR | +@@ -779,7 +806,7 @@ static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot) + { + int err; + +- byt_read_dsm(slot); ++ byt_probe_slot(slot); + + err = ni_set_max_freq(slot); + if (err) +@@ -792,7 +819,7 @@ static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot) + + static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot) + { +- byt_read_dsm(slot); ++ byt_probe_slot(slot); + slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE | + MMC_CAP_WAIT_WHILE_BUSY; + return 0; +@@ -800,7 +827,7 @@ static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot) + + static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) + { +- byt_read_dsm(slot); ++ byt_probe_slot(slot); + slot->host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | + MMC_CAP_AGGRESSIVE_PM | MMC_CAP_CD_WAKE; + slot->cd_idx = 0; +diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig +index e6b8c59..736ac88 100644 +--- a/drivers/mtd/nand/Kconfig ++++ b/drivers/mtd/nand/Kconfig +@@ -328,7 +328,7 @@ config MTD_NAND_MARVELL + tristate "NAND controller support on Marvell boards" + depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \ + COMPILE_TEST +- depends on HAS_IOMEM ++ depends on HAS_IOMEM && HAS_DMA + help + This enables the NAND flash controller driver for Marvell boards, + including: +diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c +index 80d31a5..f367144 100644 +--- a/drivers/mtd/nand/vf610_nfc.c ++++ b/drivers/mtd/nand/vf610_nfc.c +@@ -752,10 +752,8 @@ static int vf610_nfc_probe(struct platform_device *pdev) + if (mtd->oobsize > 64) + mtd->oobsize = 64; + +- /* +- * mtd->ecclayout is not specified here because we're using the +- * default large page ECC layout defined in NAND core. +- */ ++ /* Use default large page ECC layout defined in NAND core */ ++ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); + if (chip->ecc.strength == 32) { + nfc->ecc_mode = ECC_60_BYTE; + chip->ecc.bytes = 60; +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +index 3e5833c..eb23f9b 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +@@ -426,6 +426,8 @@ static int xgbe_pci_resume(struct pci_dev *pdev) + struct net_device *netdev = pdata->netdev; + int ret = 0; + ++ XP_IOWRITE(pdata, XP_INT_EN, 0x1fffff); ++ + pdata->lpm_ctrl &= ~MDIO_CTRL1_LPOWER; + XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl); + +diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +index 22889fc..87c4308 100644 +--- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c ++++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +@@ -226,6 +226,10 @@ static int aq_pci_probe(struct pci_dev *pdev, + goto err_ioremap; + + self->aq_hw = kzalloc(sizeof(*self->aq_hw), GFP_KERNEL); ++ if (!self->aq_hw) { ++ err = -ENOMEM; ++ goto err_ioremap; ++ } + self->aq_hw->aq_nic_cfg = aq_nic_get_cfg(self); + + for (bar = 0; bar < 4; ++bar) { +@@ -235,19 +239,19 @@ static int aq_pci_probe(struct pci_dev *pdev, + mmio_pa = pci_resource_start(pdev, bar); + if (mmio_pa == 0U) { + err = -EIO; +- goto err_ioremap; ++ goto err_free_aq_hw; + } + + reg_sz = pci_resource_len(pdev, bar); + if ((reg_sz <= 24 /*ATL_REGS_SIZE*/)) { + err = -EIO; +- goto err_ioremap; ++ goto err_free_aq_hw; + } + + self->aq_hw->mmio = ioremap_nocache(mmio_pa, reg_sz); + if (!self->aq_hw->mmio) { + err = -EIO; +- goto err_ioremap; ++ goto err_free_aq_hw; + } + break; + } +@@ -255,7 +259,7 @@ static int aq_pci_probe(struct pci_dev *pdev, + + if (bar == 4) { + err = -EIO; +- goto err_ioremap; ++ goto err_free_aq_hw; + } + + numvecs = min((u8)AQ_CFG_VECS_DEF, +@@ -290,6 +294,8 @@ static int aq_pci_probe(struct pci_dev *pdev, + aq_pci_free_irq_vectors(self); + err_hwinit: + iounmap(self->aq_hw->mmio); ++err_free_aq_hw: ++ kfree(self->aq_hw); + err_ioremap: + free_netdev(ndev); + err_pci_func: +diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c +index a77ee2f..c1841db 100644 +--- a/drivers/net/ethernet/broadcom/tg3.c ++++ b/drivers/net/ethernet/broadcom/tg3.c +@@ -820,7 +820,7 @@ static int tg3_ape_event_lock(struct tg3 *tp, u32 timeout_us) + + tg3_ape_unlock(tp, TG3_APE_LOCK_MEM); + +- udelay(10); ++ usleep_range(10, 20); + timeout_us -= (timeout_us > 10) ? 10 : timeout_us; + } + +@@ -922,8 +922,8 @@ static int tg3_ape_send_event(struct tg3 *tp, u32 event) + if (!(apedata & APE_FW_STATUS_READY)) + return -EAGAIN; + +- /* Wait for up to 1 millisecond for APE to service previous event. */ +- err = tg3_ape_event_lock(tp, 1000); ++ /* Wait for up to 20 millisecond for APE to service previous event. */ ++ err = tg3_ape_event_lock(tp, 20000); + if (err) + return err; + +@@ -946,6 +946,7 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind) + + switch (kind) { + case RESET_KIND_INIT: ++ tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_COUNT, tp->ape_hb++); + tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, + APE_HOST_SEG_SIG_MAGIC); + tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN, +@@ -962,13 +963,6 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind) + event = APE_EVENT_STATUS_STATE_START; + break; + case RESET_KIND_SHUTDOWN: +- /* With the interface we are currently using, +- * APE does not track driver state. Wiping +- * out the HOST SEGMENT SIGNATURE forces +- * the APE to assume OS absent status. +- */ +- tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0); +- + if (device_may_wakeup(&tp->pdev->dev) && + tg3_flag(tp, WOL_ENABLE)) { + tg3_ape_write32(tp, TG3_APE_HOST_WOL_SPEED, +@@ -990,6 +984,18 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind) + tg3_ape_send_event(tp, event); + } + ++static void tg3_send_ape_heartbeat(struct tg3 *tp, ++ unsigned long interval) ++{ ++ /* Check if hb interval has exceeded */ ++ if (!tg3_flag(tp, ENABLE_APE) || ++ time_before(jiffies, tp->ape_hb_jiffies + interval)) ++ return; ++ ++ tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_COUNT, tp->ape_hb++); ++ tp->ape_hb_jiffies = jiffies; ++} ++ + static void tg3_disable_ints(struct tg3 *tp) + { + int i; +@@ -7262,6 +7268,7 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget) + } + } + ++ tg3_send_ape_heartbeat(tp, TG3_APE_HB_INTERVAL << 1); + return work_done; + + tx_recovery: +@@ -7344,6 +7351,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) + } + } + ++ tg3_send_ape_heartbeat(tp, TG3_APE_HB_INTERVAL << 1); + return work_done; + + tx_recovery: +@@ -10732,7 +10740,7 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy) + if (tg3_flag(tp, ENABLE_APE)) + /* Write our heartbeat update interval to APE. */ + tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS, +- APE_HOST_HEARTBEAT_INT_DISABLE); ++ APE_HOST_HEARTBEAT_INT_5SEC); + + tg3_write_sig_post_reset(tp, RESET_KIND_INIT); + +@@ -11077,6 +11085,9 @@ static void tg3_timer(struct timer_list *t) + tp->asf_counter = tp->asf_multiplier; + } + ++ /* Update the APE heartbeat every 5 seconds.*/ ++ tg3_send_ape_heartbeat(tp, TG3_APE_HB_INTERVAL); ++ + spin_unlock(&tp->lock); + + restart_timer: +@@ -16653,6 +16664,8 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent) + pci_state_reg); + + tg3_ape_lock_init(tp); ++ tp->ape_hb_interval = ++ msecs_to_jiffies(APE_HOST_HEARTBEAT_INT_5SEC); + } + + /* Set up tp->grc_local_ctrl before calling +diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h +index 47f51cc..1d61aa3 100644 +--- a/drivers/net/ethernet/broadcom/tg3.h ++++ b/drivers/net/ethernet/broadcom/tg3.h +@@ -2508,6 +2508,7 @@ + #define TG3_APE_LOCK_PHY3 5 + #define TG3_APE_LOCK_GPIO 7 + ++#define TG3_APE_HB_INTERVAL (tp->ape_hb_interval) + #define TG3_EEPROM_SB_F1R2_MBA_OFF 0x10 + + +@@ -3423,6 +3424,10 @@ struct tg3 { + struct device *hwmon_dev; + bool link_up; + bool pcierr_recovery; ++ ++ u32 ape_hb; ++ unsigned long ape_hb_interval; ++ unsigned long ape_hb_jiffies; + }; + + /* Accessor macros for chip and asic attributes +diff --git a/drivers/net/ethernet/cavium/common/cavium_ptp.c b/drivers/net/ethernet/cavium/common/cavium_ptp.c +index c87c9c6..d59497a 100644 +--- a/drivers/net/ethernet/cavium/common/cavium_ptp.c ++++ b/drivers/net/ethernet/cavium/common/cavium_ptp.c +@@ -75,6 +75,8 @@ EXPORT_SYMBOL(cavium_ptp_get); + + void cavium_ptp_put(struct cavium_ptp *ptp) + { ++ if (!ptp) ++ return; + pci_dev_put(ptp->pdev); + } + EXPORT_SYMBOL(cavium_ptp_put); +diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c +index b68cde9..7d9c5ff 100644 +--- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c ++++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c +@@ -67,11 +67,6 @@ module_param(cpi_alg, int, S_IRUGO); + MODULE_PARM_DESC(cpi_alg, + "PFC algorithm (0=none, 1=VLAN, 2=VLAN16, 3=IP Diffserv)"); + +-struct nicvf_xdp_tx { +- u64 dma_addr; +- u8 qidx; +-}; +- + static inline u8 nicvf_netdev_qidx(struct nicvf *nic, u8 qidx) + { + if (nic->sqs_mode) +@@ -507,29 +502,14 @@ static int nicvf_init_resources(struct nicvf *nic) + return 0; + } + +-static void nicvf_unmap_page(struct nicvf *nic, struct page *page, u64 dma_addr) +-{ +- /* Check if it's a recycled page, if not unmap the DMA mapping. +- * Recycled page holds an extra reference. +- */ +- if (page_ref_count(page) == 1) { +- dma_addr &= PAGE_MASK; +- dma_unmap_page_attrs(&nic->pdev->dev, dma_addr, +- RCV_FRAG_LEN + XDP_HEADROOM, +- DMA_FROM_DEVICE, +- DMA_ATTR_SKIP_CPU_SYNC); +- } +-} +- + static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog, + struct cqe_rx_t *cqe_rx, struct snd_queue *sq, + struct rcv_queue *rq, struct sk_buff **skb) + { + struct xdp_buff xdp; + struct page *page; +- struct nicvf_xdp_tx *xdp_tx = NULL; + u32 action; +- u16 len, err, offset = 0; ++ u16 len, offset = 0; + u64 dma_addr, cpu_addr; + void *orig_data; + +@@ -543,7 +523,7 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog, + cpu_addr = (u64)phys_to_virt(cpu_addr); + page = virt_to_page((void *)cpu_addr); + +- xdp.data_hard_start = page_address(page) + RCV_BUF_HEADROOM; ++ xdp.data_hard_start = page_address(page); + xdp.data = (void *)cpu_addr; + xdp_set_data_meta_invalid(&xdp); + xdp.data_end = xdp.data + len; +@@ -563,7 +543,18 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog, + + switch (action) { + case XDP_PASS: +- nicvf_unmap_page(nic, page, dma_addr); ++ /* Check if it's a recycled page, if not ++ * unmap the DMA mapping. ++ * ++ * Recycled page holds an extra reference. ++ */ ++ if (page_ref_count(page) == 1) { ++ dma_addr &= PAGE_MASK; ++ dma_unmap_page_attrs(&nic->pdev->dev, dma_addr, ++ RCV_FRAG_LEN + XDP_PACKET_HEADROOM, ++ DMA_FROM_DEVICE, ++ DMA_ATTR_SKIP_CPU_SYNC); ++ } + + /* Build SKB and pass on packet to network stack */ + *skb = build_skb(xdp.data, +@@ -576,20 +567,6 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog, + case XDP_TX: + nicvf_xdp_sq_append_pkt(nic, sq, (u64)xdp.data, dma_addr, len); + return true; +- case XDP_REDIRECT: +- /* Save DMA address for use while transmitting */ +- xdp_tx = (struct nicvf_xdp_tx *)page_address(page); +- xdp_tx->dma_addr = dma_addr; +- xdp_tx->qidx = nicvf_netdev_qidx(nic, cqe_rx->rq_idx); +- +- err = xdp_do_redirect(nic->pnicvf->netdev, &xdp, prog); +- if (!err) +- return true; +- +- /* Free the page on error */ +- nicvf_unmap_page(nic, page, dma_addr); +- put_page(page); +- break; + default: + bpf_warn_invalid_xdp_action(action); + /* fall through */ +@@ -597,7 +574,18 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog, + trace_xdp_exception(nic->netdev, prog, action); + /* fall through */ + case XDP_DROP: +- nicvf_unmap_page(nic, page, dma_addr); ++ /* Check if it's a recycled page, if not ++ * unmap the DMA mapping. ++ * ++ * Recycled page holds an extra reference. ++ */ ++ if (page_ref_count(page) == 1) { ++ dma_addr &= PAGE_MASK; ++ dma_unmap_page_attrs(&nic->pdev->dev, dma_addr, ++ RCV_FRAG_LEN + XDP_PACKET_HEADROOM, ++ DMA_FROM_DEVICE, ++ DMA_ATTR_SKIP_CPU_SYNC); ++ } + put_page(page); + return true; + } +@@ -1864,50 +1852,6 @@ static int nicvf_xdp(struct net_device *netdev, struct netdev_bpf *xdp) + } + } + +-static int nicvf_xdp_xmit(struct net_device *netdev, struct xdp_buff *xdp) +-{ +- struct nicvf *nic = netdev_priv(netdev); +- struct nicvf *snic = nic; +- struct nicvf_xdp_tx *xdp_tx; +- struct snd_queue *sq; +- struct page *page; +- int err, qidx; +- +- if (!netif_running(netdev) || !nic->xdp_prog) +- return -EINVAL; +- +- page = virt_to_page(xdp->data); +- xdp_tx = (struct nicvf_xdp_tx *)page_address(page); +- qidx = xdp_tx->qidx; +- +- if (xdp_tx->qidx >= nic->xdp_tx_queues) +- return -EINVAL; +- +- /* Get secondary Qset's info */ +- if (xdp_tx->qidx >= MAX_SND_QUEUES_PER_QS) { +- qidx = xdp_tx->qidx / MAX_SND_QUEUES_PER_QS; +- snic = (struct nicvf *)nic->snicvf[qidx - 1]; +- if (!snic) +- return -EINVAL; +- qidx = xdp_tx->qidx % MAX_SND_QUEUES_PER_QS; +- } +- +- sq = &snic->qs->sq[qidx]; +- err = nicvf_xdp_sq_append_pkt(snic, sq, (u64)xdp->data, +- xdp_tx->dma_addr, +- xdp->data_end - xdp->data); +- if (err) +- return -ENOMEM; +- +- nicvf_xdp_sq_doorbell(snic, sq, qidx); +- return 0; +-} +- +-static void nicvf_xdp_flush(struct net_device *dev) +-{ +- return; +-} +- + static int nicvf_config_hwtstamp(struct net_device *netdev, struct ifreq *ifr) + { + struct hwtstamp_config config; +@@ -1986,8 +1930,6 @@ static const struct net_device_ops nicvf_netdev_ops = { + .ndo_fix_features = nicvf_fix_features, + .ndo_set_features = nicvf_set_features, + .ndo_bpf = nicvf_xdp, +- .ndo_xdp_xmit = nicvf_xdp_xmit, +- .ndo_xdp_flush = nicvf_xdp_flush, + .ndo_do_ioctl = nicvf_ioctl, + }; + +diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +index 3eae9ff..d42704d 100644 +--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c ++++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +@@ -204,7 +204,7 @@ static inline int nicvf_alloc_rcv_buffer(struct nicvf *nic, struct rbdr *rbdr, + + /* Reserve space for header modifications by BPF program */ + if (rbdr->is_xdp) +- buf_len += XDP_HEADROOM; ++ buf_len += XDP_PACKET_HEADROOM; + + /* Check if it's recycled */ + if (pgcache) +@@ -224,9 +224,8 @@ static inline int nicvf_alloc_rcv_buffer(struct nicvf *nic, struct rbdr *rbdr, + nic->rb_page = NULL; + return -ENOMEM; + } +- + if (pgcache) +- pgcache->dma_addr = *rbuf + XDP_HEADROOM; ++ pgcache->dma_addr = *rbuf + XDP_PACKET_HEADROOM; + nic->rb_page_offset += buf_len; + } + +@@ -1244,7 +1243,7 @@ int nicvf_xdp_sq_append_pkt(struct nicvf *nic, struct snd_queue *sq, + int qentry; + + if (subdesc_cnt > sq->xdp_free_cnt) +- return -1; ++ return 0; + + qentry = nicvf_get_sq_desc(sq, subdesc_cnt); + +@@ -1255,7 +1254,7 @@ int nicvf_xdp_sq_append_pkt(struct nicvf *nic, struct snd_queue *sq, + + sq->xdp_desc_cnt += subdesc_cnt; + +- return 0; ++ return 1; + } + + /* Calculate no of SQ subdescriptors needed to transmit all +@@ -1656,7 +1655,7 @@ static void nicvf_unmap_rcv_buffer(struct nicvf *nic, u64 dma_addr, + if (page_ref_count(page) != 1) + return; + +- len += XDP_HEADROOM; ++ len += XDP_PACKET_HEADROOM; + /* Receive buffers in XDP mode are mapped from page start */ + dma_addr &= PAGE_MASK; + } +diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h +index ce1eed7..5e9a03c 100644 +--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h ++++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h +@@ -11,7 +11,6 @@ + + #include + #include +-#include + #include + #include "q_struct.h" + +@@ -94,9 +93,6 @@ + #define RCV_FRAG_LEN (SKB_DATA_ALIGN(DMA_BUFFER_LEN + NET_SKB_PAD) + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) + +-#define RCV_BUF_HEADROOM 128 /* To store dma address for XDP redirect */ +-#define XDP_HEADROOM (XDP_PACKET_HEADROOM + RCV_BUF_HEADROOM) +- + #define MAX_CQES_FOR_TX ((SND_QUEUE_LEN / MIN_SQ_DESC_PER_PKT_XMIT) * \ + MAX_CQE_PER_PKT_XMIT) + +diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c +index 557fd8b..00a1d2d 100644 +--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c ++++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c +@@ -472,7 +472,7 @@ int cudbg_collect_cim_la(struct cudbg_init *pdbg_init, + + if (is_t6(padap->params.chip)) { + size = padap->params.cim_la_size / 10 + 1; +- size *= 11 * sizeof(u32); ++ size *= 10 * sizeof(u32); + } else { + size = padap->params.cim_la_size / 8; + size *= 8 * sizeof(u32); +diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c +index 30485f9..143686c 100644 +--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c ++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c +@@ -102,7 +102,7 @@ static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity) + case CUDBG_CIM_LA: + if (is_t6(adap->params.chip)) { + len = adap->params.cim_la_size / 10 + 1; +- len *= 11 * sizeof(u32); ++ len *= 10 * sizeof(u32); + } else { + len = adap->params.cim_la_size / 8; + len *= 8 * sizeof(u32); +diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +index 56bc626..7b452e8 100644 +--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c ++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +@@ -4982,9 +4982,10 @@ static int cxgb4_iov_configure(struct pci_dev *pdev, int num_vfs) + + pcie_fw = readl(adap->regs + PCIE_FW_A); + /* Check if cxgb4 is the MASTER and fw is initialized */ +- if (!(pcie_fw & PCIE_FW_INIT_F) || ++ if (num_vfs && ++ (!(pcie_fw & PCIE_FW_INIT_F) || + !(pcie_fw & PCIE_FW_MASTER_VLD_F) || +- PCIE_FW_MASTER_G(pcie_fw) != CXGB4_UNIFIED_PF) { ++ PCIE_FW_MASTER_G(pcie_fw) != CXGB4_UNIFIED_PF)) { + dev_warn(&pdev->dev, + "cxgb4 driver needs to be MASTER to support SRIOV\n"); + return -EOPNOTSUPP; +@@ -5599,24 +5600,24 @@ static void remove_one(struct pci_dev *pdev) + #if IS_ENABLED(CONFIG_IPV6) + t4_cleanup_clip_tbl(adapter); + #endif +- iounmap(adapter->regs); + if (!is_t4(adapter->params.chip)) + iounmap(adapter->bar2); +- pci_disable_pcie_error_reporting(pdev); +- if ((adapter->flags & DEV_ENABLED)) { +- pci_disable_device(pdev); +- adapter->flags &= ~DEV_ENABLED; +- } +- pci_release_regions(pdev); +- kfree(adapter->mbox_log); +- synchronize_rcu(); +- kfree(adapter); + } + #ifdef CONFIG_PCI_IOV + else { + cxgb4_iov_configure(adapter->pdev, 0); + } + #endif ++ iounmap(adapter->regs); ++ pci_disable_pcie_error_reporting(pdev); ++ if ((adapter->flags & DEV_ENABLED)) { ++ pci_disable_device(pdev); ++ adapter->flags &= ~DEV_ENABLED; ++ } ++ pci_release_regions(pdev); ++ kfree(adapter->mbox_log); ++ synchronize_rcu(); ++ kfree(adapter); + } + + /* "Shutdown" quiesces the device, stopping Ingress Packet and Interrupt +diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +index 047609e..920bccd 100644 +--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c ++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +@@ -2637,7 +2637,6 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) + } + + #define EEPROM_STAT_ADDR 0x7bfc +-#define VPD_SIZE 0x800 + #define VPD_BASE 0x400 + #define VPD_BASE_OLD 0 + #define VPD_LEN 1024 +@@ -2704,15 +2703,6 @@ int t4_get_raw_vpd_params(struct adapter *adapter, struct vpd_params *p) + if (!vpd) + return -ENOMEM; + +- /* We have two VPD data structures stored in the adapter VPD area. +- * By default, Linux calculates the size of the VPD area by traversing +- * the first VPD area at offset 0x0, so we need to tell the OS what +- * our real VPD size is. +- */ +- ret = pci_set_vpd_size(adapter->pdev, VPD_SIZE); +- if (ret < 0) +- goto out; +- + /* Card information normally starts at VPD_BASE but early cards had + * it at 0. + */ +diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c +index 3bdeb29..f27f9ba 100644 +--- a/drivers/net/ethernet/freescale/gianfar.c ++++ b/drivers/net/ethernet/freescale/gianfar.c +@@ -2934,29 +2934,17 @@ static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus, + { + int size = lstatus & BD_LENGTH_MASK; + struct page *page = rxb->page; +- bool last = !!(lstatus & BD_LFLAG(RXBD_LAST)); +- +- /* Remove the FCS from the packet length */ +- if (last) +- size -= ETH_FCS_LEN; + + if (likely(first)) { + skb_put(skb, size); + } else { + /* the last fragments' length contains the full frame length */ +- if (last) ++ if (lstatus & BD_LFLAG(RXBD_LAST)) + size -= skb->len; + +- /* Add the last fragment if it contains something other than +- * the FCS, otherwise drop it and trim off any part of the FCS +- * that was already received. +- */ +- if (size > 0) +- skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, +- rxb->page_offset + RXBUF_ALIGNMENT, +- size, GFAR_RXB_TRUESIZE); +- else if (size < 0) +- pskb_trim(skb, skb->len + size); ++ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, ++ rxb->page_offset + RXBUF_ALIGNMENT, ++ size, GFAR_RXB_TRUESIZE); + } + + /* try reuse page */ +@@ -3069,12 +3057,12 @@ static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb) + if (priv->padding) + skb_pull(skb, priv->padding); + ++ /* Trim off the FCS */ ++ pskb_trim(skb, skb->len - ETH_FCS_LEN); ++ + if (ndev->features & NETIF_F_RXCSUM) + gfar_rx_checksum(skb, fcb); + +- /* Tell the skb what kind of packet this is */ +- skb->protocol = eth_type_trans(skb, ndev); +- + /* There's need to check for NETIF_F_HW_VLAN_CTAG_RX here. + * Even if vlan rx accel is disabled, on some chips + * RXFCB_VLN is pseudo randomly set. +@@ -3145,13 +3133,15 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) + continue; + } + ++ gfar_process_frame(ndev, skb); ++ + /* Increment the number of packets */ + total_pkts++; + total_bytes += skb->len; + + skb_record_rx_queue(skb, rx_queue->qindex); + +- gfar_process_frame(ndev, skb); ++ skb->protocol = eth_type_trans(skb, ndev); + + /* Send the packet up the stack */ + napi_gro_receive(&rx_queue->grp->napi_rx, skb); +diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c +index 2744726..1b3cc8b 100644 +--- a/drivers/net/ethernet/ibm/ibmvnic.c ++++ b/drivers/net/ethernet/ibm/ibmvnic.c +@@ -791,6 +791,18 @@ static int ibmvnic_login(struct net_device *netdev) + return 0; + } + ++static void release_login_buffer(struct ibmvnic_adapter *adapter) ++{ ++ kfree(adapter->login_buf); ++ adapter->login_buf = NULL; ++} ++ ++static void release_login_rsp_buffer(struct ibmvnic_adapter *adapter) ++{ ++ kfree(adapter->login_rsp_buf); ++ adapter->login_rsp_buf = NULL; ++} ++ + static void release_resources(struct ibmvnic_adapter *adapter) + { + int i; +@@ -813,6 +825,10 @@ static void release_resources(struct ibmvnic_adapter *adapter) + } + } + } ++ kfree(adapter->napi); ++ adapter->napi = NULL; ++ ++ release_login_rsp_buffer(adapter); + } + + static int set_link_state(struct ibmvnic_adapter *adapter, u8 link_state) +@@ -1057,6 +1073,35 @@ static int ibmvnic_open(struct net_device *netdev) + return rc; + } + ++static void clean_rx_pools(struct ibmvnic_adapter *adapter) ++{ ++ struct ibmvnic_rx_pool *rx_pool; ++ u64 rx_entries; ++ int rx_scrqs; ++ int i, j; ++ ++ if (!adapter->rx_pool) ++ return; ++ ++ rx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); ++ rx_entries = adapter->req_rx_add_entries_per_subcrq; ++ ++ /* Free any remaining skbs in the rx buffer pools */ ++ for (i = 0; i < rx_scrqs; i++) { ++ rx_pool = &adapter->rx_pool[i]; ++ if (!rx_pool) ++ continue; ++ ++ netdev_dbg(adapter->netdev, "Cleaning rx_pool[%d]\n", i); ++ for (j = 0; j < rx_entries; j++) { ++ if (rx_pool->rx_buff[j].skb) { ++ dev_kfree_skb_any(rx_pool->rx_buff[j].skb); ++ rx_pool->rx_buff[j].skb = NULL; ++ } ++ } ++ } ++} ++ + static void clean_tx_pools(struct ibmvnic_adapter *adapter) + { + struct ibmvnic_tx_pool *tx_pool; +@@ -1134,7 +1179,7 @@ static int __ibmvnic_close(struct net_device *netdev) + } + } + } +- ++ clean_rx_pools(adapter); + clean_tx_pools(adapter); + adapter->state = VNIC_CLOSED; + return rc; +@@ -1670,8 +1715,6 @@ static int do_reset(struct ibmvnic_adapter *adapter, + return 0; + } + +- netif_carrier_on(netdev); +- + /* kick napi */ + for (i = 0; i < adapter->req_rx_queues; i++) + napi_schedule(&adapter->napi[i]); +@@ -1679,6 +1722,8 @@ static int do_reset(struct ibmvnic_adapter *adapter, + if (adapter->reset_reason != VNIC_RESET_FAILOVER) + netdev_notify_peers(netdev); + ++ netif_carrier_on(netdev); ++ + return 0; + } + +@@ -1853,6 +1898,12 @@ static int ibmvnic_poll(struct napi_struct *napi, int budget) + be16_to_cpu(next->rx_comp.rc)); + /* free the entry */ + next->rx_comp.first = 0; ++ dev_kfree_skb_any(rx_buff->skb); ++ remove_buff_from_pool(adapter, rx_buff); ++ continue; ++ } else if (!rx_buff->skb) { ++ /* free the entry */ ++ next->rx_comp.first = 0; + remove_buff_from_pool(adapter, rx_buff); + continue; + } +@@ -3013,6 +3064,7 @@ static void send_login(struct ibmvnic_adapter *adapter) + struct vnic_login_client_data *vlcd; + int i; + ++ release_login_rsp_buffer(adapter); + client_data_len = vnic_client_data_len(adapter); + + buffer_size = +@@ -3738,6 +3790,7 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq, + ibmvnic_remove(adapter->vdev); + return -EIO; + } ++ release_login_buffer(adapter); + complete(&adapter->init_done); + + return 0; +diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +index 0da5aa2..9fc063a 100644 +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +@@ -1888,6 +1888,14 @@ static void ixgbe_dma_sync_frag(struct ixgbe_ring *rx_ring, + ixgbe_rx_pg_size(rx_ring), + DMA_FROM_DEVICE, + IXGBE_RX_DMA_ATTR); ++ } else if (ring_uses_build_skb(rx_ring)) { ++ unsigned long offset = (unsigned long)(skb->data) & ~PAGE_MASK; ++ ++ dma_sync_single_range_for_cpu(rx_ring->dev, ++ IXGBE_CB(skb)->dma, ++ offset, ++ skb_headlen(skb), ++ DMA_FROM_DEVICE); + } else { + struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0]; + +diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c +index a1d7b88..5a1668c 100644 +--- a/drivers/net/ethernet/marvell/mvpp2.c ++++ b/drivers/net/ethernet/marvell/mvpp2.c +@@ -7137,6 +7137,7 @@ static void mvpp2_set_rx_mode(struct net_device *dev) + int id = port->id; + bool allmulti = dev->flags & IFF_ALLMULTI; + ++retry: + mvpp2_prs_mac_promisc_set(priv, id, dev->flags & IFF_PROMISC); + mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_ALL, allmulti); + mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_IP6, allmulti); +@@ -7144,9 +7145,13 @@ static void mvpp2_set_rx_mode(struct net_device *dev) + /* Remove all port->id's mcast enries */ + mvpp2_prs_mcast_del_all(priv, id); + +- if (allmulti && !netdev_mc_empty(dev)) { +- netdev_for_each_mc_addr(ha, dev) +- mvpp2_prs_mac_da_accept(priv, id, ha->addr, true); ++ if (!allmulti) { ++ netdev_for_each_mc_addr(ha, dev) { ++ if (mvpp2_prs_mac_da_accept(priv, id, ha->addr, true)) { ++ allmulti = true; ++ goto retry; ++ } ++ } + } + } + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.c +index 0be4575..fd50916 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.c +@@ -96,10 +96,10 @@ static void print_lyr_2_4_hdrs(struct trace_seq *p, + "%pI4"); + } else if (ethertype.v == ETH_P_IPV6) { + static const struct in6_addr full_ones = { +- .in6_u.u6_addr32 = {htonl(0xffffffff), +- htonl(0xffffffff), +- htonl(0xffffffff), +- htonl(0xffffffff)}, ++ .in6_u.u6_addr32 = {__constant_htonl(0xffffffff), ++ __constant_htonl(0xffffffff), ++ __constant_htonl(0xffffffff), ++ __constant_htonl(0xffffffff)}, + }; + DECLARE_MASK_VAL(struct in6_addr, src_ipv6); + DECLARE_MASK_VAL(struct in6_addr, dst_ipv6); +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +index 47bab84..da94c8c 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -1768,13 +1768,16 @@ static void mlx5e_build_rq_param(struct mlx5e_priv *priv, + param->wq.linear = 1; + } + +-static void mlx5e_build_drop_rq_param(struct mlx5e_rq_param *param) ++static void mlx5e_build_drop_rq_param(struct mlx5_core_dev *mdev, ++ struct mlx5e_rq_param *param) + { + void *rqc = param->rqc; + void *wq = MLX5_ADDR_OF(rqc, rqc, wq); + + MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_LINKED_LIST); + MLX5_SET(wq, wq, log_wq_stride, ilog2(sizeof(struct mlx5e_rx_wqe))); ++ ++ param->wq.buf_numa_node = dev_to_node(&mdev->pdev->dev); + } + + static void mlx5e_build_sq_param_common(struct mlx5e_priv *priv, +@@ -2634,6 +2637,9 @@ static int mlx5e_alloc_drop_cq(struct mlx5_core_dev *mdev, + struct mlx5e_cq *cq, + struct mlx5e_cq_param *param) + { ++ param->wq.buf_numa_node = dev_to_node(&mdev->pdev->dev); ++ param->wq.db_numa_node = dev_to_node(&mdev->pdev->dev); ++ + return mlx5e_alloc_cq_common(mdev, param, cq); + } + +@@ -2645,7 +2651,7 @@ static int mlx5e_open_drop_rq(struct mlx5_core_dev *mdev, + struct mlx5e_cq *cq = &drop_rq->cq; + int err; + +- mlx5e_build_drop_rq_param(&rq_param); ++ mlx5e_build_drop_rq_param(mdev, &rq_param); + + err = mlx5e_alloc_drop_cq(mdev, cq, &cq_param); + if (err) +@@ -2994,8 +3000,8 @@ static int mlx5e_setup_tc_block(struct net_device *dev, + } + #endif + +-int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type, +- void *type_data) ++static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type, ++ void *type_data) + { + switch (type) { + #ifdef CONFIG_MLX5_ESWITCH +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +index 0d4bb06..e5c3ab4 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + #include "en.h" + #include "en_tc.h" + #include "eswitch.h" +@@ -546,20 +547,33 @@ bool mlx5e_post_rx_mpwqes(struct mlx5e_rq *rq) + return true; + } + ++static void mlx5e_lro_update_tcp_hdr(struct mlx5_cqe64 *cqe, struct tcphdr *tcp) ++{ ++ u8 l4_hdr_type = get_cqe_l4_hdr_type(cqe); ++ u8 tcp_ack = (l4_hdr_type == CQE_L4_HDR_TYPE_TCP_ACK_NO_DATA) || ++ (l4_hdr_type == CQE_L4_HDR_TYPE_TCP_ACK_AND_DATA); ++ ++ tcp->check = 0; ++ tcp->psh = get_cqe_lro_tcppsh(cqe); ++ ++ if (tcp_ack) { ++ tcp->ack = 1; ++ tcp->ack_seq = cqe->lro_ack_seq_num; ++ tcp->window = cqe->lro_tcp_win; ++ } ++} ++ + static void mlx5e_lro_update_hdr(struct sk_buff *skb, struct mlx5_cqe64 *cqe, + u32 cqe_bcnt) + { + struct ethhdr *eth = (struct ethhdr *)(skb->data); + struct tcphdr *tcp; + int network_depth = 0; ++ __wsum check; + __be16 proto; + u16 tot_len; + void *ip_p; + +- u8 l4_hdr_type = get_cqe_l4_hdr_type(cqe); +- u8 tcp_ack = (l4_hdr_type == CQE_L4_HDR_TYPE_TCP_ACK_NO_DATA) || +- (l4_hdr_type == CQE_L4_HDR_TYPE_TCP_ACK_AND_DATA); +- + proto = __vlan_get_protocol(skb, eth->h_proto, &network_depth); + + tot_len = cqe_bcnt - network_depth; +@@ -576,23 +590,30 @@ static void mlx5e_lro_update_hdr(struct sk_buff *skb, struct mlx5_cqe64 *cqe, + ipv4->check = 0; + ipv4->check = ip_fast_csum((unsigned char *)ipv4, + ipv4->ihl); ++ ++ mlx5e_lro_update_tcp_hdr(cqe, tcp); ++ check = csum_partial(tcp, tcp->doff * 4, ++ csum_unfold((__force __sum16)cqe->check_sum)); ++ /* Almost done, don't forget the pseudo header */ ++ tcp->check = csum_tcpudp_magic(ipv4->saddr, ipv4->daddr, ++ tot_len - sizeof(struct iphdr), ++ IPPROTO_TCP, check); + } else { ++ u16 payload_len = tot_len - sizeof(struct ipv6hdr); + struct ipv6hdr *ipv6 = ip_p; + + tcp = ip_p + sizeof(struct ipv6hdr); + skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; + + ipv6->hop_limit = cqe->lro_min_ttl; +- ipv6->payload_len = cpu_to_be16(tot_len - +- sizeof(struct ipv6hdr)); +- } +- +- tcp->psh = get_cqe_lro_tcppsh(cqe); +- +- if (tcp_ack) { +- tcp->ack = 1; +- tcp->ack_seq = cqe->lro_ack_seq_num; +- tcp->window = cqe->lro_tcp_win; ++ ipv6->payload_len = cpu_to_be16(payload_len); ++ ++ mlx5e_lro_update_tcp_hdr(cqe, tcp); ++ check = csum_partial(tcp, tcp->doff * 4, ++ csum_unfold((__force __sum16)cqe->check_sum)); ++ /* Almost done, don't forget the pseudo header */ ++ tcp->check = csum_ipv6_magic(&ipv6->saddr, &ipv6->daddr, payload_len, ++ IPPROTO_TCP, check); + } + } + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c +index 5a46082..7079764 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c +@@ -216,7 +216,8 @@ mlx5e_test_loopback_validate(struct sk_buff *skb, + if (iph->protocol != IPPROTO_UDP) + goto out; + +- udph = udp_hdr(skb); ++ /* Don't assume skb_transport_header() was set */ ++ udph = (struct udphdr *)((u8 *)iph + 4 * iph->ihl); + if (udph->dest != htons(9)) + goto out; + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +index fd98b0d..fa86a14 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +@@ -2529,7 +2529,8 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, + if (tcf_vlan_action(a) == TCA_VLAN_ACT_POP) { + attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP; + } else if (tcf_vlan_action(a) == TCA_VLAN_ACT_PUSH) { +- if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q)) ++ if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q) || ++ tcf_vlan_push_prio(a)) + return -EOPNOTSUPP; + + attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +index 569b42a..11b4f10 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +@@ -176,7 +176,7 @@ static inline u16 mlx5e_calc_min_inline(enum mlx5_inline_modes mode, + default: + hlen = mlx5e_skb_l2_header_offset(skb); + } +- return min_t(u16, hlen, skb->len); ++ return min_t(u16, hlen, skb_headlen(skb)); + } + + static inline void mlx5e_tx_skb_pull_inline(unsigned char **skb_data, +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +index 5ecf2cd..c2b1d7d 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +@@ -1529,6 +1529,10 @@ static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num, + + esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num); + ++ /* Create steering drop counters for ingress and egress ACLs */ ++ if (vport_num && esw->mode == SRIOV_LEGACY) ++ esw_vport_create_drop_counters(vport); ++ + /* Restore old vport configuration */ + esw_apply_vport_conf(esw, vport); + +@@ -1545,10 +1549,6 @@ static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num, + if (!vport_num) + vport->info.trusted = true; + +- /* create steering drop counters for ingress and egress ACLs */ +- if (vport_num && esw->mode == SRIOV_LEGACY) +- esw_vport_create_drop_counters(vport); +- + esw_vport_change_handle_locked(vport); + + esw->enabled_vports++; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +index c025c98..31fc2cf 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +@@ -1429,7 +1429,8 @@ static bool check_conflicting_actions(u32 action1, u32 action2) + + if (xored_actions & (MLX5_FLOW_CONTEXT_ACTION_DROP | + MLX5_FLOW_CONTEXT_ACTION_ENCAP | +- MLX5_FLOW_CONTEXT_ACTION_DECAP)) ++ MLX5_FLOW_CONTEXT_ACTION_DECAP | ++ MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)) + return true; + + return false; +@@ -1758,8 +1759,11 @@ _mlx5_add_flow_rules(struct mlx5_flow_table *ft, + + /* Collect all fgs which has a matching match_criteria */ + err = build_match_list(&match_head, ft, spec); +- if (err) ++ if (err) { ++ if (take_write) ++ up_write_ref_node(&ft->node); + return ERR_PTR(err); ++ } + + if (!take_write) + up_read_ref_node(&ft->node); +@@ -1768,8 +1772,11 @@ _mlx5_add_flow_rules(struct mlx5_flow_table *ft, + dest_num, version); + free_match_list(&match_head); + if (!IS_ERR(rule) || +- (PTR_ERR(rule) != -ENOENT && PTR_ERR(rule) != -EAGAIN)) ++ (PTR_ERR(rule) != -ENOENT && PTR_ERR(rule) != -EAGAIN)) { ++ if (take_write) ++ up_write_ref_node(&ft->node); + return rule; ++ } + + if (!take_write) { + nested_down_write_ref_node(&ft->node, FS_LOCK_GRANDPARENT); +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c +index 21d29f7..d39b0b7 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c +@@ -124,7 +124,7 @@ void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force) + trigger_cmd_completions(dev); + } + +- mlx5_core_event(dev, MLX5_DEV_EVENT_SYS_ERROR, 0); ++ mlx5_core_event(dev, MLX5_DEV_EVENT_SYS_ERROR, 1); + mlx5_core_err(dev, "end\n"); + + unlock: +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +index e159243..8570355 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +@@ -34,6 +34,7 @@ + #include + #include + #include "en.h" ++#include "clock.h" + + enum { + MLX5_CYCLES_SHIFT = 23 +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c +index 2ef641c9..ae391e4 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c +@@ -551,7 +551,7 @@ static int handle_hca_cap(struct mlx5_core_dev *dev) + MLX5_SET(cmd_hca_cap, + set_hca_cap, + cache_line_128byte, +- cache_line_size() == 128 ? 1 : 0); ++ cache_line_size() >= 128 ? 1 : 0); + + if (MLX5_CAP_GEN_MAX(dev, dct)) + MLX5_SET(cmd_hca_cap, set_hca_cap, dct, 1); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +index f6963b0..122506d 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +@@ -107,20 +107,20 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = { + MLXSW_AFK_ELEMENT_INFO_U32(VID, 0x10, 8, 12), + MLXSW_AFK_ELEMENT_INFO_U32(PCP, 0x10, 20, 3), + MLXSW_AFK_ELEMENT_INFO_U32(TCP_FLAGS, 0x10, 23, 9), +- MLXSW_AFK_ELEMENT_INFO_U32(IP_TTL_, 0x14, 0, 8), +- MLXSW_AFK_ELEMENT_INFO_U32(IP_ECN, 0x14, 9, 2), +- MLXSW_AFK_ELEMENT_INFO_U32(IP_DSCP, 0x14, 11, 6), +- MLXSW_AFK_ELEMENT_INFO_U32(SRC_IP4, 0x18, 0, 32), +- MLXSW_AFK_ELEMENT_INFO_U32(DST_IP4, 0x1C, 0, 32), +- MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_HI, 0x18, 8), +- MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_LO, 0x20, 8), +- MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_HI, 0x28, 8), +- MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_LO, 0x30, 8), + MLXSW_AFK_ELEMENT_INFO_U32(DST_L4_PORT, 0x14, 0, 16), + MLXSW_AFK_ELEMENT_INFO_U32(SRC_L4_PORT, 0x14, 16, 16), ++ MLXSW_AFK_ELEMENT_INFO_U32(IP_TTL_, 0x18, 0, 8), ++ MLXSW_AFK_ELEMENT_INFO_U32(IP_ECN, 0x18, 9, 2), ++ MLXSW_AFK_ELEMENT_INFO_U32(IP_DSCP, 0x18, 11, 6), ++ MLXSW_AFK_ELEMENT_INFO_U32(SRC_IP4, 0x20, 0, 32), ++ MLXSW_AFK_ELEMENT_INFO_U32(DST_IP4, 0x24, 0, 32), ++ MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_HI, 0x20, 8), ++ MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_LO, 0x28, 8), ++ MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_HI, 0x30, 8), ++ MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_LO, 0x38, 8), + }; + +-#define MLXSW_AFK_ELEMENT_STORAGE_SIZE 0x38 ++#define MLXSW_AFK_ELEMENT_STORAGE_SIZE 0x40 + + struct mlxsw_afk_element_inst { /* element instance in actual block */ + const struct mlxsw_afk_element_info *info; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +index 3dcc58d..c7e941a 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +@@ -1459,6 +1459,7 @@ mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) + } + + mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port; ++ mlxsw_sp_port_vlan->ref_count = 1; + mlxsw_sp_port_vlan->vid = vid; + list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list); + +@@ -1486,8 +1487,10 @@ mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); +- if (mlxsw_sp_port_vlan) ++ if (mlxsw_sp_port_vlan) { ++ mlxsw_sp_port_vlan->ref_count++; + return mlxsw_sp_port_vlan; ++ } + + return mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid); + } +@@ -1496,6 +1499,9 @@ void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) + { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + ++ if (--mlxsw_sp_port_vlan->ref_count != 0) ++ return; ++ + if (mlxsw_sp_port_vlan->bridge_port) + mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); + else if (fid) +@@ -4207,13 +4213,12 @@ static struct devlink_resource_ops mlxsw_sp_resource_kvd_hash_double_ops = { + .size_validate = mlxsw_sp_resource_kvd_hash_double_size_validate, + }; + +-static struct devlink_resource_size_params mlxsw_sp_kvd_size_params; +-static struct devlink_resource_size_params mlxsw_sp_linear_size_params; +-static struct devlink_resource_size_params mlxsw_sp_hash_single_size_params; +-static struct devlink_resource_size_params mlxsw_sp_hash_double_size_params; +- + static void +-mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core) ++mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core, ++ struct devlink_resource_size_params *kvd_size_params, ++ struct devlink_resource_size_params *linear_size_params, ++ struct devlink_resource_size_params *hash_double_size_params, ++ struct devlink_resource_size_params *hash_single_size_params) + { + u32 single_size_min = MLXSW_CORE_RES_GET(mlxsw_core, + KVD_SINGLE_MIN_SIZE); +@@ -4222,37 +4227,35 @@ mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core) + u32 kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE); + u32 linear_size_min = 0; + +- /* KVD top resource */ +- mlxsw_sp_kvd_size_params.size_min = kvd_size; +- mlxsw_sp_kvd_size_params.size_max = kvd_size; +- mlxsw_sp_kvd_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY; +- mlxsw_sp_kvd_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY; +- +- /* Linear part init */ +- mlxsw_sp_linear_size_params.size_min = linear_size_min; +- mlxsw_sp_linear_size_params.size_max = kvd_size - single_size_min - +- double_size_min; +- mlxsw_sp_linear_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY; +- mlxsw_sp_linear_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY; +- +- /* Hash double part init */ +- mlxsw_sp_hash_double_size_params.size_min = double_size_min; +- mlxsw_sp_hash_double_size_params.size_max = kvd_size - single_size_min - +- linear_size_min; +- mlxsw_sp_hash_double_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY; +- mlxsw_sp_hash_double_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY; +- +- /* Hash single part init */ +- mlxsw_sp_hash_single_size_params.size_min = single_size_min; +- mlxsw_sp_hash_single_size_params.size_max = kvd_size - double_size_min - +- linear_size_min; +- mlxsw_sp_hash_single_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY; +- mlxsw_sp_hash_single_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY; ++ devlink_resource_size_params_init(kvd_size_params, kvd_size, kvd_size, ++ MLXSW_SP_KVD_GRANULARITY, ++ DEVLINK_RESOURCE_UNIT_ENTRY); ++ devlink_resource_size_params_init(linear_size_params, linear_size_min, ++ kvd_size - single_size_min - ++ double_size_min, ++ MLXSW_SP_KVD_GRANULARITY, ++ DEVLINK_RESOURCE_UNIT_ENTRY); ++ devlink_resource_size_params_init(hash_double_size_params, ++ double_size_min, ++ kvd_size - single_size_min - ++ linear_size_min, ++ MLXSW_SP_KVD_GRANULARITY, ++ DEVLINK_RESOURCE_UNIT_ENTRY); ++ devlink_resource_size_params_init(hash_single_size_params, ++ single_size_min, ++ kvd_size - double_size_min - ++ linear_size_min, ++ MLXSW_SP_KVD_GRANULARITY, ++ DEVLINK_RESOURCE_UNIT_ENTRY); + } + + static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) + { + struct devlink *devlink = priv_to_devlink(mlxsw_core); ++ struct devlink_resource_size_params hash_single_size_params; ++ struct devlink_resource_size_params hash_double_size_params; ++ struct devlink_resource_size_params linear_size_params; ++ struct devlink_resource_size_params kvd_size_params; + u32 kvd_size, single_size, double_size, linear_size; + const struct mlxsw_config_profile *profile; + int err; +@@ -4261,13 +4264,17 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) + if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE)) + return -EIO; + +- mlxsw_sp_resource_size_params_prepare(mlxsw_core); ++ mlxsw_sp_resource_size_params_prepare(mlxsw_core, &kvd_size_params, ++ &linear_size_params, ++ &hash_double_size_params, ++ &hash_single_size_params); ++ + kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE); + err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD, + true, kvd_size, + MLXSW_SP_RESOURCE_KVD, + DEVLINK_RESOURCE_ID_PARENT_TOP, +- &mlxsw_sp_kvd_size_params, ++ &kvd_size_params, + &mlxsw_sp_resource_kvd_ops); + if (err) + return err; +@@ -4277,7 +4284,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) + false, linear_size, + MLXSW_SP_RESOURCE_KVD_LINEAR, + MLXSW_SP_RESOURCE_KVD, +- &mlxsw_sp_linear_size_params, ++ &linear_size_params, + &mlxsw_sp_resource_kvd_linear_ops); + if (err) + return err; +@@ -4291,7 +4298,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) + false, double_size, + MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, + MLXSW_SP_RESOURCE_KVD, +- &mlxsw_sp_hash_double_size_params, ++ &hash_double_size_params, + &mlxsw_sp_resource_kvd_hash_double_ops); + if (err) + return err; +@@ -4301,7 +4308,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) + false, single_size, + MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, + MLXSW_SP_RESOURCE_KVD, +- &mlxsw_sp_hash_single_size_params, ++ &hash_single_size_params, + &mlxsw_sp_resource_kvd_hash_single_ops); + if (err) + return err; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +index bdd8f94a..4ec1ca3 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +@@ -211,6 +211,7 @@ struct mlxsw_sp_port_vlan { + struct list_head list; + struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp_fid *fid; ++ unsigned int ref_count; + u16 vid; + struct mlxsw_sp_bridge_port *bridge_port; + struct list_head bridge_vlan_node; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +index bbd238e..54262af 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +@@ -112,11 +112,11 @@ static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1, + [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1, + [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1, ++ [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, + }; + + static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1, +- [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, + }; + + static const int *mlxsw_sp_packet_type_sfgc_types[] = { +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +index f0b25ba..f7948e9 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +@@ -788,6 +788,9 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp, + u32 tb_id, + struct netlink_ext_ack *extack) + { ++ struct mlxsw_sp_mr_table *mr4_table; ++ struct mlxsw_sp_fib *fib4; ++ struct mlxsw_sp_fib *fib6; + struct mlxsw_sp_vr *vr; + int err; + +@@ -796,29 +799,30 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp, + NL_SET_ERR_MSG(extack, "spectrum: Exceeded number of supported virtual routers"); + return ERR_PTR(-EBUSY); + } +- vr->fib4 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4); +- if (IS_ERR(vr->fib4)) +- return ERR_CAST(vr->fib4); +- vr->fib6 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6); +- if (IS_ERR(vr->fib6)) { +- err = PTR_ERR(vr->fib6); ++ fib4 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4); ++ if (IS_ERR(fib4)) ++ return ERR_CAST(fib4); ++ fib6 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6); ++ if (IS_ERR(fib6)) { ++ err = PTR_ERR(fib6); + goto err_fib6_create; + } +- vr->mr4_table = mlxsw_sp_mr_table_create(mlxsw_sp, vr->id, +- MLXSW_SP_L3_PROTO_IPV4); +- if (IS_ERR(vr->mr4_table)) { +- err = PTR_ERR(vr->mr4_table); ++ mr4_table = mlxsw_sp_mr_table_create(mlxsw_sp, vr->id, ++ MLXSW_SP_L3_PROTO_IPV4); ++ if (IS_ERR(mr4_table)) { ++ err = PTR_ERR(mr4_table); + goto err_mr_table_create; + } ++ vr->fib4 = fib4; ++ vr->fib6 = fib6; ++ vr->mr4_table = mr4_table; + vr->tb_id = tb_id; + return vr; + + err_mr_table_create: +- mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib6); +- vr->fib6 = NULL; ++ mlxsw_sp_fib_destroy(mlxsw_sp, fib6); + err_fib6_create: +- mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib4); +- vr->fib4 = NULL; ++ mlxsw_sp_fib_destroy(mlxsw_sp, fib4); + return ERR_PTR(err); + } + +@@ -3790,6 +3794,9 @@ mlxsw_sp_fib4_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry) + struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group; + int i; + ++ if (!list_is_singular(&nh_grp->fib_list)) ++ return; ++ + for (i = 0; i < nh_grp->count; i++) { + struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i]; + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +index 593ad31..161bcdc 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +@@ -1203,6 +1203,7 @@ static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port, + bool dynamic) + { + char *sfd_pl; ++ u8 num_rec; + int err; + + sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); +@@ -1212,9 +1213,16 @@ static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port, + mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0); + mlxsw_reg_sfd_uc_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic), + mac, fid, action, local_port); ++ num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); +- kfree(sfd_pl); ++ if (err) ++ goto out; ++ ++ if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl)) ++ err = -EBUSY; + ++out: ++ kfree(sfd_pl); + return err; + } + +@@ -1239,6 +1247,7 @@ static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id, + bool adding, bool dynamic) + { + char *sfd_pl; ++ u8 num_rec; + int err; + + sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); +@@ -1249,9 +1258,16 @@ static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id, + mlxsw_reg_sfd_uc_lag_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic), + mac, fid, MLXSW_REG_SFD_REC_ACTION_NOP, + lag_vid, lag_id); ++ num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); +- kfree(sfd_pl); ++ if (err) ++ goto out; ++ ++ if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl)) ++ err = -EBUSY; + ++out: ++ kfree(sfd_pl); + return err; + } + +@@ -1296,6 +1312,7 @@ static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr, + u16 fid, u16 mid_idx, bool adding) + { + char *sfd_pl; ++ u8 num_rec; + int err; + + sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); +@@ -1305,7 +1322,15 @@ static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr, + mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0); + mlxsw_reg_sfd_mc_pack(sfd_pl, 0, addr, fid, + MLXSW_REG_SFD_REC_ACTION_NOP, mid_idx); ++ num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); ++ if (err) ++ goto out; ++ ++ if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl)) ++ err = -EBUSY; ++ ++out: + kfree(sfd_pl); + return err; + } +diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +index 7e7704d..c494918 100644 +--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c ++++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +@@ -43,12 +43,6 @@ + + /* Local Definitions and Declarations */ + +-struct rmnet_walk_data { +- struct net_device *real_dev; +- struct list_head *head; +- struct rmnet_port *port; +-}; +- + static int rmnet_is_real_dev_registered(const struct net_device *real_dev) + { + return rcu_access_pointer(real_dev->rx_handler) == rmnet_rx_handler; +@@ -112,17 +106,14 @@ static int rmnet_register_real_device(struct net_device *real_dev) + static void rmnet_unregister_bridge(struct net_device *dev, + struct rmnet_port *port) + { +- struct net_device *rmnet_dev, *bridge_dev; + struct rmnet_port *bridge_port; ++ struct net_device *bridge_dev; + + if (port->rmnet_mode != RMNET_EPMODE_BRIDGE) + return; + + /* bridge slave handling */ + if (!port->nr_rmnet_devs) { +- rmnet_dev = netdev_master_upper_dev_get_rcu(dev); +- netdev_upper_dev_unlink(dev, rmnet_dev); +- + bridge_dev = port->bridge_ep; + + bridge_port = rmnet_get_port_rtnl(bridge_dev); +@@ -132,9 +123,6 @@ static void rmnet_unregister_bridge(struct net_device *dev, + bridge_dev = port->bridge_ep; + + bridge_port = rmnet_get_port_rtnl(bridge_dev); +- rmnet_dev = netdev_master_upper_dev_get_rcu(bridge_dev); +- netdev_upper_dev_unlink(bridge_dev, rmnet_dev); +- + rmnet_unregister_real_device(bridge_dev, bridge_port); + } + } +@@ -173,10 +161,6 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev, + if (err) + goto err1; + +- err = netdev_master_upper_dev_link(dev, real_dev, NULL, NULL, extack); +- if (err) +- goto err2; +- + port->rmnet_mode = mode; + + hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]); +@@ -193,8 +177,6 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev, + + return 0; + +-err2: +- rmnet_vnd_dellink(mux_id, port, ep); + err1: + rmnet_unregister_real_device(real_dev, port); + err0: +@@ -204,14 +186,13 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev, + + static void rmnet_dellink(struct net_device *dev, struct list_head *head) + { ++ struct rmnet_priv *priv = netdev_priv(dev); + struct net_device *real_dev; + struct rmnet_endpoint *ep; + struct rmnet_port *port; + u8 mux_id; + +- rcu_read_lock(); +- real_dev = netdev_master_upper_dev_get_rcu(dev); +- rcu_read_unlock(); ++ real_dev = priv->real_dev; + + if (!real_dev || !rmnet_is_real_dev_registered(real_dev)) + return; +@@ -219,7 +200,6 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head) + port = rmnet_get_port_rtnl(real_dev); + + mux_id = rmnet_vnd_get_mux(dev); +- netdev_upper_dev_unlink(dev, real_dev); + + ep = rmnet_get_endpoint(port, mux_id); + if (ep) { +@@ -233,30 +213,13 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head) + unregister_netdevice_queue(dev, head); + } + +-static int rmnet_dev_walk_unreg(struct net_device *rmnet_dev, void *data) +-{ +- struct rmnet_walk_data *d = data; +- struct rmnet_endpoint *ep; +- u8 mux_id; +- +- mux_id = rmnet_vnd_get_mux(rmnet_dev); +- ep = rmnet_get_endpoint(d->port, mux_id); +- if (ep) { +- hlist_del_init_rcu(&ep->hlnode); +- rmnet_vnd_dellink(mux_id, d->port, ep); +- kfree(ep); +- } +- netdev_upper_dev_unlink(rmnet_dev, d->real_dev); +- unregister_netdevice_queue(rmnet_dev, d->head); +- +- return 0; +-} +- + static void rmnet_force_unassociate_device(struct net_device *dev) + { + struct net_device *real_dev = dev; +- struct rmnet_walk_data d; ++ struct hlist_node *tmp_ep; ++ struct rmnet_endpoint *ep; + struct rmnet_port *port; ++ unsigned long bkt_ep; + LIST_HEAD(list); + + if (!rmnet_is_real_dev_registered(real_dev)) +@@ -264,16 +227,19 @@ static void rmnet_force_unassociate_device(struct net_device *dev) + + ASSERT_RTNL(); + +- d.real_dev = real_dev; +- d.head = &list; +- + port = rmnet_get_port_rtnl(dev); +- d.port = port; + + rcu_read_lock(); + rmnet_unregister_bridge(dev, port); + +- netdev_walk_all_lower_dev_rcu(real_dev, rmnet_dev_walk_unreg, &d); ++ hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) { ++ unregister_netdevice_queue(ep->egress_dev, &list); ++ rmnet_vnd_dellink(ep->mux_id, port, ep); ++ ++ hlist_del_init_rcu(&ep->hlnode); ++ kfree(ep); ++ } ++ + rcu_read_unlock(); + unregister_netdevice_many(&list); + +@@ -422,11 +388,6 @@ int rmnet_add_bridge(struct net_device *rmnet_dev, + if (err) + return -EBUSY; + +- err = netdev_master_upper_dev_link(slave_dev, rmnet_dev, NULL, NULL, +- extack); +- if (err) +- return -EINVAL; +- + slave_port = rmnet_get_port(slave_dev); + slave_port->rmnet_mode = RMNET_EPMODE_BRIDGE; + slave_port->bridge_ep = real_dev; +@@ -449,7 +410,6 @@ int rmnet_del_bridge(struct net_device *rmnet_dev, + port->rmnet_mode = RMNET_EPMODE_VND; + port->bridge_ep = NULL; + +- netdev_upper_dev_unlink(slave_dev, rmnet_dev); + slave_port = rmnet_get_port(slave_dev); + rmnet_unregister_real_device(slave_dev, slave_port); + +diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c +index 6bc328f..b0dbca0 100644 +--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c ++++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c +@@ -38,6 +38,11 @@ static u8 rmnet_map_do_flow_control(struct sk_buff *skb, + } + + ep = rmnet_get_endpoint(port, mux_id); ++ if (!ep) { ++ kfree_skb(skb); ++ return RX_HANDLER_CONSUMED; ++ } ++ + vnd = ep->egress_dev; + + ip_family = cmd->flow_control.ip_family; +diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +index 570a227..346d310 100644 +--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c ++++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +@@ -121,7 +121,7 @@ static void rmnet_get_stats64(struct net_device *dev, + memset(&total_stats, 0, sizeof(struct rmnet_vnd_stats)); + + for_each_possible_cpu(cpu) { +- pcpu_ptr = this_cpu_ptr(priv->pcpu_stats); ++ pcpu_ptr = per_cpu_ptr(priv->pcpu_stats, cpu); + + do { + start = u64_stats_fetch_begin_irq(&pcpu_ptr->syncp); +diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c +index c87f57c..a95fbd5 100644 +--- a/drivers/net/ethernet/renesas/ravb_main.c ++++ b/drivers/net/ethernet/renesas/ravb_main.c +@@ -2255,9 +2255,6 @@ static int ravb_wol_setup(struct net_device *ndev) + /* Enable MagicPacket */ + ravb_modify(ndev, ECMR, ECMR_MPDE, ECMR_MPDE); + +- /* Increased clock usage so device won't be suspended */ +- clk_enable(priv->clk); +- + return enable_irq_wake(priv->emac_irq); + } + +@@ -2276,9 +2273,6 @@ static int ravb_wol_restore(struct net_device *ndev) + if (ret < 0) + return ret; + +- /* Restore clock usage count */ +- clk_disable(priv->clk); +- + return disable_irq_wake(priv->emac_irq); + } + +diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c +index a197e11..14c839b 100644 +--- a/drivers/net/ethernet/renesas/sh_eth.c ++++ b/drivers/net/ethernet/renesas/sh_eth.c +@@ -40,7 +40,6 @@ + #include + #include + #include +-#include + #include + #include + +@@ -440,6 +439,17 @@ static void sh_eth_modify(struct net_device *ndev, int enum_index, u32 clear, + enum_index); + } + ++static void sh_eth_tsu_write(struct sh_eth_private *mdp, u32 data, ++ int enum_index) ++{ ++ iowrite32(data, mdp->tsu_addr + mdp->reg_offset[enum_index]); ++} ++ ++static u32 sh_eth_tsu_read(struct sh_eth_private *mdp, int enum_index) ++{ ++ return ioread32(mdp->tsu_addr + mdp->reg_offset[enum_index]); ++} ++ + static bool sh_eth_is_gether(struct sh_eth_private *mdp) + { + return mdp->reg_offset == sh_eth_offset_gigabit; +@@ -2304,7 +2314,7 @@ static void sh_eth_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) + wol->supported = 0; + wol->wolopts = 0; + +- if (mdp->cd->magic && mdp->clk) { ++ if (mdp->cd->magic) { + wol->supported = WAKE_MAGIC; + wol->wolopts = mdp->wol_enabled ? WAKE_MAGIC : 0; + } +@@ -2314,7 +2324,7 @@ static int sh_eth_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) + { + struct sh_eth_private *mdp = netdev_priv(ndev); + +- if (!mdp->cd->magic || !mdp->clk || wol->wolopts & ~WAKE_MAGIC) ++ if (!mdp->cd->magic || wol->wolopts & ~WAKE_MAGIC) + return -EOPNOTSUPP; + + mdp->wol_enabled = !!(wol->wolopts & WAKE_MAGIC); +@@ -3153,11 +3163,6 @@ static int sh_eth_drv_probe(struct platform_device *pdev) + goto out_release; + } + +- /* Get clock, if not found that's OK but Wake-On-Lan is unavailable */ +- mdp->clk = devm_clk_get(&pdev->dev, NULL); +- if (IS_ERR(mdp->clk)) +- mdp->clk = NULL; +- + ndev->base_addr = res->start; + + spin_lock_init(&mdp->lock); +@@ -3278,7 +3283,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev) + if (ret) + goto out_napi_del; + +- if (mdp->cd->magic && mdp->clk) ++ if (mdp->cd->magic) + device_set_wakeup_capable(&pdev->dev, 1); + + /* print device information */ +@@ -3331,9 +3336,6 @@ static int sh_eth_wol_setup(struct net_device *ndev) + /* Enable MagicPacket */ + sh_eth_modify(ndev, ECMR, ECMR_MPDE, ECMR_MPDE); + +- /* Increased clock usage so device won't be suspended */ +- clk_enable(mdp->clk); +- + return enable_irq_wake(ndev->irq); + } + +@@ -3359,9 +3361,6 @@ static int sh_eth_wol_restore(struct net_device *ndev) + if (ret < 0) + return ret; + +- /* Restore clock usage count */ +- clk_disable(mdp->clk); +- + return disable_irq_wake(ndev->irq); + } + +diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h +index a6753cc..e5fe701 100644 +--- a/drivers/net/ethernet/renesas/sh_eth.h ++++ b/drivers/net/ethernet/renesas/sh_eth.h +@@ -567,15 +567,4 @@ static inline void *sh_eth_tsu_get_offset(struct sh_eth_private *mdp, + return mdp->tsu_addr + mdp->reg_offset[enum_index]; + } + +-static inline void sh_eth_tsu_write(struct sh_eth_private *mdp, u32 data, +- int enum_index) +-{ +- iowrite32(data, mdp->tsu_addr + mdp->reg_offset[enum_index]); +-} +- +-static inline u32 sh_eth_tsu_read(struct sh_eth_private *mdp, int enum_index) +-{ +- return ioread32(mdp->tsu_addr + mdp->reg_offset[enum_index]); +-} +- + #endif /* #ifndef __SH_ETH_H__ */ +diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig +index 63aca9f..4c2f612e 100644 +--- a/drivers/net/ethernet/smsc/Kconfig ++++ b/drivers/net/ethernet/smsc/Kconfig +@@ -20,7 +20,7 @@ if NET_VENDOR_SMSC + + config SMC9194 + tristate "SMC 9194 support" +- depends on (ISA || MAC && BROKEN) ++ depends on ISA + select CRC32 + ---help--- + This is support for the SMC9xxx based Ethernet cards. Choose this +diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c +index 17e529a..0265d70 100644 +--- a/drivers/net/hyperv/netvsc.c ++++ b/drivers/net/hyperv/netvsc.c +@@ -852,13 +852,6 @@ int netvsc_send(struct net_device *ndev, + if (unlikely(!net_device || net_device->destroy)) + return -ENODEV; + +- /* We may race with netvsc_connect_vsp()/netvsc_init_buf() and get +- * here before the negotiation with the host is finished and +- * send_section_map may not be allocated yet. +- */ +- if (unlikely(!net_device->send_section_map)) +- return -EAGAIN; +- + nvchan = &net_device->chan_table[packet->q_idx]; + packet->send_buf_index = NETVSC_INVALID_INDEX; + packet->cp_partial = false; +@@ -866,10 +859,8 @@ int netvsc_send(struct net_device *ndev, + /* Send control message directly without accessing msd (Multi-Send + * Data) field which may be changed during data packet processing. + */ +- if (!skb) { +- cur_send = packet; +- goto send_now; +- } ++ if (!skb) ++ return netvsc_send_pkt(device, packet, net_device, pb, skb); + + /* batch packets in send buffer if possible */ + msdp = &nvchan->msd; +@@ -953,7 +944,6 @@ int netvsc_send(struct net_device *ndev, + } + } + +-send_now: + if (cur_send) + ret = netvsc_send_pkt(device, cur_send, net_device, pb, skb); + +@@ -1217,9 +1207,10 @@ int netvsc_poll(struct napi_struct *napi, int budget) + if (send_recv_completions(ndev, net_device, nvchan) == 0 && + work_done < budget && + napi_complete_done(napi, work_done) && +- hv_end_read(&channel->inbound)) { ++ hv_end_read(&channel->inbound) && ++ napi_schedule_prep(napi)) { + hv_begin_read(&channel->inbound); +- napi_reschedule(napi); ++ __napi_schedule(napi); + } + + /* Driver may overshoot since multiple packets per descriptor */ +@@ -1242,7 +1233,7 @@ void netvsc_channel_cb(void *context) + /* disable interupts from host */ + hv_begin_read(rbi); + +- __napi_schedule(&nvchan->napi); ++ __napi_schedule_irqoff(&nvchan->napi); + } + } + +@@ -1296,7 +1287,6 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, + netvsc_channel_cb, net_device->chan_table); + + if (ret != 0) { +- netif_napi_del(&net_device->chan_table[0].napi); + netdev_err(ndev, "unable to open channel: %d\n", ret); + goto cleanup; + } +@@ -1306,11 +1296,6 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, + + napi_enable(&net_device->chan_table[0].napi); + +- /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is +- * populated. +- */ +- rcu_assign_pointer(net_device_ctx->nvdev, net_device); +- + /* Connect with the NetVsp */ + ret = netvsc_connect_vsp(device, net_device, device_info); + if (ret != 0) { +@@ -1319,6 +1304,11 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, + goto close; + } + ++ /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is ++ * populated. ++ */ ++ rcu_assign_pointer(net_device_ctx->nvdev, net_device); ++ + return net_device; + + close: +@@ -1329,6 +1319,7 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, + vmbus_close(device->channel); + + cleanup: ++ netif_napi_del(&net_device->chan_table[0].napi); + free_netvsc_device(&net_device->rcu); + + return ERR_PTR(ret); +diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c +index c5584c2..cdb78ee 100644 +--- a/drivers/net/hyperv/netvsc_drv.c ++++ b/drivers/net/hyperv/netvsc_drv.c +@@ -66,10 +66,36 @@ static int debug = -1; + module_param(debug, int, S_IRUGO); + MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + +-static void netvsc_set_multicast_list(struct net_device *net) ++static void netvsc_change_rx_flags(struct net_device *net, int change) + { +- struct net_device_context *net_device_ctx = netdev_priv(net); +- struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); ++ struct net_device_context *ndev_ctx = netdev_priv(net); ++ struct net_device *vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev); ++ int inc; ++ ++ if (!vf_netdev) ++ return; ++ ++ if (change & IFF_PROMISC) { ++ inc = (net->flags & IFF_PROMISC) ? 1 : -1; ++ dev_set_promiscuity(vf_netdev, inc); ++ } ++ ++ if (change & IFF_ALLMULTI) { ++ inc = (net->flags & IFF_ALLMULTI) ? 1 : -1; ++ dev_set_allmulti(vf_netdev, inc); ++ } ++} ++ ++static void netvsc_set_rx_mode(struct net_device *net) ++{ ++ struct net_device_context *ndev_ctx = netdev_priv(net); ++ struct net_device *vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev); ++ struct netvsc_device *nvdev = rtnl_dereference(ndev_ctx->nvdev); ++ ++ if (vf_netdev) { ++ dev_uc_sync(vf_netdev, net); ++ dev_mc_sync(vf_netdev, net); ++ } + + rndis_filter_update(nvdev); + } +@@ -91,12 +117,11 @@ static int netvsc_open(struct net_device *net) + return ret; + } + +- netif_tx_wake_all_queues(net); +- + rdev = nvdev->extension; +- +- if (!rdev->link_state) ++ if (!rdev->link_state) { + netif_carrier_on(net); ++ netif_tx_wake_all_queues(net); ++ } + + if (vf_netdev) { + /* Setting synthetic device up transparently sets +@@ -299,8 +324,19 @@ static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb, + rcu_read_lock(); + vf_netdev = rcu_dereference(ndc->vf_netdev); + if (vf_netdev) { +- txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0; +- qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping; ++ const struct net_device_ops *vf_ops = vf_netdev->netdev_ops; ++ ++ if (vf_ops->ndo_select_queue) ++ txq = vf_ops->ndo_select_queue(vf_netdev, skb, ++ accel_priv, fallback); ++ else ++ txq = fallback(vf_netdev, skb); ++ ++ /* Record the queue selected by VF so that it can be ++ * used for common case where VF has more queues than ++ * the synthetic device. ++ */ ++ qdisc_skb_cb(skb)->slave_dev_queue_mapping = txq; + } else { + txq = netvsc_pick_tx(ndev, skb); + } +@@ -1576,7 +1612,8 @@ static const struct net_device_ops device_ops = { + .ndo_open = netvsc_open, + .ndo_stop = netvsc_close, + .ndo_start_xmit = netvsc_start_xmit, +- .ndo_set_rx_mode = netvsc_set_multicast_list, ++ .ndo_change_rx_flags = netvsc_change_rx_flags, ++ .ndo_set_rx_mode = netvsc_set_rx_mode, + .ndo_change_mtu = netvsc_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = netvsc_set_mac_addr, +@@ -1807,6 +1844,11 @@ static void __netvsc_vf_setup(struct net_device *ndev, + netdev_warn(vf_netdev, + "unable to change mtu to %u\n", ndev->mtu); + ++ /* set multicast etc flags on VF */ ++ dev_change_flags(vf_netdev, ndev->flags | IFF_SLAVE); ++ dev_uc_sync(vf_netdev, ndev); ++ dev_mc_sync(vf_netdev, ndev); ++ + if (netif_running(ndev)) { + ret = dev_open(vf_netdev); + if (ret) +diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c +index c3ca191..8927c48 100644 +--- a/drivers/net/hyperv/rndis_filter.c ++++ b/drivers/net/hyperv/rndis_filter.c +@@ -854,15 +854,19 @@ static void rndis_set_multicast(struct work_struct *w) + { + struct rndis_device *rdev + = container_of(w, struct rndis_device, mcast_work); ++ u32 filter = NDIS_PACKET_TYPE_DIRECTED; ++ unsigned int flags = rdev->ndev->flags; + +- if (rdev->ndev->flags & IFF_PROMISC) +- rndis_filter_set_packet_filter(rdev, +- NDIS_PACKET_TYPE_PROMISCUOUS); +- else +- rndis_filter_set_packet_filter(rdev, +- NDIS_PACKET_TYPE_BROADCAST | +- NDIS_PACKET_TYPE_ALL_MULTICAST | +- NDIS_PACKET_TYPE_DIRECTED); ++ if (flags & IFF_PROMISC) { ++ filter = NDIS_PACKET_TYPE_PROMISCUOUS; ++ } else { ++ if (flags & IFF_ALLMULTI) ++ flags |= NDIS_PACKET_TYPE_ALL_MULTICAST; ++ if (flags & IFF_BROADCAST) ++ flags |= NDIS_PACKET_TYPE_BROADCAST; ++ } ++ ++ rndis_filter_set_packet_filter(rdev, filter); + } + + void rndis_filter_update(struct netvsc_device *nvdev) +@@ -1340,6 +1344,9 @@ void rndis_filter_device_remove(struct hv_device *dev, + { + struct rndis_device *rndis_dev = net_dev->extension; + ++ /* Don't try and setup sub channels if about to halt */ ++ cancel_work_sync(&net_dev->subchan_work); ++ + /* Halt and release the rndis device */ + rndis_filter_halt_device(rndis_dev); + +diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c +index a0f2be8..8fc02d9 100644 +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -1451,7 +1451,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, + /* the macvlan port may be freed by macvlan_uninit when fail to register. + * so we destroy the macvlan port only when it's valid. + */ +- if (create && macvlan_port_get_rtnl(dev)) ++ if (create && macvlan_port_get_rtnl(lowerdev)) + macvlan_port_destroy(port->dev); + return err; + } +diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c +index e3e29c2..a6f924f 100644 +--- a/drivers/net/phy/phy.c ++++ b/drivers/net/phy/phy.c +@@ -819,7 +819,7 @@ void phy_start(struct phy_device *phydev) + break; + case PHY_HALTED: + /* if phy was suspended, bring the physical link up again */ +- phy_resume(phydev); ++ __phy_resume(phydev); + + /* make sure interrupts are re-enabled for the PHY */ + if (phy_interrupt_is_valid(phydev)) { +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index b13eed2..478405e 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -135,9 +135,7 @@ static int mdio_bus_phy_resume(struct device *dev) + if (!mdio_bus_phy_may_suspend(phydev)) + goto no_resume; + +- mutex_lock(&phydev->lock); + ret = phy_resume(phydev); +- mutex_unlock(&phydev->lock); + if (ret < 0) + return ret; + +@@ -1041,9 +1039,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, + if (err) + goto error; + +- mutex_lock(&phydev->lock); + phy_resume(phydev); +- mutex_unlock(&phydev->lock); + phy_led_triggers_register(phydev); + + return err; +@@ -1172,7 +1168,7 @@ int phy_suspend(struct phy_device *phydev) + } + EXPORT_SYMBOL(phy_suspend); + +-int phy_resume(struct phy_device *phydev) ++int __phy_resume(struct phy_device *phydev) + { + struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver); + int ret = 0; +@@ -1189,6 +1185,18 @@ int phy_resume(struct phy_device *phydev) + + return ret; + } ++EXPORT_SYMBOL(__phy_resume); ++ ++int phy_resume(struct phy_device *phydev) ++{ ++ int ret; ++ ++ mutex_lock(&phydev->lock); ++ ret = __phy_resume(phydev); ++ mutex_unlock(&phydev->lock); ++ ++ return ret; ++} + EXPORT_SYMBOL(phy_resume); + + int phy_loopback(struct phy_device *phydev, bool enable) +@@ -1382,7 +1390,7 @@ int genphy_setup_forced(struct phy_device *phydev) + ctl |= BMCR_FULLDPLX; + + return phy_modify(phydev, MII_BMCR, +- BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN, ctl); ++ ~(BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN), ctl); + } + EXPORT_SYMBOL(genphy_setup_forced); + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index 255a5de..fa2a9bd 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -3161,6 +3161,15 @@ ppp_connect_channel(struct channel *pch, int unit) + goto outl; + + ppp_lock(ppp); ++ spin_lock_bh(&pch->downl); ++ if (!pch->chan) { ++ /* Don't connect unregistered channels */ ++ spin_unlock_bh(&pch->downl); ++ ppp_unlock(ppp); ++ ret = -ENOTCONN; ++ goto outl; ++ } ++ spin_unlock_bh(&pch->downl); + if (pch->file.hdrlen > ppp->file.hdrlen) + ppp->file.hdrlen = pch->file.hdrlen; + hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */ +diff --git a/drivers/net/thunderbolt.c b/drivers/net/thunderbolt.c +index ca5e375..e0d6760 100644 +--- a/drivers/net/thunderbolt.c ++++ b/drivers/net/thunderbolt.c +@@ -166,6 +166,8 @@ struct tbnet_ring { + * @connected_work: Worker that finalizes the ThunderboltIP connection + * setup and enables DMA paths for high speed data + * transfers ++ * @disconnect_work: Worker that handles tearing down the ThunderboltIP ++ * connection + * @rx_hdr: Copy of the currently processed Rx frame. Used when a + * network packet consists of multiple Thunderbolt frames. + * In host byte order. +@@ -190,6 +192,7 @@ struct tbnet { + int login_retries; + struct delayed_work login_work; + struct work_struct connected_work; ++ struct work_struct disconnect_work; + struct thunderbolt_ip_frame_header rx_hdr; + struct tbnet_ring rx_ring; + atomic_t frame_id; +@@ -445,7 +448,7 @@ static int tbnet_handle_packet(const void *buf, size_t size, void *data) + case TBIP_LOGOUT: + ret = tbnet_logout_response(net, route, sequence, command_id); + if (!ret) +- tbnet_tear_down(net, false); ++ queue_work(system_long_wq, &net->disconnect_work); + break; + + default: +@@ -659,6 +662,13 @@ static void tbnet_login_work(struct work_struct *work) + } + } + ++static void tbnet_disconnect_work(struct work_struct *work) ++{ ++ struct tbnet *net = container_of(work, typeof(*net), disconnect_work); ++ ++ tbnet_tear_down(net, false); ++} ++ + static bool tbnet_check_frame(struct tbnet *net, const struct tbnet_frame *tf, + const struct thunderbolt_ip_frame_header *hdr) + { +@@ -881,6 +891,7 @@ static int tbnet_stop(struct net_device *dev) + + napi_disable(&net->napi); + ++ cancel_work_sync(&net->disconnect_work); + tbnet_tear_down(net, true); + + tb_ring_free(net->rx_ring.ring); +@@ -1195,6 +1206,7 @@ static int tbnet_probe(struct tb_service *svc, const struct tb_service_id *id) + net = netdev_priv(dev); + INIT_DELAYED_WORK(&net->login_work, tbnet_login_work); + INIT_WORK(&net->connected_work, tbnet_connected_work); ++ INIT_WORK(&net->disconnect_work, tbnet_disconnect_work); + mutex_init(&net->connection_lock); + atomic_set(&net->command_id, 0); + atomic_set(&net->frame_id, 0); +@@ -1270,10 +1282,7 @@ static int __maybe_unused tbnet_suspend(struct device *dev) + stop_login(net); + if (netif_running(net->dev)) { + netif_device_detach(net->dev); +- tb_ring_stop(net->rx_ring.ring); +- tb_ring_stop(net->tx_ring.ring); +- tbnet_free_buffers(&net->rx_ring); +- tbnet_free_buffers(&net->tx_ring); ++ tbnet_tear_down(net, true); + } + + return 0; +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index 81e6cc9..7433bb2 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -181,7 +181,6 @@ struct tun_file { + struct tun_struct *detached; + struct ptr_ring tx_ring; + struct xdp_rxq_info xdp_rxq; +- int xdp_pending_pkts; + }; + + struct tun_flow_entry { +@@ -1489,27 +1488,23 @@ static struct sk_buff *tun_napi_alloc_frags(struct tun_file *tfile, + skb->truesize += skb->data_len; + + for (i = 1; i < it->nr_segs; i++) { ++ struct page_frag *pfrag = ¤t->task_frag; + size_t fragsz = it->iov[i].iov_len; +- unsigned long offset; +- struct page *page; +- void *data; + + if (fragsz == 0 || fragsz > PAGE_SIZE) { + err = -EINVAL; + goto free; + } + +- local_bh_disable(); +- data = napi_alloc_frag(fragsz); +- local_bh_enable(); +- if (!data) { ++ if (!skb_page_frag_refill(fragsz, pfrag, GFP_KERNEL)) { + err = -ENOMEM; + goto free; + } + +- page = virt_to_head_page(data); +- offset = data - page_address(page); +- skb_fill_page_desc(skb, i - 1, page, offset, fragsz); ++ skb_fill_page_desc(skb, i - 1, pfrag->page, ++ pfrag->offset, fragsz); ++ page_ref_inc(pfrag->page); ++ pfrag->offset += fragsz; + } + + return skb; +@@ -1647,6 +1642,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, + else + *skb_xdp = 0; + ++ preempt_disable(); + rcu_read_lock(); + xdp_prog = rcu_dereference(tun->xdp_prog); + if (xdp_prog && !*skb_xdp) { +@@ -1666,11 +1662,12 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, + case XDP_REDIRECT: + get_page(alloc_frag->page); + alloc_frag->offset += buflen; +- ++tfile->xdp_pending_pkts; + err = xdp_do_redirect(tun->dev, &xdp, xdp_prog); ++ xdp_do_flush_map(); + if (err) + goto err_redirect; + rcu_read_unlock(); ++ preempt_enable(); + return NULL; + case XDP_TX: + xdp_xmit = true; +@@ -1692,6 +1689,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, + skb = build_skb(buf, buflen); + if (!skb) { + rcu_read_unlock(); ++ preempt_enable(); + return ERR_PTR(-ENOMEM); + } + +@@ -1704,10 +1702,12 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, + skb->dev = tun->dev; + generic_xdp_tx(skb, xdp_prog); + rcu_read_unlock(); ++ preempt_enable(); + return NULL; + } + + rcu_read_unlock(); ++ preempt_enable(); + + return skb; + +@@ -1715,6 +1715,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, + put_page(alloc_frag->page); + err_xdp: + rcu_read_unlock(); ++ preempt_enable(); + this_cpu_inc(tun->pcpu_stats->rx_dropped); + return NULL; + } +@@ -1988,11 +1989,6 @@ static ssize_t tun_chr_write_iter(struct kiocb *iocb, struct iov_iter *from) + result = tun_get_user(tun, tfile, NULL, from, + file->f_flags & O_NONBLOCK, false); + +- if (tfile->xdp_pending_pkts) { +- tfile->xdp_pending_pkts = 0; +- xdp_do_flush_map(); +- } +- + tun_put(tun); + return result; + } +@@ -2329,13 +2325,6 @@ static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len) + ret = tun_get_user(tun, tfile, m->msg_control, &m->msg_iter, + m->msg_flags & MSG_DONTWAIT, + m->msg_flags & MSG_MORE); +- +- if (tfile->xdp_pending_pkts >= NAPI_POLL_WEIGHT || +- !(m->msg_flags & MSG_MORE)) { +- tfile->xdp_pending_pkts = 0; +- xdp_do_flush_map(); +- } +- + tun_put(tun); + return ret; + } +@@ -3167,7 +3156,6 @@ static int tun_chr_open(struct inode *inode, struct file * file) + sock_set_flag(&tfile->sk, SOCK_ZEROCOPY); + + memset(&tfile->tx_ring, 0, sizeof(tfile->tx_ring)); +- tfile->xdp_pending_pkts = 0; + + return 0; + } +diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c +index 05dca3e..fff4b13 100644 +--- a/drivers/net/usb/cdc_ether.c ++++ b/drivers/net/usb/cdc_ether.c +@@ -896,6 +896,12 @@ static const struct usb_device_id products[] = { + USB_CDC_PROTO_NONE), + .driver_info = (unsigned long)&wwan_info, + }, { ++ /* Cinterion PLS8 modem by GEMALTO */ ++ USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0061, USB_CLASS_COMM, ++ USB_CDC_SUBCLASS_ETHERNET, ++ USB_CDC_PROTO_NONE), ++ .driver_info = (unsigned long)&wwan_info, ++}, { + USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, + USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 958b2e8..86f7196 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -1794,7 +1794,7 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) + + tx_data += len; + agg->skb_len += len; +- agg->skb_num++; ++ agg->skb_num += skb_shinfo(skb)->gso_segs ?: 1; + + dev_kfree_skb_any(skb); + +diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c +index d0a1137..7a6a1fe 100644 +--- a/drivers/net/usb/smsc75xx.c ++++ b/drivers/net/usb/smsc75xx.c +@@ -954,10 +954,11 @@ static int smsc75xx_set_features(struct net_device *netdev, + /* it's racing here! */ + + ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); +- if (ret < 0) ++ if (ret < 0) { + netdev_warn(dev->net, "Error writing RFE_CTL\n"); +- +- return ret; ++ return ret; ++ } ++ return 0; + } + + static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm) +diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c +index 626c273..2337460 100644 +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -443,12 +443,8 @@ static bool __virtnet_xdp_xmit(struct virtnet_info *vi, + sg_init_one(sq->sg, xdp->data, xdp->data_end - xdp->data); + + err = virtqueue_add_outbuf(sq->vq, sq->sg, 1, xdp->data, GFP_ATOMIC); +- if (unlikely(err)) { +- struct page *page = virt_to_head_page(xdp->data); +- +- put_page(page); +- return false; +- } ++ if (unlikely(err)) ++ return false; /* Caller handle free/refcnt */ + + return true; + } +@@ -456,8 +452,18 @@ static bool __virtnet_xdp_xmit(struct virtnet_info *vi, + static int virtnet_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp) + { + struct virtnet_info *vi = netdev_priv(dev); +- bool sent = __virtnet_xdp_xmit(vi, xdp); ++ struct receive_queue *rq = vi->rq; ++ struct bpf_prog *xdp_prog; ++ bool sent; ++ ++ /* Only allow ndo_xdp_xmit if XDP is loaded on dev, as this ++ * indicate XDP resources have been successfully allocated. ++ */ ++ xdp_prog = rcu_dereference(rq->xdp_prog); ++ if (!xdp_prog) ++ return -ENXIO; + ++ sent = __virtnet_xdp_xmit(vi, xdp); + if (!sent) + return -ENOSPC; + return 0; +@@ -498,6 +504,7 @@ static struct page *xdp_linearize_page(struct receive_queue *rq, + page_off += *len; + + while (--*num_buf) { ++ int tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + unsigned int buflen; + void *buf; + int off; +@@ -512,7 +519,7 @@ static struct page *xdp_linearize_page(struct receive_queue *rq, + /* guard against a misconfigured or uncooperative backend that + * is sending packet larger than the MTU. + */ +- if ((page_off + buflen) > PAGE_SIZE) { ++ if ((page_off + buflen + tailroom) > PAGE_SIZE) { + put_page(p); + goto err_buf; + } +@@ -546,8 +553,11 @@ static struct sk_buff *receive_small(struct net_device *dev, + unsigned int buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + struct page *page = virt_to_head_page(buf); +- unsigned int delta = 0, err; ++ unsigned int delta = 0; + struct page *xdp_page; ++ bool sent; ++ int err; ++ + len -= vi->hdr_len; + + rcu_read_lock(); +@@ -558,7 +568,7 @@ static struct sk_buff *receive_small(struct net_device *dev, + void *orig_data; + u32 act; + +- if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags)) ++ if (unlikely(hdr->hdr.gso_type)) + goto err_xdp; + + if (unlikely(xdp_headroom < virtnet_get_headroom(vi))) { +@@ -596,16 +606,19 @@ static struct sk_buff *receive_small(struct net_device *dev, + delta = orig_data - xdp.data; + break; + case XDP_TX: +- if (unlikely(!__virtnet_xdp_xmit(vi, &xdp))) ++ sent = __virtnet_xdp_xmit(vi, &xdp); ++ if (unlikely(!sent)) { + trace_xdp_exception(vi->dev, xdp_prog, act); +- else +- *xdp_xmit = true; ++ goto err_xdp; ++ } ++ *xdp_xmit = true; + rcu_read_unlock(); + goto xdp_xmit; + case XDP_REDIRECT: + err = xdp_do_redirect(dev, &xdp, xdp_prog); +- if (!err) +- *xdp_xmit = true; ++ if (err) ++ goto err_xdp; ++ *xdp_xmit = true; + rcu_read_unlock(); + goto xdp_xmit; + default: +@@ -677,6 +690,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, + struct bpf_prog *xdp_prog; + unsigned int truesize; + unsigned int headroom = mergeable_ctx_to_headroom(ctx); ++ bool sent; + int err; + + head_skb = NULL; +@@ -689,7 +703,12 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, + void *data; + u32 act; + +- /* This happens when rx buffer size is underestimated */ ++ /* This happens when rx buffer size is underestimated ++ * or headroom is not enough because of the buffer ++ * was refilled before XDP is set. This should only ++ * happen for the first several packets, so we don't ++ * care much about its performance. ++ */ + if (unlikely(num_buf > 1 || + headroom < virtnet_get_headroom(vi))) { + /* linearize data for XDP */ +@@ -724,9 +743,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, + + act = bpf_prog_run_xdp(xdp_prog, &xdp); + +- if (act != XDP_PASS) +- ewma_pkt_len_add(&rq->mrg_avg_pkt_len, len); +- + switch (act) { + case XDP_PASS: + /* recalculate offset to account for any header +@@ -746,18 +762,28 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, + } + break; + case XDP_TX: +- if (unlikely(!__virtnet_xdp_xmit(vi, &xdp))) ++ sent = __virtnet_xdp_xmit(vi, &xdp); ++ if (unlikely(!sent)) { + trace_xdp_exception(vi->dev, xdp_prog, act); +- else +- *xdp_xmit = true; ++ if (unlikely(xdp_page != page)) ++ put_page(xdp_page); ++ goto err_xdp; ++ } ++ *xdp_xmit = true; + if (unlikely(xdp_page != page)) + goto err_xdp; + rcu_read_unlock(); + goto xdp_xmit; + case XDP_REDIRECT: + err = xdp_do_redirect(dev, &xdp, xdp_prog); +- if (!err) +- *xdp_xmit = true; ++ if (err) { ++ if (unlikely(xdp_page != page)) ++ put_page(xdp_page); ++ goto err_xdp; ++ } ++ *xdp_xmit = true; ++ if (unlikely(xdp_page != page)) ++ goto err_xdp; + rcu_read_unlock(); + goto xdp_xmit; + default: +@@ -1003,13 +1029,18 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq, + } + + static unsigned int get_mergeable_buf_len(struct receive_queue *rq, +- struct ewma_pkt_len *avg_pkt_len) ++ struct ewma_pkt_len *avg_pkt_len, ++ unsigned int room) + { + const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); + unsigned int len; + +- len = hdr_len + clamp_t(unsigned int, ewma_pkt_len_read(avg_pkt_len), ++ if (room) ++ return PAGE_SIZE - room; ++ ++ len = hdr_len + clamp_t(unsigned int, ewma_pkt_len_read(avg_pkt_len), + rq->min_buf_len, PAGE_SIZE - hdr_len); ++ + return ALIGN(len, L1_CACHE_BYTES); + } + +@@ -1018,21 +1049,27 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, + { + struct page_frag *alloc_frag = &rq->alloc_frag; + unsigned int headroom = virtnet_get_headroom(vi); ++ unsigned int tailroom = headroom ? sizeof(struct skb_shared_info) : 0; ++ unsigned int room = SKB_DATA_ALIGN(headroom + tailroom); + char *buf; + void *ctx; + int err; + unsigned int len, hole; + +- len = get_mergeable_buf_len(rq, &rq->mrg_avg_pkt_len); +- if (unlikely(!skb_page_frag_refill(len + headroom, alloc_frag, gfp))) ++ /* Extra tailroom is needed to satisfy XDP's assumption. This ++ * means rx frags coalescing won't work, but consider we've ++ * disabled GSO for XDP, it won't be a big issue. ++ */ ++ len = get_mergeable_buf_len(rq, &rq->mrg_avg_pkt_len, room); ++ if (unlikely(!skb_page_frag_refill(len + room, alloc_frag, gfp))) + return -ENOMEM; + + buf = (char *)page_address(alloc_frag->page) + alloc_frag->offset; + buf += headroom; /* advance address leaving hole at front of pkt */ + get_page(alloc_frag->page); +- alloc_frag->offset += len + headroom; ++ alloc_frag->offset += len + room; + hole = alloc_frag->size - alloc_frag->offset; +- if (hole < len + headroom) { ++ if (hole < len + room) { + /* To avoid internal fragmentation, if there is very likely not + * enough space for another buffer, add the remaining space to + * the current buffer. +@@ -2175,8 +2212,9 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog, + } + + /* Make sure NAPI is not using any XDP TX queues for RX. */ +- for (i = 0; i < vi->max_queue_pairs; i++) +- napi_disable(&vi->rq[i].napi); ++ if (netif_running(dev)) ++ for (i = 0; i < vi->max_queue_pairs; i++) ++ napi_disable(&vi->rq[i].napi); + + netif_set_real_num_rx_queues(dev, curr_qp + xdp_qp); + err = _virtnet_set_queues(vi, curr_qp + xdp_qp); +@@ -2195,7 +2233,8 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog, + } + if (old_prog) + bpf_prog_put(old_prog); +- virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi); ++ if (netif_running(dev)) ++ virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi); + } + + return 0; +@@ -2566,12 +2605,15 @@ static ssize_t mergeable_rx_buffer_size_show(struct netdev_rx_queue *queue, + { + struct virtnet_info *vi = netdev_priv(queue->dev); + unsigned int queue_index = get_netdev_rx_queue_index(queue); ++ unsigned int headroom = virtnet_get_headroom(vi); ++ unsigned int tailroom = headroom ? sizeof(struct skb_shared_info) : 0; + struct ewma_pkt_len *avg; + + BUG_ON(queue_index >= vi->max_queue_pairs); + avg = &vi->rq[queue_index].mrg_avg_pkt_len; + return sprintf(buf, "%u\n", +- get_mergeable_buf_len(&vi->rq[queue_index], avg)); ++ get_mergeable_buf_len(&vi->rq[queue_index], avg, ++ SKB_DATA_ALIGN(headroom + tailroom))); + } + + static struct rx_queue_attribute mergeable_rx_buffer_size_attribute = +diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c +index afeca6b..ab8b3cb 100644 +--- a/drivers/net/wan/hdlc_ppp.c ++++ b/drivers/net/wan/hdlc_ppp.c +@@ -574,7 +574,10 @@ static void ppp_timer(struct timer_list *t) + ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0, + 0, NULL); + proto->restart_counter--; +- } else ++ } else if (netif_carrier_ok(proto->dev)) ++ ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0, ++ 0, NULL); ++ else + ppp_cp_event(proto->dev, proto->pid, TO_BAD, 0, 0, + 0, NULL); + break; +diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c +index 1cf22e6..6e0af81 100644 +--- a/drivers/net/wireless/mac80211_hwsim.c ++++ b/drivers/net/wireless/mac80211_hwsim.c +@@ -3516,7 +3516,7 @@ static int __init init_mac80211_hwsim(void) + + spin_lock_init(&hwsim_radio_lock); + +- hwsim_wq = alloc_workqueue("hwsim_wq",WQ_MEM_RECLAIM,0); ++ hwsim_wq = alloc_workqueue("hwsim_wq", 0, 0); + if (!hwsim_wq) + return -ENOMEM; + rhashtable_init(&hwsim_radios_rht, &hwsim_rht_params); +diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c +index 8328d39..3127bc8 100644 +--- a/drivers/net/xen-netfront.c ++++ b/drivers/net/xen-netfront.c +@@ -2005,7 +2005,10 @@ static void netback_changed(struct xenbus_device *dev, + case XenbusStateInitialised: + case XenbusStateReconfiguring: + case XenbusStateReconfigured: ++ break; ++ + case XenbusStateUnknown: ++ wake_up_all(&module_unload_q); + break; + + case XenbusStateInitWait: +@@ -2136,7 +2139,9 @@ static int xennet_remove(struct xenbus_device *dev) + xenbus_switch_state(dev, XenbusStateClosing); + wait_event(module_unload_q, + xenbus_read_driver_state(dev->otherend) == +- XenbusStateClosing); ++ XenbusStateClosing || ++ xenbus_read_driver_state(dev->otherend) == ++ XenbusStateUnknown); + + xenbus_switch_state(dev, XenbusStateClosed); + wait_event(module_unload_q, +diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c +index 10041ac..06f8dcc 100644 +--- a/drivers/nvdimm/pmem.c ++++ b/drivers/nvdimm/pmem.c +@@ -335,8 +335,7 @@ static int pmem_attach_disk(struct device *dev, + dev_warn(dev, "unable to guarantee persistence of writes\n"); + fua = 0; + } +- wbc = nvdimm_has_cache(nd_region) && +- !test_bit(ND_REGION_PERSIST_CACHE, &nd_region->flags); ++ wbc = nvdimm_has_cache(nd_region); + + if (!devm_request_mem_region(dev, res->start, resource_size(res), + dev_name(&ndns->dev))) { +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index f431c32..7aeca5d 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -120,8 +120,12 @@ int nvme_reset_ctrl_sync(struct nvme_ctrl *ctrl) + int ret; + + ret = nvme_reset_ctrl(ctrl); +- if (!ret) ++ if (!ret) { + flush_work(&ctrl->reset_work); ++ if (ctrl->state != NVME_CTRL_LIVE) ++ ret = -ENETRESET; ++ } ++ + return ret; + } + EXPORT_SYMBOL_GPL(nvme_reset_ctrl_sync); +@@ -265,7 +269,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, + switch (new_state) { + case NVME_CTRL_ADMIN_ONLY: + switch (old_state) { +- case NVME_CTRL_RECONNECTING: ++ case NVME_CTRL_CONNECTING: + changed = true; + /* FALLTHRU */ + default: +@@ -276,7 +280,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, + switch (old_state) { + case NVME_CTRL_NEW: + case NVME_CTRL_RESETTING: +- case NVME_CTRL_RECONNECTING: ++ case NVME_CTRL_CONNECTING: + changed = true; + /* FALLTHRU */ + default: +@@ -294,9 +298,9 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, + break; + } + break; +- case NVME_CTRL_RECONNECTING: ++ case NVME_CTRL_CONNECTING: + switch (old_state) { +- case NVME_CTRL_LIVE: ++ case NVME_CTRL_NEW: + case NVME_CTRL_RESETTING: + changed = true; + /* FALLTHRU */ +@@ -309,7 +313,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, + case NVME_CTRL_LIVE: + case NVME_CTRL_ADMIN_ONLY: + case NVME_CTRL_RESETTING: +- case NVME_CTRL_RECONNECTING: ++ case NVME_CTRL_CONNECTING: + changed = true; + /* FALLTHRU */ + default: +@@ -518,9 +522,11 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req, + u64 slba = nvme_block_nr(ns, bio->bi_iter.bi_sector); + u32 nlb = bio->bi_iter.bi_size >> ns->lba_shift; + +- range[n].cattr = cpu_to_le32(0); +- range[n].nlb = cpu_to_le32(nlb); +- range[n].slba = cpu_to_le64(slba); ++ if (n < segments) { ++ range[n].cattr = cpu_to_le32(0); ++ range[n].nlb = cpu_to_le32(nlb); ++ range[n].slba = cpu_to_le64(slba); ++ } + n++; + } + +@@ -794,13 +800,9 @@ static void nvme_keep_alive_end_io(struct request *rq, blk_status_t status) + + static int nvme_keep_alive(struct nvme_ctrl *ctrl) + { +- struct nvme_command c; + struct request *rq; + +- memset(&c, 0, sizeof(c)); +- c.common.opcode = nvme_admin_keep_alive; +- +- rq = nvme_alloc_request(ctrl->admin_q, &c, BLK_MQ_REQ_RESERVED, ++ rq = nvme_alloc_request(ctrl->admin_q, &ctrl->ka_cmd, BLK_MQ_REQ_RESERVED, + NVME_QID_ANY); + if (IS_ERR(rq)) + return PTR_ERR(rq); +@@ -832,6 +834,8 @@ void nvme_start_keep_alive(struct nvme_ctrl *ctrl) + return; + + INIT_DELAYED_WORK(&ctrl->ka_work, nvme_keep_alive_work); ++ memset(&ctrl->ka_cmd, 0, sizeof(ctrl->ka_cmd)); ++ ctrl->ka_cmd.common.opcode = nvme_admin_keep_alive; + schedule_delayed_work(&ctrl->ka_work, ctrl->kato * HZ); + } + EXPORT_SYMBOL_GPL(nvme_start_keep_alive); +@@ -1117,14 +1121,19 @@ static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns, + + static void nvme_update_formats(struct nvme_ctrl *ctrl) + { +- struct nvme_ns *ns; ++ struct nvme_ns *ns, *next; ++ LIST_HEAD(rm_list); + + mutex_lock(&ctrl->namespaces_mutex); + list_for_each_entry(ns, &ctrl->namespaces, list) { +- if (ns->disk && nvme_revalidate_disk(ns->disk)) +- nvme_ns_remove(ns); ++ if (ns->disk && nvme_revalidate_disk(ns->disk)) { ++ list_move_tail(&ns->list, &rm_list); ++ } + } + mutex_unlock(&ctrl->namespaces_mutex); ++ ++ list_for_each_entry_safe(ns, next, &rm_list, list) ++ nvme_ns_remove(ns); + } + + static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects) +@@ -2687,7 +2696,7 @@ static ssize_t nvme_sysfs_show_state(struct device *dev, + [NVME_CTRL_LIVE] = "live", + [NVME_CTRL_ADMIN_ONLY] = "only-admin", + [NVME_CTRL_RESETTING] = "resetting", +- [NVME_CTRL_RECONNECTING]= "reconnecting", ++ [NVME_CTRL_CONNECTING] = "connecting", + [NVME_CTRL_DELETING] = "deleting", + [NVME_CTRL_DEAD] = "dead", + }; +@@ -2835,7 +2844,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl, + } + + static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid, +- struct nvme_id_ns *id, bool *new) ++ struct nvme_id_ns *id) + { + struct nvme_ctrl *ctrl = ns->ctrl; + bool is_shared = id->nmic & (1 << 0); +@@ -2851,8 +2860,6 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid, + ret = PTR_ERR(head); + goto out_unlock; + } +- +- *new = true; + } else { + struct nvme_ns_ids ids; + +@@ -2864,8 +2871,6 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid, + ret = -EINVAL; + goto out_unlock; + } +- +- *new = false; + } + + list_add_tail(&ns->siblings, &head->list); +@@ -2936,7 +2941,6 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) + struct nvme_id_ns *id; + char disk_name[DISK_NAME_LEN]; + int node = dev_to_node(ctrl->dev), flags = GENHD_FL_EXT_DEVT; +- bool new = true; + + ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node); + if (!ns) +@@ -2962,7 +2966,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) + if (id->ncap == 0) + goto out_free_id; + +- if (nvme_init_ns_head(ns, nsid, id, &new)) ++ if (nvme_init_ns_head(ns, nsid, id)) + goto out_free_id; + nvme_setup_streams_ns(ctrl, ns); + +@@ -3028,9 +3032,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) + pr_warn("%s: failed to register lightnvm sysfs group for identification\n", + ns->disk->disk_name); + +- if (new) +- nvme_mpath_add_disk(ns->head); +- nvme_mpath_add_disk_links(ns); ++ nvme_mpath_add_disk(ns->head); + return; + out_unlink_ns: + mutex_lock(&ctrl->subsys->lock); +@@ -3050,7 +3052,6 @@ static void nvme_ns_remove(struct nvme_ns *ns) + return; + + if (ns->disk && ns->disk->flags & GENHD_FL_UP) { +- nvme_mpath_remove_disk_links(ns); + sysfs_remove_group(&disk_to_dev(ns->disk)->kobj, + &nvme_ns_id_attr_group); + if (ns->ndev) +diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c +index 5dd4cee..8f0f34d 100644 +--- a/drivers/nvme/host/fabrics.c ++++ b/drivers/nvme/host/fabrics.c +@@ -493,7 +493,7 @@ EXPORT_SYMBOL_GPL(nvmf_should_reconnect); + */ + int nvmf_register_transport(struct nvmf_transport_ops *ops) + { +- if (!ops->create_ctrl || !ops->module) ++ if (!ops->create_ctrl) + return -EINVAL; + + down_write(&nvmf_transports_rwsem); +@@ -650,6 +650,11 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, + ret = -EINVAL; + goto out; + } ++ if (opts->discovery_nqn) { ++ pr_debug("Ignoring nr_io_queues value for discovery controller\n"); ++ break; ++ } ++ + opts->nr_io_queues = min_t(unsigned int, + num_online_cpus(), token); + break; +diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h +index 25b19f7..a3145d9 100644 +--- a/drivers/nvme/host/fabrics.h ++++ b/drivers/nvme/host/fabrics.h +@@ -171,13 +171,14 @@ static inline blk_status_t nvmf_check_init_req(struct nvme_ctrl *ctrl, + cmd->common.opcode != nvme_fabrics_command || + cmd->fabrics.fctype != nvme_fabrics_type_connect) { + /* +- * Reconnecting state means transport disruption, which can take +- * a long time and even might fail permanently, fail fast to +- * give upper layers a chance to failover. ++ * Connecting state means transport disruption or initial ++ * establishment, which can take a long time and even might ++ * fail permanently, fail fast to give upper layers a chance ++ * to failover. + * Deleting state means that the ctrl will never accept commands + * again, fail it permanently. + */ +- if (ctrl->state == NVME_CTRL_RECONNECTING || ++ if (ctrl->state == NVME_CTRL_CONNECTING || + ctrl->state == NVME_CTRL_DELETING) { + nvme_req(rq)->status = NVME_SC_ABORT_REQ; + return BLK_STS_IOERR; +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index b856d7c..1dc1387 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -55,9 +55,7 @@ struct nvme_fc_queue { + + enum nvme_fcop_flags { + FCOP_FLAGS_TERMIO = (1 << 0), +- FCOP_FLAGS_RELEASED = (1 << 1), +- FCOP_FLAGS_COMPLETE = (1 << 2), +- FCOP_FLAGS_AEN = (1 << 3), ++ FCOP_FLAGS_AEN = (1 << 1), + }; + + struct nvmefc_ls_req_op { +@@ -532,7 +530,7 @@ nvme_fc_resume_controller(struct nvme_fc_ctrl *ctrl) + { + switch (ctrl->ctrl.state) { + case NVME_CTRL_NEW: +- case NVME_CTRL_RECONNECTING: ++ case NVME_CTRL_CONNECTING: + /* + * As all reconnects were suppressed, schedule a + * connect. +@@ -777,7 +775,7 @@ nvme_fc_ctrl_connectivity_loss(struct nvme_fc_ctrl *ctrl) + } + break; + +- case NVME_CTRL_RECONNECTING: ++ case NVME_CTRL_CONNECTING: + /* + * The association has already been terminated and the + * controller is attempting reconnects. No need to do anything +@@ -1208,7 +1206,7 @@ nvme_fc_connect_admin_queue(struct nvme_fc_ctrl *ctrl, + sizeof(struct fcnvme_lsdesc_cr_assoc_cmd)); + + assoc_rqst->assoc_cmd.ersp_ratio = cpu_to_be16(ersp_ratio); +- assoc_rqst->assoc_cmd.sqsize = cpu_to_be16(qsize); ++ assoc_rqst->assoc_cmd.sqsize = cpu_to_be16(qsize - 1); + /* Linux supports only Dynamic controllers */ + assoc_rqst->assoc_cmd.cntlid = cpu_to_be16(0xffff); + uuid_copy(&assoc_rqst->assoc_cmd.hostid, &ctrl->ctrl.opts->host->id); +@@ -1323,7 +1321,7 @@ nvme_fc_connect_queue(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue, + sizeof(struct fcnvme_lsdesc_cr_conn_cmd)); + conn_rqst->connect_cmd.ersp_ratio = cpu_to_be16(ersp_ratio); + conn_rqst->connect_cmd.qid = cpu_to_be16(queue->qnum); +- conn_rqst->connect_cmd.sqsize = cpu_to_be16(qsize); ++ conn_rqst->connect_cmd.sqsize = cpu_to_be16(qsize - 1); + + lsop->queue = queue; + lsreq->rqstaddr = conn_rqst; +@@ -1470,7 +1468,6 @@ nvme_fc_xmt_disconnect_assoc(struct nvme_fc_ctrl *ctrl) + + /* *********************** NVME Ctrl Routines **************************** */ + +-static void __nvme_fc_final_op_cleanup(struct request *rq); + static void nvme_fc_error_recovery(struct nvme_fc_ctrl *ctrl, char *errmsg); + + static int +@@ -1512,13 +1509,19 @@ nvme_fc_exit_request(struct blk_mq_tag_set *set, struct request *rq, + static int + __nvme_fc_abort_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_fcp_op *op) + { +- int state; ++ unsigned long flags; ++ int opstate; ++ ++ spin_lock_irqsave(&ctrl->lock, flags); ++ opstate = atomic_xchg(&op->state, FCPOP_STATE_ABORTED); ++ if (opstate != FCPOP_STATE_ACTIVE) ++ atomic_set(&op->state, opstate); ++ else if (ctrl->flags & FCCTRL_TERMIO) ++ ctrl->iocnt++; ++ spin_unlock_irqrestore(&ctrl->lock, flags); + +- state = atomic_xchg(&op->state, FCPOP_STATE_ABORTED); +- if (state != FCPOP_STATE_ACTIVE) { +- atomic_set(&op->state, state); ++ if (opstate != FCPOP_STATE_ACTIVE) + return -ECANCELED; +- } + + ctrl->lport->ops->fcp_abort(&ctrl->lport->localport, + &ctrl->rport->remoteport, +@@ -1532,60 +1535,26 @@ static void + nvme_fc_abort_aen_ops(struct nvme_fc_ctrl *ctrl) + { + struct nvme_fc_fcp_op *aen_op = ctrl->aen_ops; +- unsigned long flags; +- int i, ret; +- +- for (i = 0; i < NVME_NR_AEN_COMMANDS; i++, aen_op++) { +- if (atomic_read(&aen_op->state) != FCPOP_STATE_ACTIVE) +- continue; +- +- spin_lock_irqsave(&ctrl->lock, flags); +- if (ctrl->flags & FCCTRL_TERMIO) { +- ctrl->iocnt++; +- aen_op->flags |= FCOP_FLAGS_TERMIO; +- } +- spin_unlock_irqrestore(&ctrl->lock, flags); +- +- ret = __nvme_fc_abort_op(ctrl, aen_op); +- if (ret) { +- /* +- * if __nvme_fc_abort_op failed the io wasn't +- * active. Thus this call path is running in +- * parallel to the io complete. Treat as non-error. +- */ ++ int i; + +- /* back out the flags/counters */ +- spin_lock_irqsave(&ctrl->lock, flags); +- if (ctrl->flags & FCCTRL_TERMIO) +- ctrl->iocnt--; +- aen_op->flags &= ~FCOP_FLAGS_TERMIO; +- spin_unlock_irqrestore(&ctrl->lock, flags); +- return; +- } +- } ++ for (i = 0; i < NVME_NR_AEN_COMMANDS; i++, aen_op++) ++ __nvme_fc_abort_op(ctrl, aen_op); + } + +-static inline int ++static inline void + __nvme_fc_fcpop_chk_teardowns(struct nvme_fc_ctrl *ctrl, +- struct nvme_fc_fcp_op *op) ++ struct nvme_fc_fcp_op *op, int opstate) + { + unsigned long flags; +- bool complete_rq = false; + +- spin_lock_irqsave(&ctrl->lock, flags); +- if (unlikely(op->flags & FCOP_FLAGS_TERMIO)) { ++ if (opstate == FCPOP_STATE_ABORTED) { ++ spin_lock_irqsave(&ctrl->lock, flags); + if (ctrl->flags & FCCTRL_TERMIO) { + if (!--ctrl->iocnt) + wake_up(&ctrl->ioabort_wait); + } ++ spin_unlock_irqrestore(&ctrl->lock, flags); + } +- if (op->flags & FCOP_FLAGS_RELEASED) +- complete_rq = true; +- else +- op->flags |= FCOP_FLAGS_COMPLETE; +- spin_unlock_irqrestore(&ctrl->lock, flags); +- +- return complete_rq; + } + + static void +@@ -1601,6 +1570,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req) + __le16 status = cpu_to_le16(NVME_SC_SUCCESS << 1); + union nvme_result result; + bool terminate_assoc = true; ++ int opstate; + + /* + * WARNING: +@@ -1639,11 +1609,12 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req) + * association to be terminated. + */ + ++ opstate = atomic_xchg(&op->state, FCPOP_STATE_COMPLETE); ++ + fc_dma_sync_single_for_cpu(ctrl->lport->dev, op->fcp_req.rspdma, + sizeof(op->rsp_iu), DMA_FROM_DEVICE); + +- if (atomic_read(&op->state) == FCPOP_STATE_ABORTED || +- op->flags & FCOP_FLAGS_TERMIO) ++ if (opstate == FCPOP_STATE_ABORTED) + status = cpu_to_le16(NVME_SC_ABORT_REQ << 1); + else if (freq->status) + status = cpu_to_le16(NVME_SC_INTERNAL << 1); +@@ -1708,7 +1679,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req) + done: + if (op->flags & FCOP_FLAGS_AEN) { + nvme_complete_async_event(&queue->ctrl->ctrl, status, &result); +- __nvme_fc_fcpop_chk_teardowns(ctrl, op); ++ __nvme_fc_fcpop_chk_teardowns(ctrl, op, opstate); + atomic_set(&op->state, FCPOP_STATE_IDLE); + op->flags = FCOP_FLAGS_AEN; /* clear other flags */ + nvme_fc_ctrl_put(ctrl); +@@ -1722,13 +1693,11 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req) + if (status && + (blk_queue_dying(rq->q) || + ctrl->ctrl.state == NVME_CTRL_NEW || +- ctrl->ctrl.state == NVME_CTRL_RECONNECTING)) ++ ctrl->ctrl.state == NVME_CTRL_CONNECTING)) + status |= cpu_to_le16(NVME_SC_DNR << 1); + +- if (__nvme_fc_fcpop_chk_teardowns(ctrl, op)) +- __nvme_fc_final_op_cleanup(rq); +- else +- nvme_end_request(rq, status, result); ++ __nvme_fc_fcpop_chk_teardowns(ctrl, op, opstate); ++ nvme_end_request(rq, status, result); + + check_error: + if (terminate_assoc) +@@ -2415,46 +2384,16 @@ nvme_fc_submit_async_event(struct nvme_ctrl *arg) + } + + static void +-__nvme_fc_final_op_cleanup(struct request *rq) ++nvme_fc_complete_rq(struct request *rq) + { + struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq); + struct nvme_fc_ctrl *ctrl = op->ctrl; + + atomic_set(&op->state, FCPOP_STATE_IDLE); +- op->flags &= ~(FCOP_FLAGS_TERMIO | FCOP_FLAGS_RELEASED | +- FCOP_FLAGS_COMPLETE); + + nvme_fc_unmap_data(ctrl, rq, op); + nvme_complete_rq(rq); + nvme_fc_ctrl_put(ctrl); +- +-} +- +-static void +-nvme_fc_complete_rq(struct request *rq) +-{ +- struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq); +- struct nvme_fc_ctrl *ctrl = op->ctrl; +- unsigned long flags; +- bool completed = false; +- +- /* +- * the core layer, on controller resets after calling +- * nvme_shutdown_ctrl(), calls complete_rq without our +- * calling blk_mq_complete_request(), thus there may still +- * be live i/o outstanding with the LLDD. Means transport has +- * to track complete calls vs fcpio_done calls to know what +- * path to take on completes and dones. +- */ +- spin_lock_irqsave(&ctrl->lock, flags); +- if (op->flags & FCOP_FLAGS_COMPLETE) +- completed = true; +- else +- op->flags |= FCOP_FLAGS_RELEASED; +- spin_unlock_irqrestore(&ctrl->lock, flags); +- +- if (completed) +- __nvme_fc_final_op_cleanup(rq); + } + + /* +@@ -2476,35 +2415,11 @@ nvme_fc_terminate_exchange(struct request *req, void *data, bool reserved) + struct nvme_ctrl *nctrl = data; + struct nvme_fc_ctrl *ctrl = to_fc_ctrl(nctrl); + struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(req); +- unsigned long flags; +- int status; + + if (!blk_mq_request_started(req)) + return; + +- spin_lock_irqsave(&ctrl->lock, flags); +- if (ctrl->flags & FCCTRL_TERMIO) { +- ctrl->iocnt++; +- op->flags |= FCOP_FLAGS_TERMIO; +- } +- spin_unlock_irqrestore(&ctrl->lock, flags); +- +- status = __nvme_fc_abort_op(ctrl, op); +- if (status) { +- /* +- * if __nvme_fc_abort_op failed the io wasn't +- * active. Thus this call path is running in +- * parallel to the io complete. Treat as non-error. +- */ +- +- /* back out the flags/counters */ +- spin_lock_irqsave(&ctrl->lock, flags); +- if (ctrl->flags & FCCTRL_TERMIO) +- ctrl->iocnt--; +- op->flags &= ~FCOP_FLAGS_TERMIO; +- spin_unlock_irqrestore(&ctrl->lock, flags); +- return; +- } ++ __nvme_fc_abort_op(ctrl, op); + } + + +@@ -2566,11 +2481,11 @@ nvme_fc_create_io_queues(struct nvme_fc_ctrl *ctrl) + goto out_free_tag_set; + } + +- ret = nvme_fc_create_hw_io_queues(ctrl, ctrl->ctrl.opts->queue_size); ++ ret = nvme_fc_create_hw_io_queues(ctrl, ctrl->ctrl.sqsize + 1); + if (ret) + goto out_cleanup_blk_queue; + +- ret = nvme_fc_connect_io_queues(ctrl, ctrl->ctrl.opts->queue_size); ++ ret = nvme_fc_connect_io_queues(ctrl, ctrl->ctrl.sqsize + 1); + if (ret) + goto out_delete_hw_queues; + +@@ -2617,11 +2532,11 @@ nvme_fc_reinit_io_queues(struct nvme_fc_ctrl *ctrl) + if (ret) + goto out_free_io_queues; + +- ret = nvme_fc_create_hw_io_queues(ctrl, ctrl->ctrl.opts->queue_size); ++ ret = nvme_fc_create_hw_io_queues(ctrl, ctrl->ctrl.sqsize + 1); + if (ret) + goto out_free_io_queues; + +- ret = nvme_fc_connect_io_queues(ctrl, ctrl->ctrl.opts->queue_size); ++ ret = nvme_fc_connect_io_queues(ctrl, ctrl->ctrl.sqsize + 1); + if (ret) + goto out_delete_hw_queues; + +@@ -2717,13 +2632,12 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) + nvme_fc_init_queue(ctrl, 0); + + ret = __nvme_fc_create_hw_queue(ctrl, &ctrl->queues[0], 0, +- NVME_AQ_BLK_MQ_DEPTH); ++ NVME_AQ_DEPTH); + if (ret) + goto out_free_queue; + + ret = nvme_fc_connect_admin_queue(ctrl, &ctrl->queues[0], +- NVME_AQ_BLK_MQ_DEPTH, +- (NVME_AQ_BLK_MQ_DEPTH / 4)); ++ NVME_AQ_DEPTH, (NVME_AQ_DEPTH / 4)); + if (ret) + goto out_delete_hw_queue; + +@@ -2751,7 +2665,7 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) + } + + ctrl->ctrl.sqsize = +- min_t(int, NVME_CAP_MQES(ctrl->ctrl.cap) + 1, ctrl->ctrl.sqsize); ++ min_t(int, NVME_CAP_MQES(ctrl->ctrl.cap), ctrl->ctrl.sqsize); + + ret = nvme_enable_ctrl(&ctrl->ctrl, ctrl->ctrl.cap); + if (ret) +@@ -2784,6 +2698,14 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) + opts->queue_size = ctrl->ctrl.maxcmd; + } + ++ if (opts->queue_size > ctrl->ctrl.sqsize + 1) { ++ /* warn if sqsize is lower than queue_size */ ++ dev_warn(ctrl->ctrl.device, ++ "queue_size %zu > ctrl sqsize %u, clamping down\n", ++ opts->queue_size, ctrl->ctrl.sqsize + 1); ++ opts->queue_size = ctrl->ctrl.sqsize + 1; ++ } ++ + ret = nvme_fc_init_aen_ops(ctrl); + if (ret) + goto out_term_aen_ops; +@@ -2943,7 +2865,7 @@ nvme_fc_reconnect_or_delete(struct nvme_fc_ctrl *ctrl, int status) + unsigned long recon_delay = ctrl->ctrl.opts->reconnect_delay * HZ; + bool recon = true; + +- if (ctrl->ctrl.state != NVME_CTRL_RECONNECTING) ++ if (ctrl->ctrl.state != NVME_CTRL_CONNECTING) + return; + + if (portptr->port_state == FC_OBJSTATE_ONLINE) +@@ -2991,10 +2913,10 @@ nvme_fc_reset_ctrl_work(struct work_struct *work) + /* will block will waiting for io to terminate */ + nvme_fc_delete_association(ctrl); + +- if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RECONNECTING)) { ++ if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) { + dev_err(ctrl->ctrl.device, + "NVME-FC{%d}: error_recovery: Couldn't change state " +- "to RECONNECTING\n", ctrl->cnum); ++ "to CONNECTING\n", ctrl->cnum); + return; + } + +@@ -3195,7 +3117,7 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, + * transport errors (frame drop, LS failure) inherently must kill + * the association. The transport is coded so that any command used + * to create the association (prior to a LIVE state transition +- * while NEW or RECONNECTING) will fail if it completes in error or ++ * while NEW or CONNECTING) will fail if it completes in error or + * times out. + * + * As such: as the connect request was mostly likely due to a +diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c +index 3b211d9..060f69e 100644 +--- a/drivers/nvme/host/multipath.c ++++ b/drivers/nvme/host/multipath.c +@@ -198,30 +198,16 @@ void nvme_mpath_add_disk(struct nvme_ns_head *head) + { + if (!head->disk) + return; +- device_add_disk(&head->subsys->dev, head->disk); +- if (sysfs_create_group(&disk_to_dev(head->disk)->kobj, +- &nvme_ns_id_attr_group)) +- pr_warn("%s: failed to create sysfs group for identification\n", +- head->disk->disk_name); +-} +- +-void nvme_mpath_add_disk_links(struct nvme_ns *ns) +-{ +- struct kobject *slave_disk_kobj, *holder_disk_kobj; +- +- if (!ns->head->disk) +- return; +- +- slave_disk_kobj = &disk_to_dev(ns->disk)->kobj; +- if (sysfs_create_link(ns->head->disk->slave_dir, slave_disk_kobj, +- kobject_name(slave_disk_kobj))) +- return; + +- holder_disk_kobj = &disk_to_dev(ns->head->disk)->kobj; +- if (sysfs_create_link(ns->disk->part0.holder_dir, holder_disk_kobj, +- kobject_name(holder_disk_kobj))) +- sysfs_remove_link(ns->head->disk->slave_dir, +- kobject_name(slave_disk_kobj)); ++ mutex_lock(&head->subsys->lock); ++ if (!(head->disk->flags & GENHD_FL_UP)) { ++ device_add_disk(&head->subsys->dev, head->disk); ++ if (sysfs_create_group(&disk_to_dev(head->disk)->kobj, ++ &nvme_ns_id_attr_group)) ++ pr_warn("%s: failed to create sysfs group for identification\n", ++ head->disk->disk_name); ++ } ++ mutex_unlock(&head->subsys->lock); + } + + void nvme_mpath_remove_disk(struct nvme_ns_head *head) +@@ -238,14 +224,3 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head) + blk_cleanup_queue(head->disk->queue); + put_disk(head->disk); + } +- +-void nvme_mpath_remove_disk_links(struct nvme_ns *ns) +-{ +- if (!ns->head->disk) +- return; +- +- sysfs_remove_link(ns->disk->part0.holder_dir, +- kobject_name(&disk_to_dev(ns->head->disk)->kobj)); +- sysfs_remove_link(ns->head->disk->slave_dir, +- kobject_name(&disk_to_dev(ns->disk)->kobj)); +-} +diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h +index 8e4550f..d733b14 100644 +--- a/drivers/nvme/host/nvme.h ++++ b/drivers/nvme/host/nvme.h +@@ -123,7 +123,7 @@ enum nvme_ctrl_state { + NVME_CTRL_LIVE, + NVME_CTRL_ADMIN_ONLY, /* Only admin queue live */ + NVME_CTRL_RESETTING, +- NVME_CTRL_RECONNECTING, ++ NVME_CTRL_CONNECTING, + NVME_CTRL_DELETING, + NVME_CTRL_DEAD, + }; +@@ -183,6 +183,7 @@ struct nvme_ctrl { + struct work_struct scan_work; + struct work_struct async_event_work; + struct delayed_work ka_work; ++ struct nvme_command ka_cmd; + struct work_struct fw_act_work; + + /* Power saving configuration */ +@@ -409,9 +410,7 @@ bool nvme_req_needs_failover(struct request *req, blk_status_t error); + void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl); + int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl,struct nvme_ns_head *head); + void nvme_mpath_add_disk(struct nvme_ns_head *head); +-void nvme_mpath_add_disk_links(struct nvme_ns *ns); + void nvme_mpath_remove_disk(struct nvme_ns_head *head); +-void nvme_mpath_remove_disk_links(struct nvme_ns *ns); + + static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns) + { +@@ -453,12 +452,6 @@ static inline void nvme_mpath_add_disk(struct nvme_ns_head *head) + static inline void nvme_mpath_remove_disk(struct nvme_ns_head *head) + { + } +-static inline void nvme_mpath_add_disk_links(struct nvme_ns *ns) +-{ +-} +-static inline void nvme_mpath_remove_disk_links(struct nvme_ns *ns) +-{ +-} + static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns) + { + } +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 6fe7af0..b6f43b7 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -1141,7 +1141,7 @@ static bool nvme_should_reset(struct nvme_dev *dev, u32 csts) + /* If there is a reset/reinit ongoing, we shouldn't reset again. */ + switch (dev->ctrl.state) { + case NVME_CTRL_RESETTING: +- case NVME_CTRL_RECONNECTING: ++ case NVME_CTRL_CONNECTING: + return false; + default: + break; +@@ -1153,12 +1153,6 @@ static bool nvme_should_reset(struct nvme_dev *dev, u32 csts) + if (!(csts & NVME_CSTS_CFS) && !nssro) + return false; + +- /* If PCI error recovery process is happening, we cannot reset or +- * the recovery mechanism will surely fail. +- */ +- if (pci_channel_offline(to_pci_dev(dev->dev))) +- return false; +- + return true; + } + +@@ -1189,6 +1183,13 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved) + struct nvme_command cmd; + u32 csts = readl(dev->bar + NVME_REG_CSTS); + ++ /* If PCI error recovery process is happening, we cannot reset or ++ * the recovery mechanism will surely fail. ++ */ ++ mb(); ++ if (pci_channel_offline(to_pci_dev(dev->dev))) ++ return BLK_EH_RESET_TIMER; ++ + /* + * Reset immediately if the controller is failed + */ +@@ -1215,13 +1216,17 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved) + * cancellation error. All outstanding requests are completed on + * shutdown, so we return BLK_EH_HANDLED. + */ +- if (dev->ctrl.state == NVME_CTRL_RESETTING) { ++ switch (dev->ctrl.state) { ++ case NVME_CTRL_CONNECTING: ++ case NVME_CTRL_RESETTING: + dev_warn(dev->ctrl.device, + "I/O %d QID %d timeout, disable controller\n", + req->tag, nvmeq->qid); + nvme_dev_disable(dev, false); + nvme_req(req)->flags |= NVME_REQ_CANCELLED; + return BLK_EH_HANDLED; ++ default: ++ break; + } + + /* +@@ -1364,18 +1369,14 @@ static int nvme_cmb_qdepth(struct nvme_dev *dev, int nr_io_queues, + static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq, + int qid, int depth) + { +- if (qid && dev->cmb && use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) { +- unsigned offset = (qid - 1) * roundup(SQ_SIZE(depth), +- dev->ctrl.page_size); +- nvmeq->sq_dma_addr = dev->cmb_bus_addr + offset; +- nvmeq->sq_cmds_io = dev->cmb + offset; +- } else { +- nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth), +- &nvmeq->sq_dma_addr, GFP_KERNEL); +- if (!nvmeq->sq_cmds) +- return -ENOMEM; +- } ++ /* CMB SQEs will be mapped before creation */ ++ if (qid && dev->cmb && use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) ++ return 0; + ++ nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth), ++ &nvmeq->sq_dma_addr, GFP_KERNEL); ++ if (!nvmeq->sq_cmds) ++ return -ENOMEM; + return 0; + } + +@@ -1449,10 +1450,17 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) + struct nvme_dev *dev = nvmeq->dev; + int result; + ++ if (dev->cmb && use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) { ++ unsigned offset = (qid - 1) * roundup(SQ_SIZE(nvmeq->q_depth), ++ dev->ctrl.page_size); ++ nvmeq->sq_dma_addr = dev->cmb_bus_addr + offset; ++ nvmeq->sq_cmds_io = dev->cmb + offset; ++ } ++ + nvmeq->cq_vector = qid - 1; + result = adapter_alloc_cq(dev, qid, nvmeq); + if (result < 0) +- return result; ++ goto release_vector; + + result = adapter_alloc_sq(dev, qid, nvmeq); + if (result < 0) +@@ -1466,9 +1474,12 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) + return result; + + release_sq: ++ dev->online_queues--; + adapter_delete_sq(dev, qid); + release_cq: + adapter_delete_cq(dev, qid); ++ release_vector: ++ nvmeq->cq_vector = -1; + return result; + } + +@@ -1903,7 +1914,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) + int result, nr_io_queues; + unsigned long size; + +- nr_io_queues = num_present_cpus(); ++ nr_io_queues = num_possible_cpus(); + result = nvme_set_queue_count(&dev->ctrl, &nr_io_queues); + if (result < 0) + return result; +@@ -2288,12 +2299,12 @@ static void nvme_reset_work(struct work_struct *work) + nvme_dev_disable(dev, false); + + /* +- * Introduce RECONNECTING state from nvme-fc/rdma transports to mark the ++ * Introduce CONNECTING state from nvme-fc/rdma transports to mark the + * initializing procedure here. + */ +- if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RECONNECTING)) { ++ if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_CONNECTING)) { + dev_warn(dev->ctrl.device, +- "failed to mark controller RECONNECTING\n"); ++ "failed to mark controller CONNECTING\n"); + goto out; + } + +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index 2bc059f..4d84a73 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -887,7 +887,7 @@ static void nvme_rdma_free_ctrl(struct nvme_ctrl *nctrl) + static void nvme_rdma_reconnect_or_remove(struct nvme_rdma_ctrl *ctrl) + { + /* If we are resetting/deleting then do nothing */ +- if (ctrl->ctrl.state != NVME_CTRL_RECONNECTING) { ++ if (ctrl->ctrl.state != NVME_CTRL_CONNECTING) { + WARN_ON_ONCE(ctrl->ctrl.state == NVME_CTRL_NEW || + ctrl->ctrl.state == NVME_CTRL_LIVE); + return; +@@ -973,7 +973,7 @@ static void nvme_rdma_error_recovery_work(struct work_struct *work) + blk_mq_unquiesce_queue(ctrl->ctrl.admin_q); + nvme_start_queues(&ctrl->ctrl); + +- if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RECONNECTING)) { ++ if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) { + /* state change failure should never happen */ + WARN_ON_ONCE(1); + return; +@@ -1051,7 +1051,7 @@ static void nvme_rdma_unmap_data(struct nvme_rdma_queue *queue, + struct nvme_rdma_device *dev = queue->device; + struct ib_device *ibdev = dev->dev; + +- if (!blk_rq_bytes(rq)) ++ if (!blk_rq_payload_bytes(rq)) + return; + + if (req->mr) { +@@ -1166,7 +1166,7 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue, + + c->common.flags |= NVME_CMD_SGL_METABUF; + +- if (!blk_rq_bytes(rq)) ++ if (!blk_rq_payload_bytes(rq)) + return nvme_rdma_set_sg_null(c); + + req->sg_table.sgl = req->first_sgl; +@@ -1756,7 +1756,7 @@ static void nvme_rdma_reset_ctrl_work(struct work_struct *work) + nvme_stop_ctrl(&ctrl->ctrl); + nvme_rdma_shutdown_ctrl(ctrl, false); + +- if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RECONNECTING)) { ++ if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) { + /* state change failure should never happen */ + WARN_ON_ONCE(1); + return; +@@ -1784,11 +1784,8 @@ static void nvme_rdma_reset_ctrl_work(struct work_struct *work) + return; + + out_fail: +- dev_warn(ctrl->ctrl.device, "Removing after reset failure\n"); +- nvme_remove_namespaces(&ctrl->ctrl); +- nvme_rdma_shutdown_ctrl(ctrl, true); +- nvme_uninit_ctrl(&ctrl->ctrl); +- nvme_put_ctrl(&ctrl->ctrl); ++ ++ctrl->ctrl.nr_reconnects; ++ nvme_rdma_reconnect_or_remove(ctrl); + } + + static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = { +@@ -1942,6 +1939,9 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev, + if (!ctrl->queues) + goto out_uninit_ctrl; + ++ changed = nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING); ++ WARN_ON_ONCE(!changed); ++ + ret = nvme_rdma_configure_admin_queue(ctrl, true); + if (ret) + goto out_kfree_queues; +diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c +index 0bd7371..a78029e 100644 +--- a/drivers/nvme/target/core.c ++++ b/drivers/nvme/target/core.c +@@ -520,9 +520,12 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq, + goto fail; + } + +- /* either variant of SGLs is fine, as we don't support metadata */ +- if (unlikely((flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METABUF && +- (flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METASEG)) { ++ /* ++ * For fabrics, PSDT field shall describe metadata pointer (MPTR) that ++ * contains an address of a single contiguous physical buffer that is ++ * byte aligned. ++ */ ++ if (unlikely((flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METABUF)) { + status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; + goto fail; + } +diff --git a/drivers/nvme/target/io-cmd.c b/drivers/nvme/target/io-cmd.c +index 0a4372a..28bbdff 100644 +--- a/drivers/nvme/target/io-cmd.c ++++ b/drivers/nvme/target/io-cmd.c +@@ -105,10 +105,13 @@ static void nvmet_execute_flush(struct nvmet_req *req) + static u16 nvmet_discard_range(struct nvmet_ns *ns, + struct nvme_dsm_range *range, struct bio **bio) + { +- if (__blkdev_issue_discard(ns->bdev, ++ int ret; ++ ++ ret = __blkdev_issue_discard(ns->bdev, + le64_to_cpu(range->slba) << (ns->blksize_shift - 9), + le32_to_cpu(range->nlb) << (ns->blksize_shift - 9), +- GFP_KERNEL, 0, bio)) ++ GFP_KERNEL, 0, bio); ++ if (ret && ret != -EOPNOTSUPP) + return NVME_SC_INTERNAL | NVME_SC_DNR; + return 0; + } +diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c +index 7991ec3..861d150 100644 +--- a/drivers/nvme/target/loop.c ++++ b/drivers/nvme/target/loop.c +@@ -184,7 +184,7 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx, + return BLK_STS_OK; + } + +- if (blk_rq_bytes(req)) { ++ if (blk_rq_payload_bytes(req)) { + iod->sg_table.sgl = iod->first_sgl; + if (sg_alloc_table_chained(&iod->sg_table, + blk_rq_nr_phys_segments(req), +@@ -193,7 +193,7 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx, + + iod->req.sg = iod->sg_table.sgl; + iod->req.sg_cnt = blk_rq_map_sg(req->q, req, iod->sg_table.sgl); +- iod->req.transfer_len = blk_rq_bytes(req); ++ iod->req.transfer_len = blk_rq_payload_bytes(req); + } + + blk_mq_start_request(req); +diff --git a/drivers/of/property.c b/drivers/of/property.c +index 36ed84e..f46828e 100644 +--- a/drivers/of/property.c ++++ b/drivers/of/property.c +@@ -977,11 +977,11 @@ static int of_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, + return 0; + } + +-static void * ++static const void * + of_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, + const struct device *dev) + { +- return (void *)of_device_get_match_data(dev); ++ return of_device_get_match_data(dev); + } + + const struct fwnode_operations of_fwnode_ops = { +diff --git a/drivers/opp/cpu.c b/drivers/opp/cpu.c +index 2d87bc1..0c09107 100644 +--- a/drivers/opp/cpu.c ++++ b/drivers/opp/cpu.c +@@ -55,7 +55,7 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev, + if (max_opps <= 0) + return max_opps ? max_opps : -ENODATA; + +- freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_ATOMIC); ++ freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_KERNEL); + if (!freq_table) + return -ENOMEM; + +diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c +index 8de2d5c..dc9303a 100644 +--- a/drivers/pci/dwc/pcie-designware-host.c ++++ b/drivers/pci/dwc/pcie-designware-host.c +@@ -613,7 +613,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp) + /* setup bus numbers */ + val = dw_pcie_readl_dbi(pci, PCI_PRIMARY_BUS); + val &= 0xff000000; +- val |= 0x00010100; ++ val |= 0x00ff0100; + dw_pcie_writel_dbi(pci, PCI_PRIMARY_BUS, val); + + /* setup command register */ +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index fc73401..8b14bd3 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -3419,22 +3419,29 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PORT_RIDGE, + + static void quirk_chelsio_extend_vpd(struct pci_dev *dev) + { +- pci_set_vpd_size(dev, 8192); +-} +- +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x20, quirk_chelsio_extend_vpd); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x21, quirk_chelsio_extend_vpd); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x22, quirk_chelsio_extend_vpd); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x23, quirk_chelsio_extend_vpd); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x24, quirk_chelsio_extend_vpd); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x25, quirk_chelsio_extend_vpd); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x26, quirk_chelsio_extend_vpd); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x30, quirk_chelsio_extend_vpd); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x31, quirk_chelsio_extend_vpd); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x32, quirk_chelsio_extend_vpd); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x35, quirk_chelsio_extend_vpd); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x36, quirk_chelsio_extend_vpd); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x37, quirk_chelsio_extend_vpd); ++ int chip = (dev->device & 0xf000) >> 12; ++ int func = (dev->device & 0x0f00) >> 8; ++ int prod = (dev->device & 0x00ff) >> 0; ++ ++ /* ++ * If this is a T3-based adapter, there's a 1KB VPD area at offset ++ * 0xc00 which contains the preferred VPD values. If this is a T4 or ++ * later based adapter, the special VPD is at offset 0x400 for the ++ * Physical Functions (the SR-IOV Virtual Functions have no VPD ++ * Capabilities). The PCI VPD Access core routines will normally ++ * compute the size of the VPD by parsing the VPD Data Structure at ++ * offset 0x000. This will result in silent failures when attempting ++ * to accesses these other VPD areas which are beyond those computed ++ * limits. ++ */ ++ if (chip == 0x0 && prod >= 0x20) ++ pci_set_vpd_size(dev, 8192); ++ else if (chip >= 0x4 && func < 0x8) ++ pci_set_vpd_size(dev, 2048); ++} ++ ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID, ++ quirk_chelsio_extend_vpd); + + #ifdef CONFIG_ACPI + /* +diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c +index 369d48d..3654472 100644 +--- a/drivers/pci/setup-res.c ++++ b/drivers/pci/setup-res.c +@@ -401,6 +401,10 @@ void pci_release_resource(struct pci_dev *dev, int resno) + struct resource *res = dev->resource + resno; + + pci_info(dev, "BAR %d: releasing %pR\n", resno, res); ++ ++ if (!res->parent) ++ return; ++ + release_resource(res); + res->end = resource_size(res) - 1; + res->start = 0; +diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c +index 7bc5eee..f63db34 100644 +--- a/drivers/perf/arm_pmu.c ++++ b/drivers/perf/arm_pmu.c +@@ -17,7 +17,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -26,6 +25,9 @@ + + #include + ++static DEFINE_PER_CPU(struct arm_pmu *, cpu_armpmu); ++static DEFINE_PER_CPU(int, cpu_irq); ++ + static int + armpmu_map_cache_event(const unsigned (*cache_map) + [PERF_COUNT_HW_CACHE_MAX] +@@ -320,17 +322,9 @@ validate_group(struct perf_event *event) + return 0; + } + +-static struct arm_pmu_platdata *armpmu_get_platdata(struct arm_pmu *armpmu) +-{ +- struct platform_device *pdev = armpmu->plat_device; +- +- return pdev ? dev_get_platdata(&pdev->dev) : NULL; +-} +- + static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) + { + struct arm_pmu *armpmu; +- struct arm_pmu_platdata *plat; + int ret; + u64 start_clock, finish_clock; + +@@ -341,14 +335,11 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) + * dereference. + */ + armpmu = *(void **)dev; +- +- plat = armpmu_get_platdata(armpmu); ++ if (WARN_ON_ONCE(!armpmu)) ++ return IRQ_NONE; + + start_clock = sched_clock(); +- if (plat && plat->handle_irq) +- ret = plat->handle_irq(irq, armpmu, armpmu->handle_irq); +- else +- ret = armpmu->handle_irq(irq, armpmu); ++ ret = armpmu->handle_irq(irq, armpmu); + finish_clock = sched_clock(); + + perf_sample_event_took(finish_clock - start_clock); +@@ -531,54 +522,41 @@ int perf_num_counters(void) + } + EXPORT_SYMBOL_GPL(perf_num_counters); + +-void armpmu_free_irq(struct arm_pmu *armpmu, int cpu) ++static int armpmu_count_irq_users(const int irq) + { +- struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; +- int irq = per_cpu(hw_events->irq, cpu); ++ int cpu, count = 0; + +- if (!cpumask_test_and_clear_cpu(cpu, &armpmu->active_irqs)) +- return; +- +- if (irq_is_percpu_devid(irq)) { +- free_percpu_irq(irq, &hw_events->percpu_pmu); +- cpumask_clear(&armpmu->active_irqs); +- return; ++ for_each_possible_cpu(cpu) { ++ if (per_cpu(cpu_irq, cpu) == irq) ++ count++; + } + +- free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu)); ++ return count; + } + +-void armpmu_free_irqs(struct arm_pmu *armpmu) ++void armpmu_free_irq(int irq, int cpu) + { +- int cpu; ++ if (per_cpu(cpu_irq, cpu) == 0) ++ return; ++ if (WARN_ON(irq != per_cpu(cpu_irq, cpu))) ++ return; ++ ++ if (!irq_is_percpu_devid(irq)) ++ free_irq(irq, per_cpu_ptr(&cpu_armpmu, cpu)); ++ else if (armpmu_count_irq_users(irq) == 1) ++ free_percpu_irq(irq, &cpu_armpmu); + +- for_each_cpu(cpu, &armpmu->supported_cpus) +- armpmu_free_irq(armpmu, cpu); ++ per_cpu(cpu_irq, cpu) = 0; + } + +-int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) ++int armpmu_request_irq(int irq, int cpu) + { + int err = 0; +- struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; + const irq_handler_t handler = armpmu_dispatch_irq; +- int irq = per_cpu(hw_events->irq, cpu); + if (!irq) + return 0; + +- if (irq_is_percpu_devid(irq) && cpumask_empty(&armpmu->active_irqs)) { +- err = request_percpu_irq(irq, handler, "arm-pmu", +- &hw_events->percpu_pmu); +- } else if (irq_is_percpu_devid(irq)) { +- int other_cpu = cpumask_first(&armpmu->active_irqs); +- int other_irq = per_cpu(hw_events->irq, other_cpu); +- +- if (irq != other_irq) { +- pr_warn("mismatched PPIs detected.\n"); +- err = -EINVAL; +- goto err_out; +- } +- } else { +- struct arm_pmu_platdata *platdata = armpmu_get_platdata(armpmu); ++ if (!irq_is_percpu_devid(irq)) { + unsigned long irq_flags; + + err = irq_force_affinity(irq, cpumask_of(cpu)); +@@ -589,22 +567,22 @@ int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) + goto err_out; + } + +- if (platdata && platdata->irq_flags) { +- irq_flags = platdata->irq_flags; +- } else { +- irq_flags = IRQF_PERCPU | +- IRQF_NOBALANCING | +- IRQF_NO_THREAD; +- } ++ irq_flags = IRQF_PERCPU | ++ IRQF_NOBALANCING | ++ IRQF_NO_THREAD; + ++ irq_set_status_flags(irq, IRQ_NOAUTOEN); + err = request_irq(irq, handler, irq_flags, "arm-pmu", +- per_cpu_ptr(&hw_events->percpu_pmu, cpu)); ++ per_cpu_ptr(&cpu_armpmu, cpu)); ++ } else if (armpmu_count_irq_users(irq) == 0) { ++ err = request_percpu_irq(irq, handler, "arm-pmu", ++ &cpu_armpmu); + } + + if (err) + goto err_out; + +- cpumask_set_cpu(cpu, &armpmu->active_irqs); ++ per_cpu(cpu_irq, cpu) = irq; + return 0; + + err_out: +@@ -612,19 +590,6 @@ int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) + return err; + } + +-int armpmu_request_irqs(struct arm_pmu *armpmu) +-{ +- int cpu, err; +- +- for_each_cpu(cpu, &armpmu->supported_cpus) { +- err = armpmu_request_irq(armpmu, cpu); +- if (err) +- break; +- } +- +- return err; +-} +- + static int armpmu_get_cpu_irq(struct arm_pmu *pmu, int cpu) + { + struct pmu_hw_events __percpu *hw_events = pmu->hw_events; +@@ -647,12 +612,14 @@ static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node) + if (pmu->reset) + pmu->reset(pmu); + ++ per_cpu(cpu_armpmu, cpu) = pmu; ++ + irq = armpmu_get_cpu_irq(pmu, cpu); + if (irq) { +- if (irq_is_percpu_devid(irq)) { ++ if (irq_is_percpu_devid(irq)) + enable_percpu_irq(irq, IRQ_TYPE_NONE); +- return 0; +- } ++ else ++ enable_irq(irq); + } + + return 0; +@@ -667,8 +634,14 @@ static int arm_perf_teardown_cpu(unsigned int cpu, struct hlist_node *node) + return 0; + + irq = armpmu_get_cpu_irq(pmu, cpu); +- if (irq && irq_is_percpu_devid(irq)) +- disable_percpu_irq(irq); ++ if (irq) { ++ if (irq_is_percpu_devid(irq)) ++ disable_percpu_irq(irq); ++ else ++ disable_irq_nosync(irq); ++ } ++ ++ per_cpu(cpu_armpmu, cpu) = NULL; + + return 0; + } +@@ -800,18 +773,18 @@ static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu) + &cpu_pmu->node); + } + +-struct arm_pmu *armpmu_alloc(void) ++static struct arm_pmu *__armpmu_alloc(gfp_t flags) + { + struct arm_pmu *pmu; + int cpu; + +- pmu = kzalloc(sizeof(*pmu), GFP_KERNEL); ++ pmu = kzalloc(sizeof(*pmu), flags); + if (!pmu) { + pr_info("failed to allocate PMU device!\n"); + goto out; + } + +- pmu->hw_events = alloc_percpu(struct pmu_hw_events); ++ pmu->hw_events = alloc_percpu_gfp(struct pmu_hw_events, flags); + if (!pmu->hw_events) { + pr_info("failed to allocate per-cpu PMU data.\n"); + goto out_free_pmu; +@@ -857,6 +830,17 @@ struct arm_pmu *armpmu_alloc(void) + return NULL; + } + ++struct arm_pmu *armpmu_alloc(void) ++{ ++ return __armpmu_alloc(GFP_KERNEL); ++} ++ ++struct arm_pmu *armpmu_alloc_atomic(void) ++{ ++ return __armpmu_alloc(GFP_ATOMIC); ++} ++ ++ + void armpmu_free(struct arm_pmu *pmu) + { + free_percpu(pmu->hw_events); +diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c +index 705f1a3..0f19751 100644 +--- a/drivers/perf/arm_pmu_acpi.c ++++ b/drivers/perf/arm_pmu_acpi.c +@@ -11,6 +11,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + +@@ -87,7 +89,13 @@ static int arm_pmu_acpi_parse_irqs(void) + pr_warn("No ACPI PMU IRQ for CPU%d\n", cpu); + } + ++ /* ++ * Log and request the IRQ so the core arm_pmu code can manage ++ * it. We'll have to sanity-check IRQs later when we associate ++ * them with their PMUs. ++ */ + per_cpu(pmu_irqs, cpu) = irq; ++ armpmu_request_irq(irq, cpu); + } + + return 0; +@@ -127,7 +135,7 @@ static struct arm_pmu *arm_pmu_acpi_find_alloc_pmu(void) + return pmu; + } + +- pmu = armpmu_alloc(); ++ pmu = armpmu_alloc_atomic(); + if (!pmu) { + pr_warn("Unable to allocate PMU for CPU%d\n", + smp_processor_id()); +@@ -140,6 +148,35 @@ static struct arm_pmu *arm_pmu_acpi_find_alloc_pmu(void) + } + + /* ++ * Check whether the new IRQ is compatible with those already associated with ++ * the PMU (e.g. we don't have mismatched PPIs). ++ */ ++static bool pmu_irq_matches(struct arm_pmu *pmu, int irq) ++{ ++ struct pmu_hw_events __percpu *hw_events = pmu->hw_events; ++ int cpu; ++ ++ if (!irq) ++ return true; ++ ++ for_each_cpu(cpu, &pmu->supported_cpus) { ++ int other_irq = per_cpu(hw_events->irq, cpu); ++ if (!other_irq) ++ continue; ++ ++ if (irq == other_irq) ++ continue; ++ if (!irq_is_percpu_devid(irq) && !irq_is_percpu_devid(other_irq)) ++ continue; ++ ++ pr_warn("mismatched PPIs detected\n"); ++ return false; ++ } ++ ++ return true; ++} ++ ++/* + * This must run before the common arm_pmu hotplug logic, so that we can + * associate a CPU and its interrupt before the common code tries to manage the + * affinity and so on. +@@ -164,19 +201,14 @@ static int arm_pmu_acpi_cpu_starting(unsigned int cpu) + if (!pmu) + return -ENOMEM; + +- cpumask_set_cpu(cpu, &pmu->supported_cpus); +- + per_cpu(probed_pmus, cpu) = pmu; + +- /* +- * Log and request the IRQ so the core arm_pmu code can manage it. In +- * some situations (e.g. mismatched PPIs), we may fail to request the +- * IRQ. However, it may be too late for us to do anything about it. +- * The common ARM PMU code will log a warning in this case. +- */ +- hw_events = pmu->hw_events; +- per_cpu(hw_events->irq, cpu) = irq; +- armpmu_request_irq(pmu, cpu); ++ if (pmu_irq_matches(pmu, irq)) { ++ hw_events = pmu->hw_events; ++ per_cpu(hw_events->irq, cpu) = irq; ++ } ++ ++ cpumask_set_cpu(cpu, &pmu->supported_cpus); + + /* + * Ideally, we'd probe the PMU here when we find the first matching +@@ -247,11 +279,6 @@ static int arm_pmu_acpi_init(void) + if (acpi_disabled) + return 0; + +- /* +- * We can't request IRQs yet, since we don't know the cookie value +- * until we know which CPUs share the same logical PMU. We'll handle +- * that in arm_pmu_acpi_cpu_starting(). +- */ + ret = arm_pmu_acpi_parse_irqs(); + if (ret) + return ret; +diff --git a/drivers/perf/arm_pmu_platform.c b/drivers/perf/arm_pmu_platform.c +index 46501cc..7729eda 100644 +--- a/drivers/perf/arm_pmu_platform.c ++++ b/drivers/perf/arm_pmu_platform.c +@@ -127,13 +127,6 @@ static int pmu_parse_irqs(struct arm_pmu *pmu) + pdev->dev.of_node); + } + +- /* +- * Some platforms have all PMU IRQs OR'd into a single IRQ, with a +- * special platdata function that attempts to demux them. +- */ +- if (dev_get_platdata(&pdev->dev)) +- cpumask_setall(&pmu->supported_cpus); +- + for (i = 0; i < num_irqs; i++) { + int cpu, irq; + +@@ -164,6 +157,36 @@ static int pmu_parse_irqs(struct arm_pmu *pmu) + return 0; + } + ++static int armpmu_request_irqs(struct arm_pmu *armpmu) ++{ ++ struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; ++ int cpu, err; ++ ++ for_each_cpu(cpu, &armpmu->supported_cpus) { ++ int irq = per_cpu(hw_events->irq, cpu); ++ if (!irq) ++ continue; ++ ++ err = armpmu_request_irq(irq, cpu); ++ if (err) ++ break; ++ } ++ ++ return err; ++} ++ ++static void armpmu_free_irqs(struct arm_pmu *armpmu) ++{ ++ int cpu; ++ struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; ++ ++ for_each_cpu(cpu, &armpmu->supported_cpus) { ++ int irq = per_cpu(hw_events->irq, cpu); ++ ++ armpmu_free_irq(irq, cpu); ++ } ++} ++ + int arm_pmu_device_probe(struct platform_device *pdev, + const struct of_device_id *of_table, + const struct pmu_probe_info *probe_table) +diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg.c b/drivers/pinctrl/meson/pinctrl-meson-axg.c +index 1fda9d6..4b91ff7 100644 +--- a/drivers/pinctrl/meson/pinctrl-meson-axg.c ++++ b/drivers/pinctrl/meson/pinctrl-meson-axg.c +@@ -716,7 +716,7 @@ static const char * const uart_b_groups[] = { + "uart_tx_b_x", "uart_rx_b_x", "uart_cts_b_x", "uart_rts_b_x", + }; + +-static const char * const uart_ao_b_gpioz_groups[] = { ++static const char * const uart_ao_b_z_groups[] = { + "uart_ao_tx_b_z", "uart_ao_rx_b_z", + "uart_ao_cts_b_z", "uart_ao_rts_b_z", + }; +@@ -855,7 +855,7 @@ static struct meson_pmx_func meson_axg_periphs_functions[] = { + FUNCTION(nand), + FUNCTION(uart_a), + FUNCTION(uart_b), +- FUNCTION(uart_ao_b_gpioz), ++ FUNCTION(uart_ao_b_z), + FUNCTION(i2c0), + FUNCTION(i2c1), + FUNCTION(i2c2), +diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c +index 6dec6ab..d859973 100644 +--- a/drivers/platform/chrome/chromeos_laptop.c ++++ b/drivers/platform/chrome/chromeos_laptop.c +@@ -423,7 +423,7 @@ static int chromeos_laptop_probe(struct platform_device *pdev) + return ret; + } + +-static const struct chromeos_laptop samsung_series_5_550 = { ++static struct chromeos_laptop samsung_series_5_550 = { + .i2c_peripherals = { + /* Touchpad. */ + { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, +@@ -432,14 +432,14 @@ static const struct chromeos_laptop samsung_series_5_550 = { + }, + }; + +-static const struct chromeos_laptop samsung_series_5 = { ++static struct chromeos_laptop samsung_series_5 = { + .i2c_peripherals = { + /* Light Sensor. */ + { .add = setup_tsl2583_als, I2C_ADAPTER_SMBUS }, + }, + }; + +-static const struct chromeos_laptop chromebook_pixel = { ++static struct chromeos_laptop chromebook_pixel = { + .i2c_peripherals = { + /* Touch Screen. */ + { .add = setup_atmel_1664s_ts, I2C_ADAPTER_PANEL }, +@@ -450,14 +450,14 @@ static const struct chromeos_laptop chromebook_pixel = { + }, + }; + +-static const struct chromeos_laptop hp_chromebook_14 = { ++static struct chromeos_laptop hp_chromebook_14 = { + .i2c_peripherals = { + /* Touchpad. */ + { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 }, + }, + }; + +-static const struct chromeos_laptop dell_chromebook_11 = { ++static struct chromeos_laptop dell_chromebook_11 = { + .i2c_peripherals = { + /* Touchpad. */ + { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 }, +@@ -466,28 +466,28 @@ static const struct chromeos_laptop dell_chromebook_11 = { + }, + }; + +-static const struct chromeos_laptop toshiba_cb35 = { ++static struct chromeos_laptop toshiba_cb35 = { + .i2c_peripherals = { + /* Touchpad. */ + { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 }, + }, + }; + +-static const struct chromeos_laptop acer_c7_chromebook = { ++static struct chromeos_laptop acer_c7_chromebook = { + .i2c_peripherals = { + /* Touchpad. */ + { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, + }, + }; + +-static const struct chromeos_laptop acer_ac700 = { ++static struct chromeos_laptop acer_ac700 = { + .i2c_peripherals = { + /* Light Sensor. */ + { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS }, + }, + }; + +-static const struct chromeos_laptop acer_c720 = { ++static struct chromeos_laptop acer_c720 = { + .i2c_peripherals = { + /* Touchscreen. */ + { .add = setup_atmel_1664s_ts, I2C_ADAPTER_DESIGNWARE_1 }, +@@ -500,14 +500,14 @@ static const struct chromeos_laptop acer_c720 = { + }, + }; + +-static const struct chromeos_laptop hp_pavilion_14_chromebook = { ++static struct chromeos_laptop hp_pavilion_14_chromebook = { + .i2c_peripherals = { + /* Touchpad. */ + { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, + }, + }; + +-static const struct chromeos_laptop cr48 = { ++static struct chromeos_laptop cr48 = { + .i2c_peripherals = { + /* Light Sensor. */ + { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS }, +diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig +index 9a8f964..d10ffe5 100644 +--- a/drivers/platform/x86/Kconfig ++++ b/drivers/platform/x86/Kconfig +@@ -105,31 +105,44 @@ config ASUS_LAPTOP + + If you have an ACPI-compatible ASUS laptop, say Y or M here. + ++# ++# If the DELL_SMBIOS_SMM feature is enabled, the DELL_SMBIOS driver ++# becomes dependent on the DCDBAS driver. The "depends" line prevents a ++# configuration where DELL_SMBIOS=y while DCDBAS=m. ++# + config DELL_SMBIOS +- tristate ++ tristate "Dell SMBIOS driver" ++ depends on DCDBAS || DCDBAS=n ++ ---help--- ++ This provides support for the Dell SMBIOS calling interface. ++ If you have a Dell computer you should enable this option. ++ ++ Be sure to select at least one backend for it to work properly. + + config DELL_SMBIOS_WMI +- tristate "Dell SMBIOS calling interface (WMI implementation)" ++ bool "Dell SMBIOS driver WMI backend" ++ default y + depends on ACPI_WMI + select DELL_WMI_DESCRIPTOR +- select DELL_SMBIOS ++ depends on DELL_SMBIOS + ---help--- + This provides an implementation for the Dell SMBIOS calling interface + communicated over ACPI-WMI. + +- If you have a Dell computer from >2007 you should say Y or M here. ++ If you have a Dell computer from >2007 you should say Y here. + If you aren't sure and this module doesn't work for your computer + it just won't load. + + config DELL_SMBIOS_SMM +- tristate "Dell SMBIOS calling interface (SMM implementation)" ++ bool "Dell SMBIOS driver SMM backend" ++ default y + depends on DCDBAS +- select DELL_SMBIOS ++ depends on DELL_SMBIOS + ---help--- + This provides an implementation for the Dell SMBIOS calling interface + communicated over SMI/SMM. + +- If you have a Dell computer from <=2017 you should say Y or M here. ++ If you have a Dell computer from <=2017 you should say Y here. + If you aren't sure and this module doesn't work for your computer + it just won't load. + +diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile +index c388608..2ba6cb7 100644 +--- a/drivers/platform/x86/Makefile ++++ b/drivers/platform/x86/Makefile +@@ -13,8 +13,9 @@ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o + obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o + obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o + obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o +-obj-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o +-obj-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o ++dell-smbios-objs := dell-smbios-base.o ++dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o ++dell-smbios-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o + obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o + obj-$(CONFIG_DELL_WMI) += dell-wmi.o + obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o +diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c +index 2a68f59..c52c672 100644 +--- a/drivers/platform/x86/dell-laptop.c ++++ b/drivers/platform/x86/dell-laptop.c +@@ -127,24 +127,6 @@ static const struct dmi_system_id dell_device_table[] __initconst = { + }, + }, + { +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_CHASSIS_TYPE, "30"), /*Tablet*/ +- }, +- }, +- { +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /*Convertible*/ +- }, +- }, +- { +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +- DMI_MATCH(DMI_CHASSIS_TYPE, "32"), /*Detachable*/ +- }, +- }, +- { + .ident = "Dell Computer Corporation", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), +@@ -1279,7 +1261,7 @@ static int kbd_get_state(struct kbd_state *state) + struct calling_interface_buffer buffer; + int ret; + +- dell_fill_request(&buffer, 0, 0, 0, 0); ++ dell_fill_request(&buffer, 0x1, 0, 0, 0); + ret = dell_send_request(&buffer, + CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); + if (ret) +diff --git a/drivers/platform/x86/dell-smbios-base.c b/drivers/platform/x86/dell-smbios-base.c +new file mode 100644 +index 0000000..5bcf8a1 +--- /dev/null ++++ b/drivers/platform/x86/dell-smbios-base.c +@@ -0,0 +1,648 @@ ++/* ++ * Common functions for kernel modules using Dell SMBIOS ++ * ++ * Copyright (c) Red Hat ++ * Copyright (c) 2014 Gabriele Mazzotta ++ * Copyright (c) 2014 Pali Rohár ++ * ++ * Based on documentation in the libsmbios package: ++ * Copyright (C) 2005-2014 Dell Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "dell-smbios.h" ++ ++static u32 da_supported_commands; ++static int da_num_tokens; ++static struct platform_device *platform_device; ++static struct calling_interface_token *da_tokens; ++static struct device_attribute *token_location_attrs; ++static struct device_attribute *token_value_attrs; ++static struct attribute **token_attrs; ++static DEFINE_MUTEX(smbios_mutex); ++ ++struct smbios_device { ++ struct list_head list; ++ struct device *device; ++ int (*call_fn)(struct calling_interface_buffer *arg); ++}; ++ ++struct smbios_call { ++ u32 need_capability; ++ int cmd_class; ++ int cmd_select; ++}; ++ ++/* calls that are whitelisted for given capabilities */ ++static struct smbios_call call_whitelist[] = { ++ /* generally tokens are allowed, but may be further filtered or ++ * restricted by token blacklist or whitelist ++ */ ++ {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_STD}, ++ {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_AC}, ++ {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_BAT}, ++ {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD}, ++ {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_AC}, ++ {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT}, ++ /* used by userspace: fwupdate */ ++ {CAP_SYS_ADMIN, CLASS_ADMIN_PROP, SELECT_ADMIN_PROP}, ++ /* used by userspace: fwupd */ ++ {CAP_SYS_ADMIN, CLASS_INFO, SELECT_DOCK}, ++ {CAP_SYS_ADMIN, CLASS_FLASH_INTERFACE, SELECT_FLASH_INTERFACE}, ++}; ++ ++/* calls that are explicitly blacklisted */ ++static struct smbios_call call_blacklist[] = { ++ {0x0000, 1, 7}, /* manufacturing use */ ++ {0x0000, 6, 5}, /* manufacturing use */ ++ {0x0000, 11, 3}, /* write once */ ++ {0x0000, 11, 7}, /* write once */ ++ {0x0000, 11, 11}, /* write once */ ++ {0x0000, 19, -1}, /* diagnostics */ ++ /* handled by kernel: dell-laptop */ ++ {0x0000, CLASS_INFO, SELECT_RFKILL}, ++ {0x0000, CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT}, ++}; ++ ++struct token_range { ++ u32 need_capability; ++ u16 min; ++ u16 max; ++}; ++ ++/* tokens that are whitelisted for given capabilities */ ++static struct token_range token_whitelist[] = { ++ /* used by userspace: fwupdate */ ++ {CAP_SYS_ADMIN, CAPSULE_EN_TOKEN, CAPSULE_DIS_TOKEN}, ++ /* can indicate to userspace that WMI is needed */ ++ {0x0000, WSMT_EN_TOKEN, WSMT_DIS_TOKEN} ++}; ++ ++/* tokens that are explicitly blacklisted */ ++static struct token_range token_blacklist[] = { ++ {0x0000, 0x0058, 0x0059}, /* ME use */ ++ {0x0000, 0x00CD, 0x00D0}, /* raid shadow copy */ ++ {0x0000, 0x013A, 0x01FF}, /* sata shadow copy */ ++ {0x0000, 0x0175, 0x0176}, /* write once */ ++ {0x0000, 0x0195, 0x0197}, /* diagnostics */ ++ {0x0000, 0x01DC, 0x01DD}, /* manufacturing use */ ++ {0x0000, 0x027D, 0x0284}, /* diagnostics */ ++ {0x0000, 0x02E3, 0x02E3}, /* manufacturing use */ ++ {0x0000, 0x02FF, 0x02FF}, /* manufacturing use */ ++ {0x0000, 0x0300, 0x0302}, /* manufacturing use */ ++ {0x0000, 0x0325, 0x0326}, /* manufacturing use */ ++ {0x0000, 0x0332, 0x0335}, /* fan control */ ++ {0x0000, 0x0350, 0x0350}, /* manufacturing use */ ++ {0x0000, 0x0363, 0x0363}, /* manufacturing use */ ++ {0x0000, 0x0368, 0x0368}, /* manufacturing use */ ++ {0x0000, 0x03F6, 0x03F7}, /* manufacturing use */ ++ {0x0000, 0x049E, 0x049F}, /* manufacturing use */ ++ {0x0000, 0x04A0, 0x04A3}, /* disagnostics */ ++ {0x0000, 0x04E6, 0x04E7}, /* manufacturing use */ ++ {0x0000, 0x4000, 0x7FFF}, /* internal BIOS use */ ++ {0x0000, 0x9000, 0x9001}, /* internal BIOS use */ ++ {0x0000, 0xA000, 0xBFFF}, /* write only */ ++ {0x0000, 0xEFF0, 0xEFFF}, /* internal BIOS use */ ++ /* handled by kernel: dell-laptop */ ++ {0x0000, BRIGHTNESS_TOKEN, BRIGHTNESS_TOKEN}, ++ {0x0000, KBD_LED_OFF_TOKEN, KBD_LED_AUTO_TOKEN}, ++ {0x0000, KBD_LED_AC_TOKEN, KBD_LED_AC_TOKEN}, ++ {0x0000, KBD_LED_AUTO_25_TOKEN, KBD_LED_AUTO_75_TOKEN}, ++ {0x0000, KBD_LED_AUTO_100_TOKEN, KBD_LED_AUTO_100_TOKEN}, ++ {0x0000, GLOBAL_MIC_MUTE_ENABLE, GLOBAL_MIC_MUTE_DISABLE}, ++}; ++ ++static LIST_HEAD(smbios_device_list); ++ ++int dell_smbios_error(int value) ++{ ++ switch (value) { ++ case 0: /* Completed successfully */ ++ return 0; ++ case -1: /* Completed with error */ ++ return -EIO; ++ case -2: /* Function not supported */ ++ return -ENXIO; ++ default: /* Unknown error */ ++ return -EINVAL; ++ } ++} ++EXPORT_SYMBOL_GPL(dell_smbios_error); ++ ++int dell_smbios_register_device(struct device *d, void *call_fn) ++{ ++ struct smbios_device *priv; ++ ++ priv = devm_kzalloc(d, sizeof(struct smbios_device), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ get_device(d); ++ priv->device = d; ++ priv->call_fn = call_fn; ++ mutex_lock(&smbios_mutex); ++ list_add_tail(&priv->list, &smbios_device_list); ++ mutex_unlock(&smbios_mutex); ++ dev_dbg(d, "Added device: %s\n", d->driver->name); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(dell_smbios_register_device); ++ ++void dell_smbios_unregister_device(struct device *d) ++{ ++ struct smbios_device *priv; ++ ++ mutex_lock(&smbios_mutex); ++ list_for_each_entry(priv, &smbios_device_list, list) { ++ if (priv->device == d) { ++ list_del(&priv->list); ++ put_device(d); ++ break; ++ } ++ } ++ mutex_unlock(&smbios_mutex); ++ dev_dbg(d, "Remove device: %s\n", d->driver->name); ++} ++EXPORT_SYMBOL_GPL(dell_smbios_unregister_device); ++ ++int dell_smbios_call_filter(struct device *d, ++ struct calling_interface_buffer *buffer) ++{ ++ u16 t = 0; ++ int i; ++ ++ /* can't make calls over 30 */ ++ if (buffer->cmd_class > 30) { ++ dev_dbg(d, "class too big: %u\n", buffer->cmd_class); ++ return -EINVAL; ++ } ++ ++ /* supported calls on the particular system */ ++ if (!(da_supported_commands & (1 << buffer->cmd_class))) { ++ dev_dbg(d, "invalid command, supported commands: 0x%8x\n", ++ da_supported_commands); ++ return -EINVAL; ++ } ++ ++ /* match against call blacklist */ ++ for (i = 0; i < ARRAY_SIZE(call_blacklist); i++) { ++ if (buffer->cmd_class != call_blacklist[i].cmd_class) ++ continue; ++ if (buffer->cmd_select != call_blacklist[i].cmd_select && ++ call_blacklist[i].cmd_select != -1) ++ continue; ++ dev_dbg(d, "blacklisted command: %u/%u\n", ++ buffer->cmd_class, buffer->cmd_select); ++ return -EINVAL; ++ } ++ ++ /* if a token call, find token ID */ ++ ++ if ((buffer->cmd_class == CLASS_TOKEN_READ || ++ buffer->cmd_class == CLASS_TOKEN_WRITE) && ++ buffer->cmd_select < 3) { ++ /* find the matching token ID */ ++ for (i = 0; i < da_num_tokens; i++) { ++ if (da_tokens[i].location != buffer->input[0]) ++ continue; ++ t = da_tokens[i].tokenID; ++ break; ++ } ++ ++ /* token call; but token didn't exist */ ++ if (!t) { ++ dev_dbg(d, "token at location %04x doesn't exist\n", ++ buffer->input[0]); ++ return -EINVAL; ++ } ++ ++ /* match against token blacklist */ ++ for (i = 0; i < ARRAY_SIZE(token_blacklist); i++) { ++ if (!token_blacklist[i].min || !token_blacklist[i].max) ++ continue; ++ if (t >= token_blacklist[i].min && ++ t <= token_blacklist[i].max) ++ return -EINVAL; ++ } ++ ++ /* match against token whitelist */ ++ for (i = 0; i < ARRAY_SIZE(token_whitelist); i++) { ++ if (!token_whitelist[i].min || !token_whitelist[i].max) ++ continue; ++ if (t < token_whitelist[i].min || ++ t > token_whitelist[i].max) ++ continue; ++ if (!token_whitelist[i].need_capability || ++ capable(token_whitelist[i].need_capability)) { ++ dev_dbg(d, "whitelisted token: %x\n", t); ++ return 0; ++ } ++ ++ } ++ } ++ /* match against call whitelist */ ++ for (i = 0; i < ARRAY_SIZE(call_whitelist); i++) { ++ if (buffer->cmd_class != call_whitelist[i].cmd_class) ++ continue; ++ if (buffer->cmd_select != call_whitelist[i].cmd_select) ++ continue; ++ if (!call_whitelist[i].need_capability || ++ capable(call_whitelist[i].need_capability)) { ++ dev_dbg(d, "whitelisted capable command: %u/%u\n", ++ buffer->cmd_class, buffer->cmd_select); ++ return 0; ++ } ++ dev_dbg(d, "missing capability %d for %u/%u\n", ++ call_whitelist[i].need_capability, ++ buffer->cmd_class, buffer->cmd_select); ++ ++ } ++ ++ /* not in a whitelist, only allow processes with capabilities */ ++ if (capable(CAP_SYS_RAWIO)) { ++ dev_dbg(d, "Allowing %u/%u due to CAP_SYS_RAWIO\n", ++ buffer->cmd_class, buffer->cmd_select); ++ return 0; ++ } ++ ++ return -EACCES; ++} ++EXPORT_SYMBOL_GPL(dell_smbios_call_filter); ++ ++int dell_smbios_call(struct calling_interface_buffer *buffer) ++{ ++ int (*call_fn)(struct calling_interface_buffer *) = NULL; ++ struct device *selected_dev = NULL; ++ struct smbios_device *priv; ++ int ret; ++ ++ mutex_lock(&smbios_mutex); ++ list_for_each_entry(priv, &smbios_device_list, list) { ++ if (!selected_dev || priv->device->id >= selected_dev->id) { ++ dev_dbg(priv->device, "Trying device ID: %d\n", ++ priv->device->id); ++ call_fn = priv->call_fn; ++ selected_dev = priv->device; ++ } ++ } ++ ++ if (!selected_dev) { ++ ret = -ENODEV; ++ pr_err("No dell-smbios drivers are loaded\n"); ++ goto out_smbios_call; ++ } ++ ++ ret = call_fn(buffer); ++ ++out_smbios_call: ++ mutex_unlock(&smbios_mutex); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(dell_smbios_call); ++ ++struct calling_interface_token *dell_smbios_find_token(int tokenid) ++{ ++ int i; ++ ++ for (i = 0; i < da_num_tokens; i++) { ++ if (da_tokens[i].tokenID == tokenid) ++ return &da_tokens[i]; ++ } ++ ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(dell_smbios_find_token); ++ ++static BLOCKING_NOTIFIER_HEAD(dell_laptop_chain_head); ++ ++int dell_laptop_register_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_register(&dell_laptop_chain_head, nb); ++} ++EXPORT_SYMBOL_GPL(dell_laptop_register_notifier); ++ ++int dell_laptop_unregister_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_unregister(&dell_laptop_chain_head, nb); ++} ++EXPORT_SYMBOL_GPL(dell_laptop_unregister_notifier); ++ ++void dell_laptop_call_notifier(unsigned long action, void *data) ++{ ++ blocking_notifier_call_chain(&dell_laptop_chain_head, action, data); ++} ++EXPORT_SYMBOL_GPL(dell_laptop_call_notifier); ++ ++static void __init parse_da_table(const struct dmi_header *dm) ++{ ++ /* Final token is a terminator, so we don't want to copy it */ ++ int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; ++ struct calling_interface_token *new_da_tokens; ++ struct calling_interface_structure *table = ++ container_of(dm, struct calling_interface_structure, header); ++ ++ /* ++ * 4 bytes of table header, plus 7 bytes of Dell header ++ * plus at least 6 bytes of entry ++ */ ++ ++ if (dm->length < 17) ++ return; ++ ++ da_supported_commands = table->supportedCmds; ++ ++ new_da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) * ++ sizeof(struct calling_interface_token), ++ GFP_KERNEL); ++ ++ if (!new_da_tokens) ++ return; ++ da_tokens = new_da_tokens; ++ ++ memcpy(da_tokens+da_num_tokens, table->tokens, ++ sizeof(struct calling_interface_token) * tokens); ++ ++ da_num_tokens += tokens; ++} ++ ++static void zero_duplicates(struct device *dev) ++{ ++ int i, j; ++ ++ for (i = 0; i < da_num_tokens; i++) { ++ if (da_tokens[i].tokenID == 0) ++ continue; ++ for (j = i+1; j < da_num_tokens; j++) { ++ if (da_tokens[j].tokenID == 0) ++ continue; ++ if (da_tokens[i].tokenID == da_tokens[j].tokenID) { ++ dev_dbg(dev, "Zeroing dup token ID %x(%x/%x)\n", ++ da_tokens[j].tokenID, ++ da_tokens[j].location, ++ da_tokens[j].value); ++ da_tokens[j].tokenID = 0; ++ } ++ } ++ } ++} ++ ++static void __init find_tokens(const struct dmi_header *dm, void *dummy) ++{ ++ switch (dm->type) { ++ case 0xd4: /* Indexed IO */ ++ case 0xd5: /* Protected Area Type 1 */ ++ case 0xd6: /* Protected Area Type 2 */ ++ break; ++ case 0xda: /* Calling interface */ ++ parse_da_table(dm); ++ break; ++ } ++} ++ ++static int match_attribute(struct device *dev, ++ struct device_attribute *attr) ++{ ++ int i; ++ ++ for (i = 0; i < da_num_tokens * 2; i++) { ++ if (!token_attrs[i]) ++ continue; ++ if (strcmp(token_attrs[i]->name, attr->attr.name) == 0) ++ return i/2; ++ } ++ dev_dbg(dev, "couldn't match: %s\n", attr->attr.name); ++ return -EINVAL; ++} ++ ++static ssize_t location_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int i; ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ ++ i = match_attribute(dev, attr); ++ if (i > 0) ++ return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].location); ++ return 0; ++} ++ ++static ssize_t value_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int i; ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ ++ i = match_attribute(dev, attr); ++ if (i > 0) ++ return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].value); ++ return 0; ++} ++ ++static struct attribute_group smbios_attribute_group = { ++ .name = "tokens" ++}; ++ ++static struct platform_driver platform_driver = { ++ .driver = { ++ .name = "dell-smbios", ++ }, ++}; ++ ++static int build_tokens_sysfs(struct platform_device *dev) ++{ ++ char *location_name; ++ char *value_name; ++ size_t size; ++ int ret; ++ int i, j; ++ ++ /* (number of tokens + 1 for null terminated */ ++ size = sizeof(struct device_attribute) * (da_num_tokens + 1); ++ token_location_attrs = kzalloc(size, GFP_KERNEL); ++ if (!token_location_attrs) ++ return -ENOMEM; ++ token_value_attrs = kzalloc(size, GFP_KERNEL); ++ if (!token_value_attrs) ++ goto out_allocate_value; ++ ++ /* need to store both location and value + terminator*/ ++ size = sizeof(struct attribute *) * ((2 * da_num_tokens) + 1); ++ token_attrs = kzalloc(size, GFP_KERNEL); ++ if (!token_attrs) ++ goto out_allocate_attrs; ++ ++ for (i = 0, j = 0; i < da_num_tokens; i++) { ++ /* skip empty */ ++ if (da_tokens[i].tokenID == 0) ++ continue; ++ /* add location */ ++ location_name = kasprintf(GFP_KERNEL, "%04x_location", ++ da_tokens[i].tokenID); ++ if (location_name == NULL) ++ goto out_unwind_strings; ++ sysfs_attr_init(&token_location_attrs[i].attr); ++ token_location_attrs[i].attr.name = location_name; ++ token_location_attrs[i].attr.mode = 0444; ++ token_location_attrs[i].show = location_show; ++ token_attrs[j++] = &token_location_attrs[i].attr; ++ ++ /* add value */ ++ value_name = kasprintf(GFP_KERNEL, "%04x_value", ++ da_tokens[i].tokenID); ++ if (value_name == NULL) ++ goto loop_fail_create_value; ++ sysfs_attr_init(&token_value_attrs[i].attr); ++ token_value_attrs[i].attr.name = value_name; ++ token_value_attrs[i].attr.mode = 0444; ++ token_value_attrs[i].show = value_show; ++ token_attrs[j++] = &token_value_attrs[i].attr; ++ continue; ++ ++loop_fail_create_value: ++ kfree(value_name); ++ goto out_unwind_strings; ++ } ++ smbios_attribute_group.attrs = token_attrs; ++ ++ ret = sysfs_create_group(&dev->dev.kobj, &smbios_attribute_group); ++ if (ret) ++ goto out_unwind_strings; ++ return 0; ++ ++out_unwind_strings: ++ for (i = i-1; i > 0; i--) { ++ kfree(token_location_attrs[i].attr.name); ++ kfree(token_value_attrs[i].attr.name); ++ } ++ kfree(token_attrs); ++out_allocate_attrs: ++ kfree(token_value_attrs); ++out_allocate_value: ++ kfree(token_location_attrs); ++ ++ return -ENOMEM; ++} ++ ++static void free_group(struct platform_device *pdev) ++{ ++ int i; ++ ++ sysfs_remove_group(&pdev->dev.kobj, ++ &smbios_attribute_group); ++ for (i = 0; i < da_num_tokens; i++) { ++ kfree(token_location_attrs[i].attr.name); ++ kfree(token_value_attrs[i].attr.name); ++ } ++ kfree(token_attrs); ++ kfree(token_value_attrs); ++ kfree(token_location_attrs); ++} ++ ++static int __init dell_smbios_init(void) ++{ ++ const struct dmi_device *valid; ++ int ret, wmi, smm; ++ ++ valid = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL); ++ if (!valid) { ++ pr_err("Unable to run on non-Dell system\n"); ++ return -ENODEV; ++ } ++ ++ dmi_walk(find_tokens, NULL); ++ ++ if (!da_tokens) { ++ pr_info("Unable to find dmi tokens\n"); ++ return -ENODEV; ++ } ++ ++ ret = platform_driver_register(&platform_driver); ++ if (ret) ++ goto fail_platform_driver; ++ ++ platform_device = platform_device_alloc("dell-smbios", 0); ++ if (!platform_device) { ++ ret = -ENOMEM; ++ goto fail_platform_device_alloc; ++ } ++ ret = platform_device_add(platform_device); ++ if (ret) ++ goto fail_platform_device_add; ++ ++ /* duplicate tokens will cause problems building sysfs files */ ++ zero_duplicates(&platform_device->dev); ++ ++ ret = build_tokens_sysfs(platform_device); ++ if (ret) ++ goto fail_create_group; ++ ++ /* register backends */ ++ wmi = init_dell_smbios_wmi(); ++ if (wmi) ++ pr_debug("Failed to initialize WMI backend: %d\n", wmi); ++ smm = init_dell_smbios_smm(); ++ if (smm) ++ pr_debug("Failed to initialize SMM backend: %d\n", smm); ++ if (wmi && smm) { ++ pr_err("No SMBIOS backends available (wmi: %d, smm: %d)\n", ++ wmi, smm); ++ goto fail_sysfs; ++ } ++ ++ return 0; ++ ++fail_sysfs: ++ free_group(platform_device); ++ ++fail_create_group: ++ platform_device_del(platform_device); ++ ++fail_platform_device_add: ++ platform_device_put(platform_device); ++ ++fail_platform_device_alloc: ++ platform_driver_unregister(&platform_driver); ++ ++fail_platform_driver: ++ kfree(da_tokens); ++ return ret; ++} ++ ++static void __exit dell_smbios_exit(void) ++{ ++ exit_dell_smbios_wmi(); ++ exit_dell_smbios_smm(); ++ mutex_lock(&smbios_mutex); ++ if (platform_device) { ++ free_group(platform_device); ++ platform_device_unregister(platform_device); ++ platform_driver_unregister(&platform_driver); ++ } ++ kfree(da_tokens); ++ mutex_unlock(&smbios_mutex); ++} ++ ++subsys_initcall(dell_smbios_init); ++module_exit(dell_smbios_exit); ++ ++MODULE_AUTHOR("Matthew Garrett "); ++MODULE_AUTHOR("Gabriele Mazzotta "); ++MODULE_AUTHOR("Pali Rohár "); ++MODULE_AUTHOR("Mario Limonciello "); ++MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/x86/dell-smbios-smm.c b/drivers/platform/x86/dell-smbios-smm.c +index 89f65c4..e9e9da5 100644 +--- a/drivers/platform/x86/dell-smbios-smm.c ++++ b/drivers/platform/x86/dell-smbios-smm.c +@@ -58,7 +58,7 @@ static const struct dmi_system_id dell_device_table[] __initconst = { + }; + MODULE_DEVICE_TABLE(dmi, dell_device_table); + +-static void __init parse_da_table(const struct dmi_header *dm) ++static void parse_da_table(const struct dmi_header *dm) + { + struct calling_interface_structure *table = + container_of(dm, struct calling_interface_structure, header); +@@ -73,7 +73,7 @@ static void __init parse_da_table(const struct dmi_header *dm) + da_command_code = table->cmdIOCode; + } + +-static void __init find_cmd_address(const struct dmi_header *dm, void *dummy) ++static void find_cmd_address(const struct dmi_header *dm, void *dummy) + { + switch (dm->type) { + case 0xda: /* Calling interface */ +@@ -128,7 +128,7 @@ static bool test_wsmt_enabled(void) + return false; + } + +-static int __init dell_smbios_smm_init(void) ++int init_dell_smbios_smm(void) + { + int ret; + /* +@@ -176,7 +176,7 @@ static int __init dell_smbios_smm_init(void) + return ret; + } + +-static void __exit dell_smbios_smm_exit(void) ++void exit_dell_smbios_smm(void) + { + if (platform_device) { + dell_smbios_unregister_device(&platform_device->dev); +@@ -184,13 +184,3 @@ static void __exit dell_smbios_smm_exit(void) + free_page((unsigned long)buffer); + } + } +- +-subsys_initcall(dell_smbios_smm_init); +-module_exit(dell_smbios_smm_exit); +- +-MODULE_AUTHOR("Matthew Garrett "); +-MODULE_AUTHOR("Gabriele Mazzotta "); +-MODULE_AUTHOR("Pali Rohár "); +-MODULE_AUTHOR("Mario Limonciello "); +-MODULE_DESCRIPTION("Dell SMBIOS communications over SMI"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c +index 609557a..fbefedb 100644 +--- a/drivers/platform/x86/dell-smbios-wmi.c ++++ b/drivers/platform/x86/dell-smbios-wmi.c +@@ -228,7 +228,7 @@ static const struct wmi_device_id dell_smbios_wmi_id_table[] = { + { }, + }; + +-static void __init parse_b1_table(const struct dmi_header *dm) ++static void parse_b1_table(const struct dmi_header *dm) + { + struct misc_bios_flags_structure *flags = + container_of(dm, struct misc_bios_flags_structure, header); +@@ -242,7 +242,7 @@ static void __init parse_b1_table(const struct dmi_header *dm) + wmi_supported = 1; + } + +-static void __init find_b1(const struct dmi_header *dm, void *dummy) ++static void find_b1(const struct dmi_header *dm, void *dummy) + { + switch (dm->type) { + case 0xb1: /* misc bios flags */ +@@ -261,7 +261,7 @@ static struct wmi_driver dell_smbios_wmi_driver = { + .filter_callback = dell_smbios_wmi_filter, + }; + +-static int __init init_dell_smbios_wmi(void) ++int init_dell_smbios_wmi(void) + { + dmi_walk(find_b1, NULL); + +@@ -271,15 +271,9 @@ static int __init init_dell_smbios_wmi(void) + return wmi_driver_register(&dell_smbios_wmi_driver); + } + +-static void __exit exit_dell_smbios_wmi(void) ++void exit_dell_smbios_wmi(void) + { + wmi_driver_unregister(&dell_smbios_wmi_driver); + } + +-module_init(init_dell_smbios_wmi); +-module_exit(exit_dell_smbios_wmi); +- + MODULE_ALIAS("wmi:" DELL_WMI_SMBIOS_GUID); +-MODULE_AUTHOR("Mario Limonciello "); +-MODULE_DESCRIPTION("Dell SMBIOS communications over WMI"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c +deleted file mode 100644 +index 8541cde..0000000 +--- a/drivers/platform/x86/dell-smbios.c ++++ /dev/null +@@ -1,627 +0,0 @@ +-/* +- * Common functions for kernel modules using Dell SMBIOS +- * +- * Copyright (c) Red Hat +- * Copyright (c) 2014 Gabriele Mazzotta +- * Copyright (c) 2014 Pali Rohár +- * +- * Based on documentation in the libsmbios package: +- * Copyright (C) 2005-2014 Dell Inc. +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include "dell-smbios.h" +- +-static u32 da_supported_commands; +-static int da_num_tokens; +-static struct platform_device *platform_device; +-static struct calling_interface_token *da_tokens; +-static struct device_attribute *token_location_attrs; +-static struct device_attribute *token_value_attrs; +-static struct attribute **token_attrs; +-static DEFINE_MUTEX(smbios_mutex); +- +-struct smbios_device { +- struct list_head list; +- struct device *device; +- int (*call_fn)(struct calling_interface_buffer *); +-}; +- +-struct smbios_call { +- u32 need_capability; +- int cmd_class; +- int cmd_select; +-}; +- +-/* calls that are whitelisted for given capabilities */ +-static struct smbios_call call_whitelist[] = { +- /* generally tokens are allowed, but may be further filtered or +- * restricted by token blacklist or whitelist +- */ +- {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_STD}, +- {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_AC}, +- {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_BAT}, +- {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD}, +- {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_AC}, +- {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT}, +- /* used by userspace: fwupdate */ +- {CAP_SYS_ADMIN, CLASS_ADMIN_PROP, SELECT_ADMIN_PROP}, +- /* used by userspace: fwupd */ +- {CAP_SYS_ADMIN, CLASS_INFO, SELECT_DOCK}, +- {CAP_SYS_ADMIN, CLASS_FLASH_INTERFACE, SELECT_FLASH_INTERFACE}, +-}; +- +-/* calls that are explicitly blacklisted */ +-static struct smbios_call call_blacklist[] = { +- {0x0000, 1, 7}, /* manufacturing use */ +- {0x0000, 6, 5}, /* manufacturing use */ +- {0x0000, 11, 3}, /* write once */ +- {0x0000, 11, 7}, /* write once */ +- {0x0000, 11, 11}, /* write once */ +- {0x0000, 19, -1}, /* diagnostics */ +- /* handled by kernel: dell-laptop */ +- {0x0000, CLASS_INFO, SELECT_RFKILL}, +- {0x0000, CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT}, +-}; +- +-struct token_range { +- u32 need_capability; +- u16 min; +- u16 max; +-}; +- +-/* tokens that are whitelisted for given capabilities */ +-static struct token_range token_whitelist[] = { +- /* used by userspace: fwupdate */ +- {CAP_SYS_ADMIN, CAPSULE_EN_TOKEN, CAPSULE_DIS_TOKEN}, +- /* can indicate to userspace that WMI is needed */ +- {0x0000, WSMT_EN_TOKEN, WSMT_DIS_TOKEN} +-}; +- +-/* tokens that are explicitly blacklisted */ +-static struct token_range token_blacklist[] = { +- {0x0000, 0x0058, 0x0059}, /* ME use */ +- {0x0000, 0x00CD, 0x00D0}, /* raid shadow copy */ +- {0x0000, 0x013A, 0x01FF}, /* sata shadow copy */ +- {0x0000, 0x0175, 0x0176}, /* write once */ +- {0x0000, 0x0195, 0x0197}, /* diagnostics */ +- {0x0000, 0x01DC, 0x01DD}, /* manufacturing use */ +- {0x0000, 0x027D, 0x0284}, /* diagnostics */ +- {0x0000, 0x02E3, 0x02E3}, /* manufacturing use */ +- {0x0000, 0x02FF, 0x02FF}, /* manufacturing use */ +- {0x0000, 0x0300, 0x0302}, /* manufacturing use */ +- {0x0000, 0x0325, 0x0326}, /* manufacturing use */ +- {0x0000, 0x0332, 0x0335}, /* fan control */ +- {0x0000, 0x0350, 0x0350}, /* manufacturing use */ +- {0x0000, 0x0363, 0x0363}, /* manufacturing use */ +- {0x0000, 0x0368, 0x0368}, /* manufacturing use */ +- {0x0000, 0x03F6, 0x03F7}, /* manufacturing use */ +- {0x0000, 0x049E, 0x049F}, /* manufacturing use */ +- {0x0000, 0x04A0, 0x04A3}, /* disagnostics */ +- {0x0000, 0x04E6, 0x04E7}, /* manufacturing use */ +- {0x0000, 0x4000, 0x7FFF}, /* internal BIOS use */ +- {0x0000, 0x9000, 0x9001}, /* internal BIOS use */ +- {0x0000, 0xA000, 0xBFFF}, /* write only */ +- {0x0000, 0xEFF0, 0xEFFF}, /* internal BIOS use */ +- /* handled by kernel: dell-laptop */ +- {0x0000, BRIGHTNESS_TOKEN, BRIGHTNESS_TOKEN}, +- {0x0000, KBD_LED_OFF_TOKEN, KBD_LED_AUTO_TOKEN}, +- {0x0000, KBD_LED_AC_TOKEN, KBD_LED_AC_TOKEN}, +- {0x0000, KBD_LED_AUTO_25_TOKEN, KBD_LED_AUTO_75_TOKEN}, +- {0x0000, KBD_LED_AUTO_100_TOKEN, KBD_LED_AUTO_100_TOKEN}, +- {0x0000, GLOBAL_MIC_MUTE_ENABLE, GLOBAL_MIC_MUTE_DISABLE}, +-}; +- +-static LIST_HEAD(smbios_device_list); +- +-int dell_smbios_error(int value) +-{ +- switch (value) { +- case 0: /* Completed successfully */ +- return 0; +- case -1: /* Completed with error */ +- return -EIO; +- case -2: /* Function not supported */ +- return -ENXIO; +- default: /* Unknown error */ +- return -EINVAL; +- } +-} +-EXPORT_SYMBOL_GPL(dell_smbios_error); +- +-int dell_smbios_register_device(struct device *d, void *call_fn) +-{ +- struct smbios_device *priv; +- +- priv = devm_kzalloc(d, sizeof(struct smbios_device), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- get_device(d); +- priv->device = d; +- priv->call_fn = call_fn; +- mutex_lock(&smbios_mutex); +- list_add_tail(&priv->list, &smbios_device_list); +- mutex_unlock(&smbios_mutex); +- dev_dbg(d, "Added device: %s\n", d->driver->name); +- return 0; +-} +-EXPORT_SYMBOL_GPL(dell_smbios_register_device); +- +-void dell_smbios_unregister_device(struct device *d) +-{ +- struct smbios_device *priv; +- +- mutex_lock(&smbios_mutex); +- list_for_each_entry(priv, &smbios_device_list, list) { +- if (priv->device == d) { +- list_del(&priv->list); +- put_device(d); +- break; +- } +- } +- mutex_unlock(&smbios_mutex); +- dev_dbg(d, "Remove device: %s\n", d->driver->name); +-} +-EXPORT_SYMBOL_GPL(dell_smbios_unregister_device); +- +-int dell_smbios_call_filter(struct device *d, +- struct calling_interface_buffer *buffer) +-{ +- u16 t = 0; +- int i; +- +- /* can't make calls over 30 */ +- if (buffer->cmd_class > 30) { +- dev_dbg(d, "class too big: %u\n", buffer->cmd_class); +- return -EINVAL; +- } +- +- /* supported calls on the particular system */ +- if (!(da_supported_commands & (1 << buffer->cmd_class))) { +- dev_dbg(d, "invalid command, supported commands: 0x%8x\n", +- da_supported_commands); +- return -EINVAL; +- } +- +- /* match against call blacklist */ +- for (i = 0; i < ARRAY_SIZE(call_blacklist); i++) { +- if (buffer->cmd_class != call_blacklist[i].cmd_class) +- continue; +- if (buffer->cmd_select != call_blacklist[i].cmd_select && +- call_blacklist[i].cmd_select != -1) +- continue; +- dev_dbg(d, "blacklisted command: %u/%u\n", +- buffer->cmd_class, buffer->cmd_select); +- return -EINVAL; +- } +- +- /* if a token call, find token ID */ +- +- if ((buffer->cmd_class == CLASS_TOKEN_READ || +- buffer->cmd_class == CLASS_TOKEN_WRITE) && +- buffer->cmd_select < 3) { +- /* find the matching token ID */ +- for (i = 0; i < da_num_tokens; i++) { +- if (da_tokens[i].location != buffer->input[0]) +- continue; +- t = da_tokens[i].tokenID; +- break; +- } +- +- /* token call; but token didn't exist */ +- if (!t) { +- dev_dbg(d, "token at location %04x doesn't exist\n", +- buffer->input[0]); +- return -EINVAL; +- } +- +- /* match against token blacklist */ +- for (i = 0; i < ARRAY_SIZE(token_blacklist); i++) { +- if (!token_blacklist[i].min || !token_blacklist[i].max) +- continue; +- if (t >= token_blacklist[i].min && +- t <= token_blacklist[i].max) +- return -EINVAL; +- } +- +- /* match against token whitelist */ +- for (i = 0; i < ARRAY_SIZE(token_whitelist); i++) { +- if (!token_whitelist[i].min || !token_whitelist[i].max) +- continue; +- if (t < token_whitelist[i].min || +- t > token_whitelist[i].max) +- continue; +- if (!token_whitelist[i].need_capability || +- capable(token_whitelist[i].need_capability)) { +- dev_dbg(d, "whitelisted token: %x\n", t); +- return 0; +- } +- +- } +- } +- /* match against call whitelist */ +- for (i = 0; i < ARRAY_SIZE(call_whitelist); i++) { +- if (buffer->cmd_class != call_whitelist[i].cmd_class) +- continue; +- if (buffer->cmd_select != call_whitelist[i].cmd_select) +- continue; +- if (!call_whitelist[i].need_capability || +- capable(call_whitelist[i].need_capability)) { +- dev_dbg(d, "whitelisted capable command: %u/%u\n", +- buffer->cmd_class, buffer->cmd_select); +- return 0; +- } +- dev_dbg(d, "missing capability %d for %u/%u\n", +- call_whitelist[i].need_capability, +- buffer->cmd_class, buffer->cmd_select); +- +- } +- +- /* not in a whitelist, only allow processes with capabilities */ +- if (capable(CAP_SYS_RAWIO)) { +- dev_dbg(d, "Allowing %u/%u due to CAP_SYS_RAWIO\n", +- buffer->cmd_class, buffer->cmd_select); +- return 0; +- } +- +- return -EACCES; +-} +-EXPORT_SYMBOL_GPL(dell_smbios_call_filter); +- +-int dell_smbios_call(struct calling_interface_buffer *buffer) +-{ +- int (*call_fn)(struct calling_interface_buffer *) = NULL; +- struct device *selected_dev = NULL; +- struct smbios_device *priv; +- int ret; +- +- mutex_lock(&smbios_mutex); +- list_for_each_entry(priv, &smbios_device_list, list) { +- if (!selected_dev || priv->device->id >= selected_dev->id) { +- dev_dbg(priv->device, "Trying device ID: %d\n", +- priv->device->id); +- call_fn = priv->call_fn; +- selected_dev = priv->device; +- } +- } +- +- if (!selected_dev) { +- ret = -ENODEV; +- pr_err("No dell-smbios drivers are loaded\n"); +- goto out_smbios_call; +- } +- +- ret = call_fn(buffer); +- +-out_smbios_call: +- mutex_unlock(&smbios_mutex); +- return ret; +-} +-EXPORT_SYMBOL_GPL(dell_smbios_call); +- +-struct calling_interface_token *dell_smbios_find_token(int tokenid) +-{ +- int i; +- +- for (i = 0; i < da_num_tokens; i++) { +- if (da_tokens[i].tokenID == tokenid) +- return &da_tokens[i]; +- } +- +- return NULL; +-} +-EXPORT_SYMBOL_GPL(dell_smbios_find_token); +- +-static BLOCKING_NOTIFIER_HEAD(dell_laptop_chain_head); +- +-int dell_laptop_register_notifier(struct notifier_block *nb) +-{ +- return blocking_notifier_chain_register(&dell_laptop_chain_head, nb); +-} +-EXPORT_SYMBOL_GPL(dell_laptop_register_notifier); +- +-int dell_laptop_unregister_notifier(struct notifier_block *nb) +-{ +- return blocking_notifier_chain_unregister(&dell_laptop_chain_head, nb); +-} +-EXPORT_SYMBOL_GPL(dell_laptop_unregister_notifier); +- +-void dell_laptop_call_notifier(unsigned long action, void *data) +-{ +- blocking_notifier_call_chain(&dell_laptop_chain_head, action, data); +-} +-EXPORT_SYMBOL_GPL(dell_laptop_call_notifier); +- +-static void __init parse_da_table(const struct dmi_header *dm) +-{ +- /* Final token is a terminator, so we don't want to copy it */ +- int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; +- struct calling_interface_token *new_da_tokens; +- struct calling_interface_structure *table = +- container_of(dm, struct calling_interface_structure, header); +- +- /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least +- 6 bytes of entry */ +- +- if (dm->length < 17) +- return; +- +- da_supported_commands = table->supportedCmds; +- +- new_da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) * +- sizeof(struct calling_interface_token), +- GFP_KERNEL); +- +- if (!new_da_tokens) +- return; +- da_tokens = new_da_tokens; +- +- memcpy(da_tokens+da_num_tokens, table->tokens, +- sizeof(struct calling_interface_token) * tokens); +- +- da_num_tokens += tokens; +-} +- +-static void zero_duplicates(struct device *dev) +-{ +- int i, j; +- +- for (i = 0; i < da_num_tokens; i++) { +- if (da_tokens[i].tokenID == 0) +- continue; +- for (j = i+1; j < da_num_tokens; j++) { +- if (da_tokens[j].tokenID == 0) +- continue; +- if (da_tokens[i].tokenID == da_tokens[j].tokenID) { +- dev_dbg(dev, "Zeroing dup token ID %x(%x/%x)\n", +- da_tokens[j].tokenID, +- da_tokens[j].location, +- da_tokens[j].value); +- da_tokens[j].tokenID = 0; +- } +- } +- } +-} +- +-static void __init find_tokens(const struct dmi_header *dm, void *dummy) +-{ +- switch (dm->type) { +- case 0xd4: /* Indexed IO */ +- case 0xd5: /* Protected Area Type 1 */ +- case 0xd6: /* Protected Area Type 2 */ +- break; +- case 0xda: /* Calling interface */ +- parse_da_table(dm); +- break; +- } +-} +- +-static int match_attribute(struct device *dev, +- struct device_attribute *attr) +-{ +- int i; +- +- for (i = 0; i < da_num_tokens * 2; i++) { +- if (!token_attrs[i]) +- continue; +- if (strcmp(token_attrs[i]->name, attr->attr.name) == 0) +- return i/2; +- } +- dev_dbg(dev, "couldn't match: %s\n", attr->attr.name); +- return -EINVAL; +-} +- +-static ssize_t location_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- int i; +- +- if (!capable(CAP_SYS_ADMIN)) +- return -EPERM; +- +- i = match_attribute(dev, attr); +- if (i > 0) +- return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].location); +- return 0; +-} +- +-static ssize_t value_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- int i; +- +- if (!capable(CAP_SYS_ADMIN)) +- return -EPERM; +- +- i = match_attribute(dev, attr); +- if (i > 0) +- return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].value); +- return 0; +-} +- +-static struct attribute_group smbios_attribute_group = { +- .name = "tokens" +-}; +- +-static struct platform_driver platform_driver = { +- .driver = { +- .name = "dell-smbios", +- }, +-}; +- +-static int build_tokens_sysfs(struct platform_device *dev) +-{ +- char *location_name; +- char *value_name; +- size_t size; +- int ret; +- int i, j; +- +- /* (number of tokens + 1 for null terminated */ +- size = sizeof(struct device_attribute) * (da_num_tokens + 1); +- token_location_attrs = kzalloc(size, GFP_KERNEL); +- if (!token_location_attrs) +- return -ENOMEM; +- token_value_attrs = kzalloc(size, GFP_KERNEL); +- if (!token_value_attrs) +- goto out_allocate_value; +- +- /* need to store both location and value + terminator*/ +- size = sizeof(struct attribute *) * ((2 * da_num_tokens) + 1); +- token_attrs = kzalloc(size, GFP_KERNEL); +- if (!token_attrs) +- goto out_allocate_attrs; +- +- for (i = 0, j = 0; i < da_num_tokens; i++) { +- /* skip empty */ +- if (da_tokens[i].tokenID == 0) +- continue; +- /* add location */ +- location_name = kasprintf(GFP_KERNEL, "%04x_location", +- da_tokens[i].tokenID); +- if (location_name == NULL) +- goto out_unwind_strings; +- sysfs_attr_init(&token_location_attrs[i].attr); +- token_location_attrs[i].attr.name = location_name; +- token_location_attrs[i].attr.mode = 0444; +- token_location_attrs[i].show = location_show; +- token_attrs[j++] = &token_location_attrs[i].attr; +- +- /* add value */ +- value_name = kasprintf(GFP_KERNEL, "%04x_value", +- da_tokens[i].tokenID); +- if (value_name == NULL) +- goto loop_fail_create_value; +- sysfs_attr_init(&token_value_attrs[i].attr); +- token_value_attrs[i].attr.name = value_name; +- token_value_attrs[i].attr.mode = 0444; +- token_value_attrs[i].show = value_show; +- token_attrs[j++] = &token_value_attrs[i].attr; +- continue; +- +-loop_fail_create_value: +- kfree(value_name); +- goto out_unwind_strings; +- } +- smbios_attribute_group.attrs = token_attrs; +- +- ret = sysfs_create_group(&dev->dev.kobj, &smbios_attribute_group); +- if (ret) +- goto out_unwind_strings; +- return 0; +- +-out_unwind_strings: +- for (i = i-1; i > 0; i--) { +- kfree(token_location_attrs[i].attr.name); +- kfree(token_value_attrs[i].attr.name); +- } +- kfree(token_attrs); +-out_allocate_attrs: +- kfree(token_value_attrs); +-out_allocate_value: +- kfree(token_location_attrs); +- +- return -ENOMEM; +-} +- +-static void free_group(struct platform_device *pdev) +-{ +- int i; +- +- sysfs_remove_group(&pdev->dev.kobj, +- &smbios_attribute_group); +- for (i = 0; i < da_num_tokens; i++) { +- kfree(token_location_attrs[i].attr.name); +- kfree(token_value_attrs[i].attr.name); +- } +- kfree(token_attrs); +- kfree(token_value_attrs); +- kfree(token_location_attrs); +-} +- +-static int __init dell_smbios_init(void) +-{ +- const struct dmi_device *valid; +- int ret; +- +- valid = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL); +- if (!valid) { +- pr_err("Unable to run on non-Dell system\n"); +- return -ENODEV; +- } +- +- dmi_walk(find_tokens, NULL); +- +- if (!da_tokens) { +- pr_info("Unable to find dmi tokens\n"); +- return -ENODEV; +- } +- +- ret = platform_driver_register(&platform_driver); +- if (ret) +- goto fail_platform_driver; +- +- platform_device = platform_device_alloc("dell-smbios", 0); +- if (!platform_device) { +- ret = -ENOMEM; +- goto fail_platform_device_alloc; +- } +- ret = platform_device_add(platform_device); +- if (ret) +- goto fail_platform_device_add; +- +- /* duplicate tokens will cause problems building sysfs files */ +- zero_duplicates(&platform_device->dev); +- +- ret = build_tokens_sysfs(platform_device); +- if (ret) +- goto fail_create_group; +- +- return 0; +- +-fail_create_group: +- platform_device_del(platform_device); +- +-fail_platform_device_add: +- platform_device_put(platform_device); +- +-fail_platform_device_alloc: +- platform_driver_unregister(&platform_driver); +- +-fail_platform_driver: +- kfree(da_tokens); +- return ret; +-} +- +-static void __exit dell_smbios_exit(void) +-{ +- mutex_lock(&smbios_mutex); +- if (platform_device) { +- free_group(platform_device); +- platform_device_unregister(platform_device); +- platform_driver_unregister(&platform_driver); +- } +- kfree(da_tokens); +- mutex_unlock(&smbios_mutex); +-} +- +-subsys_initcall(dell_smbios_init); +-module_exit(dell_smbios_exit); +- +-MODULE_AUTHOR("Matthew Garrett "); +-MODULE_AUTHOR("Gabriele Mazzotta "); +-MODULE_AUTHOR("Pali Rohár "); +-MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h +index 138d478..d8adaf9 100644 +--- a/drivers/platform/x86/dell-smbios.h ++++ b/drivers/platform/x86/dell-smbios.h +@@ -75,4 +75,29 @@ int dell_laptop_register_notifier(struct notifier_block *nb); + int dell_laptop_unregister_notifier(struct notifier_block *nb); + void dell_laptop_call_notifier(unsigned long action, void *data); + +-#endif ++/* for the supported backends */ ++#ifdef CONFIG_DELL_SMBIOS_WMI ++int init_dell_smbios_wmi(void); ++void exit_dell_smbios_wmi(void); ++#else /* CONFIG_DELL_SMBIOS_WMI */ ++static inline int init_dell_smbios_wmi(void) ++{ ++ return -ENODEV; ++} ++static inline void exit_dell_smbios_wmi(void) ++{} ++#endif /* CONFIG_DELL_SMBIOS_WMI */ ++ ++#ifdef CONFIG_DELL_SMBIOS_SMM ++int init_dell_smbios_smm(void); ++void exit_dell_smbios_smm(void); ++#else /* CONFIG_DELL_SMBIOS_SMM */ ++static inline int init_dell_smbios_smm(void) ++{ ++ return -ENODEV; ++} ++static inline void exit_dell_smbios_smm(void) ++{} ++#endif /* CONFIG_DELL_SMBIOS_SMM */ ++ ++#endif /* _DELL_SMBIOS_H_ */ +diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c +index 5b6f18b18..535199c 100644 +--- a/drivers/platform/x86/ideapad-laptop.c ++++ b/drivers/platform/x86/ideapad-laptop.c +@@ -113,7 +113,7 @@ MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth."); + /* + * ACPI Helpers + */ +-#define IDEAPAD_EC_TIMEOUT (100) /* in ms */ ++#define IDEAPAD_EC_TIMEOUT (200) /* in ms */ + + static int read_method_int(acpi_handle handle, const char *method, int *val) + { +diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c +index d1a0131..5e3df19 100644 +--- a/drivers/platform/x86/intel-hid.c ++++ b/drivers/platform/x86/intel-hid.c +@@ -376,6 +376,7 @@ static int intel_hid_remove(struct platform_device *device) + { + acpi_handle handle = ACPI_HANDLE(&device->dev); + ++ device_init_wakeup(&device->dev, false); + acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); + intel_hid_set_enable(&device->dev, false); + intel_button_array_enable(&device->dev, false); +diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c +index b703d6f..c13780b8 100644 +--- a/drivers/platform/x86/intel-vbtn.c ++++ b/drivers/platform/x86/intel-vbtn.c +@@ -7,6 +7,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -97,9 +98,35 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) + dev_dbg(&device->dev, "unknown event index 0x%x\n", event); + } + +-static int intel_vbtn_probe(struct platform_device *device) ++static void detect_tablet_mode(struct platform_device *device) + { ++ const char *chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE); ++ struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev); ++ acpi_handle handle = ACPI_HANDLE(&device->dev); + struct acpi_buffer vgbs_output = { ACPI_ALLOCATE_BUFFER, NULL }; ++ union acpi_object *obj; ++ acpi_status status; ++ int m; ++ ++ if (!(chassis_type && strcmp(chassis_type, "31") == 0)) ++ goto out; ++ ++ status = acpi_evaluate_object(handle, "VGBS", NULL, &vgbs_output); ++ if (ACPI_FAILURE(status)) ++ goto out; ++ ++ obj = vgbs_output.pointer; ++ if (!(obj && obj->type == ACPI_TYPE_INTEGER)) ++ goto out; ++ ++ m = !(obj->integer.value & TABLET_MODE_FLAG); ++ input_report_switch(priv->input_dev, SW_TABLET_MODE, m); ++out: ++ kfree(vgbs_output.pointer); ++} ++ ++static int intel_vbtn_probe(struct platform_device *device) ++{ + acpi_handle handle = ACPI_HANDLE(&device->dev); + struct intel_vbtn_priv *priv; + acpi_status status; +@@ -122,22 +149,7 @@ static int intel_vbtn_probe(struct platform_device *device) + return err; + } + +- /* +- * VGBS being present and returning something means we have +- * a tablet mode switch. +- */ +- status = acpi_evaluate_object(handle, "VGBS", NULL, &vgbs_output); +- if (ACPI_SUCCESS(status)) { +- union acpi_object *obj = vgbs_output.pointer; +- +- if (obj && obj->type == ACPI_TYPE_INTEGER) { +- int m = !(obj->integer.value & TABLET_MODE_FLAG); +- +- input_report_switch(priv->input_dev, SW_TABLET_MODE, m); +- } +- } +- +- kfree(vgbs_output.pointer); ++ detect_tablet_mode(device); + + status = acpi_install_notify_handler(handle, + ACPI_DEVICE_NOTIFY, +@@ -154,6 +166,7 @@ static int intel_vbtn_remove(struct platform_device *device) + { + acpi_handle handle = ACPI_HANDLE(&device->dev); + ++ device_init_wakeup(&device->dev, false); + acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); + + /* +diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c +index daa68ac..8796211 100644 +--- a/drivers/platform/x86/wmi.c ++++ b/drivers/platform/x86/wmi.c +@@ -933,7 +933,7 @@ static int wmi_dev_probe(struct device *dev) + goto probe_failure; + } + +- buf = kmalloc(strlen(wdriver->driver.name) + 4, GFP_KERNEL); ++ buf = kmalloc(strlen(wdriver->driver.name) + 5, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto probe_string_failure; +@@ -945,7 +945,7 @@ static int wmi_dev_probe(struct device *dev) + wblock->char_dev.mode = 0444; + ret = misc_register(&wblock->char_dev); + if (ret) { +- dev_warn(dev, "failed to register char dev: %d", ret); ++ dev_warn(dev, "failed to register char dev: %d\n", ret); + ret = -ENOMEM; + goto probe_misc_failure; + } +@@ -1048,7 +1048,7 @@ static int wmi_create_device(struct device *wmi_bus_dev, + + if (result) { + dev_warn(wmi_bus_dev, +- "%s data block query control method not found", ++ "%s data block query control method not found\n", + method); + return result; + } +@@ -1198,7 +1198,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) + + retval = device_add(&wblock->dev.dev); + if (retval) { +- dev_err(wmi_bus_dev, "failed to register %pULL\n", ++ dev_err(wmi_bus_dev, "failed to register %pUL\n", + wblock->gblock.guid); + if (debug_event) + wmi_method_enable(wblock, 0); +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index dd4708c..1fc0c08 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -4310,7 +4310,7 @@ static int _regulator_resume_early(struct device *dev, void *data) + + rstate = regulator_get_suspend_state(rdev, *state); + if (rstate == NULL) +- return -EINVAL; ++ return 0; + + mutex_lock(&rdev->mutex); + +diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c +index 72c8b3e..e0a9c44 100644 +--- a/drivers/regulator/stm32-vrefbuf.c ++++ b/drivers/regulator/stm32-vrefbuf.c +@@ -51,7 +51,7 @@ static int stm32_vrefbuf_enable(struct regulator_dev *rdev) + * arbitrary timeout. + */ + ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val, +- !(val & STM32_VRR), 650, 10000); ++ val & STM32_VRR, 650, 10000); + if (ret) { + dev_err(&rdev->dev, "stm32 vrefbuf timed out!\n"); + val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); +diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c +index a7c15f0..ecef8e7 100644 +--- a/drivers/s390/block/dasd.c ++++ b/drivers/s390/block/dasd.c +@@ -2581,8 +2581,6 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr) + case DASD_CQR_QUEUED: + /* request was not started - just set to cleared */ + cqr->status = DASD_CQR_CLEARED; +- if (cqr->callback_data == DASD_SLEEPON_START_TAG) +- cqr->callback_data = DASD_SLEEPON_END_TAG; + break; + case DASD_CQR_IN_IO: + /* request in IO - terminate IO and release again */ +@@ -3902,9 +3900,12 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device) + wait_event(dasd_flush_wq, + (cqr->status != DASD_CQR_CLEAR_PENDING)); + +- /* mark sleepon requests as ended */ +- if (cqr->callback_data == DASD_SLEEPON_START_TAG) +- cqr->callback_data = DASD_SLEEPON_END_TAG; ++ /* ++ * requeue requests to blocklayer will only work ++ * for block device requests ++ */ ++ if (_dasd_requeue_request(cqr)) ++ continue; + + /* remove requests from device and block queue */ + list_del_init(&cqr->devlist); +@@ -3917,13 +3918,6 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device) + cqr = refers; + } + +- /* +- * requeue requests to blocklayer will only work +- * for block device requests +- */ +- if (_dasd_requeue_request(cqr)) +- continue; +- + if (cqr->block) + list_del_init(&cqr->blocklist); + cqr->block->base->discipline->free_cp( +@@ -3940,8 +3934,7 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device) + list_splice_tail(&requeue_queue, &device->ccw_queue); + spin_unlock_irq(get_ccwdev_lock(device->cdev)); + } +- /* wake up generic waitqueue for eventually ended sleepon requests */ +- wake_up(&generic_waitq); ++ dasd_schedule_device_bh(device); + return rc; + } + +diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c +index 1319122..9169af7 100644 +--- a/drivers/s390/cio/device_fsm.c ++++ b/drivers/s390/cio/device_fsm.c +@@ -795,6 +795,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) + + ccw_device_set_timeout(cdev, 0); + cdev->private->iretry = 255; ++ cdev->private->async_kill_io_rc = -ETIMEDOUT; + ret = ccw_device_cancel_halt_clear(cdev); + if (ret == -EBUSY) { + ccw_device_set_timeout(cdev, 3*HZ); +@@ -871,7 +872,7 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) + /* OK, i/o is dead now. Call interrupt handler. */ + if (cdev->handler) + cdev->handler(cdev, cdev->private->intparm, +- ERR_PTR(-EIO)); ++ ERR_PTR(cdev->private->async_kill_io_rc)); + } + + static void +@@ -888,14 +889,16 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event) + ccw_device_online_verify(cdev, 0); + if (cdev->handler) + cdev->handler(cdev, cdev->private->intparm, +- ERR_PTR(-EIO)); ++ ERR_PTR(cdev->private->async_kill_io_rc)); + } + + void ccw_device_kill_io(struct ccw_device *cdev) + { + int ret; + ++ ccw_device_set_timeout(cdev, 0); + cdev->private->iretry = 255; ++ cdev->private->async_kill_io_rc = -EIO; + ret = ccw_device_cancel_halt_clear(cdev); + if (ret == -EBUSY) { + ccw_device_set_timeout(cdev, 3*HZ); +diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c +index 1caf6a3..75ce12a 100644 +--- a/drivers/s390/cio/device_ops.c ++++ b/drivers/s390/cio/device_ops.c +@@ -159,7 +159,7 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) + } + + /** +- * ccw_device_start_key() - start a s390 channel program with key ++ * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to +@@ -170,10 +170,15 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) + * @key: storage key to be used for the I/O + * @flags: additional flags; defines the action to be performed for I/O + * processing. ++ * @expires: timeout value in jiffies + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). ++ * This function notifies the device driver if the channel program has not ++ * completed during the time specified by @expires. If a timeout occurs, the ++ * channel program is terminated via xsch, hsch or csch, and the device's ++ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; +@@ -182,9 +187,9 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) + * Context: + * Interrupts disabled, ccw device lock held + */ +-int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, +- unsigned long intparm, __u8 lpm, __u8 key, +- unsigned long flags) ++int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, ++ unsigned long intparm, __u8 lpm, __u8 key, ++ unsigned long flags, int expires) + { + struct subchannel *sch; + int ret; +@@ -224,6 +229,8 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + switch (ret) { + case 0: + cdev->private->intparm = intparm; ++ if (expires) ++ ccw_device_set_timeout(cdev, expires); + break; + case -EACCES: + case -ENODEV: +@@ -234,7 +241,7 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + } + + /** +- * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key ++ * ccw_device_start_key() - start a s390 channel program with key + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to +@@ -245,15 +252,10 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + * @key: storage key to be used for the I/O + * @flags: additional flags; defines the action to be performed for I/O + * processing. +- * @expires: timeout value in jiffies + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). +- * This function notifies the device driver if the channel program has not +- * completed during the time specified by @expires. If a timeout occurs, the +- * channel program is terminated via xsch, hsch or csch, and the device's +- * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; +@@ -262,19 +264,12 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + * Context: + * Interrupts disabled, ccw device lock held + */ +-int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, +- unsigned long intparm, __u8 lpm, __u8 key, +- unsigned long flags, int expires) ++int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, ++ unsigned long intparm, __u8 lpm, __u8 key, ++ unsigned long flags) + { +- int ret; +- +- if (!cdev) +- return -ENODEV; +- ccw_device_set_timeout(cdev, expires); +- ret = ccw_device_start_key(cdev, cpa, intparm, lpm, key, flags); +- if (ret != 0) +- ccw_device_set_timeout(cdev, 0); +- return ret; ++ return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm, key, ++ flags, 0); + } + + /** +@@ -489,18 +484,20 @@ void ccw_device_get_id(struct ccw_device *cdev, struct ccw_dev_id *dev_id) + EXPORT_SYMBOL(ccw_device_get_id); + + /** +- * ccw_device_tm_start_key() - perform start function ++ * ccw_device_tm_start_timeout_key() - perform start function + * @cdev: ccw device on which to perform the start function + * @tcw: transport-command word to be started + * @intparm: user defined parameter to be passed to the interrupt handler + * @lpm: mask of paths to use + * @key: storage key to use for storage access ++ * @expires: time span in jiffies after which to abort request + * + * Start the tcw on the given ccw device. Return zero on success, non-zero + * otherwise. + */ +-int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, +- unsigned long intparm, u8 lpm, u8 key) ++int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw, ++ unsigned long intparm, u8 lpm, u8 key, ++ int expires) + { + struct subchannel *sch; + int rc; +@@ -527,37 +524,32 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, + return -EACCES; + } + rc = cio_tm_start_key(sch, tcw, lpm, key); +- if (rc == 0) ++ if (rc == 0) { + cdev->private->intparm = intparm; ++ if (expires) ++ ccw_device_set_timeout(cdev, expires); ++ } + return rc; + } +-EXPORT_SYMBOL(ccw_device_tm_start_key); ++EXPORT_SYMBOL(ccw_device_tm_start_timeout_key); + + /** +- * ccw_device_tm_start_timeout_key() - perform start function ++ * ccw_device_tm_start_key() - perform start function + * @cdev: ccw device on which to perform the start function + * @tcw: transport-command word to be started + * @intparm: user defined parameter to be passed to the interrupt handler + * @lpm: mask of paths to use + * @key: storage key to use for storage access +- * @expires: time span in jiffies after which to abort request + * + * Start the tcw on the given ccw device. Return zero on success, non-zero + * otherwise. + */ +-int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw, +- unsigned long intparm, u8 lpm, u8 key, +- int expires) ++int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, ++ unsigned long intparm, u8 lpm, u8 key) + { +- int ret; +- +- ccw_device_set_timeout(cdev, expires); +- ret = ccw_device_tm_start_key(cdev, tcw, intparm, lpm, key); +- if (ret != 0) +- ccw_device_set_timeout(cdev, 0); +- return ret; ++ return ccw_device_tm_start_timeout_key(cdev, tcw, intparm, lpm, key, 0); + } +-EXPORT_SYMBOL(ccw_device_tm_start_timeout_key); ++EXPORT_SYMBOL(ccw_device_tm_start_key); + + /** + * ccw_device_tm_start() - perform start function +diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h +index af571d8..90e4e3a 100644 +--- a/drivers/s390/cio/io_sch.h ++++ b/drivers/s390/cio/io_sch.h +@@ -157,6 +157,7 @@ struct ccw_device_private { + unsigned long intparm; /* user interruption parameter */ + struct qdio_irq *qdio_data; + struct irb irb; /* device status */ ++ int async_kill_io_rc; + struct senseid senseid; /* SenseID info */ + struct pgid pgid[8]; /* path group IDs per chpid*/ + struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */ +diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c +index ca72f33..c8b308c 100644 +--- a/drivers/s390/net/qeth_core_main.c ++++ b/drivers/s390/net/qeth_core_main.c +@@ -2134,24 +2134,25 @@ int qeth_send_control_data(struct qeth_card *card, int len, + } + reply->callback = reply_cb; + reply->param = reply_param; +- if (card->state == CARD_STATE_DOWN) +- reply->seqno = QETH_IDX_COMMAND_SEQNO; +- else +- reply->seqno = card->seqno.ipa++; ++ + init_waitqueue_head(&reply->wait_q); +- spin_lock_irqsave(&card->lock, flags); +- list_add_tail(&reply->list, &card->cmd_waiter_list); +- spin_unlock_irqrestore(&card->lock, flags); + + while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ; +- qeth_prepare_control_data(card, len, iob); + + if (IS_IPA(iob->data)) { + cmd = __ipa_cmd(iob); ++ cmd->hdr.seqno = card->seqno.ipa++; ++ reply->seqno = cmd->hdr.seqno; + event_timeout = QETH_IPA_TIMEOUT; + } else { ++ reply->seqno = QETH_IDX_COMMAND_SEQNO; + event_timeout = QETH_TIMEOUT; + } ++ qeth_prepare_control_data(card, len, iob); ++ ++ spin_lock_irqsave(&card->lock, flags); ++ list_add_tail(&reply->list, &card->cmd_waiter_list); ++ spin_unlock_irqrestore(&card->lock, flags); + + timeout = jiffies + event_timeout; + +@@ -2933,7 +2934,7 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card, + memset(cmd, 0, sizeof(struct qeth_ipa_cmd)); + cmd->hdr.command = command; + cmd->hdr.initiator = IPA_CMD_INITIATOR_HOST; +- cmd->hdr.seqno = card->seqno.ipa; ++ /* cmd->hdr.seqno is set by qeth_send_control_data() */ + cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type); + cmd->hdr.rel_adapter_no = (__u8) card->info.portno; + if (card->options.layer2) +@@ -3898,10 +3899,12 @@ EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags); + int qeth_get_elements_no(struct qeth_card *card, + struct sk_buff *skb, int extra_elems, int data_offset) + { +- int elements = qeth_get_elements_for_range( +- (addr_t)skb->data + data_offset, +- (addr_t)skb->data + skb_headlen(skb)) + +- qeth_get_elements_for_frags(skb); ++ addr_t end = (addr_t)skb->data + skb_headlen(skb); ++ int elements = qeth_get_elements_for_frags(skb); ++ addr_t start = (addr_t)skb->data + data_offset; ++ ++ if (start != end) ++ elements += qeth_get_elements_for_range(start, end); + + if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { + QETH_DBF_MESSAGE(2, "Invalid size of IP packet " +diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h +index bdd45f4..498fe9a 100644 +--- a/drivers/s390/net/qeth_l3.h ++++ b/drivers/s390/net/qeth_l3.h +@@ -40,8 +40,40 @@ struct qeth_ipaddr { + unsigned int pfxlen; + } a6; + } u; +- + }; ++ ++static inline bool qeth_l3_addr_match_ip(struct qeth_ipaddr *a1, ++ struct qeth_ipaddr *a2) ++{ ++ if (a1->proto != a2->proto) ++ return false; ++ if (a1->proto == QETH_PROT_IPV6) ++ return ipv6_addr_equal(&a1->u.a6.addr, &a2->u.a6.addr); ++ return a1->u.a4.addr == a2->u.a4.addr; ++} ++ ++static inline bool qeth_l3_addr_match_all(struct qeth_ipaddr *a1, ++ struct qeth_ipaddr *a2) ++{ ++ /* Assumes that the pair was obtained via qeth_l3_addr_find_by_ip(), ++ * so 'proto' and 'addr' match for sure. ++ * ++ * For ucast: ++ * - 'mac' is always 0. ++ * - 'mask'/'pfxlen' for RXIP/VIPA is always 0. For NORMAL, matching ++ * values are required to avoid mixups in takeover eligibility. ++ * ++ * For mcast, ++ * - 'mac' is mapped from the IP, and thus always matches. ++ * - 'mask'/'pfxlen' is always 0. ++ */ ++ if (a1->type != a2->type) ++ return false; ++ if (a1->proto == QETH_PROT_IPV6) ++ return a1->u.a6.pfxlen == a2->u.a6.pfxlen; ++ return a1->u.a4.mask == a2->u.a4.mask; ++} ++ + static inline u64 qeth_l3_ipaddr_hash(struct qeth_ipaddr *addr) + { + u64 ret = 0; +diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c +index b0c888e8..962a04b 100644 +--- a/drivers/s390/net/qeth_l3_main.c ++++ b/drivers/s390/net/qeth_l3_main.c +@@ -67,6 +67,24 @@ void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr, + qeth_l3_ipaddr6_to_string(addr, buf); + } + ++static struct qeth_ipaddr *qeth_l3_find_addr_by_ip(struct qeth_card *card, ++ struct qeth_ipaddr *query) ++{ ++ u64 key = qeth_l3_ipaddr_hash(query); ++ struct qeth_ipaddr *addr; ++ ++ if (query->is_multicast) { ++ hash_for_each_possible(card->ip_mc_htable, addr, hnode, key) ++ if (qeth_l3_addr_match_ip(addr, query)) ++ return addr; ++ } else { ++ hash_for_each_possible(card->ip_htable, addr, hnode, key) ++ if (qeth_l3_addr_match_ip(addr, query)) ++ return addr; ++ } ++ return NULL; ++} ++ + static void qeth_l3_convert_addr_to_bits(u8 *addr, u8 *bits, int len) + { + int i, j; +@@ -120,34 +138,6 @@ static bool qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card, + return rc; + } + +-inline int +-qeth_l3_ipaddrs_is_equal(struct qeth_ipaddr *addr1, struct qeth_ipaddr *addr2) +-{ +- return addr1->proto == addr2->proto && +- !memcmp(&addr1->u, &addr2->u, sizeof(addr1->u)) && +- ether_addr_equal_64bits(addr1->mac, addr2->mac); +-} +- +-static struct qeth_ipaddr * +-qeth_l3_ip_from_hash(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) +-{ +- struct qeth_ipaddr *addr; +- +- if (tmp_addr->is_multicast) { +- hash_for_each_possible(card->ip_mc_htable, addr, +- hnode, qeth_l3_ipaddr_hash(tmp_addr)) +- if (qeth_l3_ipaddrs_is_equal(tmp_addr, addr)) +- return addr; +- } else { +- hash_for_each_possible(card->ip_htable, addr, +- hnode, qeth_l3_ipaddr_hash(tmp_addr)) +- if (qeth_l3_ipaddrs_is_equal(tmp_addr, addr)) +- return addr; +- } +- +- return NULL; +-} +- + int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) + { + int rc = 0; +@@ -162,23 +152,18 @@ int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) + QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8); + } + +- addr = qeth_l3_ip_from_hash(card, tmp_addr); +- if (!addr) ++ addr = qeth_l3_find_addr_by_ip(card, tmp_addr); ++ if (!addr || !qeth_l3_addr_match_all(addr, tmp_addr)) + return -ENOENT; + + addr->ref_counter--; +- if (addr->ref_counter > 0 && (addr->type == QETH_IP_TYPE_NORMAL || +- addr->type == QETH_IP_TYPE_RXIP)) ++ if (addr->type == QETH_IP_TYPE_NORMAL && addr->ref_counter > 0) + return rc; + if (addr->in_progress) + return -EINPROGRESS; + +- if (!qeth_card_hw_is_reachable(card)) { +- addr->disp_flag = QETH_DISP_ADDR_DELETE; +- return 0; +- } +- +- rc = qeth_l3_deregister_addr_entry(card, addr); ++ if (qeth_card_hw_is_reachable(card)) ++ rc = qeth_l3_deregister_addr_entry(card, addr); + + hash_del(&addr->hnode); + kfree(addr); +@@ -190,6 +175,7 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) + { + int rc = 0; + struct qeth_ipaddr *addr; ++ char buf[40]; + + QETH_CARD_TEXT(card, 4, "addip"); + +@@ -200,8 +186,20 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) + QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8); + } + +- addr = qeth_l3_ip_from_hash(card, tmp_addr); +- if (!addr) { ++ addr = qeth_l3_find_addr_by_ip(card, tmp_addr); ++ if (addr) { ++ if (tmp_addr->type != QETH_IP_TYPE_NORMAL) ++ return -EADDRINUSE; ++ if (qeth_l3_addr_match_all(addr, tmp_addr)) { ++ addr->ref_counter++; ++ return 0; ++ } ++ qeth_l3_ipaddr_to_string(tmp_addr->proto, (u8 *)&tmp_addr->u, ++ buf); ++ dev_warn(&card->gdev->dev, ++ "Registering IP address %s failed\n", buf); ++ return -EADDRINUSE; ++ } else { + addr = qeth_l3_get_addr_buffer(tmp_addr->proto); + if (!addr) + return -ENOMEM; +@@ -241,19 +239,15 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) + (rc == IPA_RC_LAN_OFFLINE)) { + addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING; + if (addr->ref_counter < 1) { +- qeth_l3_delete_ip(card, addr); ++ qeth_l3_deregister_addr_entry(card, addr); ++ hash_del(&addr->hnode); + kfree(addr); + } + } else { + hash_del(&addr->hnode); + kfree(addr); + } +- } else { +- if (addr->type == QETH_IP_TYPE_NORMAL || +- addr->type == QETH_IP_TYPE_RXIP) +- addr->ref_counter++; + } +- + return rc; + } + +@@ -321,11 +315,7 @@ static void qeth_l3_recover_ip(struct qeth_card *card) + spin_lock_bh(&card->ip_lock); + + hash_for_each_safe(card->ip_htable, i, tmp, addr, hnode) { +- if (addr->disp_flag == QETH_DISP_ADDR_DELETE) { +- qeth_l3_deregister_addr_entry(card, addr); +- hash_del(&addr->hnode); +- kfree(addr); +- } else if (addr->disp_flag == QETH_DISP_ADDR_ADD) { ++ if (addr->disp_flag == QETH_DISP_ADDR_ADD) { + if (addr->proto == QETH_PROT_IPV4) { + addr->in_progress = 1; + spin_unlock_bh(&card->ip_lock); +@@ -643,12 +633,7 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto, + return -ENOMEM; + + spin_lock_bh(&card->ip_lock); +- +- if (qeth_l3_ip_from_hash(card, ipaddr)) +- rc = -EEXIST; +- else +- rc = qeth_l3_add_ip(card, ipaddr); +- ++ rc = qeth_l3_add_ip(card, ipaddr); + spin_unlock_bh(&card->ip_lock); + + kfree(ipaddr); +@@ -713,12 +698,7 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto, + return -ENOMEM; + + spin_lock_bh(&card->ip_lock); +- +- if (qeth_l3_ip_from_hash(card, ipaddr)) +- rc = -EEXIST; +- else +- rc = qeth_l3_add_ip(card, ipaddr); +- ++ rc = qeth_l3_add_ip(card, ipaddr); + spin_unlock_bh(&card->ip_lock); + + kfree(ipaddr); +@@ -1239,8 +1219,9 @@ qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev) + tmp->u.a4.addr = be32_to_cpu(im4->multiaddr); + tmp->is_multicast = 1; + +- ipm = qeth_l3_ip_from_hash(card, tmp); ++ ipm = qeth_l3_find_addr_by_ip(card, tmp); + if (ipm) { ++ /* for mcast, by-IP match means full match */ + ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING; + } else { + ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4); +@@ -1319,8 +1300,9 @@ static void qeth_l3_add_mc6_to_hash(struct qeth_card *card, + sizeof(struct in6_addr)); + tmp->is_multicast = 1; + +- ipm = qeth_l3_ip_from_hash(card, tmp); ++ ipm = qeth_l3_find_addr_by_ip(card, tmp); + if (ipm) { ++ /* for mcast, by-IP match means full match */ + ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING; + continue; + } +@@ -2450,11 +2432,12 @@ static void qeth_tso_fill_header(struct qeth_card *card, + static int qeth_l3_get_elements_no_tso(struct qeth_card *card, + struct sk_buff *skb, int extra_elems) + { +- addr_t tcpdptr = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb); +- int elements = qeth_get_elements_for_range( +- tcpdptr, +- (addr_t)skb->data + skb_headlen(skb)) + +- qeth_get_elements_for_frags(skb); ++ addr_t start = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb); ++ addr_t end = (addr_t)skb->data + skb_headlen(skb); ++ int elements = qeth_get_elements_for_frags(skb); ++ ++ if (start != end) ++ elements += qeth_get_elements_for_range(start, end); + + if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { + QETH_DBF_MESSAGE(2, +diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c +index ba2e0856..8f5c1d7 100644 +--- a/drivers/s390/virtio/virtio_ccw.c ++++ b/drivers/s390/virtio/virtio_ccw.c +@@ -1297,6 +1297,9 @@ static int virtio_ccw_cio_notify(struct ccw_device *cdev, int event) + vcdev->device_lost = true; + rc = NOTIFY_DONE; + break; ++ case CIO_OPER: ++ rc = NOTIFY_OK; ++ break; + default: + rc = NOTIFY_DONE; + break; +@@ -1309,6 +1312,27 @@ static struct ccw_device_id virtio_ids[] = { + {}, + }; + ++#ifdef CONFIG_PM_SLEEP ++static int virtio_ccw_freeze(struct ccw_device *cdev) ++{ ++ struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev); ++ ++ return virtio_device_freeze(&vcdev->vdev); ++} ++ ++static int virtio_ccw_restore(struct ccw_device *cdev) ++{ ++ struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev); ++ int ret; ++ ++ ret = virtio_ccw_set_transport_rev(vcdev); ++ if (ret) ++ return ret; ++ ++ return virtio_device_restore(&vcdev->vdev); ++} ++#endif ++ + static struct ccw_driver virtio_ccw_driver = { + .driver = { + .owner = THIS_MODULE, +@@ -1321,6 +1345,11 @@ static struct ccw_driver virtio_ccw_driver = { + .set_online = virtio_ccw_online, + .notify = virtio_ccw_cio_notify, + .int_class = IRQIO_VIR, ++#ifdef CONFIG_PM_SLEEP ++ .freeze = virtio_ccw_freeze, ++ .thaw = virtio_ccw_restore, ++ .restore = virtio_ccw_restore, ++#endif + }; + + static int __init pure_hex(char **cp, unsigned int *val, int min_digit, +diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile +index fcfd28d..de1b3fc 100644 +--- a/drivers/scsi/Makefile ++++ b/drivers/scsi/Makefile +@@ -185,7 +185,6 @@ ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \ + CFLAGS_ncr53c8xx.o := $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m) + zalon7xx-objs := zalon.o ncr53c8xx.o + NCR_Q720_mod-objs := NCR_Q720.o ncr53c8xx.o +-oktagon_esp_mod-objs := oktagon_esp.o oktagon_io.o + + # Files generated that shall be removed upon make clean + clean-files := 53c700_d.h 53c700_u.h +diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c +index b3b931a..2664ea0 100644 +--- a/drivers/scsi/aacraid/linit.c ++++ b/drivers/scsi/aacraid/linit.c +@@ -1693,8 +1693,10 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) + * Map in the registers from the adapter. + */ + aac->base_size = AAC_MIN_FOOTPRINT_SIZE; +- if ((*aac_drivers[index].init)(aac)) ++ if ((*aac_drivers[index].init)(aac)) { ++ error = -ENODEV; + goto out_unmap; ++ } + + if (aac->sync_mode) { + if (aac_sync_mode) +diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c +deleted file mode 100644 +index 828ae3d..0000000 +--- a/drivers/scsi/aic7xxx/aiclib.c ++++ /dev/null +@@ -1,34 +0,0 @@ +-/* +- * Implementation of Utility functions for all SCSI device types. +- * +- * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs. +- * Copyright (c) 1997, 1998 Kenneth D. Merry. +- * All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions, and the following disclaimer, +- * without modification, immediately at the beginning of the file. +- * 2. The name of the author may not be used to endorse or promote products +- * derived from this software without specific prior written permission. +- * +- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR +- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +- * SUCH DAMAGE. +- * +- * $FreeBSD: src/sys/cam/scsi/scsi_all.c,v 1.38 2002/09/23 04:56:35 mjacob Exp $ +- * $Id$ +- */ +- +-#include "aiclib.h" +- +diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c +index 8e2f767..5a645b8 100644 +--- a/drivers/scsi/bnx2fc/bnx2fc_io.c ++++ b/drivers/scsi/bnx2fc/bnx2fc_io.c +@@ -1889,6 +1889,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, + /* we will not receive ABTS response for this IO */ + BNX2FC_IO_DBG(io_req, "Timer context finished processing " + "this scsi cmd\n"); ++ return; + } + + /* Cancel the timeout_work, as we received IO completion */ +diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c +index be5ee2d..7dbbbb8 100644 +--- a/drivers/scsi/csiostor/csio_lnode.c ++++ b/drivers/scsi/csiostor/csio_lnode.c +@@ -114,7 +114,7 @@ static enum csio_ln_ev fwevt_to_lnevt[] = { + static struct csio_lnode * + csio_ln_lookup_by_portid(struct csio_hw *hw, uint8_t portid) + { +- struct csio_lnode *ln = hw->rln; ++ struct csio_lnode *ln; + struct list_head *tmp; + + /* Match siblings lnode with portid */ +diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c +index 022e421..4b44325 100644 +--- a/drivers/scsi/device_handler/scsi_dh_alua.c ++++ b/drivers/scsi/device_handler/scsi_dh_alua.c +@@ -876,6 +876,11 @@ static void alua_rtpg_work(struct work_struct *work) + + /** + * alua_rtpg_queue() - cause RTPG to be submitted asynchronously ++ * @pg: ALUA port group associated with @sdev. ++ * @sdev: SCSI device for which to submit an RTPG. ++ * @qdata: Information about the callback to invoke after the RTPG. ++ * @force: Whether or not to submit an RTPG if a work item that will submit an ++ * RTPG already has been scheduled. + * + * Returns true if and only if alua_rtpg_work() will be called asynchronously. + * That function is responsible for calling @qdata->fn(). +diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c +index 57bf43e..dd94649 100644 +--- a/drivers/scsi/hosts.c ++++ b/drivers/scsi/hosts.c +@@ -328,8 +328,6 @@ static void scsi_host_dev_release(struct device *dev) + if (shost->work_q) + destroy_workqueue(shost->work_q); + +- destroy_rcu_head(&shost->rcu); +- + if (shost->shost_state == SHOST_CREATED) { + /* + * Free the shost_dev device name here if scsi_host_alloc() +@@ -404,7 +402,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) + INIT_LIST_HEAD(&shost->starved_list); + init_waitqueue_head(&shost->host_wait); + mutex_init(&shost->scan_mutex); +- init_rcu_head(&shost->rcu); + + index = ida_simple_get(&host_index_ida, 0, 0, GFP_KERNEL); + if (index < 0) +diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h +index 9a0696f..b81a53c 100644 +--- a/drivers/scsi/ibmvscsi/ibmvfc.h ++++ b/drivers/scsi/ibmvscsi/ibmvfc.h +@@ -367,7 +367,7 @@ enum ibmvfc_fcp_rsp_info_codes { + }; + + struct ibmvfc_fcp_rsp_info { +- __be16 reserved; ++ u8 reserved[3]; + u8 rsp_code; + u8 reserved2[4]; + }__attribute__((packed, aligned (2))); +diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c +index 073ced0..dc8e850 100644 +--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c ++++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c +@@ -216,36 +216,30 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance, + /** + * megasas_fire_cmd_fusion - Sends command to the FW + * @instance: Adapter soft state +- * @req_desc: 32bit or 64bit Request descriptor ++ * @req_desc: 64bit Request descriptor + * +- * Perform PCI Write. Ventura supports 32 bit Descriptor. +- * Prior to Ventura (12G) MR controller supports 64 bit Descriptor. ++ * Perform PCI Write. + */ + + static void + megasas_fire_cmd_fusion(struct megasas_instance *instance, + union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc) + { +- if (instance->adapter_type == VENTURA_SERIES) +- writel(le32_to_cpu(req_desc->u.low), +- &instance->reg_set->inbound_single_queue_port); +- else { + #if defined(writeq) && defined(CONFIG_64BIT) +- u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) | +- le32_to_cpu(req_desc->u.low)); ++ u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) | ++ le32_to_cpu(req_desc->u.low)); + +- writeq(req_data, &instance->reg_set->inbound_low_queue_port); ++ writeq(req_data, &instance->reg_set->inbound_low_queue_port); + #else +- unsigned long flags; +- spin_lock_irqsave(&instance->hba_lock, flags); +- writel(le32_to_cpu(req_desc->u.low), +- &instance->reg_set->inbound_low_queue_port); +- writel(le32_to_cpu(req_desc->u.high), +- &instance->reg_set->inbound_high_queue_port); +- mmiowb(); +- spin_unlock_irqrestore(&instance->hba_lock, flags); ++ unsigned long flags; ++ spin_lock_irqsave(&instance->hba_lock, flags); ++ writel(le32_to_cpu(req_desc->u.low), ++ &instance->reg_set->inbound_low_queue_port); ++ writel(le32_to_cpu(req_desc->u.high), ++ &instance->reg_set->inbound_high_queue_port); ++ mmiowb(); ++ spin_unlock_irqrestore(&instance->hba_lock, flags); + #endif +- } + } + + /** +@@ -982,7 +976,6 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) + const char *sys_info; + MFI_CAPABILITIES *drv_ops; + u32 scratch_pad_2; +- unsigned long flags; + ktime_t time; + bool cur_fw_64bit_dma_capable; + +@@ -1121,14 +1114,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) + break; + } + +- /* For Ventura also IOC INIT required 64 bit Descriptor write. */ +- spin_lock_irqsave(&instance->hba_lock, flags); +- writel(le32_to_cpu(req_desc.u.low), +- &instance->reg_set->inbound_low_queue_port); +- writel(le32_to_cpu(req_desc.u.high), +- &instance->reg_set->inbound_high_queue_port); +- mmiowb(); +- spin_unlock_irqrestore(&instance->hba_lock, flags); ++ megasas_fire_cmd_fusion(instance, &req_desc); + + wait_and_poll(instance, cmd, MFI_POLL_TIMEOUT_SECS); + +diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c +index 13d6e4e..0aafbfd 100644 +--- a/drivers/scsi/mpt3sas/mpt3sas_base.c ++++ b/drivers/scsi/mpt3sas/mpt3sas_base.c +@@ -2410,8 +2410,11 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) + continue; + } + +- for_each_cpu(cpu, mask) ++ for_each_cpu_and(cpu, mask, cpu_online_mask) { ++ if (cpu >= ioc->cpu_msix_table_sz) ++ break; + ioc->cpu_msix_table[cpu] = reply_q->msix_index; ++ } + } + return; + } +@@ -6294,14 +6297,14 @@ _base_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase) + } + + /** +- * _wait_for_commands_to_complete - reset controller ++ * mpt3sas_wait_for_commands_to_complete - reset controller + * @ioc: Pointer to MPT_ADAPTER structure + * + * This function is waiting 10s for all pending commands to complete + * prior to putting controller in reset. + */ +-static void +-_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc) ++void ++mpt3sas_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc) + { + u32 ioc_state; + +@@ -6374,7 +6377,7 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, + is_fault = 1; + } + _base_reset_handler(ioc, MPT3_IOC_PRE_RESET); +- _wait_for_commands_to_complete(ioc); ++ mpt3sas_wait_for_commands_to_complete(ioc); + _base_mask_interrupts(ioc); + r = _base_make_ioc_ready(ioc, type); + if (r) +diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h +index 789bc42..99ccf83 100644 +--- a/drivers/scsi/mpt3sas/mpt3sas_base.h ++++ b/drivers/scsi/mpt3sas/mpt3sas_base.h +@@ -1433,6 +1433,9 @@ void mpt3sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc, + + int mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc); + ++void ++mpt3sas_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc); ++ + + /* scsih shared API */ + struct scsi_cmnd *mpt3sas_scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc, +diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c +index 74fca18..c2ea13c7 100644 +--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c ++++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c +@@ -2835,7 +2835,8 @@ scsih_abort(struct scsi_cmnd *scmd) + _scsih_tm_display_info(ioc, scmd); + + sas_device_priv_data = scmd->device->hostdata; +- if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { ++ if (!sas_device_priv_data || !sas_device_priv_data->sas_target || ++ ioc->remove_host) { + sdev_printk(KERN_INFO, scmd->device, + "device been deleted! scmd(%p)\n", scmd); + scmd->result = DID_NO_CONNECT << 16; +@@ -2898,7 +2899,8 @@ scsih_dev_reset(struct scsi_cmnd *scmd) + _scsih_tm_display_info(ioc, scmd); + + sas_device_priv_data = scmd->device->hostdata; +- if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { ++ if (!sas_device_priv_data || !sas_device_priv_data->sas_target || ++ ioc->remove_host) { + sdev_printk(KERN_INFO, scmd->device, + "device been deleted! scmd(%p)\n", scmd); + scmd->result = DID_NO_CONNECT << 16; +@@ -2961,7 +2963,8 @@ scsih_target_reset(struct scsi_cmnd *scmd) + _scsih_tm_display_info(ioc, scmd); + + sas_device_priv_data = scmd->device->hostdata; +- if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { ++ if (!sas_device_priv_data || !sas_device_priv_data->sas_target || ++ ioc->remove_host) { + starget_printk(KERN_INFO, starget, "target been deleted! scmd(%p)\n", + scmd); + scmd->result = DID_NO_CONNECT << 16; +@@ -3019,7 +3022,7 @@ scsih_host_reset(struct scsi_cmnd *scmd) + ioc->name, scmd); + scsi_print_command(scmd); + +- if (ioc->is_driver_loading) { ++ if (ioc->is_driver_loading || ioc->remove_host) { + pr_info(MPT3SAS_FMT "Blocking the host reset\n", + ioc->name); + r = FAILED; +@@ -4453,7 +4456,7 @@ _scsih_flush_running_cmds(struct MPT3SAS_ADAPTER *ioc) + st = scsi_cmd_priv(scmd); + mpt3sas_base_clear_st(ioc, st); + scsi_dma_unmap(scmd); +- if (ioc->pci_error_recovery) ++ if (ioc->pci_error_recovery || ioc->remove_host) + scmd->result = DID_NO_CONNECT << 16; + else + scmd->result = DID_RESET << 16; +@@ -9739,6 +9742,10 @@ static void scsih_remove(struct pci_dev *pdev) + unsigned long flags; + + ioc->remove_host = 1; ++ ++ mpt3sas_wait_for_commands_to_complete(ioc); ++ _scsih_flush_running_cmds(ioc); ++ + _scsih_fw_event_cleanup_queue(ioc); + + spin_lock_irqsave(&ioc->fw_event_lock, flags); +@@ -9815,6 +9822,10 @@ scsih_shutdown(struct pci_dev *pdev) + unsigned long flags; + + ioc->remove_host = 1; ++ ++ mpt3sas_wait_for_commands_to_complete(ioc); ++ _scsih_flush_running_cmds(ioc); ++ + _scsih_fw_event_cleanup_queue(ioc); + + spin_lock_irqsave(&ioc->fw_event_lock, flags); +diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c +index 667d769..d09afe1 100644 +--- a/drivers/scsi/qedi/qedi_fw.c ++++ b/drivers/scsi/qedi/qedi_fw.c +@@ -762,6 +762,11 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi, + + iscsi_cid = cqe->conn_id; + qedi_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid]; ++ if (!qedi_conn) { ++ QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, ++ "icid not found 0x%x\n", cqe->conn_id); ++ return; ++ } + + /* Based on this itt get the corresponding qedi_cmd */ + spin_lock_bh(&qedi_conn->tmf_work_lock); +diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c +index 029e2e6..f57a94b 100644 +--- a/drivers/scsi/qedi/qedi_main.c ++++ b/drivers/scsi/qedi/qedi_main.c +@@ -1724,7 +1724,6 @@ static ssize_t qedi_show_boot_eth_info(void *data, int type, char *buf) + { + struct qedi_ctx *qedi = data; + struct nvm_iscsi_initiator *initiator; +- char *str = buf; + int rc = 1; + u32 ipv6_en, dhcp_en, ip_len; + struct nvm_iscsi_block *block; +@@ -1758,32 +1757,32 @@ static ssize_t qedi_show_boot_eth_info(void *data, int type, char *buf) + + switch (type) { + case ISCSI_BOOT_ETH_IP_ADDR: +- rc = snprintf(str, ip_len, fmt, ip); ++ rc = snprintf(buf, ip_len, fmt, ip); + break; + case ISCSI_BOOT_ETH_SUBNET_MASK: +- rc = snprintf(str, ip_len, fmt, sub); ++ rc = snprintf(buf, ip_len, fmt, sub); + break; + case ISCSI_BOOT_ETH_GATEWAY: +- rc = snprintf(str, ip_len, fmt, gw); ++ rc = snprintf(buf, ip_len, fmt, gw); + break; + case ISCSI_BOOT_ETH_FLAGS: +- rc = snprintf(str, 3, "%hhd\n", ++ rc = snprintf(buf, 3, "%hhd\n", + SYSFS_FLAG_FW_SEL_BOOT); + break; + case ISCSI_BOOT_ETH_INDEX: +- rc = snprintf(str, 3, "0\n"); ++ rc = snprintf(buf, 3, "0\n"); + break; + case ISCSI_BOOT_ETH_MAC: +- rc = sysfs_format_mac(str, qedi->mac, ETH_ALEN); ++ rc = sysfs_format_mac(buf, qedi->mac, ETH_ALEN); + break; + case ISCSI_BOOT_ETH_VLAN: +- rc = snprintf(str, 12, "%d\n", ++ rc = snprintf(buf, 12, "%d\n", + GET_FIELD2(initiator->generic_cont0, + NVM_ISCSI_CFG_INITIATOR_VLAN)); + break; + case ISCSI_BOOT_ETH_ORIGIN: + if (dhcp_en) +- rc = snprintf(str, 3, "3\n"); ++ rc = snprintf(buf, 3, "3\n"); + break; + default: + rc = 0; +@@ -1819,7 +1818,6 @@ static ssize_t qedi_show_boot_ini_info(void *data, int type, char *buf) + { + struct qedi_ctx *qedi = data; + struct nvm_iscsi_initiator *initiator; +- char *str = buf; + int rc; + struct nvm_iscsi_block *block; + +@@ -1831,8 +1829,8 @@ static ssize_t qedi_show_boot_ini_info(void *data, int type, char *buf) + + switch (type) { + case ISCSI_BOOT_INI_INITIATOR_NAME: +- rc = snprintf(str, NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, "%s\n", +- initiator->initiator_name.byte); ++ rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, ++ initiator->initiator_name.byte); + break; + default: + rc = 0; +@@ -1860,7 +1858,6 @@ static ssize_t + qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type, + char *buf, enum qedi_nvm_tgts idx) + { +- char *str = buf; + int rc = 1; + u32 ctrl_flags, ipv6_en, chap_en, mchap_en, ip_len; + struct nvm_iscsi_block *block; +@@ -1899,48 +1896,48 @@ qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type, + + switch (type) { + case ISCSI_BOOT_TGT_NAME: +- rc = snprintf(str, NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, "%s\n", +- block->target[idx].target_name.byte); ++ rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, ++ block->target[idx].target_name.byte); + break; + case ISCSI_BOOT_TGT_IP_ADDR: + if (ipv6_en) +- rc = snprintf(str, ip_len, "%pI6\n", ++ rc = snprintf(buf, ip_len, "%pI6\n", + block->target[idx].ipv6_addr.byte); + else +- rc = snprintf(str, ip_len, "%pI4\n", ++ rc = snprintf(buf, ip_len, "%pI4\n", + block->target[idx].ipv4_addr.byte); + break; + case ISCSI_BOOT_TGT_PORT: +- rc = snprintf(str, 12, "%d\n", ++ rc = snprintf(buf, 12, "%d\n", + GET_FIELD2(block->target[idx].generic_cont0, + NVM_ISCSI_CFG_TARGET_TCP_PORT)); + break; + case ISCSI_BOOT_TGT_LUN: +- rc = snprintf(str, 22, "%.*d\n", ++ rc = snprintf(buf, 22, "%.*d\n", + block->target[idx].lun.value[1], + block->target[idx].lun.value[0]); + break; + case ISCSI_BOOT_TGT_CHAP_NAME: +- rc = snprintf(str, NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, "%s\n", +- chap_name); ++ rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, ++ chap_name); + break; + case ISCSI_BOOT_TGT_CHAP_SECRET: +- rc = snprintf(str, NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, "%s\n", +- chap_secret); ++ rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, ++ chap_secret); + break; + case ISCSI_BOOT_TGT_REV_CHAP_NAME: +- rc = snprintf(str, NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, "%s\n", +- mchap_name); ++ rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, ++ mchap_name); + break; + case ISCSI_BOOT_TGT_REV_CHAP_SECRET: +- rc = snprintf(str, NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, "%s\n", +- mchap_secret); ++ rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, ++ mchap_secret); + break; + case ISCSI_BOOT_TGT_FLAGS: +- rc = snprintf(str, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT); ++ rc = snprintf(buf, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT); + break; + case ISCSI_BOOT_TGT_NIC_ASSOC: +- rc = snprintf(str, 3, "0\n"); ++ rc = snprintf(buf, 3, "0\n"); + break; + default: + rc = 0; +diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h +index be7d682..c9689f9 100644 +--- a/drivers/scsi/qla2xxx/qla_def.h ++++ b/drivers/scsi/qla2xxx/qla_def.h +@@ -261,9 +261,9 @@ + struct name_list_extended { + struct get_name_list_extended *l; + dma_addr_t ldma; +- struct list_head fcports; /* protect by sess_list */ ++ struct list_head fcports; ++ spinlock_t fcports_lock; + u32 size; +- u8 sent; + }; + /* + * Timeout timer counts in seconds +@@ -2217,6 +2217,7 @@ typedef struct { + + /* FCP-4 types */ + #define FC4_TYPE_FCP_SCSI 0x08 ++#define FC4_TYPE_NVME 0x28 + #define FC4_TYPE_OTHER 0x0 + #define FC4_TYPE_UNKNOWN 0xff + +diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c +index 5bf9a59..403fa09 100644 +--- a/drivers/scsi/qla2xxx/qla_gs.c ++++ b/drivers/scsi/qla2xxx/qla_gs.c +@@ -3179,6 +3179,7 @@ int qla24xx_async_gidpn(scsi_qla_host_t *vha, fc_port_t *fcport) + sp->free(sp); + fcport->flags &= ~FCF_ASYNC_SENT; + done: ++ fcport->flags &= ~FCF_ASYNC_ACTIVE; + return rval; + } + +@@ -3370,6 +3371,7 @@ int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_t *fcport) + sp->free(sp); + fcport->flags &= ~FCF_ASYNC_SENT; + done: ++ fcport->flags &= ~FCF_ASYNC_ACTIVE; + return rval; + } + +@@ -3971,6 +3973,9 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) + spin_lock_irqsave(&vha->work_lock, flags); + vha->scan.scan_flags &= ~SF_SCANNING; + spin_unlock_irqrestore(&vha->work_lock, flags); ++ ++ if ((fc4type == FC4_TYPE_FCP_SCSI) && vha->flags.nvme_enabled) ++ qla24xx_async_gpnft(vha, FC4_TYPE_NVME); + } + + static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) +diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c +index aececf66..00329dd 100644 +--- a/drivers/scsi/qla2xxx/qla_init.c ++++ b/drivers/scsi/qla2xxx/qla_init.c +@@ -59,8 +59,6 @@ qla2x00_sp_timeout(struct timer_list *t) + req->outstanding_cmds[sp->handle] = NULL; + iocb = &sp->u.iocb_cmd; + iocb->timeout(sp); +- if (sp->type != SRB_ELS_DCMD) +- sp->free(sp); + spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); + } + +@@ -102,7 +100,6 @@ qla2x00_async_iocb_timeout(void *data) + srb_t *sp = data; + fc_port_t *fcport = sp->fcport; + struct srb_iocb *lio = &sp->u.iocb_cmd; +- struct event_arg ea; + + if (fcport) { + ql_dbg(ql_dbg_disc, fcport->vha, 0x2071, +@@ -117,25 +114,13 @@ qla2x00_async_iocb_timeout(void *data) + + switch (sp->type) { + case SRB_LOGIN_CMD: +- if (!fcport) +- break; + /* Retry as needed. */ + lio->u.logio.data[0] = MBS_COMMAND_ERROR; + lio->u.logio.data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ? + QLA_LOGIO_LOGIN_RETRIED : 0; +- memset(&ea, 0, sizeof(ea)); +- ea.event = FCME_PLOGI_DONE; +- ea.fcport = sp->fcport; +- ea.data[0] = lio->u.logio.data[0]; +- ea.data[1] = lio->u.logio.data[1]; +- ea.sp = sp; +- qla24xx_handle_plogi_done_event(fcport->vha, &ea); ++ sp->done(sp, QLA_FUNCTION_TIMEOUT); + break; + case SRB_LOGOUT_CMD: +- if (!fcport) +- break; +- qlt_logo_completion_handler(fcport, QLA_FUNCTION_TIMEOUT); +- break; + case SRB_CT_PTHRU_CMD: + case SRB_MB_IOCB: + case SRB_NACK_PLOGI: +@@ -228,6 +213,7 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, + sp->free(sp); + fcport->flags &= ~FCF_ASYNC_SENT; + done: ++ fcport->flags &= ~FCF_ASYNC_ACTIVE; + return rval; + } + +@@ -235,12 +221,10 @@ static void + qla2x00_async_logout_sp_done(void *ptr, int res) + { + srb_t *sp = ptr; +- struct srb_iocb *lio = &sp->u.iocb_cmd; + + sp->fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); +- if (!test_bit(UNLOADING, &sp->vha->dpc_flags)) +- qla2x00_post_async_logout_done_work(sp->vha, sp->fcport, +- lio->u.logio.data); ++ sp->fcport->login_gen++; ++ qlt_logo_completion_handler(sp->fcport, res); + sp->free(sp); + } + +@@ -280,7 +264,7 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) + done_free_sp: + sp->free(sp); + done: +- fcport->flags &= ~FCF_ASYNC_SENT; ++ fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); + return rval; + } + +@@ -288,6 +272,7 @@ void + qla2x00_async_prlo_done(struct scsi_qla_host *vha, fc_port_t *fcport, + uint16_t *data) + { ++ fcport->flags &= ~FCF_ASYNC_ACTIVE; + /* Don't re-login in target mode */ + if (!fcport->tgt_session) + qla2x00_mark_device_lost(vha, fcport, 1, 0); +@@ -301,6 +286,7 @@ qla2x00_async_prlo_sp_done(void *s, int res) + struct srb_iocb *lio = &sp->u.iocb_cmd; + struct scsi_qla_host *vha = sp->vha; + ++ sp->fcport->flags &= ~FCF_ASYNC_ACTIVE; + if (!test_bit(UNLOADING, &vha->dpc_flags)) + qla2x00_post_async_prlo_done_work(sp->fcport->vha, sp->fcport, + lio->u.logio.data); +@@ -339,6 +325,7 @@ qla2x00_async_prlo(struct scsi_qla_host *vha, fc_port_t *fcport) + done_free_sp: + sp->free(sp); + done: ++ fcport->flags &= ~FCF_ASYNC_ACTIVE; + return rval; + } + +@@ -392,6 +379,8 @@ qla2x00_async_adisc_sp_done(void *ptr, int res) + "Async done-%s res %x %8phC\n", + sp->name, res, sp->fcport->port_name); + ++ sp->fcport->flags &= ~FCF_ASYNC_SENT; ++ + memset(&ea, 0, sizeof(ea)); + ea.event = FCME_ADISC_DONE; + ea.rc = res; +@@ -442,7 +431,7 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, + done_free_sp: + sp->free(sp); + done: +- fcport->flags &= ~FCF_ASYNC_SENT; ++ fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); + qla2x00_post_async_adisc_work(vha, fcport, data); + return rval; + } +@@ -660,8 +649,7 @@ qla24xx_async_gnl_sp_done(void *s, int res) + (loop_id & 0x7fff)); + } + +- spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); +- vha->gnl.sent = 0; ++ spin_lock_irqsave(&vha->gnl.fcports_lock, flags); + + INIT_LIST_HEAD(&h); + fcport = tf = NULL; +@@ -670,12 +658,16 @@ qla24xx_async_gnl_sp_done(void *s, int res) + + list_for_each_entry_safe(fcport, tf, &h, gnl_entry) { + list_del_init(&fcport->gnl_entry); ++ spin_lock(&vha->hw->tgt.sess_lock); + fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); ++ spin_unlock(&vha->hw->tgt.sess_lock); + ea.fcport = fcport; + + qla2x00_fcport_event_handler(vha, &ea); + } ++ spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags); + ++ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); + /* create new fcport if fw has knowledge of new sessions */ + for (i = 0; i < n; i++) { + port_id_t id; +@@ -727,18 +719,21 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport) + ql_dbg(ql_dbg_disc, vha, 0x20d9, + "Async-gnlist WWPN %8phC \n", fcport->port_name); + +- spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); ++ spin_lock_irqsave(&vha->gnl.fcports_lock, flags); ++ if (!list_empty(&fcport->gnl_entry)) { ++ spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags); ++ rval = QLA_SUCCESS; ++ goto done; ++ } ++ ++ spin_lock(&vha->hw->tgt.sess_lock); + fcport->disc_state = DSC_GNL; + fcport->last_rscn_gen = fcport->rscn_gen; + fcport->last_login_gen = fcport->login_gen; ++ spin_unlock(&vha->hw->tgt.sess_lock); + + list_add_tail(&fcport->gnl_entry, &vha->gnl.fcports); +- if (vha->gnl.sent) { +- spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); +- return QLA_SUCCESS; +- } +- vha->gnl.sent = 1; +- spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); ++ spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags); + + sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); + if (!sp) +@@ -1066,6 +1061,7 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) + fc_port_t *fcport = ea->fcport; + struct port_database_24xx *pd; + struct srb *sp = ea->sp; ++ uint8_t ls; + + pd = (struct port_database_24xx *)sp->u.iocb_cmd.u.mbx.in; + +@@ -1078,7 +1074,12 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) + if (fcport->disc_state == DSC_DELETE_PEND) + return; + +- switch (pd->current_login_state) { ++ if (fcport->fc4f_nvme) ++ ls = pd->current_login_state >> 4; ++ else ++ ls = pd->current_login_state & 0xf; ++ ++ switch (ls) { + case PDS_PRLI_COMPLETE: + __qla24xx_parse_gpdb(vha, fcport, pd); + break; +@@ -1168,8 +1169,9 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) + if (fcport->scan_state != QLA_FCPORT_FOUND) + return 0; + +- if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) || +- (fcport->fw_login_state == DSC_LS_PRLI_PEND)) ++ if ((fcport->loop_id != FC_NO_LOOP_ID) && ++ ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) || ++ (fcport->fw_login_state == DSC_LS_PRLI_PEND))) + return 0; + + if (fcport->fw_login_state == DSC_LS_PLOGI_COMP) { +@@ -1544,6 +1546,7 @@ qla24xx_abort_sp_done(void *ptr, int res) + srb_t *sp = ptr; + struct srb_iocb *abt = &sp->u.iocb_cmd; + ++ del_timer(&sp->u.iocb_cmd.timer); + complete(&abt->u.abt.comp); + } + +@@ -1808,6 +1811,7 @@ qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport, + qla2x00_mark_device_lost(vha, fcport, 1, 0); + qlt_logo_completion_handler(fcport, data[0]); + fcport->login_gen++; ++ fcport->flags &= ~FCF_ASYNC_ACTIVE; + return; + } + +@@ -1815,6 +1819,7 @@ void + qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, + uint16_t *data) + { ++ fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); + if (data[0] == MBS_COMMAND_COMPLETE) { + qla2x00_update_fcport(vha, fcport); + +@@ -1822,7 +1827,6 @@ qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, + } + + /* Retry login. */ +- fcport->flags &= ~FCF_ASYNC_SENT; + if (data[1] & QLA_LOGIO_LOGIN_RETRIED) + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + else +diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c +index 1b62e94..8d00d55 100644 +--- a/drivers/scsi/qla2xxx/qla_iocb.c ++++ b/drivers/scsi/qla2xxx/qla_iocb.c +@@ -3275,12 +3275,11 @@ qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb) + memset(abt_iocb, 0, sizeof(struct abort_entry_24xx)); + abt_iocb->entry_type = ABORT_IOCB_TYPE; + abt_iocb->entry_count = 1; +- abt_iocb->handle = +- cpu_to_le32(MAKE_HANDLE(aio->u.abt.req_que_no, +- aio->u.abt.cmd_hndl)); ++ abt_iocb->handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle)); + abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); + abt_iocb->handle_to_abort = +- cpu_to_le32(MAKE_HANDLE(req->id, aio->u.abt.cmd_hndl)); ++ cpu_to_le32(MAKE_HANDLE(aio->u.abt.req_que_no, ++ aio->u.abt.cmd_hndl)); + abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; + abt_iocb->port_id[1] = sp->fcport->d_id.b.area; + abt_iocb->port_id[2] = sp->fcport->d_id.b.domain; +diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c +index 14109d8..89f93eb 100644 +--- a/drivers/scsi/qla2xxx/qla_isr.c ++++ b/drivers/scsi/qla2xxx/qla_isr.c +@@ -272,7 +272,8 @@ qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) + struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; + + /* Read all mbox registers? */ +- mboxes = (1 << ha->mbx_count) - 1; ++ WARN_ON_ONCE(ha->mbx_count > 32); ++ mboxes = (1ULL << ha->mbx_count) - 1; + if (!ha->mcp) + ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERROR.\n"); + else +@@ -2880,7 +2881,8 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + + /* Read all mbox registers? */ +- mboxes = (1 << ha->mbx_count) - 1; ++ WARN_ON_ONCE(ha->mbx_count > 32); ++ mboxes = (1ULL << ha->mbx_count) - 1; + if (!ha->mcp) + ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERROR.\n"); + else +diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c +index 12ee6e0..285911e 100644 +--- a/drivers/scsi/qla2xxx/qla_os.c ++++ b/drivers/scsi/qla2xxx/qla_os.c +@@ -3625,6 +3625,8 @@ qla2x00_remove_one(struct pci_dev *pdev) + } + qla2x00_wait_for_hba_ready(base_vha); + ++ qla2x00_wait_for_sess_deletion(base_vha); ++ + /* + * if UNLOAD flag is already set, then continue unload, + * where it was set first. +@@ -4575,6 +4577,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, + + spin_lock_init(&vha->work_lock); + spin_lock_init(&vha->cmd_list_lock); ++ spin_lock_init(&vha->gnl.fcports_lock); + init_waitqueue_head(&vha->fcport_waitQ); + init_waitqueue_head(&vha->vref_waitq); + +@@ -4804,9 +4807,12 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) + fcport->d_id = e->u.new_sess.id; + fcport->flags |= FCF_FABRIC_DEVICE; + fcport->fw_login_state = DSC_LS_PLOGI_PEND; +- if (e->u.new_sess.fc4_type == FC4_TYPE_FCP_SCSI) ++ if (e->u.new_sess.fc4_type == FC4_TYPE_FCP_SCSI) { + fcport->fc4_type = FC4_TYPE_FCP_SCSI; +- ++ } else if (e->u.new_sess.fc4_type == FC4_TYPE_NVME) { ++ fcport->fc4_type = FC4_TYPE_OTHER; ++ fcport->fc4f_nvme = FC4_TYPE_NVME; ++ } + memcpy(fcport->port_name, e->u.new_sess.port_name, + WWN_SIZE); + } else { +@@ -4875,6 +4881,8 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) + } + qlt_plogi_ack_unref(vha, pla); + } else { ++ fc_port_t *dfcp = NULL; ++ + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); + tfcp = qla2x00_find_fcport_by_nportid(vha, + &e->u.new_sess.id, 1); +@@ -4897,11 +4905,13 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) + default: + fcport->login_pause = 1; + tfcp->conflict = fcport; +- qlt_schedule_sess_for_deletion(tfcp); ++ dfcp = tfcp; + break; + } + } + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); ++ if (dfcp) ++ qlt_schedule_sess_for_deletion(tfcp); + + wwn = wwn_to_u64(fcport->node_name); + +diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c +index fc89af8..b49ac85 100644 +--- a/drivers/scsi/qla2xxx/qla_target.c ++++ b/drivers/scsi/qla2xxx/qla_target.c +@@ -1224,10 +1224,10 @@ static void qla24xx_chk_fcp_state(struct fc_port *sess) + } + } + +-/* ha->tgt.sess_lock supposed to be held on entry */ + void qlt_schedule_sess_for_deletion(struct fc_port *sess) + { + struct qla_tgt *tgt = sess->tgt; ++ struct qla_hw_data *ha = sess->vha->hw; + unsigned long flags; + + if (sess->disc_state == DSC_DELETE_PEND) +@@ -1244,16 +1244,16 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess) + return; + } + ++ spin_lock_irqsave(&ha->tgt.sess_lock, flags); + if (sess->deleted == QLA_SESS_DELETED) + sess->logout_on_delete = 0; + +- spin_lock_irqsave(&sess->vha->work_lock, flags); + if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) { +- spin_unlock_irqrestore(&sess->vha->work_lock, flags); ++ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + return; + } + sess->deleted = QLA_SESS_DELETION_IN_PROGRESS; +- spin_unlock_irqrestore(&sess->vha->work_lock, flags); ++ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + + sess->disc_state = DSC_DELETE_PEND; + +@@ -1262,13 +1262,10 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess) + ql_dbg(ql_dbg_tgt, sess->vha, 0xe001, + "Scheduling sess %p for deletion\n", sess); + +- /* use cancel to push work element through before re-queue */ +- cancel_work_sync(&sess->del_work); + INIT_WORK(&sess->del_work, qla24xx_delete_sess_fn); +- queue_work(sess->vha->hw->wq, &sess->del_work); ++ WARN_ON(!queue_work(sess->vha->hw->wq, &sess->del_work)); + } + +-/* ha->tgt.sess_lock supposed to be held on entry */ + static void qlt_clear_tgt_db(struct qla_tgt *tgt) + { + struct fc_port *sess; +@@ -1451,8 +1448,8 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen) + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf008, "qla_tgt_fc_port_deleted %p", sess); + + sess->local = 1; +- qlt_schedule_sess_for_deletion(sess); + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); ++ qlt_schedule_sess_for_deletion(sess); + } + + static inline int test_tgt_sess_count(struct qla_tgt *tgt) +@@ -1512,10 +1509,8 @@ int qlt_stop_phase1(struct qla_tgt *tgt) + * Lock is needed, because we still can get an incoming packet. + */ + mutex_lock(&vha->vha_tgt.tgt_mutex); +- spin_lock_irqsave(&ha->tgt.sess_lock, flags); + tgt->tgt_stop = 1; + qlt_clear_tgt_db(tgt); +- spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + mutex_unlock(&vha->vha_tgt.tgt_mutex); + mutex_unlock(&qla_tgt_mutex); + +@@ -4871,8 +4866,6 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, + sess); + qlt_send_term_imm_notif(vha, iocb, 1); + res = 0; +- spin_lock_irqsave(&tgt->ha->tgt.sess_lock, +- flags); + break; + } + +diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h +index fc23371..817f312 100644 +--- a/drivers/scsi/qla4xxx/ql4_def.h ++++ b/drivers/scsi/qla4xxx/ql4_def.h +@@ -168,6 +168,8 @@ + #define DEV_DB_NON_PERSISTENT 0 + #define DEV_DB_PERSISTENT 1 + ++#define QL4_ISP_REG_DISCONNECT 0xffffffffU ++ + #define COPY_ISID(dst_isid, src_isid) { \ + int i, j; \ + for (i = 0, j = ISID_SIZE - 1; i < ISID_SIZE;) \ +diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c +index 82e889b..fc2c97d 100644 +--- a/drivers/scsi/qla4xxx/ql4_os.c ++++ b/drivers/scsi/qla4xxx/ql4_os.c +@@ -262,6 +262,24 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { + + static struct scsi_transport_template *qla4xxx_scsi_transport; + ++static int qla4xxx_isp_check_reg(struct scsi_qla_host *ha) ++{ ++ u32 reg_val = 0; ++ int rval = QLA_SUCCESS; ++ ++ if (is_qla8022(ha)) ++ reg_val = readl(&ha->qla4_82xx_reg->host_status); ++ else if (is_qla8032(ha) || is_qla8042(ha)) ++ reg_val = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER); ++ else ++ reg_val = readw(&ha->reg->ctrl_status); ++ ++ if (reg_val == QL4_ISP_REG_DISCONNECT) ++ rval = QLA_ERROR; ++ ++ return rval; ++} ++ + static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, + uint32_t iface_type, uint32_t payload_size, + uint32_t pid, struct sockaddr *dst_addr) +@@ -9186,10 +9204,17 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) + struct srb *srb = NULL; + int ret = SUCCESS; + int wait = 0; ++ int rval; + + ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Abort command issued cmd=%p, cdb=0x%x\n", + ha->host_no, id, lun, cmd, cmd->cmnd[0]); + ++ rval = qla4xxx_isp_check_reg(ha); ++ if (rval != QLA_SUCCESS) { ++ ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); ++ return FAILED; ++ } ++ + spin_lock_irqsave(&ha->hardware_lock, flags); + srb = (struct srb *) CMD_SP(cmd); + if (!srb) { +@@ -9241,6 +9266,7 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) + struct scsi_qla_host *ha = to_qla_host(cmd->device->host); + struct ddb_entry *ddb_entry = cmd->device->hostdata; + int ret = FAILED, stat; ++ int rval; + + if (!ddb_entry) + return ret; +@@ -9260,6 +9286,12 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) + cmd, jiffies, cmd->request->timeout / HZ, + ha->dpc_flags, cmd->result, cmd->allowed)); + ++ rval = qla4xxx_isp_check_reg(ha); ++ if (rval != QLA_SUCCESS) { ++ ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); ++ return FAILED; ++ } ++ + /* FIXME: wait for hba to go online */ + stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); + if (stat != QLA_SUCCESS) { +@@ -9303,6 +9335,7 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) + struct scsi_qla_host *ha = to_qla_host(cmd->device->host); + struct ddb_entry *ddb_entry = cmd->device->hostdata; + int stat, ret; ++ int rval; + + if (!ddb_entry) + return FAILED; +@@ -9320,6 +9353,12 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) + ha->host_no, cmd, jiffies, cmd->request->timeout / HZ, + ha->dpc_flags, cmd->result, cmd->allowed)); + ++ rval = qla4xxx_isp_check_reg(ha); ++ if (rval != QLA_SUCCESS) { ++ ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); ++ return FAILED; ++ } ++ + stat = qla4xxx_reset_target(ha, ddb_entry); + if (stat != QLA_SUCCESS) { + starget_printk(KERN_INFO, scsi_target(cmd->device), +@@ -9374,9 +9413,16 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) + { + int return_status = FAILED; + struct scsi_qla_host *ha; ++ int rval; + + ha = to_qla_host(cmd->device->host); + ++ rval = qla4xxx_isp_check_reg(ha); ++ if (rval != QLA_SUCCESS) { ++ ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n"); ++ return FAILED; ++ } ++ + if ((is_qla8032(ha) || is_qla8042(ha)) && ql4xdontresethba) + qla4_83xx_set_idc_dontreset(ha); + +diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c +index d042915..ca53a5f 100644 +--- a/drivers/scsi/scsi_error.c ++++ b/drivers/scsi/scsi_error.c +@@ -223,7 +223,8 @@ static void scsi_eh_reset(struct scsi_cmnd *scmd) + + static void scsi_eh_inc_host_failed(struct rcu_head *head) + { +- struct Scsi_Host *shost = container_of(head, typeof(*shost), rcu); ++ struct scsi_cmnd *scmd = container_of(head, typeof(*scmd), rcu); ++ struct Scsi_Host *shost = scmd->device->host; + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); +@@ -259,7 +260,7 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd) + * Ensure that all tasks observe the host state change before the + * host_failed change. + */ +- call_rcu(&shost->rcu, scsi_eh_inc_host_failed); ++ call_rcu(&scmd->rcu, scsi_eh_inc_host_failed); + } + + /** +diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c +index a86df9c..c84f931 100644 +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -671,6 +671,7 @@ static bool scsi_end_request(struct request *req, blk_status_t error, + if (!blk_rq_is_scsi(req)) { + WARN_ON_ONCE(!(cmd->flags & SCMD_INITIALIZED)); + cmd->flags &= ~SCMD_INITIALIZED; ++ destroy_rcu_head(&cmd->rcu); + } + + if (req->mq_ctx) { +@@ -720,6 +721,8 @@ static blk_status_t __scsi_error_from_host_byte(struct scsi_cmnd *cmd, + int result) + { + switch (host_byte(result)) { ++ case DID_OK: ++ return BLK_STS_OK; + case DID_TRANSPORT_FAILFAST: + return BLK_STS_TRANSPORT; + case DID_TARGET_FAILURE: +@@ -1151,6 +1154,7 @@ static void scsi_initialize_rq(struct request *rq) + struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); + + scsi_req_init(&cmd->req); ++ init_rcu_head(&cmd->rcu); + cmd->jiffies_at_alloc = jiffies; + cmd->retries = 0; + } +diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c +index 40fc7a5..8c51d62 100644 +--- a/drivers/scsi/storvsc_drv.c ++++ b/drivers/scsi/storvsc_drv.c +@@ -1311,7 +1311,8 @@ static int storvsc_do_io(struct hv_device *device, + */ + cpumask_and(&alloced_mask, &stor_device->alloced_cpus, + cpumask_of_node(cpu_to_node(q_num))); +- for_each_cpu(tgt_cpu, &alloced_mask) { ++ for_each_cpu_wrap(tgt_cpu, &alloced_mask, ++ outgoing_channel->target_cpu + 1) { + if (tgt_cpu != outgoing_channel->target_cpu) { + outgoing_channel = + stor_device->stor_chns[tgt_cpu]; +@@ -1657,7 +1658,7 @@ static struct scsi_host_template scsi_driver = { + .eh_timed_out = storvsc_eh_timed_out, + .slave_alloc = storvsc_device_alloc, + .slave_configure = storvsc_device_configure, +- .cmd_per_lun = 255, ++ .cmd_per_lun = 2048, + .this_id = -1, + .use_clustering = ENABLE_CLUSTERING, + /* Make sure we dont get a sg segment crosses a page boundary */ +diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c +index ca360da..378af30 100644 +--- a/drivers/scsi/sym53c8xx_2/sym_hipd.c ++++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c +@@ -536,7 +536,7 @@ sym_getsync(struct sym_hcb *np, u_char dt, u_char sfac, u_char *divp, u_char *fa + * Look for the greatest clock divisor that allows an + * input speed faster than the period. + */ +- while (div-- > 0) ++ while (--div > 0) + if (kpc >= (div_10M[div] << 2)) break; + + /* +diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c +index a355d98..c7da2c1 100644 +--- a/drivers/scsi/ufs/ufshcd.c ++++ b/drivers/scsi/ufs/ufshcd.c +@@ -4352,6 +4352,8 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev) + /* REPORT SUPPORTED OPERATION CODES is not supported */ + sdev->no_report_opcodes = 1; + ++ /* WRITE_SAME command is not supported */ ++ sdev->no_write_same = 1; + + ufshcd_set_queue_depth(sdev); + +diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c +index 53f7275..750f931 100644 +--- a/drivers/soc/imx/gpc.c ++++ b/drivers/soc/imx/gpc.c +@@ -348,7 +348,7 @@ static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap, + if (i == 1) { + domain->supply = devm_regulator_get(dev, "pu"); + if (IS_ERR(domain->supply)) +- return PTR_ERR(domain->supply);; ++ return PTR_ERR(domain->supply); + + ret = imx_pgc_get_clocks(dev, domain); + if (ret) +@@ -470,13 +470,21 @@ static int imx_gpc_probe(struct platform_device *pdev) + + static int imx_gpc_remove(struct platform_device *pdev) + { ++ struct device_node *pgc_node; + int ret; + ++ pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc"); ++ ++ /* bail out if DT too old and doesn't provide the necessary info */ ++ if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") && ++ !pgc_node) ++ return 0; ++ + /* + * If the old DT binding is used the toplevel driver needs to + * de-register the power domains + */ +- if (!of_get_child_by_name(pdev->dev.of_node, "pgc")) { ++ if (!pgc_node) { + of_genpd_del_provider(pdev->dev.of_node); + + ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_PU].base); +diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c +index bbdc53b..6dbba5a 100644 +--- a/drivers/staging/android/ashmem.c ++++ b/drivers/staging/android/ashmem.c +@@ -702,30 +702,32 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd, + size_t pgstart, pgend; + int ret = -EINVAL; + ++ mutex_lock(&ashmem_mutex); ++ + if (unlikely(!asma->file)) +- return -EINVAL; ++ goto out_unlock; + +- if (unlikely(copy_from_user(&pin, p, sizeof(pin)))) +- return -EFAULT; ++ if (unlikely(copy_from_user(&pin, p, sizeof(pin)))) { ++ ret = -EFAULT; ++ goto out_unlock; ++ } + + /* per custom, you can pass zero for len to mean "everything onward" */ + if (!pin.len) + pin.len = PAGE_ALIGN(asma->size) - pin.offset; + + if (unlikely((pin.offset | pin.len) & ~PAGE_MASK)) +- return -EINVAL; ++ goto out_unlock; + + if (unlikely(((__u32)-1) - pin.offset < pin.len)) +- return -EINVAL; ++ goto out_unlock; + + if (unlikely(PAGE_ALIGN(asma->size) < pin.offset + pin.len)) +- return -EINVAL; ++ goto out_unlock; + + pgstart = pin.offset / PAGE_SIZE; + pgend = pgstart + (pin.len / PAGE_SIZE) - 1; + +- mutex_lock(&ashmem_mutex); +- + switch (cmd) { + case ASHMEM_PIN: + ret = ashmem_pin(asma, pgstart, pgend); +@@ -738,6 +740,7 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd, + break; + } + ++out_unlock: + mutex_unlock(&ashmem_mutex); + + return ret; +diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c +index 94e0692..49718c9 100644 +--- a/drivers/staging/android/ion/ion_cma_heap.c ++++ b/drivers/staging/android/ion/ion_cma_heap.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #include "ion.h" + +@@ -42,6 +43,22 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, + if (!pages) + return -ENOMEM; + ++ if (PageHighMem(pages)) { ++ unsigned long nr_clear_pages = nr_pages; ++ struct page *page = pages; ++ ++ while (nr_clear_pages > 0) { ++ void *vaddr = kmap_atomic(page); ++ ++ memset(vaddr, 0, PAGE_SIZE); ++ kunmap_atomic(vaddr); ++ page++; ++ nr_clear_pages--; ++ } ++ } else { ++ memset(page_address(pages), 0, size); ++ } ++ + table = kmalloc(sizeof(*table), GFP_KERNEL); + if (!table) + goto err; +diff --git a/drivers/staging/fsl-mc/bus/Kconfig b/drivers/staging/fsl-mc/bus/Kconfig +index 1f91000..b35ef7e 100644 +--- a/drivers/staging/fsl-mc/bus/Kconfig ++++ b/drivers/staging/fsl-mc/bus/Kconfig +@@ -7,7 +7,7 @@ + + config FSL_MC_BUS + bool "QorIQ DPAA2 fsl-mc bus driver" +- depends on OF && (ARCH_LAYERSCAPE || (COMPILE_TEST && (ARM || ARM64 || X86 || PPC))) ++ depends on OF && (ARCH_LAYERSCAPE || (COMPILE_TEST && (ARM || ARM64 || X86_LOCAL_APIC || PPC))) + select GENERIC_MSI_IRQ_DOMAIN + help + Driver to enable the bus infrastructure for the QorIQ DPAA2 +diff --git a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c b/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c +index 5064d5d..fc2013aa 100644 +--- a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c ++++ b/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c +@@ -73,6 +73,8 @@ static int __init its_fsl_mc_msi_init(void) + + for (np = of_find_matching_node(NULL, its_device_id); np; + np = of_find_matching_node(np, its_device_id)) { ++ if (!of_device_is_available(np)) ++ continue; + if (!of_property_read_bool(np, "msi-controller")) + continue; + +diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c +index f015955..425e8b8 100644 +--- a/drivers/staging/iio/adc/ad7192.c ++++ b/drivers/staging/iio/adc/ad7192.c +@@ -141,6 +141,8 @@ + #define AD7192_GPOCON_P1DAT BIT(1) /* P1 state */ + #define AD7192_GPOCON_P0DAT BIT(0) /* P0 state */ + ++#define AD7192_EXT_FREQ_MHZ_MIN 2457600 ++#define AD7192_EXT_FREQ_MHZ_MAX 5120000 + #define AD7192_INT_FREQ_MHZ 4915200 + + /* NOTE: +@@ -218,6 +220,12 @@ static int ad7192_calibrate_all(struct ad7192_state *st) + ARRAY_SIZE(ad7192_calib_arr)); + } + ++static inline bool ad7192_valid_external_frequency(u32 freq) ++{ ++ return (freq >= AD7192_EXT_FREQ_MHZ_MIN && ++ freq <= AD7192_EXT_FREQ_MHZ_MAX); ++} ++ + static int ad7192_setup(struct ad7192_state *st, + const struct ad7192_platform_data *pdata) + { +@@ -243,17 +251,20 @@ static int ad7192_setup(struct ad7192_state *st, + id); + + switch (pdata->clock_source_sel) { +- case AD7192_CLK_EXT_MCLK1_2: +- case AD7192_CLK_EXT_MCLK2: +- st->mclk = AD7192_INT_FREQ_MHZ; +- break; + case AD7192_CLK_INT: + case AD7192_CLK_INT_CO: +- if (pdata->ext_clk_hz) +- st->mclk = pdata->ext_clk_hz; +- else +- st->mclk = AD7192_INT_FREQ_MHZ; ++ st->mclk = AD7192_INT_FREQ_MHZ; + break; ++ case AD7192_CLK_EXT_MCLK1_2: ++ case AD7192_CLK_EXT_MCLK2: ++ if (ad7192_valid_external_frequency(pdata->ext_clk_hz)) { ++ st->mclk = pdata->ext_clk_hz; ++ break; ++ } ++ dev_err(&st->sd.spi->dev, "Invalid frequency setting %u\n", ++ pdata->ext_clk_hz); ++ ret = -EINVAL; ++ goto out; + default: + ret = -EINVAL; + goto out; +diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c +index 2b28fb9..3bcf494 100644 +--- a/drivers/staging/iio/impedance-analyzer/ad5933.c ++++ b/drivers/staging/iio/impedance-analyzer/ad5933.c +@@ -648,8 +648,6 @@ static int ad5933_register_ring_funcs_and_init(struct iio_dev *indio_dev) + /* Ring buffer functions - here trigger setup related */ + indio_dev->setup_ops = &ad5933_ring_setup_ops; + +- indio_dev->modes |= INDIO_BUFFER_HARDWARE; +- + return 0; + } + +@@ -762,7 +760,7 @@ static int ad5933_probe(struct i2c_client *client, + indio_dev->dev.parent = &client->dev; + indio_dev->info = &ad5933_info; + indio_dev->name = id->name; +- indio_dev->modes = INDIO_DIRECT_MODE; ++ indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE); + indio_dev->channels = ad5933_channels; + indio_dev->num_channels = ARRAY_SIZE(ad5933_channels); + +diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig +index f699aba..148f3ee 100644 +--- a/drivers/usb/Kconfig ++++ b/drivers/usb/Kconfig +@@ -19,6 +19,12 @@ config USB_EHCI_BIG_ENDIAN_MMIO + config USB_EHCI_BIG_ENDIAN_DESC + bool + ++config USB_UHCI_BIG_ENDIAN_MMIO ++ bool ++ ++config USB_UHCI_BIG_ENDIAN_DESC ++ bool ++ + menuconfig USB_SUPPORT + bool "USB support" + depends on HAS_IOMEM +diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c +index 06b3b54..7b366a6 100644 +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -174,6 +174,7 @@ static int acm_wb_alloc(struct acm *acm) + wb = &acm->wb[wbn]; + if (!wb->use) { + wb->use = 1; ++ wb->len = 0; + return wbn; + } + wbn = (wbn + 1) % ACM_NW; +@@ -805,16 +806,18 @@ static int acm_tty_write(struct tty_struct *tty, + static void acm_tty_flush_chars(struct tty_struct *tty) + { + struct acm *acm = tty->driver_data; +- struct acm_wb *cur = acm->putbuffer; ++ struct acm_wb *cur; + int err; + unsigned long flags; + ++ spin_lock_irqsave(&acm->write_lock, flags); ++ ++ cur = acm->putbuffer; + if (!cur) /* nothing to do */ +- return; ++ goto out; + + acm->putbuffer = NULL; + err = usb_autopm_get_interface_async(acm->control); +- spin_lock_irqsave(&acm->write_lock, flags); + if (err < 0) { + cur->use = 0; + acm->putbuffer = cur; +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 4024926..f4a5484 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -226,6 +226,9 @@ static const struct usb_device_id usb_quirk_list[] = { + { USB_DEVICE(0x1a0a, 0x0200), .driver_info = + USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, + ++ /* Corsair K70 RGB */ ++ { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT }, ++ + /* Corsair Strafe RGB */ + { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT }, + +diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c +index e4c3ce0..5bcad1d 100644 +--- a/drivers/usb/dwc2/gadget.c ++++ b/drivers/usb/dwc2/gadget.c +@@ -1917,7 +1917,9 @@ static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, + /* Not specific buffer needed for ep0 ZLP */ + dma_addr_t dma = hs_ep->desc_list_dma; + +- dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep); ++ if (!index) ++ dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep); ++ + dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, dma, 0); + } else { + dwc2_writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | +@@ -2974,9 +2976,13 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, + if (ints & DXEPINT_STSPHSERCVD) { + dev_dbg(hsotg->dev, "%s: StsPhseRcvd\n", __func__); + +- /* Move to STATUS IN for DDMA */ +- if (using_desc_dma(hsotg)) +- dwc2_hsotg_ep0_zlp(hsotg, true); ++ /* Safety check EP0 state when STSPHSERCVD asserted */ ++ if (hsotg->ep0_state == DWC2_EP0_DATA_OUT) { ++ /* Move to STATUS IN for DDMA */ ++ if (using_desc_dma(hsotg)) ++ dwc2_hsotg_ep0_zlp(hsotg, true); ++ } ++ + } + + if (ints & DXEPINT_BACK2BACKSETUP) +@@ -3375,12 +3381,6 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, + dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | + DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0); + +- dwc2_hsotg_enqueue_setup(hsotg); +- +- dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", +- dwc2_readl(hsotg->regs + DIEPCTL0), +- dwc2_readl(hsotg->regs + DOEPCTL0)); +- + /* clear global NAKs */ + val = DCTL_CGOUTNAK | DCTL_CGNPINNAK; + if (!is_usb_reset) +@@ -3391,6 +3391,12 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, + mdelay(3); + + hsotg->lx_state = DWC2_L0; ++ ++ dwc2_hsotg_enqueue_setup(hsotg); ++ ++ dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", ++ dwc2_readl(hsotg->regs + DIEPCTL0), ++ dwc2_readl(hsotg->regs + DOEPCTL0)); + } + + static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index ade2ab0..f1d838a 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -100,6 +100,8 @@ static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) + reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); + reg |= DWC3_GCTL_PRTCAPDIR(mode); + dwc3_writel(dwc->regs, DWC3_GCTL, reg); ++ ++ dwc->current_dr_role = mode; + } + + static void __dwc3_set_mode(struct work_struct *work) +@@ -133,8 +135,6 @@ static void __dwc3_set_mode(struct work_struct *work) + + dwc3_set_prtcap(dwc, dwc->desired_dr_role); + +- dwc->current_dr_role = dwc->desired_dr_role; +- + spin_unlock_irqrestore(&dwc->lock, flags); + + switch (dwc->desired_dr_role) { +@@ -219,7 +219,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) + * XHCI driver will reset the host block. If dwc3 was configured for + * host-only mode, then we can return early. + */ +- if (dwc->dr_mode == USB_DR_MODE_HOST) ++ if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST) + return 0; + + reg = dwc3_readl(dwc->regs, DWC3_DCTL); +@@ -234,6 +234,9 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) + udelay(1); + } while (--retries); + ++ phy_exit(dwc->usb3_generic_phy); ++ phy_exit(dwc->usb2_generic_phy); ++ + return -ETIMEDOUT; + } + +@@ -483,6 +486,22 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc) + parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); + } + ++static int dwc3_core_ulpi_init(struct dwc3 *dwc) ++{ ++ int intf; ++ int ret = 0; ++ ++ intf = DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3); ++ ++ if (intf == DWC3_GHWPARAMS3_HSPHY_IFC_ULPI || ++ (intf == DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI && ++ dwc->hsphy_interface && ++ !strncmp(dwc->hsphy_interface, "ulpi", 4))) ++ ret = dwc3_ulpi_init(dwc); ++ ++ return ret; ++} ++ + /** + * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core + * @dwc: Pointer to our controller context structure +@@ -494,7 +513,6 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc) + static int dwc3_phy_setup(struct dwc3 *dwc) + { + u32 reg; +- int ret; + + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); + +@@ -565,9 +583,6 @@ static int dwc3_phy_setup(struct dwc3 *dwc) + } + /* FALLTHROUGH */ + case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI: +- ret = dwc3_ulpi_init(dwc); +- if (ret) +- return ret; + /* FALLTHROUGH */ + default: + break; +@@ -724,6 +739,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc) + } + + static int dwc3_core_get_phy(struct dwc3 *dwc); ++static int dwc3_core_ulpi_init(struct dwc3 *dwc); + + /** + * dwc3_core_init - Low-level initialization of DWC3 Core +@@ -755,17 +771,27 @@ static int dwc3_core_init(struct dwc3 *dwc) + dwc->maximum_speed = USB_SPEED_HIGH; + } + +- ret = dwc3_core_get_phy(dwc); ++ ret = dwc3_phy_setup(dwc); + if (ret) + goto err0; + +- ret = dwc3_core_soft_reset(dwc); +- if (ret) +- goto err0; ++ if (!dwc->ulpi_ready) { ++ ret = dwc3_core_ulpi_init(dwc); ++ if (ret) ++ goto err0; ++ dwc->ulpi_ready = true; ++ } + +- ret = dwc3_phy_setup(dwc); ++ if (!dwc->phys_ready) { ++ ret = dwc3_core_get_phy(dwc); ++ if (ret) ++ goto err0a; ++ dwc->phys_ready = true; ++ } ++ ++ ret = dwc3_core_soft_reset(dwc); + if (ret) +- goto err0; ++ goto err0a; + + dwc3_core_setup_global_control(dwc); + dwc3_core_num_eps(dwc); +@@ -838,6 +864,9 @@ static int dwc3_core_init(struct dwc3 *dwc) + phy_exit(dwc->usb2_generic_phy); + phy_exit(dwc->usb3_generic_phy); + ++err0a: ++ dwc3_ulpi_exit(dwc); ++ + err0: + return ret; + } +@@ -916,7 +945,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) + + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: +- dwc->current_dr_role = DWC3_GCTL_PRTCAP_DEVICE; + dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); + + if (dwc->usb2_phy) +@@ -932,7 +960,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) + } + break; + case USB_DR_MODE_HOST: +- dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST; + dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); + + if (dwc->usb2_phy) +@@ -1234,7 +1261,6 @@ static int dwc3_probe(struct platform_device *pdev) + + err3: + dwc3_free_event_buffers(dwc); +- dwc3_ulpi_exit(dwc); + + err2: + pm_runtime_allow(&pdev->dev); +@@ -1284,7 +1310,7 @@ static int dwc3_remove(struct platform_device *pdev) + } + + #ifdef CONFIG_PM +-static int dwc3_suspend_common(struct dwc3 *dwc) ++static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) + { + unsigned long flags; + +@@ -1296,6 +1322,10 @@ static int dwc3_suspend_common(struct dwc3 *dwc) + dwc3_core_exit(dwc); + break; + case DWC3_GCTL_PRTCAP_HOST: ++ /* do nothing during host runtime_suspend */ ++ if (!PMSG_IS_AUTO(msg)) ++ dwc3_core_exit(dwc); ++ break; + default: + /* do nothing */ + break; +@@ -1304,7 +1334,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc) + return 0; + } + +-static int dwc3_resume_common(struct dwc3 *dwc) ++static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) + { + unsigned long flags; + int ret; +@@ -1320,6 +1350,13 @@ static int dwc3_resume_common(struct dwc3 *dwc) + spin_unlock_irqrestore(&dwc->lock, flags); + break; + case DWC3_GCTL_PRTCAP_HOST: ++ /* nothing to do on host runtime_resume */ ++ if (!PMSG_IS_AUTO(msg)) { ++ ret = dwc3_core_init(dwc); ++ if (ret) ++ return ret; ++ } ++ break; + default: + /* do nothing */ + break; +@@ -1331,12 +1368,11 @@ static int dwc3_resume_common(struct dwc3 *dwc) + static int dwc3_runtime_checks(struct dwc3 *dwc) + { + switch (dwc->current_dr_role) { +- case USB_DR_MODE_PERIPHERAL: +- case USB_DR_MODE_OTG: ++ case DWC3_GCTL_PRTCAP_DEVICE: + if (dwc->connected) + return -EBUSY; + break; +- case USB_DR_MODE_HOST: ++ case DWC3_GCTL_PRTCAP_HOST: + default: + /* do nothing */ + break; +@@ -1353,7 +1389,7 @@ static int dwc3_runtime_suspend(struct device *dev) + if (dwc3_runtime_checks(dwc)) + return -EBUSY; + +- ret = dwc3_suspend_common(dwc); ++ ret = dwc3_suspend_common(dwc, PMSG_AUTO_SUSPEND); + if (ret) + return ret; + +@@ -1369,7 +1405,7 @@ static int dwc3_runtime_resume(struct device *dev) + + device_init_wakeup(dev, false); + +- ret = dwc3_resume_common(dwc); ++ ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME); + if (ret) + return ret; + +@@ -1416,7 +1452,7 @@ static int dwc3_suspend(struct device *dev) + struct dwc3 *dwc = dev_get_drvdata(dev); + int ret; + +- ret = dwc3_suspend_common(dwc); ++ ret = dwc3_suspend_common(dwc, PMSG_SUSPEND); + if (ret) + return ret; + +@@ -1432,7 +1468,7 @@ static int dwc3_resume(struct device *dev) + + pinctrl_pm_select_default_state(dev); + +- ret = dwc3_resume_common(dwc); ++ ret = dwc3_resume_common(dwc, PMSG_RESUME); + if (ret) + return ret; + +diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h +index 03c7aaa..860d2bc 100644 +--- a/drivers/usb/dwc3/core.h ++++ b/drivers/usb/dwc3/core.h +@@ -158,13 +158,15 @@ + #define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0) + #define DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(n) (((n) >> 16) & 0xffff) + +-#define DWC3_TXFIFOQ 1 +-#define DWC3_RXFIFOQ 3 +-#define DWC3_TXREQQ 5 +-#define DWC3_RXREQQ 7 +-#define DWC3_RXINFOQ 9 +-#define DWC3_DESCFETCHQ 13 +-#define DWC3_EVENTQ 15 ++#define DWC3_TXFIFOQ 0 ++#define DWC3_RXFIFOQ 1 ++#define DWC3_TXREQQ 2 ++#define DWC3_RXREQQ 3 ++#define DWC3_RXINFOQ 4 ++#define DWC3_PSTATQ 5 ++#define DWC3_DESCFETCHQ 6 ++#define DWC3_EVENTQ 7 ++#define DWC3_AUXEVENTQ 8 + + /* Global RX Threshold Configuration Register */ + #define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19) +@@ -795,7 +797,9 @@ struct dwc3_scratchpad_array { + * @usb3_phy: pointer to USB3 PHY + * @usb2_generic_phy: pointer to USB2 PHY + * @usb3_generic_phy: pointer to USB3 PHY ++ * @phys_ready: flag to indicate that PHYs are ready + * @ulpi: pointer to ulpi interface ++ * @ulpi_ready: flag to indicate that ULPI is initialized + * @u2sel: parameter from Set SEL request. + * @u2pel: parameter from Set SEL request. + * @u1sel: parameter from Set SEL request. +@@ -893,7 +897,10 @@ struct dwc3 { + struct phy *usb2_generic_phy; + struct phy *usb3_generic_phy; + ++ bool phys_ready; ++ + struct ulpi *ulpi; ++ bool ulpi_ready; + + void __iomem *regs; + size_t regs_size; +diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c +index 7ae0eef..e54c362 100644 +--- a/drivers/usb/dwc3/dwc3-of-simple.c ++++ b/drivers/usb/dwc3/dwc3-of-simple.c +@@ -143,6 +143,7 @@ static int dwc3_of_simple_remove(struct platform_device *pdev) + clk_disable_unprepare(simple->clks[i]); + clk_put(simple->clks[i]); + } ++ simple->num_clocks = 0; + + reset_control_assert(simple->resets); + reset_control_put(simple->resets); +diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c +index a4719e8..ed8b865 100644 +--- a/drivers/usb/dwc3/dwc3-omap.c ++++ b/drivers/usb/dwc3/dwc3-omap.c +@@ -582,9 +582,25 @@ static int dwc3_omap_resume(struct device *dev) + return 0; + } + ++static void dwc3_omap_complete(struct device *dev) ++{ ++ struct dwc3_omap *omap = dev_get_drvdata(dev); ++ ++ if (extcon_get_state(omap->edev, EXTCON_USB)) ++ dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID); ++ else ++ dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF); ++ ++ if (extcon_get_state(omap->edev, EXTCON_USB_HOST)) ++ dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND); ++ else ++ dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT); ++} ++ + static const struct dev_pm_ops dwc3_omap_dev_pm_ops = { + + SET_SYSTEM_SLEEP_PM_OPS(dwc3_omap_suspend, dwc3_omap_resume) ++ .complete = dwc3_omap_complete, + }; + + #define DEV_PM_OPS (&dwc3_omap_dev_pm_ops) +diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c +index 9c2e4a1..18be31d 100644 +--- a/drivers/usb/dwc3/ep0.c ++++ b/drivers/usb/dwc3/ep0.c +@@ -854,7 +854,12 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, + trb++; + trb->ctrl &= ~DWC3_TRB_CTRL_HWO; + trace_dwc3_complete_trb(ep0, trb); +- ep0->trb_enqueue = 0; ++ ++ if (r->direction) ++ dwc->eps[1]->trb_enqueue = 0; ++ else ++ dwc->eps[0]->trb_enqueue = 0; ++ + dwc->ep0_bounced = false; + } + +diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c +index 616ef49..2bda4eb 100644 +--- a/drivers/usb/dwc3/gadget.c ++++ b/drivers/usb/dwc3/gadget.c +@@ -2745,6 +2745,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) + break; + } + ++ dwc->eps[1]->endpoint.maxpacket = dwc->gadget.ep0->maxpacket; ++ + /* Enable USB2 LPM Capability */ + + if ((dwc->revision > DWC3_REVISION_194A) && +diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c +index 8f2cf3b..c2592d8 100644 +--- a/drivers/usb/gadget/function/f_fs.c ++++ b/drivers/usb/gadget/function/f_fs.c +@@ -1855,44 +1855,20 @@ static int ffs_func_eps_enable(struct ffs_function *func) + + spin_lock_irqsave(&func->ffs->eps_lock, flags); + while(count--) { +- struct usb_endpoint_descriptor *ds; +- struct usb_ss_ep_comp_descriptor *comp_desc = NULL; +- int needs_comp_desc = false; +- int desc_idx; +- +- if (ffs->gadget->speed == USB_SPEED_SUPER) { +- desc_idx = 2; +- needs_comp_desc = true; +- } else if (ffs->gadget->speed == USB_SPEED_HIGH) +- desc_idx = 1; +- else +- desc_idx = 0; +- +- /* fall-back to lower speed if desc missing for current speed */ +- do { +- ds = ep->descs[desc_idx]; +- } while (!ds && --desc_idx >= 0); +- +- if (!ds) { +- ret = -EINVAL; +- break; +- } +- + ep->ep->driver_data = ep; +- ep->ep->desc = ds; + +- if (needs_comp_desc) { +- comp_desc = (struct usb_ss_ep_comp_descriptor *)(ds + +- USB_DT_ENDPOINT_SIZE); +- ep->ep->maxburst = comp_desc->bMaxBurst + 1; +- ep->ep->comp_desc = comp_desc; ++ ret = config_ep_by_speed(func->gadget, &func->function, ep->ep); ++ if (ret) { ++ pr_err("%s: config_ep_by_speed(%s) returned %d\n", ++ __func__, ep->ep->name, ret); ++ break; + } + + ret = usb_ep_enable(ep->ep); + if (likely(!ret)) { + epfile->ep = ep; +- epfile->in = usb_endpoint_dir_in(ds); +- epfile->isoc = usb_endpoint_xfer_isoc(ds); ++ epfile->in = usb_endpoint_dir_in(ep->ep->desc); ++ epfile->isoc = usb_endpoint_xfer_isoc(ep->ep->desc); + } else { + break; + } +@@ -2979,10 +2955,8 @@ static int _ffs_func_bind(struct usb_configuration *c, + struct ffs_data *ffs = func->ffs; + + const int full = !!func->ffs->fs_descs_count; +- const int high = gadget_is_dualspeed(func->gadget) && +- func->ffs->hs_descs_count; +- const int super = gadget_is_superspeed(func->gadget) && +- func->ffs->ss_descs_count; ++ const int high = !!func->ffs->hs_descs_count; ++ const int super = !!func->ffs->ss_descs_count; + + int fs_len, hs_len, ss_len, ret, i; + struct ffs_ep *eps_ptr; +diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c +index 11fe788..d2dc1f0 100644 +--- a/drivers/usb/gadget/function/f_uac2.c ++++ b/drivers/usb/gadget/function/f_uac2.c +@@ -524,6 +524,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + return ret; + } ++ iad_desc.bFirstInterface = ret; ++ + std_ac_if_desc.bInterfaceNumber = ret; + uac2->ac_intf = ret; + uac2->ac_alt = 0; +diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig +index 1e95670..0875d38 100644 +--- a/drivers/usb/gadget/udc/Kconfig ++++ b/drivers/usb/gadget/udc/Kconfig +@@ -274,7 +274,6 @@ config USB_SNP_UDC_PLAT + tristate "Synopsys USB 2.0 Device controller" + depends on USB_GADGET && OF && HAS_DMA + depends on EXTCON || EXTCON=n +- select USB_GADGET_DUALSPEED + select USB_SNP_CORE + default ARCH_BCM_IPROC + help +diff --git a/drivers/usb/gadget/udc/bdc/bdc_pci.c b/drivers/usb/gadget/udc/bdc/bdc_pci.c +index 1e940f0..6dbc489 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_pci.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_pci.c +@@ -77,6 +77,7 @@ static int bdc_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) + if (ret) { + dev_err(&pci->dev, + "couldn't add resources to bdc device\n"); ++ platform_device_put(bdc); + return ret; + } + +diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c +index 859d5b1..1f8b19d 100644 +--- a/drivers/usb/gadget/udc/core.c ++++ b/drivers/usb/gadget/udc/core.c +@@ -180,8 +180,8 @@ EXPORT_SYMBOL_GPL(usb_ep_alloc_request); + void usb_ep_free_request(struct usb_ep *ep, + struct usb_request *req) + { +- ep->ops->free_request(ep, req); + trace_usb_ep_free_request(ep, req, 0); ++ ep->ops->free_request(ep, req); + } + EXPORT_SYMBOL_GPL(usb_ep_free_request); + +diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c +index e5b4ee9..56b517a 100644 +--- a/drivers/usb/gadget/udc/fsl_udc_core.c ++++ b/drivers/usb/gadget/udc/fsl_udc_core.c +@@ -1305,7 +1305,7 @@ static void udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe) + { + struct fsl_ep *ep = get_ep_by_pipe(udc, pipe); + +- if (ep->name) ++ if (ep->ep.name) + nuke(ep, -ESHUTDOWN); + } + +@@ -1693,7 +1693,7 @@ static void dtd_complete_irq(struct fsl_udc *udc) + curr_ep = get_ep_by_pipe(udc, i); + + /* If the ep is configured */ +- if (curr_ep->name == NULL) { ++ if (!curr_ep->ep.name) { + WARNING("Invalid EP?"); + continue; + } +diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c +index 6e87af2..409cde4 100644 +--- a/drivers/usb/gadget/udc/renesas_usb3.c ++++ b/drivers/usb/gadget/udc/renesas_usb3.c +@@ -2410,7 +2410,7 @@ static int renesas_usb3_remove(struct platform_device *pdev) + __renesas_usb3_ep_free_request(usb3->ep0_req); + if (usb3->phy) + phy_put(usb3->phy); +- pm_runtime_disable(usb3_to_dev(usb3)); ++ pm_runtime_disable(&pdev->dev); + + return 0; + } +diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig +index 6150bed..4fcfb30 100644 +--- a/drivers/usb/host/Kconfig ++++ b/drivers/usb/host/Kconfig +@@ -633,14 +633,6 @@ config USB_UHCI_ASPEED + bool + default y if ARCH_ASPEED + +-config USB_UHCI_BIG_ENDIAN_MMIO +- bool +- default y if SPARC_LEON +- +-config USB_UHCI_BIG_ENDIAN_DESC +- bool +- default y if SPARC_LEON +- + config USB_FHCI_HCD + tristate "Freescale QE USB Host Controller support" + depends on OF_GPIO && QE_GPIO && QUICC_ENGINE +diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c +index facafdf..d7641cb 100644 +--- a/drivers/usb/host/ehci-hub.c ++++ b/drivers/usb/host/ehci-hub.c +@@ -774,12 +774,12 @@ static struct urb *request_single_step_set_feature_urb( + atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); + urb->setup_dma = dma_map_single( +- hcd->self.controller, ++ hcd->self.sysdev, + urb->setup_packet, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + urb->transfer_dma = dma_map_single( +- hcd->self.controller, ++ hcd->self.sysdev, + urb->transfer_buffer, + urb->transfer_buffer_length, + DMA_FROM_DEVICE); +diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c +index 8815832..3276304 100644 +--- a/drivers/usb/host/ehci-q.c ++++ b/drivers/usb/host/ehci-q.c +@@ -1188,10 +1188,10 @@ static int submit_single_step_set_feature( + * 15 secs after the setup + */ + if (is_setup) { +- /* SETUP pid */ ++ /* SETUP pid, and interrupt after SETUP completion */ + qtd_fill(ehci, qtd, urb->setup_dma, + sizeof(struct usb_ctrlrequest), +- token | (2 /* "setup" */ << 8), 8); ++ QTD_IOC | token | (2 /* "setup" */ << 8), 8); + + submit_async(ehci, urb, &qtd_list, GFP_ATOMIC); + return 0; /*Return now; we shall come back after 15 seconds*/ +@@ -1228,12 +1228,8 @@ static int submit_single_step_set_feature( + qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma); + list_add_tail(&qtd->qtd_list, head); + +- /* dont fill any data in such packets */ +- qtd_fill(ehci, qtd, 0, 0, token, 0); +- +- /* by default, enable interrupt on urb completion */ +- if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT))) +- qtd->hw_token |= cpu_to_hc32(ehci, QTD_IOC); ++ /* Interrupt after STATUS completion */ ++ qtd_fill(ehci, qtd, 0, 0, token | QTD_IOC, 0); + + submit_async(ehci, urb, &qtd_list, GFP_KERNEL); + +diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c +index ee96763..84f88fa 100644 +--- a/drivers/usb/host/ohci-hcd.c ++++ b/drivers/usb/host/ohci-hcd.c +@@ -74,6 +74,7 @@ static const char hcd_name [] = "ohci_hcd"; + + #define STATECHANGE_DELAY msecs_to_jiffies(300) + #define IO_WATCHDOG_DELAY msecs_to_jiffies(275) ++#define IO_WATCHDOG_OFF 0xffffff00 + + #include "ohci.h" + #include "pci-quirks.h" +@@ -231,7 +232,7 @@ static int ohci_urb_enqueue ( + } + + /* Start up the I/O watchdog timer, if it's not running */ +- if (!timer_pending(&ohci->io_watchdog) && ++ if (ohci->prev_frame_no == IO_WATCHDOG_OFF && + list_empty(&ohci->eds_in_use) && + !(ohci->flags & OHCI_QUIRK_QEMU)) { + ohci->prev_frame_no = ohci_frame_no(ohci); +@@ -501,6 +502,7 @@ static int ohci_init (struct ohci_hcd *ohci) + return 0; + + timer_setup(&ohci->io_watchdog, io_watchdog_func, 0); ++ ohci->prev_frame_no = IO_WATCHDOG_OFF; + + ohci->hcca = dma_alloc_coherent (hcd->self.controller, + sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL); +@@ -730,7 +732,7 @@ static void io_watchdog_func(struct timer_list *t) + u32 head; + struct ed *ed; + struct td *td, *td_start, *td_next; +- unsigned frame_no; ++ unsigned frame_no, prev_frame_no = IO_WATCHDOG_OFF; + unsigned long flags; + + spin_lock_irqsave(&ohci->lock, flags); +@@ -835,7 +837,7 @@ static void io_watchdog_func(struct timer_list *t) + } + } + if (!list_empty(&ohci->eds_in_use)) { +- ohci->prev_frame_no = frame_no; ++ prev_frame_no = frame_no; + ohci->prev_wdh_cnt = ohci->wdh_cnt; + ohci->prev_donehead = ohci_readl(ohci, + &ohci->regs->donehead); +@@ -845,6 +847,7 @@ static void io_watchdog_func(struct timer_list *t) + } + + done: ++ ohci->prev_frame_no = prev_frame_no; + spin_unlock_irqrestore(&ohci->lock, flags); + } + +@@ -973,6 +976,7 @@ static void ohci_stop (struct usb_hcd *hcd) + if (quirk_nec(ohci)) + flush_work(&ohci->nec_work); + del_timer_sync(&ohci->io_watchdog); ++ ohci->prev_frame_no = IO_WATCHDOG_OFF; + + ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + ohci_usb_reset(ohci); +diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c +index fb7aaa3..634f3c7 100644 +--- a/drivers/usb/host/ohci-hub.c ++++ b/drivers/usb/host/ohci-hub.c +@@ -311,8 +311,10 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) + rc = ohci_rh_suspend (ohci, 0); + spin_unlock_irq (&ohci->lock); + +- if (rc == 0) ++ if (rc == 0) { + del_timer_sync(&ohci->io_watchdog); ++ ohci->prev_frame_no = IO_WATCHDOG_OFF; ++ } + return rc; + } + +diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c +index b2ec8c3..4ccb85a 100644 +--- a/drivers/usb/host/ohci-q.c ++++ b/drivers/usb/host/ohci-q.c +@@ -1019,6 +1019,8 @@ static void finish_unlinks(struct ohci_hcd *ohci) + * have modified this list. normally it's just prepending + * entries (which we'd ignore), but paranoia won't hurt. + */ ++ *last = ed->ed_next; ++ ed->ed_next = NULL; + modified = 0; + + /* unlink urbs as requested, but rescan the list after +@@ -1077,21 +1079,22 @@ static void finish_unlinks(struct ohci_hcd *ohci) + goto rescan_this; + + /* +- * If no TDs are queued, take ED off the ed_rm_list. ++ * If no TDs are queued, ED is now idle. + * Otherwise, if the HC is running, reschedule. +- * If not, leave it on the list for further dequeues. ++ * If the HC isn't running, add ED back to the ++ * start of the list for later processing. + */ + if (list_empty(&ed->td_list)) { +- *last = ed->ed_next; +- ed->ed_next = NULL; + ed->state = ED_IDLE; + list_del(&ed->in_use_list); + } else if (ohci->rh_state == OHCI_RH_RUNNING) { +- *last = ed->ed_next; +- ed->ed_next = NULL; + ed_schedule(ohci, ed); + } else { +- last = &ed->ed_next; ++ ed->ed_next = ohci->ed_rm_list; ++ ohci->ed_rm_list = ed; ++ /* Don't loop on the same ED */ ++ if (last == &ohci->ed_rm_list) ++ last = &ed->ed_next; + } + + if (modified) +diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c +index 1615367..67ad4bb 100644 +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -66,6 +66,23 @@ + #define AX_INDXC 0x30 + #define AX_DATAC 0x34 + ++#define PT_ADDR_INDX 0xE8 ++#define PT_READ_INDX 0xE4 ++#define PT_SIG_1_ADDR 0xA520 ++#define PT_SIG_2_ADDR 0xA521 ++#define PT_SIG_3_ADDR 0xA522 ++#define PT_SIG_4_ADDR 0xA523 ++#define PT_SIG_1_DATA 0x78 ++#define PT_SIG_2_DATA 0x56 ++#define PT_SIG_3_DATA 0x34 ++#define PT_SIG_4_DATA 0x12 ++#define PT4_P1_REG 0xB521 ++#define PT4_P2_REG 0xB522 ++#define PT2_P1_REG 0xD520 ++#define PT2_P2_REG 0xD521 ++#define PT1_P1_REG 0xD522 ++#define PT1_P2_REG 0xD523 ++ + #define NB_PCIE_INDX_ADDR 0xe0 + #define NB_PCIE_INDX_DATA 0xe4 + #define PCIE_P_CNTL 0x10040 +@@ -513,6 +530,98 @@ void usb_amd_dev_put(void) + EXPORT_SYMBOL_GPL(usb_amd_dev_put); + + /* ++ * Check if port is disabled in BIOS on AMD Promontory host. ++ * BIOS Disabled ports may wake on connect/disconnect and need ++ * driver workaround to keep them disabled. ++ * Returns true if port is marked disabled. ++ */ ++bool usb_amd_pt_check_port(struct device *device, int port) ++{ ++ unsigned char value, port_shift; ++ struct pci_dev *pdev; ++ u16 reg; ++ ++ pdev = to_pci_dev(device); ++ pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_1_ADDR); ++ ++ pci_read_config_byte(pdev, PT_READ_INDX, &value); ++ if (value != PT_SIG_1_DATA) ++ return false; ++ ++ pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_2_ADDR); ++ ++ pci_read_config_byte(pdev, PT_READ_INDX, &value); ++ if (value != PT_SIG_2_DATA) ++ return false; ++ ++ pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_3_ADDR); ++ ++ pci_read_config_byte(pdev, PT_READ_INDX, &value); ++ if (value != PT_SIG_3_DATA) ++ return false; ++ ++ pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_4_ADDR); ++ ++ pci_read_config_byte(pdev, PT_READ_INDX, &value); ++ if (value != PT_SIG_4_DATA) ++ return false; ++ ++ /* Check disabled port setting, if bit is set port is enabled */ ++ switch (pdev->device) { ++ case 0x43b9: ++ case 0x43ba: ++ /* ++ * device is AMD_PROMONTORYA_4(0x43b9) or PROMONTORYA_3(0x43ba) ++ * PT4_P1_REG bits[7..1] represents USB2.0 ports 6 to 0 ++ * PT4_P2_REG bits[6..0] represents ports 13 to 7 ++ */ ++ if (port > 6) { ++ reg = PT4_P2_REG; ++ port_shift = port - 7; ++ } else { ++ reg = PT4_P1_REG; ++ port_shift = port + 1; ++ } ++ break; ++ case 0x43bb: ++ /* ++ * device is AMD_PROMONTORYA_2(0x43bb) ++ * PT2_P1_REG bits[7..5] represents USB2.0 ports 2 to 0 ++ * PT2_P2_REG bits[5..0] represents ports 9 to 3 ++ */ ++ if (port > 2) { ++ reg = PT2_P2_REG; ++ port_shift = port - 3; ++ } else { ++ reg = PT2_P1_REG; ++ port_shift = port + 5; ++ } ++ break; ++ case 0x43bc: ++ /* ++ * device is AMD_PROMONTORYA_1(0x43bc) ++ * PT1_P1_REG[7..4] represents USB2.0 ports 3 to 0 ++ * PT1_P2_REG[5..0] represents ports 9 to 4 ++ */ ++ if (port > 3) { ++ reg = PT1_P2_REG; ++ port_shift = port - 4; ++ } else { ++ reg = PT1_P1_REG; ++ port_shift = port + 4; ++ } ++ break; ++ default: ++ return false; ++ } ++ pci_write_config_word(pdev, PT_ADDR_INDX, reg); ++ pci_read_config_byte(pdev, PT_READ_INDX, &value); ++ ++ return !(value & BIT(port_shift)); ++} ++EXPORT_SYMBOL_GPL(usb_amd_pt_check_port); ++ ++/* + * Make sure the controller is completely inactive, unable to + * generate interrupts or do DMA. + */ +diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h +index b68dcb5..4ca0d9b 100644 +--- a/drivers/usb/host/pci-quirks.h ++++ b/drivers/usb/host/pci-quirks.h +@@ -17,6 +17,7 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev); + void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); + void sb800_prefetch(struct device *dev, int on); + bool usb_xhci_needs_pci_reset(struct pci_dev *pdev); ++bool usb_amd_pt_check_port(struct device *device, int port); + #else + struct pci_dev; + static inline void usb_amd_quirk_pll_disable(void) {} +@@ -25,6 +26,10 @@ static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {} + static inline void usb_amd_dev_put(void) {} + static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {} + static inline void sb800_prefetch(struct device *dev, int on) {} ++static inline bool usb_amd_pt_check_port(struct device *device, int port) ++{ ++ return false; ++} + #endif /* CONFIG_USB_PCI */ + + #endif /* __LINUX_USB_PCI_QUIRKS_H */ +diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c +index e26e685..5851052 100644 +--- a/drivers/usb/host/xhci-debugfs.c ++++ b/drivers/usb/host/xhci-debugfs.c +@@ -211,7 +211,7 @@ static void xhci_ring_dump_segment(struct seq_file *s, + static int xhci_ring_trb_show(struct seq_file *s, void *unused) + { + int i; +- struct xhci_ring *ring = s->private; ++ struct xhci_ring *ring = *(struct xhci_ring **)s->private; + struct xhci_segment *seg = ring->first_seg; + + for (i = 0; i < ring->num_segs; i++) { +@@ -387,7 +387,7 @@ void xhci_debugfs_create_endpoint(struct xhci_hcd *xhci, + + snprintf(epriv->name, sizeof(epriv->name), "ep%02d", ep_index); + epriv->root = xhci_debugfs_create_ring_dir(xhci, +- &dev->eps[ep_index].new_ring, ++ &dev->eps[ep_index].ring, + epriv->name, + spriv->root); + spriv->eps[ep_index] = epriv; +diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c +index 46d5e08..72ebbc9 100644 +--- a/drivers/usb/host/xhci-hub.c ++++ b/drivers/usb/host/xhci-hub.c +@@ -1224,17 +1224,17 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, + temp = readl(port_array[wIndex]); + break; + } +- +- /* Software should not attempt to set +- * port link state above '3' (U3) and the port +- * must be enabled. +- */ +- if ((temp & PORT_PE) == 0 || +- (link_state > USB_SS_PORT_LS_U3)) { +- xhci_warn(xhci, "Cannot set link state.\n"); ++ /* Port must be enabled */ ++ if (!(temp & PORT_PE)) { ++ retval = -ENODEV; ++ break; ++ } ++ /* Can't set port link state above '3' (U3) */ ++ if (link_state > USB_SS_PORT_LS_U3) { ++ xhci_warn(xhci, "Cannot set port %d link state %d\n", ++ wIndex, link_state); + goto error; + } +- + if (link_state == USB_SS_PORT_LS_U3) { + slot_id = xhci_find_slot_id_by_port(hcd, xhci, + wIndex + 1); +@@ -1522,6 +1522,13 @@ int xhci_bus_suspend(struct usb_hcd *hcd) + t2 |= PORT_WKOC_E | PORT_WKCONN_E; + t2 &= ~PORT_WKDISC_E; + } ++ ++ if ((xhci->quirks & XHCI_U2_DISABLE_WAKE) && ++ (hcd->speed < HCD_USB3)) { ++ if (usb_amd_pt_check_port(hcd->self.controller, ++ port_index)) ++ t2 &= ~PORT_WAKE_BITS; ++ } + } else + t2 &= ~PORT_WAKE_BITS; + +diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c +index 6c79037..5262fa5 100644 +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -42,6 +42,10 @@ + #define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8 + #define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0 + ++#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9 ++#define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba ++#define PCI_DEVICE_ID_AMD_PROMONTORYA_2 0x43bb ++#define PCI_DEVICE_ID_AMD_PROMONTORYA_1 0x43bc + #define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI 0x1142 + + static const char hcd_name[] = "xhci_hcd"; +@@ -125,6 +129,13 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + if (pdev->vendor == PCI_VENDOR_ID_AMD) + xhci->quirks |= XHCI_TRUST_TX_LENGTH; + ++ if ((pdev->vendor == PCI_VENDOR_ID_AMD) && ++ ((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) || ++ (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_3) || ++ (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_2) || ++ (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_1))) ++ xhci->quirks |= XHCI_U2_DISABLE_WAKE; ++ + if (pdev->vendor == PCI_VENDOR_ID_INTEL) { + xhci->quirks |= XHCI_LPM_SUPPORT; + xhci->quirks |= XHCI_INTEL_HOST; +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index 1eeb339..25d4b748 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -646,8 +646,6 @@ static void xhci_stop(struct usb_hcd *hcd) + return; + } + +- xhci_debugfs_exit(xhci); +- + xhci_dbc_exit(xhci); + + spin_lock_irq(&xhci->lock); +@@ -680,6 +678,7 @@ static void xhci_stop(struct usb_hcd *hcd) + + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory"); + xhci_mem_cleanup(xhci); ++ xhci_debugfs_exit(xhci); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "xhci_stop completed - status = %x", + readl(&xhci->op_regs->status)); +@@ -1014,6 +1013,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) + + xhci_dbg(xhci, "cleaning up memory\n"); + xhci_mem_cleanup(xhci); ++ xhci_debugfs_exit(xhci); + xhci_dbg(xhci, "xhci_stop completed - status = %x\n", + readl(&xhci->op_regs->status)); + +@@ -3544,12 +3544,10 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) + virt_dev->eps[i].ep_state &= ~EP_STOP_CMD_PENDING; + del_timer_sync(&virt_dev->eps[i].stop_cmd_timer); + } +- ++ xhci_debugfs_remove_slot(xhci, udev->slot_id); + ret = xhci_disable_slot(xhci, udev->slot_id); +- if (ret) { +- xhci_debugfs_remove_slot(xhci, udev->slot_id); ++ if (ret) + xhci_free_virt_device(xhci, udev->slot_id); +- } + } + + int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id) +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index 96099a2..e4d7d3d 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1822,7 +1822,7 @@ struct xhci_hcd { + /* For controller with a broken Port Disable implementation */ + #define XHCI_BROKEN_PORT_PED (1 << 25) + #define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26) +-/* Reserved. It was XHCI_U2_DISABLE_WAKE */ ++#define XHCI_U2_DISABLE_WAKE (1 << 27) + #define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28) + #define XHCI_HW_LPM_DISABLE (1 << 29) + +diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c +index 63b9e85..236a60f 100644 +--- a/drivers/usb/misc/ldusb.c ++++ b/drivers/usb/misc/ldusb.c +@@ -42,6 +42,9 @@ + #define USB_DEVICE_ID_LD_MICROCASSYTIME 0x1033 /* USB Product ID of Micro-CASSY Time (reserved) */ + #define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE 0x1035 /* USB Product ID of Micro-CASSY Temperature */ + #define USB_DEVICE_ID_LD_MICROCASSYPH 0x1038 /* USB Product ID of Micro-CASSY pH */ ++#define USB_DEVICE_ID_LD_POWERANALYSERCASSY 0x1040 /* USB Product ID of Power Analyser CASSY */ ++#define USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY 0x1042 /* USB Product ID of Converter Controller CASSY */ ++#define USB_DEVICE_ID_LD_MACHINETESTCASSY 0x1043 /* USB Product ID of Machine Test CASSY */ + #define USB_DEVICE_ID_LD_JWM 0x1080 /* USB Product ID of Joule and Wattmeter */ + #define USB_DEVICE_ID_LD_DMMP 0x1081 /* USB Product ID of Digital Multimeter P (reserved) */ + #define USB_DEVICE_ID_LD_UMIP 0x1090 /* USB Product ID of UMI P */ +@@ -84,6 +87,9 @@ static const struct usb_device_id ld_usb_table[] = { + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) }, ++ { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERANALYSERCASSY) }, ++ { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY) }, ++ { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETESTCASSY) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) }, +diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c +index 968bf1e..eef4ad5 100644 +--- a/drivers/usb/musb/musb_core.c ++++ b/drivers/usb/musb/musb_core.c +@@ -2708,7 +2708,8 @@ static int musb_resume(struct device *dev) + if ((devctl & mask) != (musb->context.devctl & mask)) + musb->port1_status = 0; + +- musb_start(musb); ++ musb_enable_interrupts(musb); ++ musb_platform_enable(musb); + + spin_lock_irqsave(&musb->lock, flags); + error = musb_run_resume_work(musb); +diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c +index 394b4ac..45ed32c 100644 +--- a/drivers/usb/musb/musb_host.c ++++ b/drivers/usb/musb/musb_host.c +@@ -391,13 +391,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb, + } + } + +- /* +- * The pipe must be broken if current urb->status is set, so don't +- * start next urb. +- * TODO: to minimize the risk of regression, only check urb->status +- * for RX, until we have a test case to understand the behavior of TX. +- */ +- if ((!status || !is_in) && qh && qh->is_ready) { ++ if (qh != NULL && qh->is_ready) { + musb_dbg(musb, "... next ep%d %cX urb %p", + hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh)); + musb_start_urb(musb, is_in, qh); +diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c +index da031c4..fbec863 100644 +--- a/drivers/usb/phy/phy-mxs-usb.c ++++ b/drivers/usb/phy/phy-mxs-usb.c +@@ -602,6 +602,9 @@ static enum usb_charger_type mxs_phy_charger_detect(struct usb_phy *phy) + void __iomem *base = phy->io_priv; + enum usb_charger_type chgr_type = UNKNOWN_TYPE; + ++ if (!regmap) ++ return UNKNOWN_TYPE; ++ + if (mxs_charger_data_contact_detect(mxs_phy)) + return chgr_type; + +diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c +index 5925d11..39fa2fc 100644 +--- a/drivers/usb/renesas_usbhs/fifo.c ++++ b/drivers/usb/renesas_usbhs/fifo.c +@@ -982,6 +982,10 @@ static int usbhsf_dma_prepare_pop_with_usb_dmac(struct usbhs_pkt *pkt, + if ((uintptr_t)pkt->buf & (USBHS_USB_DMAC_XFER_SIZE - 1)) + goto usbhsf_pio_prepare_pop; + ++ /* return at this time if the pipe is running */ ++ if (usbhs_pipe_is_running(pipe)) ++ return 0; ++ + usbhs_pipe_config_change_bfre(pipe, 1); + + ret = usbhsf_fifo_select(pipe, fifo, 0); +@@ -1172,6 +1176,7 @@ static int usbhsf_dma_pop_done_with_usb_dmac(struct usbhs_pkt *pkt, + usbhsf_fifo_clear(pipe, fifo); + pkt->actual = usbhs_dma_calc_received_size(pkt, chan, rcv_len); + ++ usbhs_pipe_running(pipe, 0); + usbhsf_dma_stop(pipe, fifo); + usbhsf_dma_unmap(pkt); + usbhsf_fifo_unselect(pipe, pipe->fifo); +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index 5db8ed5..2d8d915 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -241,6 +241,7 @@ static void option_instat_callback(struct urb *urb); + #define QUECTEL_PRODUCT_EC21 0x0121 + #define QUECTEL_PRODUCT_EC25 0x0125 + #define QUECTEL_PRODUCT_BG96 0x0296 ++#define QUECTEL_PRODUCT_EP06 0x0306 + + #define CMOTECH_VENDOR_ID 0x16d8 + #define CMOTECH_PRODUCT_6001 0x6001 +@@ -689,6 +690,10 @@ static const struct option_blacklist_info yuga_clm920_nc5_blacklist = { + .reserved = BIT(1) | BIT(4), + }; + ++static const struct option_blacklist_info quectel_ep06_blacklist = { ++ .reserved = BIT(4) | BIT(5), ++}; ++ + static const struct usb_device_id option_ids[] = { + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, +@@ -1203,6 +1208,8 @@ static const struct usb_device_id option_ids[] = { + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, ++ { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06), ++ .driver_info = (kernel_ulong_t)&quectel_ep06_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003), +diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c +index 49e5524..dd8ef36 100644 +--- a/drivers/usb/usbip/stub_dev.c ++++ b/drivers/usb/usbip/stub_dev.c +@@ -73,6 +73,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a + goto err; + + sdev->ud.tcp_socket = socket; ++ sdev->ud.sockfd = sockfd; + + spin_unlock_irq(&sdev->ud.lock); + +@@ -172,6 +173,7 @@ static void stub_shutdown_connection(struct usbip_device *ud) + if (ud->tcp_socket) { + sockfd_put(ud->tcp_socket); + ud->tcp_socket = NULL; ++ ud->sockfd = -1; + } + + /* 3. free used data */ +@@ -266,6 +268,7 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev) + sdev->ud.status = SDEV_ST_AVAILABLE; + spin_lock_init(&sdev->ud.lock); + sdev->ud.tcp_socket = NULL; ++ sdev->ud.sockfd = -1; + + INIT_LIST_HEAD(&sdev->priv_init); + INIT_LIST_HEAD(&sdev->priv_tx); +diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c +index c3e1008..20e3d46 100644 +--- a/drivers/usb/usbip/vhci_hcd.c ++++ b/drivers/usb/usbip/vhci_hcd.c +@@ -984,6 +984,7 @@ static void vhci_shutdown_connection(struct usbip_device *ud) + if (vdev->ud.tcp_socket) { + sockfd_put(vdev->ud.tcp_socket); + vdev->ud.tcp_socket = NULL; ++ vdev->ud.sockfd = -1; + } + pr_info("release socket\n"); + +@@ -1030,6 +1031,7 @@ static void vhci_device_reset(struct usbip_device *ud) + if (ud->tcp_socket) { + sockfd_put(ud->tcp_socket); + ud->tcp_socket = NULL; ++ ud->sockfd = -1; + } + ud->status = VDEV_ST_NULL; + +diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c +index e30e29a..45657e2 100644 +--- a/drivers/vfio/vfio_iommu_type1.c ++++ b/drivers/vfio/vfio_iommu_type1.c +@@ -338,11 +338,12 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, + { + struct page *page[1]; + struct vm_area_struct *vma; ++ struct vm_area_struct *vmas[1]; + int ret; + + if (mm == current->mm) { +- ret = get_user_pages_fast(vaddr, 1, !!(prot & IOMMU_WRITE), +- page); ++ ret = get_user_pages_longterm(vaddr, 1, !!(prot & IOMMU_WRITE), ++ page, vmas); + } else { + unsigned int flags = 0; + +@@ -351,7 +352,18 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, + + down_read(&mm->mmap_sem); + ret = get_user_pages_remote(NULL, mm, vaddr, 1, flags, page, +- NULL, NULL); ++ vmas, NULL); ++ /* ++ * The lifetime of a vaddr_get_pfn() page pin is ++ * userspace-controlled. In the fs-dax case this could ++ * lead to indefinite stalls in filesystem operations. ++ * Disallow attempts to pin fs-dax pages via this ++ * interface. ++ */ ++ if (ret > 0 && vma_is_fsdax(vmas[0])) { ++ ret = -EOPNOTSUPP; ++ put_page(page[0]); ++ } + up_read(&mm->mmap_sem); + } + +diff --git a/drivers/video/fbdev/geode/video_gx.c b/drivers/video/fbdev/geode/video_gx.c +index 6082f65..67773e8 100644 +--- a/drivers/video/fbdev/geode/video_gx.c ++++ b/drivers/video/fbdev/geode/video_gx.c +@@ -127,7 +127,7 @@ void gx_set_dclk_frequency(struct fb_info *info) + int timeout = 1000; + + /* Rev. 1 Geode GXs use a 14 MHz reference clock instead of 48 MHz. */ +- if (cpu_data(0).x86_mask == 1) { ++ if (cpu_data(0).x86_stepping == 1) { + pll_table = gx_pll_table_14MHz; + pll_table_len = ARRAY_SIZE(gx_pll_table_14MHz); + } else { +diff --git a/drivers/video/fbdev/sbuslib.c b/drivers/video/fbdev/sbuslib.c +index af6fc97..a436d44 100644 +--- a/drivers/video/fbdev/sbuslib.c ++++ b/drivers/video/fbdev/sbuslib.c +@@ -122,7 +122,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, + unsigned char __user *ured; + unsigned char __user *ugreen; + unsigned char __user *ublue; +- int index, count, i; ++ unsigned int index, count, i; + + if (get_user(index, &c->index) || + __get_user(count, &c->count) || +@@ -161,7 +161,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, + unsigned char __user *ugreen; + unsigned char __user *ublue; + struct fb_cmap *cmap = &info->cmap; +- int index, count, i; ++ unsigned int index, count, i; + u8 red, green, blue; + + if (get_user(index, &c->index) || +diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c +index eb30f3e..71458f4 100644 +--- a/drivers/virtio/virtio_ring.c ++++ b/drivers/virtio/virtio_ring.c +@@ -428,8 +428,6 @@ static inline int virtqueue_add(struct virtqueue *_vq, + i = virtio16_to_cpu(_vq->vdev, vq->vring.desc[i].next); + } + +- vq->vq.num_free += total_sg; +- + if (indirect) + kfree(desc); + +diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig +index aff773b..37460cd 100644 +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -226,6 +226,7 @@ config ZIIRAVE_WATCHDOG + config RAVE_SP_WATCHDOG + tristate "RAVE SP Watchdog timer" + depends on RAVE_SP_CORE ++ depends on NVMEM || !NVMEM + select WATCHDOG_CORE + help + Support for the watchdog on RAVE SP device. +@@ -903,6 +904,7 @@ config F71808E_WDT + config SP5100_TCO + tristate "AMD/ATI SP5100 TCO Timer/Watchdog" + depends on X86 && PCI ++ select WATCHDOG_CORE + ---help--- + Hardware watchdog driver for the AMD/ATI SP5100 chipset. The TCO + (Total Cost of Ownership) timer is a watchdog timer that will reboot +@@ -1008,6 +1010,7 @@ config WAFER_WDT + config I6300ESB_WDT + tristate "Intel 6300ESB Timer/Watchdog" + depends on PCI ++ select WATCHDOG_CORE + ---help--- + Hardware driver for the watchdog timer built into the Intel + 6300ESB controller hub. +@@ -1837,6 +1840,7 @@ config WATCHDOG_SUN4V + config XEN_WDT + tristate "Xen Watchdog support" + depends on XEN ++ select WATCHDOG_CORE + help + Say Y here to support the hypervisor watchdog capability provided + by Xen 4.0 and newer. The watchdog timeout period is normally one +diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c +index e0678c1..3a33c53 100644 +--- a/drivers/watchdog/f71808e_wdt.c ++++ b/drivers/watchdog/f71808e_wdt.c +@@ -566,7 +566,8 @@ static ssize_t watchdog_write(struct file *file, const char __user *buf, + char c; + if (get_user(c, buf + i)) + return -EFAULT; +- expect_close = (c == 'V'); ++ if (c == 'V') ++ expect_close = true; + } + + /* Properly order writes across fork()ed processes */ +diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c +index f1f00df..b0a1580 100644 +--- a/drivers/watchdog/hpwdt.c ++++ b/drivers/watchdog/hpwdt.c +@@ -28,16 +28,7 @@ + #include + #include + #include +-#ifdef CONFIG_HPWDT_NMI_DECODING +-#include +-#include +-#include +-#include +-#include +-#include +-#endif /* CONFIG_HPWDT_NMI_DECODING */ + #include +-#include + + #define HPWDT_VERSION "1.4.0" + #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) +@@ -48,6 +39,9 @@ + static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */ + static unsigned int reload; /* the computed soft_margin */ + static bool nowayout = WATCHDOG_NOWAYOUT; ++#ifdef CONFIG_HPWDT_NMI_DECODING ++static unsigned int allow_kdump = 1; ++#endif + static char expect_release; + static unsigned long hpwdt_is_open; + +@@ -63,373 +57,6 @@ static const struct pci_device_id hpwdt_devices[] = { + }; + MODULE_DEVICE_TABLE(pci, hpwdt_devices); + +-#ifdef CONFIG_HPWDT_NMI_DECODING +-#define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */ +-#define CRU_BIOS_SIGNATURE_VALUE 0x55524324 +-#define PCI_BIOS32_PARAGRAPH_LEN 16 +-#define PCI_ROM_BASE1 0x000F0000 +-#define ROM_SIZE 0x10000 +- +-struct bios32_service_dir { +- u32 signature; +- u32 entry_point; +- u8 revision; +- u8 length; +- u8 checksum; +- u8 reserved[5]; +-}; +- +-/* type 212 */ +-struct smbios_cru64_info { +- u8 type; +- u8 byte_length; +- u16 handle; +- u32 signature; +- u64 physical_address; +- u32 double_length; +- u32 double_offset; +-}; +-#define SMBIOS_CRU64_INFORMATION 212 +- +-/* type 219 */ +-struct smbios_proliant_info { +- u8 type; +- u8 byte_length; +- u16 handle; +- u32 power_features; +- u32 omega_features; +- u32 reserved; +- u32 misc_features; +-}; +-#define SMBIOS_ICRU_INFORMATION 219 +- +- +-struct cmn_registers { +- union { +- struct { +- u8 ral; +- u8 rah; +- u16 rea2; +- }; +- u32 reax; +- } u1; +- union { +- struct { +- u8 rbl; +- u8 rbh; +- u8 reb2l; +- u8 reb2h; +- }; +- u32 rebx; +- } u2; +- union { +- struct { +- u8 rcl; +- u8 rch; +- u16 rec2; +- }; +- u32 recx; +- } u3; +- union { +- struct { +- u8 rdl; +- u8 rdh; +- u16 red2; +- }; +- u32 redx; +- } u4; +- +- u32 resi; +- u32 redi; +- u16 rds; +- u16 res; +- u32 reflags; +-} __attribute__((packed)); +- +-static unsigned int hpwdt_nmi_decoding; +-static unsigned int allow_kdump = 1; +-static unsigned int is_icru; +-static unsigned int is_uefi; +-static DEFINE_SPINLOCK(rom_lock); +-static void *cru_rom_addr; +-static struct cmn_registers cmn_regs; +- +-extern asmlinkage void asminline_call(struct cmn_registers *pi86Regs, +- unsigned long *pRomEntry); +- +-#ifdef CONFIG_X86_32 +-/* --32 Bit Bios------------------------------------------------------------ */ +- +-#define HPWDT_ARCH 32 +- +-asm(".text \n\t" +- ".align 4 \n\t" +- ".globl asminline_call \n" +- "asminline_call: \n\t" +- "pushl %ebp \n\t" +- "movl %esp, %ebp \n\t" +- "pusha \n\t" +- "pushf \n\t" +- "push %es \n\t" +- "push %ds \n\t" +- "pop %es \n\t" +- "movl 8(%ebp),%eax \n\t" +- "movl 4(%eax),%ebx \n\t" +- "movl 8(%eax),%ecx \n\t" +- "movl 12(%eax),%edx \n\t" +- "movl 16(%eax),%esi \n\t" +- "movl 20(%eax),%edi \n\t" +- "movl (%eax),%eax \n\t" +- "push %cs \n\t" +- "call *12(%ebp) \n\t" +- "pushf \n\t" +- "pushl %eax \n\t" +- "movl 8(%ebp),%eax \n\t" +- "movl %ebx,4(%eax) \n\t" +- "movl %ecx,8(%eax) \n\t" +- "movl %edx,12(%eax) \n\t" +- "movl %esi,16(%eax) \n\t" +- "movl %edi,20(%eax) \n\t" +- "movw %ds,24(%eax) \n\t" +- "movw %es,26(%eax) \n\t" +- "popl %ebx \n\t" +- "movl %ebx,(%eax) \n\t" +- "popl %ebx \n\t" +- "movl %ebx,28(%eax) \n\t" +- "pop %es \n\t" +- "popf \n\t" +- "popa \n\t" +- "leave \n\t" +- "ret \n\t" +- ".previous"); +- +- +-/* +- * cru_detect +- * +- * Routine Description: +- * This function uses the 32-bit BIOS Service Directory record to +- * search for a $CRU record. +- * +- * Return Value: +- * 0 : SUCCESS +- * <0 : FAILURE +- */ +-static int cru_detect(unsigned long map_entry, +- unsigned long map_offset) +-{ +- void *bios32_map; +- unsigned long *bios32_entrypoint; +- unsigned long cru_physical_address; +- unsigned long cru_length; +- unsigned long physical_bios_base = 0; +- unsigned long physical_bios_offset = 0; +- int retval = -ENODEV; +- +- bios32_map = ioremap(map_entry, (2 * PAGE_SIZE)); +- +- if (bios32_map == NULL) +- return -ENODEV; +- +- bios32_entrypoint = bios32_map + map_offset; +- +- cmn_regs.u1.reax = CRU_BIOS_SIGNATURE_VALUE; +- +- set_memory_x((unsigned long)bios32_map, 2); +- asminline_call(&cmn_regs, bios32_entrypoint); +- +- if (cmn_regs.u1.ral != 0) { +- pr_warn("Call succeeded but with an error: 0x%x\n", +- cmn_regs.u1.ral); +- } else { +- physical_bios_base = cmn_regs.u2.rebx; +- physical_bios_offset = cmn_regs.u4.redx; +- cru_length = cmn_regs.u3.recx; +- cru_physical_address = +- physical_bios_base + physical_bios_offset; +- +- /* If the values look OK, then map it in. */ +- if ((physical_bios_base + physical_bios_offset)) { +- cru_rom_addr = +- ioremap(cru_physical_address, cru_length); +- if (cru_rom_addr) { +- set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK, +- (cru_length + PAGE_SIZE - 1) >> PAGE_SHIFT); +- retval = 0; +- } +- } +- +- pr_debug("CRU Base Address: 0x%lx\n", physical_bios_base); +- pr_debug("CRU Offset Address: 0x%lx\n", physical_bios_offset); +- pr_debug("CRU Length: 0x%lx\n", cru_length); +- pr_debug("CRU Mapped Address: %p\n", &cru_rom_addr); +- } +- iounmap(bios32_map); +- return retval; +-} +- +-/* +- * bios_checksum +- */ +-static int bios_checksum(const char __iomem *ptr, int len) +-{ +- char sum = 0; +- int i; +- +- /* +- * calculate checksum of size bytes. This should add up +- * to zero if we have a valid header. +- */ +- for (i = 0; i < len; i++) +- sum += ptr[i]; +- +- return ((sum == 0) && (len > 0)); +-} +- +-/* +- * bios32_present +- * +- * Routine Description: +- * This function finds the 32-bit BIOS Service Directory +- * +- * Return Value: +- * 0 : SUCCESS +- * <0 : FAILURE +- */ +-static int bios32_present(const char __iomem *p) +-{ +- struct bios32_service_dir *bios_32_ptr; +- int length; +- unsigned long map_entry, map_offset; +- +- bios_32_ptr = (struct bios32_service_dir *) p; +- +- /* +- * Search for signature by checking equal to the swizzled value +- * instead of calling another routine to perform a strcmp. +- */ +- if (bios_32_ptr->signature == PCI_BIOS32_SD_VALUE) { +- length = bios_32_ptr->length * PCI_BIOS32_PARAGRAPH_LEN; +- if (bios_checksum(p, length)) { +- /* +- * According to the spec, we're looking for the +- * first 4KB-aligned address below the entrypoint +- * listed in the header. The Service Directory code +- * is guaranteed to occupy no more than 2 4KB pages. +- */ +- map_entry = bios_32_ptr->entry_point & ~(PAGE_SIZE - 1); +- map_offset = bios_32_ptr->entry_point - map_entry; +- +- return cru_detect(map_entry, map_offset); +- } +- } +- return -ENODEV; +-} +- +-static int detect_cru_service(void) +-{ +- char __iomem *p, *q; +- int rc = -1; +- +- /* +- * Search from 0x0f0000 through 0x0fffff, inclusive. +- */ +- p = ioremap(PCI_ROM_BASE1, ROM_SIZE); +- if (p == NULL) +- return -ENOMEM; +- +- for (q = p; q < p + ROM_SIZE; q += 16) { +- rc = bios32_present(q); +- if (!rc) +- break; +- } +- iounmap(p); +- return rc; +-} +-/* ------------------------------------------------------------------------- */ +-#endif /* CONFIG_X86_32 */ +-#ifdef CONFIG_X86_64 +-/* --64 Bit Bios------------------------------------------------------------ */ +- +-#define HPWDT_ARCH 64 +- +-asm(".text \n\t" +- ".align 4 \n\t" +- ".globl asminline_call \n\t" +- ".type asminline_call, @function \n\t" +- "asminline_call: \n\t" +- FRAME_BEGIN +- "pushq %rax \n\t" +- "pushq %rbx \n\t" +- "pushq %rdx \n\t" +- "pushq %r12 \n\t" +- "pushq %r9 \n\t" +- "movq %rsi, %r12 \n\t" +- "movq %rdi, %r9 \n\t" +- "movl 4(%r9),%ebx \n\t" +- "movl 8(%r9),%ecx \n\t" +- "movl 12(%r9),%edx \n\t" +- "movl 16(%r9),%esi \n\t" +- "movl 20(%r9),%edi \n\t" +- "movl (%r9),%eax \n\t" +- "call *%r12 \n\t" +- "pushfq \n\t" +- "popq %r12 \n\t" +- "movl %eax, (%r9) \n\t" +- "movl %ebx, 4(%r9) \n\t" +- "movl %ecx, 8(%r9) \n\t" +- "movl %edx, 12(%r9) \n\t" +- "movl %esi, 16(%r9) \n\t" +- "movl %edi, 20(%r9) \n\t" +- "movq %r12, %rax \n\t" +- "movl %eax, 28(%r9) \n\t" +- "popq %r9 \n\t" +- "popq %r12 \n\t" +- "popq %rdx \n\t" +- "popq %rbx \n\t" +- "popq %rax \n\t" +- FRAME_END +- "ret \n\t" +- ".previous"); +- +-/* +- * dmi_find_cru +- * +- * Routine Description: +- * This function checks whether or not a SMBIOS/DMI record is +- * the 64bit CRU info or not +- */ +-static void dmi_find_cru(const struct dmi_header *dm, void *dummy) +-{ +- struct smbios_cru64_info *smbios_cru64_ptr; +- unsigned long cru_physical_address; +- +- if (dm->type == SMBIOS_CRU64_INFORMATION) { +- smbios_cru64_ptr = (struct smbios_cru64_info *) dm; +- if (smbios_cru64_ptr->signature == CRU_BIOS_SIGNATURE_VALUE) { +- cru_physical_address = +- smbios_cru64_ptr->physical_address + +- smbios_cru64_ptr->double_offset; +- cru_rom_addr = ioremap(cru_physical_address, +- smbios_cru64_ptr->double_length); +- set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK, +- smbios_cru64_ptr->double_length >> PAGE_SHIFT); +- } +- } +-} +- +-static int detect_cru_service(void) +-{ +- cru_rom_addr = NULL; +- +- dmi_walk(dmi_find_cru, NULL); +- +- /* if cru_rom_addr has been set then we found a CRU service */ +- return ((cru_rom_addr != NULL) ? 0 : -ENODEV); +-} +-/* ------------------------------------------------------------------------- */ +-#endif /* CONFIG_X86_64 */ +-#endif /* CONFIG_HPWDT_NMI_DECODING */ + + /* + * Watchdog operations +@@ -486,30 +113,12 @@ static int hpwdt_my_nmi(void) + */ + static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) + { +- unsigned long rom_pl; +- static int die_nmi_called; +- +- if (!hpwdt_nmi_decoding) +- return NMI_DONE; +- + if ((ulReason == NMI_UNKNOWN) && !hpwdt_my_nmi()) + return NMI_DONE; + +- spin_lock_irqsave(&rom_lock, rom_pl); +- if (!die_nmi_called && !is_icru && !is_uefi) +- asminline_call(&cmn_regs, cru_rom_addr); +- die_nmi_called = 1; +- spin_unlock_irqrestore(&rom_lock, rom_pl); +- + if (allow_kdump) + hpwdt_stop(); + +- if (!is_icru && !is_uefi) { +- if (cmn_regs.u1.ral == 0) { +- nmi_panic(regs, "An NMI occurred, but unable to determine source.\n"); +- return NMI_HANDLED; +- } +- } + nmi_panic(regs, "An NMI occurred. Depending on your system the reason " + "for the NMI is logged in any one of the following " + "resources:\n" +@@ -675,84 +284,11 @@ static struct miscdevice hpwdt_miscdev = { + * Init & Exit + */ + +-#ifdef CONFIG_HPWDT_NMI_DECODING +-#ifdef CONFIG_X86_LOCAL_APIC +-static void hpwdt_check_nmi_decoding(struct pci_dev *dev) +-{ +- /* +- * If nmi_watchdog is turned off then we can turn on +- * our nmi decoding capability. +- */ +- hpwdt_nmi_decoding = 1; +-} +-#else +-static void hpwdt_check_nmi_decoding(struct pci_dev *dev) +-{ +- dev_warn(&dev->dev, "NMI decoding is disabled. " +- "Your kernel does not support a NMI Watchdog.\n"); +-} +-#endif /* CONFIG_X86_LOCAL_APIC */ +- +-/* +- * dmi_find_icru +- * +- * Routine Description: +- * This function checks whether or not we are on an iCRU-based server. +- * This check is independent of architecture and needs to be made for +- * any ProLiant system. +- */ +-static void dmi_find_icru(const struct dmi_header *dm, void *dummy) +-{ +- struct smbios_proliant_info *smbios_proliant_ptr; +- +- if (dm->type == SMBIOS_ICRU_INFORMATION) { +- smbios_proliant_ptr = (struct smbios_proliant_info *) dm; +- if (smbios_proliant_ptr->misc_features & 0x01) +- is_icru = 1; +- if (smbios_proliant_ptr->misc_features & 0x1400) +- is_uefi = 1; +- } +-} + + static int hpwdt_init_nmi_decoding(struct pci_dev *dev) + { ++#ifdef CONFIG_HPWDT_NMI_DECODING + int retval; +- +- /* +- * On typical CRU-based systems we need to map that service in +- * the BIOS. For 32 bit Operating Systems we need to go through +- * the 32 Bit BIOS Service Directory. For 64 bit Operating +- * Systems we get that service through SMBIOS. +- * +- * On systems that support the new iCRU service all we need to +- * do is call dmi_walk to get the supported flag value and skip +- * the old cru detect code. +- */ +- dmi_walk(dmi_find_icru, NULL); +- if (!is_icru && !is_uefi) { +- +- /* +- * We need to map the ROM to get the CRU service. +- * For 32 bit Operating Systems we need to go through the 32 Bit +- * BIOS Service Directory +- * For 64 bit Operating Systems we get that service through SMBIOS. +- */ +- retval = detect_cru_service(); +- if (retval < 0) { +- dev_warn(&dev->dev, +- "Unable to detect the %d Bit CRU Service.\n", +- HPWDT_ARCH); +- return retval; +- } +- +- /* +- * We know this is the only CRU call we need to make so lets keep as +- * few instructions as possible once the NMI comes in. +- */ +- cmn_regs.u1.rah = 0x0D; +- cmn_regs.u1.ral = 0x02; +- } +- + /* + * Only one function can register for NMI_UNKNOWN + */ +@@ -780,45 +316,26 @@ static int hpwdt_init_nmi_decoding(struct pci_dev *dev) + dev_warn(&dev->dev, + "Unable to register a die notifier (err=%d).\n", + retval); +- if (cru_rom_addr) +- iounmap(cru_rom_addr); + return retval; ++#endif /* CONFIG_HPWDT_NMI_DECODING */ ++ return 0; + } + + static void hpwdt_exit_nmi_decoding(void) + { ++#ifdef CONFIG_HPWDT_NMI_DECODING + unregister_nmi_handler(NMI_UNKNOWN, "hpwdt"); + unregister_nmi_handler(NMI_SERR, "hpwdt"); + unregister_nmi_handler(NMI_IO_CHECK, "hpwdt"); +- if (cru_rom_addr) +- iounmap(cru_rom_addr); +-} +-#else /* !CONFIG_HPWDT_NMI_DECODING */ +-static void hpwdt_check_nmi_decoding(struct pci_dev *dev) +-{ +-} +- +-static int hpwdt_init_nmi_decoding(struct pci_dev *dev) +-{ +- return 0; ++#endif + } + +-static void hpwdt_exit_nmi_decoding(void) +-{ +-} +-#endif /* CONFIG_HPWDT_NMI_DECODING */ +- + static int hpwdt_init_one(struct pci_dev *dev, + const struct pci_device_id *ent) + { + int retval; + + /* +- * Check if we can do NMI decoding or not +- */ +- hpwdt_check_nmi_decoding(dev); +- +- /* + * First let's find out if we are on an iLO2+ server. We will + * not run on a legacy ASM box. + * So we only support the G5 ProLiant servers and higher. +@@ -922,6 +439,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + #ifdef CONFIG_HPWDT_NMI_DECODING + module_param(allow_kdump, int, 0); + MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs"); +-#endif /* !CONFIG_HPWDT_NMI_DECODING */ ++#endif /* CONFIG_HPWDT_NMI_DECODING */ + + module_pci_driver(hpwdt_driver); +diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c +index 316c2eb..e8bd988 100644 +--- a/drivers/watchdog/sbsa_gwdt.c ++++ b/drivers/watchdog/sbsa_gwdt.c +@@ -50,6 +50,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -159,7 +160,7 @@ static unsigned int sbsa_gwdt_get_timeleft(struct watchdog_device *wdd) + !(readl(gwdt->control_base + SBSA_GWDT_WCS) & SBSA_GWDT_WCS_WS0)) + timeleft += readl(gwdt->control_base + SBSA_GWDT_WOR); + +- timeleft += readq(gwdt->control_base + SBSA_GWDT_WCV) - ++ timeleft += lo_hi_readq(gwdt->control_base + SBSA_GWDT_WCV) - + arch_counter_get_cntvct(); + + do_div(timeleft, gwdt->clk); +diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c +index 1ab4bd1..762378f 100644 +--- a/drivers/xen/events/events_base.c ++++ b/drivers/xen/events/events_base.c +@@ -755,8 +755,8 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, + mutex_unlock(&irq_mapping_update_lock); + return irq; + error_irq: +- for (; i >= 0; i--) +- __unbind_from_irq(irq + i); ++ while (nvec--) ++ __unbind_from_irq(irq + nvec); + mutex_unlock(&irq_mapping_update_lock); + return ret; + } +diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c +index 156e5ae..b1092fb 100644 +--- a/drivers/xen/pvcalls-back.c ++++ b/drivers/xen/pvcalls-back.c +@@ -416,7 +416,7 @@ static int pvcalls_back_connect(struct xenbus_device *dev, + sock); + if (!map) { + ret = -EFAULT; +- sock_release(map->sock); ++ sock_release(sock); + } + + out: +diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c +index 753d9cb..2f11ca7 100644 +--- a/drivers/xen/pvcalls-front.c ++++ b/drivers/xen/pvcalls-front.c +@@ -60,6 +60,7 @@ struct sock_mapping { + bool active_socket; + struct list_head list; + struct socket *sock; ++ atomic_t refcount; + union { + struct { + int irq; +@@ -72,20 +73,25 @@ struct sock_mapping { + wait_queue_head_t inflight_conn_req; + } active; + struct { +- /* Socket status */ ++ /* ++ * Socket status, needs to be 64-bit aligned due to the ++ * test_and_* functions which have this requirement on arm64. ++ */ + #define PVCALLS_STATUS_UNINITALIZED 0 + #define PVCALLS_STATUS_BIND 1 + #define PVCALLS_STATUS_LISTEN 2 +- uint8_t status; ++ uint8_t status __attribute__((aligned(8))); + /* + * Internal state-machine flags. + * Only one accept operation can be inflight for a socket. + * Only one poll operation can be inflight for a given socket. ++ * flags needs to be 64-bit aligned due to the test_and_* ++ * functions which have this requirement on arm64. + */ + #define PVCALLS_FLAG_ACCEPT_INFLIGHT 0 + #define PVCALLS_FLAG_POLL_INFLIGHT 1 + #define PVCALLS_FLAG_POLL_RET 2 +- uint8_t flags; ++ uint8_t flags __attribute__((aligned(8))); + uint32_t inflight_req_id; + struct sock_mapping *accept_map; + wait_queue_head_t inflight_accept_req; +@@ -93,6 +99,32 @@ struct sock_mapping { + }; + }; + ++static inline struct sock_mapping *pvcalls_enter_sock(struct socket *sock) ++{ ++ struct sock_mapping *map; ++ ++ if (!pvcalls_front_dev || ++ dev_get_drvdata(&pvcalls_front_dev->dev) == NULL) ++ return ERR_PTR(-ENOTCONN); ++ ++ map = (struct sock_mapping *)sock->sk->sk_send_head; ++ if (map == NULL) ++ return ERR_PTR(-ENOTSOCK); ++ ++ pvcalls_enter(); ++ atomic_inc(&map->refcount); ++ return map; ++} ++ ++static inline void pvcalls_exit_sock(struct socket *sock) ++{ ++ struct sock_mapping *map; ++ ++ map = (struct sock_mapping *)sock->sk->sk_send_head; ++ atomic_dec(&map->refcount); ++ pvcalls_exit(); ++} ++ + static inline int get_request(struct pvcalls_bedata *bedata, int *req_id) + { + *req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1); +@@ -369,31 +401,23 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr, + if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM) + return -EOPNOTSUPP; + +- pvcalls_enter(); +- if (!pvcalls_front_dev) { +- pvcalls_exit(); +- return -ENOTCONN; +- } ++ map = pvcalls_enter_sock(sock); ++ if (IS_ERR(map)) ++ return PTR_ERR(map); + + bedata = dev_get_drvdata(&pvcalls_front_dev->dev); + +- map = (struct sock_mapping *)sock->sk->sk_send_head; +- if (!map) { +- pvcalls_exit(); +- return -ENOTSOCK; +- } +- + spin_lock(&bedata->socket_lock); + ret = get_request(bedata, &req_id); + if (ret < 0) { + spin_unlock(&bedata->socket_lock); +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return ret; + } + ret = create_active(map, &evtchn); + if (ret < 0) { + spin_unlock(&bedata->socket_lock); +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return ret; + } + +@@ -423,7 +447,7 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr, + smp_rmb(); + ret = bedata->rsp[req_id].ret; + bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return ret; + } + +@@ -488,23 +512,15 @@ int pvcalls_front_sendmsg(struct socket *sock, struct msghdr *msg, + if (flags & (MSG_CONFIRM|MSG_DONTROUTE|MSG_EOR|MSG_OOB)) + return -EOPNOTSUPP; + +- pvcalls_enter(); +- if (!pvcalls_front_dev) { +- pvcalls_exit(); +- return -ENOTCONN; +- } ++ map = pvcalls_enter_sock(sock); ++ if (IS_ERR(map)) ++ return PTR_ERR(map); + bedata = dev_get_drvdata(&pvcalls_front_dev->dev); + +- map = (struct sock_mapping *) sock->sk->sk_send_head; +- if (!map) { +- pvcalls_exit(); +- return -ENOTSOCK; +- } +- + mutex_lock(&map->active.out_mutex); + if ((flags & MSG_DONTWAIT) && !pvcalls_front_write_todo(map)) { + mutex_unlock(&map->active.out_mutex); +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return -EAGAIN; + } + if (len > INT_MAX) +@@ -526,7 +542,7 @@ int pvcalls_front_sendmsg(struct socket *sock, struct msghdr *msg, + tot_sent = sent; + + mutex_unlock(&map->active.out_mutex); +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return tot_sent; + } + +@@ -591,19 +607,11 @@ int pvcalls_front_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, + if (flags & (MSG_CMSG_CLOEXEC|MSG_ERRQUEUE|MSG_OOB|MSG_TRUNC)) + return -EOPNOTSUPP; + +- pvcalls_enter(); +- if (!pvcalls_front_dev) { +- pvcalls_exit(); +- return -ENOTCONN; +- } ++ map = pvcalls_enter_sock(sock); ++ if (IS_ERR(map)) ++ return PTR_ERR(map); + bedata = dev_get_drvdata(&pvcalls_front_dev->dev); + +- map = (struct sock_mapping *) sock->sk->sk_send_head; +- if (!map) { +- pvcalls_exit(); +- return -ENOTSOCK; +- } +- + mutex_lock(&map->active.in_mutex); + if (len > XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER)) + len = XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER); +@@ -623,7 +631,7 @@ int pvcalls_front_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, + ret = 0; + + mutex_unlock(&map->active.in_mutex); +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return ret; + } + +@@ -637,24 +645,16 @@ int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len) + if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM) + return -EOPNOTSUPP; + +- pvcalls_enter(); +- if (!pvcalls_front_dev) { +- pvcalls_exit(); +- return -ENOTCONN; +- } ++ map = pvcalls_enter_sock(sock); ++ if (IS_ERR(map)) ++ return PTR_ERR(map); + bedata = dev_get_drvdata(&pvcalls_front_dev->dev); + +- map = (struct sock_mapping *) sock->sk->sk_send_head; +- if (map == NULL) { +- pvcalls_exit(); +- return -ENOTSOCK; +- } +- + spin_lock(&bedata->socket_lock); + ret = get_request(bedata, &req_id); + if (ret < 0) { + spin_unlock(&bedata->socket_lock); +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return ret; + } + req = RING_GET_REQUEST(&bedata->ring, req_id); +@@ -684,7 +684,7 @@ int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len) + bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; + + map->passive.status = PVCALLS_STATUS_BIND; +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return 0; + } + +@@ -695,21 +695,13 @@ int pvcalls_front_listen(struct socket *sock, int backlog) + struct xen_pvcalls_request *req; + int notify, req_id, ret; + +- pvcalls_enter(); +- if (!pvcalls_front_dev) { +- pvcalls_exit(); +- return -ENOTCONN; +- } ++ map = pvcalls_enter_sock(sock); ++ if (IS_ERR(map)) ++ return PTR_ERR(map); + bedata = dev_get_drvdata(&pvcalls_front_dev->dev); + +- map = (struct sock_mapping *) sock->sk->sk_send_head; +- if (!map) { +- pvcalls_exit(); +- return -ENOTSOCK; +- } +- + if (map->passive.status != PVCALLS_STATUS_BIND) { +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return -EOPNOTSUPP; + } + +@@ -717,7 +709,7 @@ int pvcalls_front_listen(struct socket *sock, int backlog) + ret = get_request(bedata, &req_id); + if (ret < 0) { + spin_unlock(&bedata->socket_lock); +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return ret; + } + req = RING_GET_REQUEST(&bedata->ring, req_id); +@@ -741,7 +733,7 @@ int pvcalls_front_listen(struct socket *sock, int backlog) + bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; + + map->passive.status = PVCALLS_STATUS_LISTEN; +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return ret; + } + +@@ -753,21 +745,13 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) + struct xen_pvcalls_request *req; + int notify, req_id, ret, evtchn, nonblock; + +- pvcalls_enter(); +- if (!pvcalls_front_dev) { +- pvcalls_exit(); +- return -ENOTCONN; +- } ++ map = pvcalls_enter_sock(sock); ++ if (IS_ERR(map)) ++ return PTR_ERR(map); + bedata = dev_get_drvdata(&pvcalls_front_dev->dev); + +- map = (struct sock_mapping *) sock->sk->sk_send_head; +- if (!map) { +- pvcalls_exit(); +- return -ENOTSOCK; +- } +- + if (map->passive.status != PVCALLS_STATUS_LISTEN) { +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return -EINVAL; + } + +@@ -785,13 +769,13 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) + goto received; + } + if (nonblock) { +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return -EAGAIN; + } + if (wait_event_interruptible(map->passive.inflight_accept_req, + !test_and_set_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, + (void *)&map->passive.flags))) { +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return -EINTR; + } + } +@@ -802,7 +786,7 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, + (void *)&map->passive.flags); + spin_unlock(&bedata->socket_lock); +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return ret; + } + map2 = kzalloc(sizeof(*map2), GFP_ATOMIC); +@@ -810,7 +794,7 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, + (void *)&map->passive.flags); + spin_unlock(&bedata->socket_lock); +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return -ENOMEM; + } + ret = create_active(map2, &evtchn); +@@ -819,7 +803,7 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, + (void *)&map->passive.flags); + spin_unlock(&bedata->socket_lock); +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return ret; + } + list_add_tail(&map2->list, &bedata->socket_mappings); +@@ -841,13 +825,13 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) + /* We could check if we have received a response before returning. */ + if (nonblock) { + WRITE_ONCE(map->passive.inflight_req_id, req_id); +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return -EAGAIN; + } + + if (wait_event_interruptible(bedata->inflight_req, + READ_ONCE(bedata->rsp[req_id].req_id) == req_id)) { +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return -EINTR; + } + /* read req_id, then the content */ +@@ -862,7 +846,7 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, + (void *)&map->passive.flags); + pvcalls_front_free_map(bedata, map2); +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return -ENOMEM; + } + newsock->sk->sk_send_head = (void *)map2; +@@ -874,7 +858,7 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags); + wake_up(&map->passive.inflight_accept_req); + +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return ret; + } + +@@ -965,23 +949,16 @@ __poll_t pvcalls_front_poll(struct file *file, struct socket *sock, + struct sock_mapping *map; + __poll_t ret; + +- pvcalls_enter(); +- if (!pvcalls_front_dev) { +- pvcalls_exit(); ++ map = pvcalls_enter_sock(sock); ++ if (IS_ERR(map)) + return EPOLLNVAL; +- } + bedata = dev_get_drvdata(&pvcalls_front_dev->dev); + +- map = (struct sock_mapping *) sock->sk->sk_send_head; +- if (!map) { +- pvcalls_exit(); +- return EPOLLNVAL; +- } + if (map->active_socket) + ret = pvcalls_front_poll_active(file, bedata, map, wait); + else + ret = pvcalls_front_poll_passive(file, bedata, map, wait); +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return ret; + } + +@@ -995,25 +972,20 @@ int pvcalls_front_release(struct socket *sock) + if (sock->sk == NULL) + return 0; + +- pvcalls_enter(); +- if (!pvcalls_front_dev) { +- pvcalls_exit(); +- return -EIO; ++ map = pvcalls_enter_sock(sock); ++ if (IS_ERR(map)) { ++ if (PTR_ERR(map) == -ENOTCONN) ++ return -EIO; ++ else ++ return 0; + } +- + bedata = dev_get_drvdata(&pvcalls_front_dev->dev); + +- map = (struct sock_mapping *) sock->sk->sk_send_head; +- if (map == NULL) { +- pvcalls_exit(); +- return 0; +- } +- + spin_lock(&bedata->socket_lock); + ret = get_request(bedata, &req_id); + if (ret < 0) { + spin_unlock(&bedata->socket_lock); +- pvcalls_exit(); ++ pvcalls_exit_sock(sock); + return ret; + } + sock->sk->sk_send_head = NULL; +@@ -1043,14 +1015,20 @@ int pvcalls_front_release(struct socket *sock) + /* + * We need to make sure that sendmsg/recvmsg on this socket have + * not started before we've cleared sk_send_head here. The +- * easiest (though not optimal) way to guarantee this is to see +- * that no pvcall (other than us) is in progress. ++ * easiest way to guarantee this is to see that no pvcalls ++ * (other than us) is in progress on this socket. + */ +- while (atomic_read(&pvcalls_refcount) > 1) ++ while (atomic_read(&map->refcount) > 1) + cpu_relax(); + + pvcalls_front_free_map(bedata, map); + } else { ++ wake_up(&bedata->inflight_req); ++ wake_up(&map->passive.inflight_accept_req); ++ ++ while (atomic_read(&map->refcount) > 1) ++ cpu_relax(); ++ + spin_lock(&bedata->socket_lock); + list_del(&map->list); + spin_unlock(&bedata->socket_lock); +diff --git a/drivers/xen/tmem.c b/drivers/xen/tmem.c +index bf13d1e..04e7b3b 100644 +--- a/drivers/xen/tmem.c ++++ b/drivers/xen/tmem.c +@@ -284,6 +284,10 @@ static int tmem_frontswap_store(unsigned type, pgoff_t offset, + int pool = tmem_frontswap_poolid; + int ret; + ++ /* THP isn't supported */ ++ if (PageTransHuge(page)) ++ return -1; ++ + if (pool < 0) + return -1; + if (ind64 != ind) +diff --git a/drivers/xen/xenbus/xenbus.h b/drivers/xen/xenbus/xenbus.h +index 149c5e7..0929811 100644 +--- a/drivers/xen/xenbus/xenbus.h ++++ b/drivers/xen/xenbus/xenbus.h +@@ -76,6 +76,7 @@ struct xb_req_data { + struct list_head list; + wait_queue_head_t wq; + struct xsd_sockmsg msg; ++ uint32_t caller_req_id; + enum xsd_sockmsg_type type; + char *body; + const struct kvec *vec; +diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c +index 5b081a0..d239fc3 100644 +--- a/drivers/xen/xenbus/xenbus_comms.c ++++ b/drivers/xen/xenbus/xenbus_comms.c +@@ -309,6 +309,7 @@ static int process_msg(void) + goto out; + + if (req->state == xb_req_state_wait_reply) { ++ req->msg.req_id = req->caller_req_id; + req->msg.type = state.msg.type; + req->msg.len = state.msg.len; + req->body = state.body; +diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c +index 74888ca..ec9eb4f 100644 +--- a/drivers/xen/xenbus/xenbus_probe.c ++++ b/drivers/xen/xenbus/xenbus_probe.c +@@ -466,8 +466,11 @@ int xenbus_probe_node(struct xen_bus_type *bus, + + /* Register with generic device framework. */ + err = device_register(&xendev->dev); +- if (err) ++ if (err) { ++ put_device(&xendev->dev); ++ xendev = NULL; + goto fail; ++ } + + return 0; + fail: +diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c +index 3e59590..3f3b293 100644 +--- a/drivers/xen/xenbus/xenbus_xs.c ++++ b/drivers/xen/xenbus/xenbus_xs.c +@@ -227,6 +227,8 @@ static void xs_send(struct xb_req_data *req, struct xsd_sockmsg *msg) + req->state = xb_req_state_queued; + init_waitqueue_head(&req->wq); + ++ /* Save the caller req_id and restore it later in the reply */ ++ req->caller_req_id = req->msg.req_id; + req->msg.req_id = xs_request_enter(req); + + mutex_lock(&xb_write_mutex); +@@ -310,6 +312,7 @@ static void *xs_talkv(struct xenbus_transaction t, + req->num_vecs = num_vecs; + req->cb = xs_wake_up; + ++ msg.req_id = 0; + msg.tx_id = t.id; + msg.type = type; + msg.len = 0; +diff --git a/fs/block_dev.c b/fs/block_dev.c +index 4a181fc..fe09ef9 100644 +--- a/fs/block_dev.c ++++ b/fs/block_dev.c +@@ -1058,6 +1058,27 @@ static int bd_prepare_to_claim(struct block_device *bdev, + return 0; + } + ++static struct gendisk *bdev_get_gendisk(struct block_device *bdev, int *partno) ++{ ++ struct gendisk *disk = get_gendisk(bdev->bd_dev, partno); ++ ++ if (!disk) ++ return NULL; ++ /* ++ * Now that we hold gendisk reference we make sure bdev we looked up is ++ * not stale. If it is, it means device got removed and created before ++ * we looked up gendisk and we fail open in such case. Associating ++ * unhashed bdev with newly created gendisk could lead to two bdevs ++ * (and thus two independent caches) being associated with one device ++ * which is bad. ++ */ ++ if (inode_unhashed(bdev->bd_inode)) { ++ put_disk_and_module(disk); ++ return NULL; ++ } ++ return disk; ++} ++ + /** + * bd_start_claiming - start claiming a block device + * @bdev: block device of interest +@@ -1094,7 +1115,7 @@ static struct block_device *bd_start_claiming(struct block_device *bdev, + * @bdev might not have been initialized properly yet, look up + * and grab the outer block device the hard way. + */ +- disk = get_gendisk(bdev->bd_dev, &partno); ++ disk = bdev_get_gendisk(bdev, &partno); + if (!disk) + return ERR_PTR(-ENXIO); + +@@ -1111,8 +1132,7 @@ static struct block_device *bd_start_claiming(struct block_device *bdev, + else + whole = bdgrab(bdev); + +- module_put(disk->fops->owner); +- put_disk(disk); ++ put_disk_and_module(disk); + if (!whole) + return ERR_PTR(-ENOMEM); + +@@ -1407,10 +1427,10 @@ static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part); + static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) + { + struct gendisk *disk; +- struct module *owner; + int ret; + int partno; + int perm = 0; ++ bool first_open = false; + + if (mode & FMODE_READ) + perm |= MAY_READ; +@@ -1430,14 +1450,14 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) + restart: + + ret = -ENXIO; +- disk = get_gendisk(bdev->bd_dev, &partno); ++ disk = bdev_get_gendisk(bdev, &partno); + if (!disk) + goto out; +- owner = disk->fops->owner; + + disk_block_events(disk); + mutex_lock_nested(&bdev->bd_mutex, for_part); + if (!bdev->bd_openers) { ++ first_open = true; + bdev->bd_disk = disk; + bdev->bd_queue = disk->queue; + bdev->bd_contains = bdev; +@@ -1463,8 +1483,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) + bdev->bd_queue = NULL; + mutex_unlock(&bdev->bd_mutex); + disk_unblock_events(disk); +- put_disk(disk); +- module_put(owner); ++ put_disk_and_module(disk); + goto restart; + } + } +@@ -1524,15 +1543,15 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) + if (ret) + goto out_unlock_bdev; + } +- /* only one opener holds refs to the module and disk */ +- put_disk(disk); +- module_put(owner); + } + bdev->bd_openers++; + if (for_part) + bdev->bd_part_count++; + mutex_unlock(&bdev->bd_mutex); + disk_unblock_events(disk); ++ /* only one opener holds refs to the module and disk */ ++ if (!first_open) ++ put_disk_and_module(disk); + return 0; + + out_clear: +@@ -1546,8 +1565,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) + out_unlock_bdev: + mutex_unlock(&bdev->bd_mutex); + disk_unblock_events(disk); +- put_disk(disk); +- module_put(owner); ++ put_disk_and_module(disk); + out: + bdput(bdev); + +@@ -1770,8 +1788,6 @@ static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) + disk->fops->release(disk, mode); + } + if (!bdev->bd_openers) { +- struct module *owner = disk->fops->owner; +- + disk_put_part(bdev->bd_part); + bdev->bd_part = NULL; + bdev->bd_disk = NULL; +@@ -1779,8 +1795,7 @@ static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) + victim = bdev->bd_contains; + bdev->bd_contains = NULL; + +- put_disk(disk); +- module_put(owner); ++ put_disk_and_module(disk); + } + mutex_unlock(&bdev->bd_mutex); + bdput(bdev); +diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c +index e4054e5..f94b2d8 100644 +--- a/fs/btrfs/backref.c ++++ b/fs/btrfs/backref.c +@@ -1264,7 +1264,16 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, + while (node) { + ref = rb_entry(node, struct prelim_ref, rbnode); + node = rb_next(&ref->rbnode); +- WARN_ON(ref->count < 0); ++ /* ++ * ref->count < 0 can happen here if there are delayed ++ * refs with a node->action of BTRFS_DROP_DELAYED_REF. ++ * prelim_ref_insert() relies on this when merging ++ * identical refs to keep the overall count correct. ++ * prelim_ref_insert() will merge only those refs ++ * which compare identically. Any refs having ++ * e.g. different offsets would not be merged, ++ * and would retain their original ref->count < 0. ++ */ + if (roots && ref->count && ref->root_id && ref->parent == 0) { + if (sc && sc->root_objectid && + ref->root_id != sc->root_objectid) { +diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h +index 1a462ab..da30877 100644 +--- a/fs/btrfs/ctree.h ++++ b/fs/btrfs/ctree.h +@@ -2974,7 +2974,7 @@ static inline void free_fs_info(struct btrfs_fs_info *fs_info) + kfree(fs_info->super_copy); + kfree(fs_info->super_for_commit); + security_free_mnt_opts(&fs_info->security_opts); +- kfree(fs_info); ++ kvfree(fs_info); + } + + /* tree mod log functions from ctree.c */ +@@ -3095,7 +3095,10 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans, + u64 inode_objectid, u64 ref_objectid, int ins_len, + int cow); + +-int btrfs_find_name_in_ext_backref(struct btrfs_path *path, ++int btrfs_find_name_in_backref(struct extent_buffer *leaf, int slot, ++ const char *name, ++ int name_len, struct btrfs_inode_ref **ref_ret); ++int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot, + u64 ref_objectid, const char *name, + int name_len, + struct btrfs_inode_extref **extref_ret); +diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c +index a1a40cf..7ab5e01 100644 +--- a/fs/btrfs/delayed-ref.c ++++ b/fs/btrfs/delayed-ref.c +@@ -821,7 +821,8 @@ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info, + spin_unlock(&delayed_refs->lock); + + if (qrecord_inserted) +- return btrfs_qgroup_trace_extent_post(fs_info, record); ++ btrfs_qgroup_trace_extent_post(fs_info, record); ++ + return 0; + + free_head_ref: +diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c +index 05751a6..c1618ab 100644 +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -2147,6 +2147,10 @@ int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr, + u64 bytes; + struct request_queue *req_q; + ++ if (!stripe->dev->bdev) { ++ ASSERT(btrfs_test_opt(fs_info, DEGRADED)); ++ continue; ++ } + req_q = bdev_get_queue(stripe->dev->bdev); + if (!blk_queue_discard(req_q)) + continue; +diff --git a/fs/btrfs/inode-item.c b/fs/btrfs/inode-item.c +index 39c968f..65e1a76 100644 +--- a/fs/btrfs/inode-item.c ++++ b/fs/btrfs/inode-item.c +@@ -22,10 +22,10 @@ + #include "transaction.h" + #include "print-tree.h" + +-static int find_name_in_backref(struct btrfs_path *path, const char *name, +- int name_len, struct btrfs_inode_ref **ref_ret) ++int btrfs_find_name_in_backref(struct extent_buffer *leaf, int slot, ++ const char *name, ++ int name_len, struct btrfs_inode_ref **ref_ret) + { +- struct extent_buffer *leaf; + struct btrfs_inode_ref *ref; + unsigned long ptr; + unsigned long name_ptr; +@@ -33,9 +33,8 @@ static int find_name_in_backref(struct btrfs_path *path, const char *name, + u32 cur_offset = 0; + int len; + +- leaf = path->nodes[0]; +- item_size = btrfs_item_size_nr(leaf, path->slots[0]); +- ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); ++ item_size = btrfs_item_size_nr(leaf, slot); ++ ptr = btrfs_item_ptr_offset(leaf, slot); + while (cur_offset < item_size) { + ref = (struct btrfs_inode_ref *)(ptr + cur_offset); + len = btrfs_inode_ref_name_len(leaf, ref); +@@ -44,18 +43,19 @@ static int find_name_in_backref(struct btrfs_path *path, const char *name, + if (len != name_len) + continue; + if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) { +- *ref_ret = ref; ++ if (ref_ret) ++ *ref_ret = ref; + return 1; + } + } + return 0; + } + +-int btrfs_find_name_in_ext_backref(struct btrfs_path *path, u64 ref_objectid, ++int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot, ++ u64 ref_objectid, + const char *name, int name_len, + struct btrfs_inode_extref **extref_ret) + { +- struct extent_buffer *leaf; + struct btrfs_inode_extref *extref; + unsigned long ptr; + unsigned long name_ptr; +@@ -63,9 +63,8 @@ int btrfs_find_name_in_ext_backref(struct btrfs_path *path, u64 ref_objectid, + u32 cur_offset = 0; + int ref_name_len; + +- leaf = path->nodes[0]; +- item_size = btrfs_item_size_nr(leaf, path->slots[0]); +- ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); ++ item_size = btrfs_item_size_nr(leaf, slot); ++ ptr = btrfs_item_ptr_offset(leaf, slot); + + /* + * Search all extended backrefs in this item. We're only +@@ -113,7 +112,9 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans, + return ERR_PTR(ret); + if (ret > 0) + return NULL; +- if (!btrfs_find_name_in_ext_backref(path, ref_objectid, name, name_len, &extref)) ++ if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], ++ ref_objectid, name, name_len, ++ &extref)) + return NULL; + return extref; + } +@@ -155,7 +156,8 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans, + * This should always succeed so error here will make the FS + * readonly. + */ +- if (!btrfs_find_name_in_ext_backref(path, ref_objectid, ++ if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], ++ ref_objectid, + name, name_len, &extref)) { + btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL); + ret = -EROFS; +@@ -225,7 +227,8 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, + } else if (ret < 0) { + goto out; + } +- if (!find_name_in_backref(path, name, name_len, &ref)) { ++ if (!btrfs_find_name_in_backref(path->nodes[0], path->slots[0], ++ name, name_len, &ref)) { + ret = -ENOENT; + search_ext_refs = 1; + goto out; +@@ -293,7 +296,9 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, + ret = btrfs_insert_empty_item(trans, root, path, &key, + ins_len); + if (ret == -EEXIST) { +- if (btrfs_find_name_in_ext_backref(path, ref_objectid, ++ if (btrfs_find_name_in_ext_backref(path->nodes[0], ++ path->slots[0], ++ ref_objectid, + name, name_len, NULL)) + goto out; + +@@ -351,7 +356,8 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, + if (ret == -EEXIST) { + u32 old_size; + +- if (find_name_in_backref(path, name, name_len, &ref)) ++ if (btrfs_find_name_in_backref(path->nodes[0], path->slots[0], ++ name, name_len, &ref)) + goto out; + + old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); +@@ -365,7 +371,9 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, + ret = 0; + } else if (ret < 0) { + if (ret == -EOVERFLOW) { +- if (find_name_in_backref(path, name, name_len, &ref)) ++ if (btrfs_find_name_in_backref(path->nodes[0], ++ path->slots[0], ++ name, name_len, &ref)) + ret = -EEXIST; + else + ret = -EMLINK; +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index 53ca025..f534701 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -1335,8 +1335,11 @@ static noinline int run_delalloc_nocow(struct inode *inode, + leaf = path->nodes[0]; + if (path->slots[0] >= btrfs_header_nritems(leaf)) { + ret = btrfs_next_leaf(root, path); +- if (ret < 0) ++ if (ret < 0) { ++ if (cow_start != (u64)-1) ++ cur_offset = cow_start; + goto error; ++ } + if (ret > 0) + break; + leaf = path->nodes[0]; +@@ -2040,12 +2043,15 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans, + struct inode *inode, struct list_head *list) + { + struct btrfs_ordered_sum *sum; ++ int ret; + + list_for_each_entry(sum, list, list) { + trans->adding_csums = true; +- btrfs_csum_file_blocks(trans, ++ ret = btrfs_csum_file_blocks(trans, + BTRFS_I(inode)->root->fs_info->csum_root, sum); + trans->adding_csums = false; ++ if (ret) ++ return ret; + } + return 0; + } +@@ -3059,7 +3065,11 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) + goto out; + } + +- add_pending_csums(trans, inode, &ordered_extent->list); ++ ret = add_pending_csums(trans, inode, &ordered_extent->list); ++ if (ret) { ++ btrfs_abort_transaction(trans, ret); ++ goto out; ++ } + + btrfs_ordered_update_i_size(inode, 0, ordered_extent); + ret = btrfs_update_inode_fallback(trans, root, inode); +@@ -3385,6 +3395,11 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, + ret = btrfs_orphan_reserve_metadata(trans, inode); + ASSERT(!ret); + if (ret) { ++ /* ++ * dec doesn't need spin_lock as ->orphan_block_rsv ++ * would be released only if ->orphan_inodes is ++ * zero. ++ */ + atomic_dec(&root->orphan_inodes); + clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED, + &inode->runtime_flags); +@@ -3399,12 +3414,17 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, + if (insert >= 1) { + ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode)); + if (ret) { +- atomic_dec(&root->orphan_inodes); + if (reserve) { + clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED, + &inode->runtime_flags); + btrfs_orphan_release_metadata(inode); + } ++ /* ++ * btrfs_orphan_commit_root may race with us and set ++ * ->orphan_block_rsv to zero, in order to avoid that, ++ * decrease ->orphan_inodes after everything is done. ++ */ ++ atomic_dec(&root->orphan_inodes); + if (ret != -EEXIST) { + clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM, + &inode->runtime_flags); +@@ -3436,28 +3456,26 @@ static int btrfs_orphan_del(struct btrfs_trans_handle *trans, + { + struct btrfs_root *root = inode->root; + int delete_item = 0; +- int release_rsv = 0; + int ret = 0; + +- spin_lock(&root->orphan_lock); + if (test_and_clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM, + &inode->runtime_flags)) + delete_item = 1; + ++ if (delete_item && trans) ++ ret = btrfs_del_orphan_item(trans, root, btrfs_ino(inode)); ++ + if (test_and_clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED, + &inode->runtime_flags)) +- release_rsv = 1; +- spin_unlock(&root->orphan_lock); ++ btrfs_orphan_release_metadata(inode); + +- if (delete_item) { ++ /* ++ * btrfs_orphan_commit_root may race with us and set ->orphan_block_rsv ++ * to zero, in order to avoid that, decrease ->orphan_inodes after ++ * everything is done. ++ */ ++ if (delete_item) + atomic_dec(&root->orphan_inodes); +- if (trans) +- ret = btrfs_del_orphan_item(trans, root, +- btrfs_ino(inode)); +- } +- +- if (release_rsv) +- btrfs_orphan_release_metadata(inode); + + return ret; + } +@@ -5281,7 +5299,7 @@ void btrfs_evict_inode(struct inode *inode) + trace_btrfs_inode_evict(inode); + + if (!root) { +- kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); ++ clear_inode(inode); + return; + } + +diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c +index 9e61dd6..aa259d6 100644 +--- a/fs/btrfs/qgroup.c ++++ b/fs/btrfs/qgroup.c +@@ -1442,8 +1442,13 @@ int btrfs_qgroup_trace_extent_post(struct btrfs_fs_info *fs_info, + int ret; + + ret = btrfs_find_all_roots(NULL, fs_info, bytenr, 0, &old_root, false); +- if (ret < 0) +- return ret; ++ if (ret < 0) { ++ fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; ++ btrfs_warn(fs_info, ++"error accounting new delayed refs extent (err code: %d), quota inconsistent", ++ ret); ++ return 0; ++ } + + /* + * Here we don't need to get the lock of +diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c +index f0c3f00..cd2298d 100644 +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -3268,8 +3268,22 @@ static int relocate_file_extent_cluster(struct inode *inode, + nr++; + } + +- btrfs_set_extent_delalloc(inode, page_start, page_end, 0, NULL, +- 0); ++ ret = btrfs_set_extent_delalloc(inode, page_start, page_end, 0, ++ NULL, 0); ++ if (ret) { ++ unlock_page(page); ++ put_page(page); ++ btrfs_delalloc_release_metadata(BTRFS_I(inode), ++ PAGE_SIZE); ++ btrfs_delalloc_release_extents(BTRFS_I(inode), ++ PAGE_SIZE); ++ ++ clear_extent_bits(&BTRFS_I(inode)->io_tree, ++ page_start, page_end, ++ EXTENT_LOCKED | EXTENT_BOUNDARY); ++ goto out; ++ ++ } + set_page_dirty(page); + + unlock_extent(&BTRFS_I(inode)->io_tree, +diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c +index f306c60..484e2af 100644 +--- a/fs/btrfs/send.c ++++ b/fs/btrfs/send.c +@@ -5005,6 +5005,9 @@ static int send_hole(struct send_ctx *sctx, u64 end) + u64 len; + int ret = 0; + ++ if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA) ++ return send_update_extent(sctx, offset, end - offset); ++ + p = fs_path_alloc(); + if (!p) + return -ENOMEM; +diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c +index 6e71a2a..4b81794 100644 +--- a/fs/btrfs/super.c ++++ b/fs/btrfs/super.c +@@ -1545,7 +1545,7 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type, + * it for searching for existing supers, so this lets us do that and + * then open_ctree will properly initialize everything later. + */ +- fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_KERNEL); ++ fs_info = kvzalloc(sizeof(struct btrfs_fs_info), GFP_KERNEL); + if (!fs_info) { + error = -ENOMEM; + goto error_sec_opts; +diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c +index a8bafed..d11c70b 100644 +--- a/fs/btrfs/sysfs.c ++++ b/fs/btrfs/sysfs.c +@@ -423,7 +423,7 @@ static ssize_t btrfs_nodesize_show(struct kobject *kobj, + { + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + +- return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->nodesize); ++ return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->nodesize); + } + + BTRFS_ATTR(, nodesize, btrfs_nodesize_show); +@@ -433,8 +433,7 @@ static ssize_t btrfs_sectorsize_show(struct kobject *kobj, + { + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + +- return snprintf(buf, PAGE_SIZE, "%u\n", +- fs_info->super_copy->sectorsize); ++ return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->sectorsize); + } + + BTRFS_ATTR(, sectorsize, btrfs_sectorsize_show); +@@ -444,8 +443,7 @@ static ssize_t btrfs_clone_alignment_show(struct kobject *kobj, + { + struct btrfs_fs_info *fs_info = to_fs_info(kobj); + +- return snprintf(buf, PAGE_SIZE, "%u\n", +- fs_info->super_copy->sectorsize); ++ return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->sectorsize); + } + + BTRFS_ATTR(, clone_alignment, btrfs_clone_alignment_show); +diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c +index 04f0714..9220f00 100644 +--- a/fs/btrfs/transaction.c ++++ b/fs/btrfs/transaction.c +@@ -1722,19 +1722,23 @@ static void update_super_roots(struct btrfs_fs_info *fs_info) + + super = fs_info->super_copy; + ++ /* update latest btrfs_super_block::chunk_root refs */ + root_item = &fs_info->chunk_root->root_item; +- super->chunk_root = root_item->bytenr; +- super->chunk_root_generation = root_item->generation; +- super->chunk_root_level = root_item->level; ++ btrfs_set_super_chunk_root(super, root_item->bytenr); ++ btrfs_set_super_chunk_root_generation(super, root_item->generation); ++ btrfs_set_super_chunk_root_level(super, root_item->level); + ++ /* update latest btrfs_super_block::root refs */ + root_item = &fs_info->tree_root->root_item; +- super->root = root_item->bytenr; +- super->generation = root_item->generation; +- super->root_level = root_item->level; ++ btrfs_set_super_root(super, root_item->bytenr); ++ btrfs_set_super_generation(super, root_item->generation); ++ btrfs_set_super_root_level(super, root_item->level); ++ + if (btrfs_test_opt(fs_info, SPACE_CACHE)) +- super->cache_generation = root_item->generation; ++ btrfs_set_super_cache_generation(super, root_item->generation); + if (test_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags)) +- super->uuid_tree_generation = root_item->generation; ++ btrfs_set_super_uuid_tree_generation(super, ++ root_item->generation); + } + + int btrfs_transaction_in_commit(struct btrfs_fs_info *info) +diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c +index afadaad..4344577 100644 +--- a/fs/btrfs/tree-log.c ++++ b/fs/btrfs/tree-log.c +@@ -29,6 +29,7 @@ + #include "hash.h" + #include "compression.h" + #include "qgroup.h" ++#include "inode-map.h" + + /* magic values for the inode_only field in btrfs_log_inode: + * +@@ -966,7 +967,9 @@ static noinline int backref_in_log(struct btrfs_root *log, + ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]); + + if (key->type == BTRFS_INODE_EXTREF_KEY) { +- if (btrfs_find_name_in_ext_backref(path, ref_objectid, ++ if (btrfs_find_name_in_ext_backref(path->nodes[0], ++ path->slots[0], ++ ref_objectid, + name, namelen, NULL)) + match = 1; + +@@ -1190,7 +1193,8 @@ static int extref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr, + read_extent_buffer(eb, *name, (unsigned long)&extref->name, + *namelen); + +- *index = btrfs_inode_extref_index(eb, extref); ++ if (index) ++ *index = btrfs_inode_extref_index(eb, extref); + if (parent_objectid) + *parent_objectid = btrfs_inode_extref_parent(eb, extref); + +@@ -1211,12 +1215,102 @@ static int ref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr, + + read_extent_buffer(eb, *name, (unsigned long)(ref + 1), *namelen); + +- *index = btrfs_inode_ref_index(eb, ref); ++ if (index) ++ *index = btrfs_inode_ref_index(eb, ref); + + return 0; + } + + /* ++ * Take an inode reference item from the log tree and iterate all names from the ++ * inode reference item in the subvolume tree with the same key (if it exists). ++ * For any name that is not in the inode reference item from the log tree, do a ++ * proper unlink of that name (that is, remove its entry from the inode ++ * reference item and both dir index keys). ++ */ ++static int unlink_old_inode_refs(struct btrfs_trans_handle *trans, ++ struct btrfs_root *root, ++ struct btrfs_path *path, ++ struct btrfs_inode *inode, ++ struct extent_buffer *log_eb, ++ int log_slot, ++ struct btrfs_key *key) ++{ ++ int ret; ++ unsigned long ref_ptr; ++ unsigned long ref_end; ++ struct extent_buffer *eb; ++ ++again: ++ btrfs_release_path(path); ++ ret = btrfs_search_slot(NULL, root, key, path, 0, 0); ++ if (ret > 0) { ++ ret = 0; ++ goto out; ++ } ++ if (ret < 0) ++ goto out; ++ ++ eb = path->nodes[0]; ++ ref_ptr = btrfs_item_ptr_offset(eb, path->slots[0]); ++ ref_end = ref_ptr + btrfs_item_size_nr(eb, path->slots[0]); ++ while (ref_ptr < ref_end) { ++ char *name = NULL; ++ int namelen; ++ u64 parent_id; ++ ++ if (key->type == BTRFS_INODE_EXTREF_KEY) { ++ ret = extref_get_fields(eb, ref_ptr, &namelen, &name, ++ NULL, &parent_id); ++ } else { ++ parent_id = key->offset; ++ ret = ref_get_fields(eb, ref_ptr, &namelen, &name, ++ NULL); ++ } ++ if (ret) ++ goto out; ++ ++ if (key->type == BTRFS_INODE_EXTREF_KEY) ++ ret = btrfs_find_name_in_ext_backref(log_eb, log_slot, ++ parent_id, name, ++ namelen, NULL); ++ else ++ ret = btrfs_find_name_in_backref(log_eb, log_slot, name, ++ namelen, NULL); ++ ++ if (!ret) { ++ struct inode *dir; ++ ++ btrfs_release_path(path); ++ dir = read_one_inode(root, parent_id); ++ if (!dir) { ++ ret = -ENOENT; ++ kfree(name); ++ goto out; ++ } ++ ret = btrfs_unlink_inode(trans, root, BTRFS_I(dir), ++ inode, name, namelen); ++ kfree(name); ++ iput(dir); ++ if (ret) ++ goto out; ++ goto again; ++ } ++ ++ kfree(name); ++ ref_ptr += namelen; ++ if (key->type == BTRFS_INODE_EXTREF_KEY) ++ ref_ptr += sizeof(struct btrfs_inode_extref); ++ else ++ ref_ptr += sizeof(struct btrfs_inode_ref); ++ } ++ ret = 0; ++ out: ++ btrfs_release_path(path); ++ return ret; ++} ++ ++/* + * replay one inode back reference item found in the log tree. + * eb, slot and key refer to the buffer and key found in the log tree. + * root is the destination we are replaying into, and path is for temp +@@ -1344,6 +1438,19 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, + } + } + ++ /* ++ * Before we overwrite the inode reference item in the subvolume tree ++ * with the item from the log tree, we must unlink all names from the ++ * parent directory that are in the subvolume's tree inode reference ++ * item, otherwise we end up with an inconsistent subvolume tree where ++ * dir index entries exist for a name but there is no inode reference ++ * item with the same name. ++ */ ++ ret = unlink_old_inode_refs(trans, root, path, BTRFS_I(inode), eb, slot, ++ key); ++ if (ret) ++ goto out; ++ + /* finally write the back reference in the inode */ + ret = overwrite_item(trans, root, path, eb, slot, key); + out: +@@ -2472,6 +2579,9 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, + clean_tree_block(fs_info, next); + btrfs_wait_tree_block_writeback(next); + btrfs_tree_unlock(next); ++ } else { ++ if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags)) ++ clear_extent_buffer_dirty(next); + } + + WARN_ON(root_owner != +@@ -2552,6 +2662,9 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans, + clean_tree_block(fs_info, next); + btrfs_wait_tree_block_writeback(next); + btrfs_tree_unlock(next); ++ } else { ++ if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags)) ++ clear_extent_buffer_dirty(next); + } + + WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID); +@@ -2630,6 +2743,9 @@ static int walk_log_tree(struct btrfs_trans_handle *trans, + clean_tree_block(fs_info, next); + btrfs_wait_tree_block_writeback(next); + btrfs_tree_unlock(next); ++ } else { ++ if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags)) ++ clear_extent_buffer_dirty(next); + } + + WARN_ON(log->root_key.objectid != +@@ -3018,13 +3134,14 @@ static void free_log_tree(struct btrfs_trans_handle *trans, + + while (1) { + ret = find_first_extent_bit(&log->dirty_log_pages, +- 0, &start, &end, EXTENT_DIRTY | EXTENT_NEW, ++ 0, &start, &end, ++ EXTENT_DIRTY | EXTENT_NEW | EXTENT_NEED_WAIT, + NULL); + if (ret) + break; + + clear_extent_bits(&log->dirty_log_pages, start, end, +- EXTENT_DIRTY | EXTENT_NEW); ++ EXTENT_DIRTY | EXTENT_NEW | EXTENT_NEED_WAIT); + } + + /* +@@ -5677,6 +5794,23 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) + path); + } + ++ if (!ret && wc.stage == LOG_WALK_REPLAY_ALL) { ++ struct btrfs_root *root = wc.replay_dest; ++ ++ btrfs_release_path(path); ++ ++ /* ++ * We have just replayed everything, and the highest ++ * objectid of fs roots probably has changed in case ++ * some inode_item's got replayed. ++ * ++ * root->objectid_mutex is not acquired as log replay ++ * could only happen during mount. ++ */ ++ ret = btrfs_find_highest_objectid(root, ++ &root->highest_objectid); ++ } ++ + key.offset = found_key.offset - 1; + wc.replay_dest->log_root = NULL; + free_extent_buffer(log->node); +@@ -5825,7 +5959,7 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans, + * this will force the logging code to walk the dentry chain + * up for the file + */ +- if (S_ISREG(inode->vfs_inode.i_mode)) ++ if (!S_ISDIR(inode->vfs_inode.i_mode)) + inode->last_unlink_trans = trans->transid; + + /* +diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c +index b5036bd..b2d05c6 100644 +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -645,6 +645,7 @@ static void btrfs_free_stale_devices(const char *path, + btrfs_sysfs_remove_fsid(fs_devs); + list_del(&fs_devs->list); + free_fs_devices(fs_devs); ++ break; + } else { + fs_devs->num_devices--; + list_del(&dev->dev_list); +@@ -4828,10 +4829,13 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, + ndevs = min(ndevs, devs_max); + + /* +- * the primary goal is to maximize the number of stripes, so use as many +- * devices as possible, even if the stripes are not maximum sized. ++ * The primary goal is to maximize the number of stripes, so use as ++ * many devices as possible, even if the stripes are not maximum sized. ++ * ++ * The DUP profile stores more than one stripe per device, the ++ * max_avail is the total size so we have to adjust. + */ +- stripe_size = devices_info[ndevs-1].max_avail; ++ stripe_size = div_u64(devices_info[ndevs - 1].max_avail, dev_stripes); + num_stripes = ndevs * dev_stripes; + + /* +@@ -4866,8 +4870,6 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, + stripe_size = devices_info[ndevs-1].max_avail; + } + +- stripe_size = div_u64(stripe_size, dev_stripes); +- + /* align to BTRFS_STRIPE_LEN */ + stripe_size = round_down(stripe_size, BTRFS_STRIPE_LEN); + +diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c +index 6582c45..0e5bd3e 100644 +--- a/fs/ceph/caps.c ++++ b/fs/ceph/caps.c +@@ -3965,6 +3965,32 @@ void ceph_put_fmode(struct ceph_inode_info *ci, int fmode) + } + + /* ++ * For a soon-to-be unlinked file, drop the AUTH_RDCACHE caps. If it ++ * looks like the link count will hit 0, drop any other caps (other ++ * than PIN) we don't specifically want (due to the file still being ++ * open). ++ */ ++int ceph_drop_caps_for_unlink(struct inode *inode) ++{ ++ struct ceph_inode_info *ci = ceph_inode(inode); ++ int drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL; ++ ++ spin_lock(&ci->i_ceph_lock); ++ if (inode->i_nlink == 1) { ++ drop |= ~(__ceph_caps_wanted(ci) | CEPH_CAP_PIN); ++ ++ ci->i_ceph_flags |= CEPH_I_NODELAY; ++ if (__ceph_caps_dirty(ci)) { ++ struct ceph_mds_client *mdsc = ++ ceph_inode_to_client(inode)->mdsc; ++ __cap_delay_requeue_front(mdsc, ci); ++ } ++ } ++ spin_unlock(&ci->i_ceph_lock); ++ return drop; ++} ++ ++/* + * Helpers for embedding cap and dentry lease releases into mds + * requests. + * +diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c +index 0c43468..f1d9c6c 100644 +--- a/fs/ceph/dir.c ++++ b/fs/ceph/dir.c +@@ -1003,26 +1003,6 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir, + } + + /* +- * For a soon-to-be unlinked file, drop the AUTH_RDCACHE caps. If it +- * looks like the link count will hit 0, drop any other caps (other +- * than PIN) we don't specifically want (due to the file still being +- * open). +- */ +-static int drop_caps_for_unlink(struct inode *inode) +-{ +- struct ceph_inode_info *ci = ceph_inode(inode); +- int drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL; +- +- spin_lock(&ci->i_ceph_lock); +- if (inode->i_nlink == 1) { +- drop |= ~(__ceph_caps_wanted(ci) | CEPH_CAP_PIN); +- ci->i_ceph_flags |= CEPH_I_NODELAY; +- } +- spin_unlock(&ci->i_ceph_lock); +- return drop; +-} +- +-/* + * rmdir and unlink are differ only by the metadata op code + */ + static int ceph_unlink(struct inode *dir, struct dentry *dentry) +@@ -1056,7 +1036,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry) + set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); + req->r_dentry_drop = CEPH_CAP_FILE_SHARED; + req->r_dentry_unless = CEPH_CAP_FILE_EXCL; +- req->r_inode_drop = drop_caps_for_unlink(inode); ++ req->r_inode_drop = ceph_drop_caps_for_unlink(inode); + err = ceph_mdsc_do_request(mdsc, dir, req); + if (!err && !req->r_reply_info.head->is_dentry) + d_delete(dentry); +@@ -1104,8 +1084,10 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry, + req->r_dentry_unless = CEPH_CAP_FILE_EXCL; + /* release LINK_RDCACHE on source inode (mds will lock it) */ + req->r_old_inode_drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL; +- if (d_really_is_positive(new_dentry)) +- req->r_inode_drop = drop_caps_for_unlink(d_inode(new_dentry)); ++ if (d_really_is_positive(new_dentry)) { ++ req->r_inode_drop = ++ ceph_drop_caps_for_unlink(d_inode(new_dentry)); ++ } + err = ceph_mdsc_do_request(mdsc, old_dir, req); + if (!err && !req->r_reply_info.head->is_dentry) { + /* +diff --git a/fs/ceph/super.c b/fs/ceph/super.c +index a62d2a9..fb2bc9c 100644 +--- a/fs/ceph/super.c ++++ b/fs/ceph/super.c +@@ -225,6 +225,7 @@ static int parse_fsopt_token(char *c, void *private) + return -ENOMEM; + break; + case Opt_mds_namespace: ++ kfree(fsopt->mds_namespace); + fsopt->mds_namespace = kstrndup(argstr[0].from, + argstr[0].to-argstr[0].from, + GFP_KERNEL); +@@ -232,6 +233,7 @@ static int parse_fsopt_token(char *c, void *private) + return -ENOMEM; + break; + case Opt_fscache_uniq: ++ kfree(fsopt->fscache_uniq); + fsopt->fscache_uniq = kstrndup(argstr[0].from, + argstr[0].to-argstr[0].from, + GFP_KERNEL); +@@ -711,14 +713,17 @@ static int __init init_caches(void) + goto bad_dentry; + + ceph_file_cachep = KMEM_CACHE(ceph_file_info, SLAB_MEM_SPREAD); +- + if (!ceph_file_cachep) + goto bad_file; + +- if ((error = ceph_fscache_register())) +- goto bad_file; ++ error = ceph_fscache_register(); ++ if (error) ++ goto bad_fscache; + + return 0; ++ ++bad_fscache: ++ kmem_cache_destroy(ceph_file_cachep); + bad_file: + kmem_cache_destroy(ceph_dentry_cachep); + bad_dentry: +@@ -836,7 +841,6 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc) + int err; + unsigned long started = jiffies; /* note the start time */ + struct dentry *root; +- int first = 0; /* first vfsmount for this super_block */ + + dout("mount start %p\n", fsc); + mutex_lock(&fsc->client->mount_mutex); +@@ -861,17 +865,17 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc) + path = fsc->mount_options->server_path + 1; + dout("mount opening path %s\n", path); + } ++ ++ err = ceph_fs_debugfs_init(fsc); ++ if (err < 0) ++ goto out; ++ + root = open_root_dentry(fsc, path, started); + if (IS_ERR(root)) { + err = PTR_ERR(root); + goto out; + } + fsc->sb->s_root = dget(root); +- first = 1; +- +- err = ceph_fs_debugfs_init(fsc); +- if (err < 0) +- goto fail; + } else { + root = dget(fsc->sb->s_root); + } +@@ -881,11 +885,6 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc) + mutex_unlock(&fsc->client->mount_mutex); + return root; + +-fail: +- if (first) { +- dput(fsc->sb->s_root); +- fsc->sb->s_root = NULL; +- } + out: + mutex_unlock(&fsc->client->mount_mutex); + return ERR_PTR(err); +diff --git a/fs/ceph/super.h b/fs/ceph/super.h +index 21b2e5b..1c2086e 100644 +--- a/fs/ceph/super.h ++++ b/fs/ceph/super.h +@@ -987,7 +987,7 @@ extern void ceph_check_caps(struct ceph_inode_info *ci, int flags, + struct ceph_mds_session *session); + extern void ceph_check_delayed_caps(struct ceph_mds_client *mdsc); + extern void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc); +- ++extern int ceph_drop_caps_for_unlink(struct inode *inode); + extern int ceph_encode_inode_release(void **p, struct inode *inode, + int mds, int drop, int unless, int force); + extern int ceph_encode_dentry_release(void **p, struct dentry *dn, +diff --git a/fs/direct-io.c b/fs/direct-io.c +index a0ca9e4..1357ef5 100644 +--- a/fs/direct-io.c ++++ b/fs/direct-io.c +@@ -1274,8 +1274,7 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, + */ + if (dio->is_async && iov_iter_rw(iter) == WRITE) { + retval = 0; +- if ((iocb->ki_filp->f_flags & O_DSYNC) || +- IS_SYNC(iocb->ki_filp->f_mapping->host)) ++ if (iocb->ki_flags & IOCB_DSYNC) + retval = dio_set_defer_completion(dio); + else if (!dio->inode->i_sb->s_dio_done_wq) { + /* +diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c +index 5f22e74..8e56842 100644 +--- a/fs/efivarfs/file.c ++++ b/fs/efivarfs/file.c +@@ -8,6 +8,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -74,6 +75,11 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf, + ssize_t size = 0; + int err; + ++ while (!__ratelimit(&file->f_cred->user->ratelimit)) { ++ if (!msleep_interruptible(50)) ++ return -EINTR; ++ } ++ + err = efivar_entry_size(var, &datasize); + + /* +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 8686379..51f940e 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -716,7 +716,7 @@ int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + __be64 *ptr; + sector_t lblock; + sector_t lend; +- int ret; ++ int ret = 0; + int eob; + unsigned int len; + struct buffer_head *bh; +@@ -728,12 +728,14 @@ int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + goto out; + } + +- if ((flags & IOMAP_REPORT) && gfs2_is_stuffed(ip)) { +- gfs2_stuffed_iomap(inode, iomap); +- if (pos >= iomap->length) +- return -ENOENT; +- ret = 0; +- goto out; ++ if (gfs2_is_stuffed(ip)) { ++ if (flags & IOMAP_REPORT) { ++ gfs2_stuffed_iomap(inode, iomap); ++ if (pos >= iomap->length) ++ ret = -ENOENT; ++ goto out; ++ } ++ BUG_ON(!(flags & IOMAP_WRITE)); + } + + lblock = pos >> inode->i_blkbits; +@@ -744,7 +746,7 @@ int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + iomap->type = IOMAP_HOLE; + iomap->length = (u64)(lend - lblock) << inode->i_blkbits; + iomap->flags = IOMAP_F_MERGED; +- bmap_lock(ip, 0); ++ bmap_lock(ip, flags & IOMAP_WRITE); + + /* + * Directory data blocks have a struct gfs2_meta_header header, so the +@@ -787,27 +789,25 @@ int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + iomap->flags |= IOMAP_F_BOUNDARY; + iomap->length = (u64)len << inode->i_blkbits; + +- ret = 0; +- + out_release: + release_metapath(&mp); +- bmap_unlock(ip, 0); ++ bmap_unlock(ip, flags & IOMAP_WRITE); + out: + trace_gfs2_iomap_end(ip, iomap, ret); + return ret; + + do_alloc: +- if (!(flags & IOMAP_WRITE)) { +- if (pos >= i_size_read(inode)) { ++ if (flags & IOMAP_WRITE) { ++ ret = gfs2_iomap_alloc(inode, iomap, flags, &mp); ++ } else if (flags & IOMAP_REPORT) { ++ loff_t size = i_size_read(inode); ++ if (pos >= size) + ret = -ENOENT; +- goto out_release; +- } +- ret = 0; +- iomap->length = hole_size(inode, lblock, &mp); +- goto out_release; ++ else if (height <= ip->i_height) ++ iomap->length = hole_size(inode, lblock, &mp); ++ else ++ iomap->length = size - pos; + } +- +- ret = gfs2_iomap_alloc(inode, iomap, flags, &mp); + goto out_release; + } + +diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c +index 2435af5..a50d781 100644 +--- a/fs/nfs/callback_proc.c ++++ b/fs/nfs/callback_proc.c +@@ -572,7 +572,7 @@ __be32 nfs4_callback_sequence(void *argp, void *resp, + } + + static bool +-validate_bitmap_values(unsigned long mask) ++validate_bitmap_values(unsigned int mask) + { + return (mask & ~RCA4_TYPE_MASK_ALL) == 0; + } +@@ -596,17 +596,15 @@ __be32 nfs4_callback_recallany(void *argp, void *resp, + goto out; + + status = cpu_to_be32(NFS4_OK); +- if (test_bit(RCA4_TYPE_MASK_RDATA_DLG, (const unsigned long *) +- &args->craa_type_mask)) ++ if (args->craa_type_mask & BIT(RCA4_TYPE_MASK_RDATA_DLG)) + flags = FMODE_READ; +- if (test_bit(RCA4_TYPE_MASK_WDATA_DLG, (const unsigned long *) +- &args->craa_type_mask)) ++ if (args->craa_type_mask & BIT(RCA4_TYPE_MASK_WDATA_DLG)) + flags |= FMODE_WRITE; +- if (test_bit(RCA4_TYPE_MASK_FILE_LAYOUT, (const unsigned long *) +- &args->craa_type_mask)) +- pnfs_recall_all_layouts(cps->clp); + if (flags) + nfs_expire_unused_delegation_types(cps->clp, flags); ++ ++ if (args->craa_type_mask & BIT(RCA4_TYPE_MASK_FILE_LAYOUT)) ++ pnfs_recall_all_layouts(cps->clp); + out: + dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); + return status; +diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c +index 8c10b05..621c517 100644 +--- a/fs/nfs/direct.c ++++ b/fs/nfs/direct.c +@@ -86,10 +86,10 @@ struct nfs_direct_req { + struct nfs_direct_mirror mirrors[NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX]; + int mirror_count; + ++ loff_t io_start; /* Start offset for I/O */ + ssize_t count, /* bytes actually processed */ + max_count, /* max expected count */ + bytes_left, /* bytes left to be sent */ +- io_start, /* start of IO */ + error; /* any reported error */ + struct completion completion; /* wait for i/o completion */ + +diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c +index 49f848f..7327930 100644 +--- a/fs/nfs/nfs3proc.c ++++ b/fs/nfs/nfs3proc.c +@@ -873,7 +873,7 @@ static void nfs3_nlm_release_call(void *data) + } + } + +-const struct nlmclnt_operations nlmclnt_fl_close_lock_ops = { ++static const struct nlmclnt_operations nlmclnt_fl_close_lock_ops = { + .nlmclnt_alloc_call = nfs3_nlm_alloc_call, + .nlmclnt_unlock_prepare = nfs3_nlm_unlock_prepare, + .nlmclnt_release_call = nfs3_nlm_release_call, +diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c +index 04612c2..9796314 100644 +--- a/fs/nfs/nfs4client.c ++++ b/fs/nfs/nfs4client.c +@@ -868,8 +868,10 @@ static int nfs4_set_client(struct nfs_server *server, + if (IS_ERR(clp)) + return PTR_ERR(clp); + +- if (server->nfs_client == clp) ++ if (server->nfs_client == clp) { ++ nfs_put_client(clp); + return -ELOOP; ++ } + + /* + * Query for the lease time on clientid setup or renewal +@@ -1244,11 +1246,11 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname, + clp->cl_proto, clnt->cl_timeout, + clp->cl_minorversion, net); + clear_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status); +- nfs_put_client(clp); + if (error != 0) { + nfs_server_insert_lists(server); + return error; + } ++ nfs_put_client(clp); + + if (server->nfs_client->cl_hostname == NULL) + server->nfs_client->cl_hostname = kstrdup(hostname, GFP_KERNEL); +diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c +index c13e826..ee723aa 100644 +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -292,8 +292,11 @@ pnfs_detach_layout_hdr(struct pnfs_layout_hdr *lo) + void + pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo) + { +- struct inode *inode = lo->plh_inode; ++ struct inode *inode; + ++ if (!lo) ++ return; ++ inode = lo->plh_inode; + pnfs_layoutreturn_before_put_layout_hdr(lo); + + if (refcount_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) { +@@ -1241,10 +1244,12 @@ bool pnfs_roc(struct inode *ino, + spin_lock(&ino->i_lock); + lo = nfsi->layout; + if (!lo || !pnfs_layout_is_valid(lo) || +- test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) ++ test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) { ++ lo = NULL; + goto out_noroc; ++ } ++ pnfs_get_layout_hdr(lo); + if (test_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) { +- pnfs_get_layout_hdr(lo); + spin_unlock(&ino->i_lock); + wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN, + TASK_UNINTERRUPTIBLE); +@@ -1312,10 +1317,12 @@ bool pnfs_roc(struct inode *ino, + struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld; + if (ld->prepare_layoutreturn) + ld->prepare_layoutreturn(args); ++ pnfs_put_layout_hdr(lo); + return true; + } + if (layoutreturn) + pnfs_send_layoutreturn(lo, &stateid, iomode, true); ++ pnfs_put_layout_hdr(lo); + return false; + } + +diff --git a/fs/nfs/write.c b/fs/nfs/write.c +index 7428a66..e7d8cea 100644 +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -1876,40 +1876,43 @@ int nfs_generic_commit_list(struct inode *inode, struct list_head *head, + return status; + } + +-int nfs_commit_inode(struct inode *inode, int how) ++static int __nfs_commit_inode(struct inode *inode, int how, ++ struct writeback_control *wbc) + { + LIST_HEAD(head); + struct nfs_commit_info cinfo; + int may_wait = how & FLUSH_SYNC; +- int error = 0; +- int res; ++ int ret, nscan; + + nfs_init_cinfo_from_inode(&cinfo, inode); + nfs_commit_begin(cinfo.mds); +- res = nfs_scan_commit(inode, &head, &cinfo); +- if (res) +- error = nfs_generic_commit_list(inode, &head, how, &cinfo); ++ for (;;) { ++ ret = nscan = nfs_scan_commit(inode, &head, &cinfo); ++ if (ret <= 0) ++ break; ++ ret = nfs_generic_commit_list(inode, &head, how, &cinfo); ++ if (ret < 0) ++ break; ++ ret = 0; ++ if (wbc && wbc->sync_mode == WB_SYNC_NONE) { ++ if (nscan < wbc->nr_to_write) ++ wbc->nr_to_write -= nscan; ++ else ++ wbc->nr_to_write = 0; ++ } ++ if (nscan < INT_MAX) ++ break; ++ cond_resched(); ++ } + nfs_commit_end(cinfo.mds); +- if (res == 0) +- return res; +- if (error < 0) +- goto out_error; +- if (!may_wait) +- goto out_mark_dirty; +- error = wait_on_commit(cinfo.mds); +- if (error < 0) +- return error; +- return res; +-out_error: +- res = error; +- /* Note: If we exit without ensuring that the commit is complete, +- * we must mark the inode as dirty. Otherwise, future calls to +- * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure +- * that the data is on the disk. +- */ +-out_mark_dirty: +- __mark_inode_dirty(inode, I_DIRTY_DATASYNC); +- return res; ++ if (ret || !may_wait) ++ return ret; ++ return wait_on_commit(cinfo.mds); ++} ++ ++int nfs_commit_inode(struct inode *inode, int how) ++{ ++ return __nfs_commit_inode(inode, how, NULL); + } + EXPORT_SYMBOL_GPL(nfs_commit_inode); + +@@ -1919,11 +1922,11 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) + int flags = FLUSH_SYNC; + int ret = 0; + +- /* no commits means nothing needs to be done */ +- if (!atomic_long_read(&nfsi->commit_info.ncommit)) +- return ret; +- + if (wbc->sync_mode == WB_SYNC_NONE) { ++ /* no commits means nothing needs to be done */ ++ if (!atomic_long_read(&nfsi->commit_info.ncommit)) ++ goto check_requests_outstanding; ++ + /* Don't commit yet if this is a non-blocking flush and there + * are a lot of outstanding writes for this mapping. + */ +@@ -1934,16 +1937,16 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) + flags = 0; + } + +- ret = nfs_commit_inode(inode, flags); +- if (ret >= 0) { +- if (wbc->sync_mode == WB_SYNC_NONE) { +- if (ret < wbc->nr_to_write) +- wbc->nr_to_write -= ret; +- else +- wbc->nr_to_write = 0; +- } +- return 0; +- } ++ ret = __nfs_commit_inode(inode, flags, wbc); ++ if (!ret) { ++ if (flags & FLUSH_SYNC) ++ return 0; ++ } else if (atomic_long_read(&nfsi->commit_info.ncommit)) ++ goto out_mark_dirty; ++ ++check_requests_outstanding: ++ if (!atomic_read(&nfsi->commit_info.rpcs_out)) ++ return ret; + out_mark_dirty: + __mark_inode_dirty(inode, I_DIRTY_DATASYNC); + return ret; +diff --git a/fs/overlayfs/Kconfig b/fs/overlayfs/Kconfig +index 406e72d..ce6ff5a 100644 +--- a/fs/overlayfs/Kconfig ++++ b/fs/overlayfs/Kconfig +@@ -24,6 +24,8 @@ config OVERLAY_FS_REDIRECT_DIR + an overlay which has redirects on a kernel that doesn't support this + feature will have unexpected results. + ++ If unsure, say N. ++ + config OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW + bool "Overlayfs: follow redirects even if redirects are turned off" + default y +@@ -32,8 +34,13 @@ config OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW + Disable this to get a possibly more secure configuration, but that + might not be backward compatible with previous kernels. + ++ If backward compatibility is not an issue, then it is safe and ++ recommended to say N here. ++ + For more information, see Documentation/filesystems/overlayfs.txt + ++ If unsure, say Y. ++ + config OVERLAY_FS_INDEX + bool "Overlayfs: turn on inodes index feature by default" + depends on OVERLAY_FS +@@ -51,6 +58,8 @@ config OVERLAY_FS_INDEX + That is, mounting an overlay which has an inodes index on a kernel + that doesn't support this feature will have unexpected results. + ++ If unsure, say N. ++ + config OVERLAY_FS_NFS_EXPORT + bool "Overlayfs: turn on NFS export feature by default" + depends on OVERLAY_FS +@@ -72,3 +81,8 @@ config OVERLAY_FS_NFS_EXPORT + Note, that the NFS export feature is not backward compatible. + That is, mounting an overlay which has a full index on a kernel + that doesn't support this feature will have unexpected results. ++ ++ Most users should say N here and enable this feature on a case-by- ++ case basis with the "nfs_export=on" mount option. ++ ++ Say N unless you fully understand the consequences. +diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c +index bb94ce9..87bd414 100644 +--- a/fs/overlayfs/export.c ++++ b/fs/overlayfs/export.c +@@ -19,6 +19,142 @@ + #include + #include "overlayfs.h" + ++static int ovl_encode_maybe_copy_up(struct dentry *dentry) ++{ ++ int err; ++ ++ if (ovl_dentry_upper(dentry)) ++ return 0; ++ ++ err = ovl_want_write(dentry); ++ if (!err) { ++ err = ovl_copy_up(dentry); ++ ovl_drop_write(dentry); ++ } ++ ++ if (err) { ++ pr_warn_ratelimited("overlayfs: failed to copy up on encode (%pd2, err=%i)\n", ++ dentry, err); ++ } ++ ++ return err; ++} ++ ++/* ++ * Before encoding a non-upper directory file handle from real layer N, we need ++ * to check if it will be possible to reconnect an overlay dentry from the real ++ * lower decoded dentry. This is done by following the overlay ancestry up to a ++ * "layer N connected" ancestor and verifying that all parents along the way are ++ * "layer N connectable". If an ancestor that is NOT "layer N connectable" is ++ * found, we need to copy up an ancestor, which is "layer N connectable", thus ++ * making that ancestor "layer N connected". For example: ++ * ++ * layer 1: /a ++ * layer 2: /a/b/c ++ * ++ * The overlay dentry /a is NOT "layer 2 connectable", because if dir /a is ++ * copied up and renamed, upper dir /a will be indexed by lower dir /a from ++ * layer 1. The dir /a from layer 2 will never be indexed, so the algorithm (*) ++ * in ovl_lookup_real_ancestor() will not be able to lookup a connected overlay ++ * dentry from the connected lower dentry /a/b/c. ++ * ++ * To avoid this problem on decode time, we need to copy up an ancestor of ++ * /a/b/c, which is "layer 2 connectable", on encode time. That ancestor is ++ * /a/b. After copy up (and index) of /a/b, it will become "layer 2 connected" ++ * and when the time comes to decode the file handle from lower dentry /a/b/c, ++ * ovl_lookup_real_ancestor() will find the indexed ancestor /a/b and decoding ++ * a connected overlay dentry will be accomplished. ++ * ++ * (*) the algorithm in ovl_lookup_real_ancestor() can be improved to lookup an ++ * entry /a in the lower layers above layer N and find the indexed dir /a from ++ * layer 1. If that improvement is made, then the check for "layer N connected" ++ * will need to verify there are no redirects in lower layers above N. In the ++ * example above, /a will be "layer 2 connectable". However, if layer 2 dir /a ++ * is a target of a layer 1 redirect, then /a will NOT be "layer 2 connectable": ++ * ++ * layer 1: /A (redirect = /a) ++ * layer 2: /a/b/c ++ */ ++ ++/* Return the lowest layer for encoding a connectable file handle */ ++static int ovl_connectable_layer(struct dentry *dentry) ++{ ++ struct ovl_entry *oe = OVL_E(dentry); ++ ++ /* We can get overlay root from root of any layer */ ++ if (dentry == dentry->d_sb->s_root) ++ return oe->numlower; ++ ++ /* ++ * If it's an unindexed merge dir, then it's not connectable with any ++ * lower layer ++ */ ++ if (ovl_dentry_upper(dentry) && ++ !ovl_test_flag(OVL_INDEX, d_inode(dentry))) ++ return 0; ++ ++ /* We can get upper/overlay path from indexed/lower dentry */ ++ return oe->lowerstack[0].layer->idx; ++} ++ ++/* ++ * @dentry is "connected" if all ancestors up to root or a "connected" ancestor ++ * have the same uppermost lower layer as the origin's layer. We may need to ++ * copy up a "connectable" ancestor to make it "connected". A "connected" dentry ++ * cannot become non "connected", so cache positive result in dentry flags. ++ * ++ * Return the connected origin layer or < 0 on error. ++ */ ++static int ovl_connect_layer(struct dentry *dentry) ++{ ++ struct dentry *next, *parent = NULL; ++ int origin_layer; ++ int err = 0; ++ ++ if (WARN_ON(dentry == dentry->d_sb->s_root) || ++ WARN_ON(!ovl_dentry_lower(dentry))) ++ return -EIO; ++ ++ origin_layer = OVL_E(dentry)->lowerstack[0].layer->idx; ++ if (ovl_dentry_test_flag(OVL_E_CONNECTED, dentry)) ++ return origin_layer; ++ ++ /* Find the topmost origin layer connectable ancestor of @dentry */ ++ next = dget(dentry); ++ for (;;) { ++ parent = dget_parent(next); ++ if (WARN_ON(parent == next)) { ++ err = -EIO; ++ break; ++ } ++ ++ /* ++ * If @parent is not origin layer connectable, then copy up ++ * @next which is origin layer connectable and we are done. ++ */ ++ if (ovl_connectable_layer(parent) < origin_layer) { ++ err = ovl_encode_maybe_copy_up(next); ++ break; ++ } ++ ++ /* If @parent is connected or indexed we are done */ ++ if (ovl_dentry_test_flag(OVL_E_CONNECTED, parent) || ++ ovl_test_flag(OVL_INDEX, d_inode(parent))) ++ break; ++ ++ dput(next); ++ next = parent; ++ } ++ ++ dput(parent); ++ dput(next); ++ ++ if (!err) ++ ovl_dentry_set_flag(OVL_E_CONNECTED, dentry); ++ ++ return err ?: origin_layer; ++} ++ + /* + * We only need to encode origin if there is a chance that the same object was + * encoded pre copy up and then we need to stay consistent with the same +@@ -41,73 +177,59 @@ + * L = lower file handle + * + * (*) Connecting an overlay dir from real lower dentry is not always +- * possible when there are redirects in lower layers. To mitigate this case, +- * we copy up the lower dir first and then encode an upper dir file handle. ++ * possible when there are redirects in lower layers and non-indexed merge dirs. ++ * To mitigate those case, we may copy up the lower dir ancestor before encode ++ * a lower dir file handle. ++ * ++ * Return 0 for upper file handle, > 0 for lower file handle or < 0 on error. + */ +-static bool ovl_should_encode_origin(struct dentry *dentry) ++static int ovl_check_encode_origin(struct dentry *dentry) + { + struct ovl_fs *ofs = dentry->d_sb->s_fs_info; + ++ /* Upper file handle for pure upper */ + if (!ovl_dentry_lower(dentry)) +- return false; ++ return 0; + + /* +- * Decoding a merge dir, whose origin's parent is under a redirected +- * lower dir is not always possible. As a simple aproximation, we do +- * not encode lower dir file handles when overlay has multiple lower +- * layers and origin is below the topmost lower layer. ++ * Upper file handle for non-indexed upper. + * +- * TODO: copy up only the parent that is under redirected lower. ++ * Root is never indexed, so if there's an upper layer, encode upper for ++ * root. + */ +- if (d_is_dir(dentry) && ofs->upper_mnt && +- OVL_E(dentry)->lowerstack[0].layer->idx > 1) +- return false; +- +- /* Decoding a non-indexed upper from origin is not implemented */ + if (ovl_dentry_upper(dentry) && + !ovl_test_flag(OVL_INDEX, d_inode(dentry))) +- return false; +- +- return true; +-} +- +-static int ovl_encode_maybe_copy_up(struct dentry *dentry) +-{ +- int err; +- +- if (ovl_dentry_upper(dentry)) + return 0; + +- err = ovl_want_write(dentry); +- if (err) +- return err; +- +- err = ovl_copy_up(dentry); ++ /* ++ * Decoding a merge dir, whose origin's ancestor is under a redirected ++ * lower dir or under a non-indexed upper is not always possible. ++ * ovl_connect_layer() will try to make origin's layer "connected" by ++ * copying up a "connectable" ancestor. ++ */ ++ if (d_is_dir(dentry) && ofs->upper_mnt) ++ return ovl_connect_layer(dentry); + +- ovl_drop_write(dentry); +- return err; ++ /* Lower file handle for indexed and non-upper dir/non-dir */ ++ return 1; + } + + static int ovl_d_to_fh(struct dentry *dentry, char *buf, int buflen) + { +- struct dentry *origin = ovl_dentry_lower(dentry); + struct ovl_fh *fh = NULL; +- int err; ++ int err, enc_lower; + + /* +- * If we should not encode a lower dir file handle, copy up and encode +- * an upper dir file handle. ++ * Check if we should encode a lower or upper file handle and maybe ++ * copy up an ancestor to make lower file handle connectable. + */ +- if (!ovl_should_encode_origin(dentry)) { +- err = ovl_encode_maybe_copy_up(dentry); +- if (err) +- goto fail; +- +- origin = NULL; +- } ++ err = enc_lower = ovl_check_encode_origin(dentry); ++ if (enc_lower < 0) ++ goto fail; + +- /* Encode an upper or origin file handle */ +- fh = ovl_encode_fh(origin ?: ovl_dentry_upper(dentry), !origin); ++ /* Encode an upper or lower file handle */ ++ fh = ovl_encode_fh(enc_lower ? ovl_dentry_lower(dentry) : ++ ovl_dentry_upper(dentry), !enc_lower); + err = PTR_ERR(fh); + if (IS_ERR(fh)) + goto fail; +@@ -355,8 +477,8 @@ static struct dentry *ovl_lookup_real_inode(struct super_block *sb, + dput(upper); + } + +- if (!this) +- return NULL; ++ if (IS_ERR_OR_NULL(this)) ++ return this; + + if (WARN_ON(ovl_dentry_real_at(this, layer->idx) != real)) { + dput(this); +@@ -498,7 +620,7 @@ static struct dentry *ovl_lookup_real(struct super_block *sb, + if (err == -ECHILD) { + this = ovl_lookup_real_ancestor(sb, real, + layer); +- err = IS_ERR(this) ? PTR_ERR(this) : 0; ++ err = PTR_ERR_OR_ZERO(this); + } + if (!err) { + dput(connected); +diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c +index fcd97b7..3b1bd46 100644 +--- a/fs/overlayfs/inode.c ++++ b/fs/overlayfs/inode.c +@@ -669,38 +669,59 @@ struct inode *ovl_lookup_inode(struct super_block *sb, struct dentry *real, + return inode; + } + ++/* ++ * Does overlay inode need to be hashed by lower inode? ++ */ ++static bool ovl_hash_bylower(struct super_block *sb, struct dentry *upper, ++ struct dentry *lower, struct dentry *index) ++{ ++ struct ovl_fs *ofs = sb->s_fs_info; ++ ++ /* No, if pure upper */ ++ if (!lower) ++ return false; ++ ++ /* Yes, if already indexed */ ++ if (index) ++ return true; ++ ++ /* Yes, if won't be copied up */ ++ if (!ofs->upper_mnt) ++ return true; ++ ++ /* No, if lower hardlink is or will be broken on copy up */ ++ if ((upper || !ovl_indexdir(sb)) && ++ !d_is_dir(lower) && d_inode(lower)->i_nlink > 1) ++ return false; ++ ++ /* No, if non-indexed upper with NFS export */ ++ if (sb->s_export_op && upper) ++ return false; ++ ++ /* Otherwise, hash by lower inode for fsnotify */ ++ return true; ++} ++ + struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry, + struct dentry *lowerdentry, struct dentry *index, + unsigned int numlower) + { +- struct ovl_fs *ofs = sb->s_fs_info; + struct inode *realinode = upperdentry ? d_inode(upperdentry) : NULL; + struct inode *inode; +- /* Already indexed or could be indexed on copy up? */ +- bool indexed = (index || (ovl_indexdir(sb) && !upperdentry)); +- struct dentry *origin = indexed ? lowerdentry : NULL; ++ bool bylower = ovl_hash_bylower(sb, upperdentry, lowerdentry, index); + bool is_dir; + +- if (WARN_ON(upperdentry && indexed && !lowerdentry)) +- return ERR_PTR(-EIO); +- + if (!realinode) + realinode = d_inode(lowerdentry); + + /* +- * Copy up origin (lower) may exist for non-indexed non-dir upper, but +- * we must not use lower as hash key in that case. +- * Hash non-dir that is or could be indexed by origin inode. +- * Hash dir that is or could be merged by origin inode. +- * Hash pure upper and non-indexed non-dir by upper inode. +- * Hash non-indexed dir by upper inode for NFS export. ++ * Copy up origin (lower) may exist for non-indexed upper, but we must ++ * not use lower as hash key if this is a broken hardlink. + */ + is_dir = S_ISDIR(realinode->i_mode); +- if (is_dir && (indexed || !sb->s_export_op || !ofs->upper_mnt)) +- origin = lowerdentry; +- +- if (upperdentry || origin) { +- struct inode *key = d_inode(origin ?: upperdentry); ++ if (upperdentry || bylower) { ++ struct inode *key = d_inode(bylower ? lowerdentry : ++ upperdentry); + unsigned int nlink = is_dir ? 1 : realinode->i_nlink; + + inode = iget5_locked(sb, (unsigned long) key, +@@ -728,6 +749,7 @@ struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry, + nlink = ovl_get_nlink(lowerdentry, upperdentry, nlink); + set_nlink(inode, nlink); + } else { ++ /* Lower hardlink that will be broken on copy up */ + inode = new_inode(sb); + if (!inode) + goto out_nomem; +diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c +index de3e6da..70fcfcc 100644 +--- a/fs/overlayfs/namei.c ++++ b/fs/overlayfs/namei.c +@@ -913,9 +913,6 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, + stack[ctr].layer = lower.layer; + ctr++; + +- if (d.stop) +- break; +- + /* + * Following redirects can have security consequences: it's like + * a symlink into the lower layer without the permission checks. +@@ -933,6 +930,9 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, + goto out_put; + } + ++ if (d.stop) ++ break; ++ + if (d.redirect && d.redirect[0] == '/' && poe != roe) { + poe = roe; + /* Find the current layer on the root dentry */ +diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h +index 0df25a9..225ff11 100644 +--- a/fs/overlayfs/overlayfs.h ++++ b/fs/overlayfs/overlayfs.h +@@ -40,6 +40,7 @@ enum ovl_inode_flag { + enum ovl_entry_flag { + OVL_E_UPPER_ALIAS, + OVL_E_OPAQUE, ++ OVL_E_CONNECTED, + }; + + /* +diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c +index 9ee37c7..7c24619 100644 +--- a/fs/overlayfs/super.c ++++ b/fs/overlayfs/super.c +@@ -1359,6 +1359,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) + + /* Root is always merge -> can have whiteouts */ + ovl_set_flag(OVL_WHITEOUTS, d_inode(root_dentry)); ++ ovl_dentry_set_flag(OVL_E_CONNECTED, root_dentry); + ovl_inode_init(d_inode(root_dentry), upperpath.dentry, + ovl_dentry_lower(root_dentry)); + +diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c +index e8a93bc..d1e8276 100644 +--- a/fs/proc/kcore.c ++++ b/fs/proc/kcore.c +@@ -510,6 +510,10 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos) + /* we have to zero-fill user buffer even if no read */ + if (copy_to_user(buffer, buf, tsz)) + return -EFAULT; ++ } else if (m->type == KCORE_USER) { ++ /* User page is handled prior to normal kernel page: */ ++ if (copy_to_user(buffer, (char *)start, tsz)) ++ return -EFAULT; + } else { + if (kern_addr_valid(start)) { + /* +diff --git a/fs/signalfd.c b/fs/signalfd.c +index 9990957..76bf9cc 100644 +--- a/fs/signalfd.c ++++ b/fs/signalfd.c +@@ -118,13 +118,22 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, + err |= __put_user(kinfo->si_trapno, &uinfo->ssi_trapno); + #endif + #ifdef BUS_MCEERR_AO +- /* ++ /* ++ * Other callers might not initialize the si_lsb field, ++ * so check explicitly for the right codes here. ++ */ ++ if (kinfo->si_signo == SIGBUS && ++ kinfo->si_code == BUS_MCEERR_AO) ++ err |= __put_user((short) kinfo->si_addr_lsb, ++ &uinfo->ssi_addr_lsb); ++#endif ++#ifdef BUS_MCEERR_AR ++ /* + * Other callers might not initialize the si_lsb field, + * so check explicitly for the right codes here. + */ + if (kinfo->si_signo == SIGBUS && +- (kinfo->si_code == BUS_MCEERR_AR || +- kinfo->si_code == BUS_MCEERR_AO)) ++ kinfo->si_code == BUS_MCEERR_AR) + err |= __put_user((short) kinfo->si_addr_lsb, + &uinfo->ssi_addr_lsb); + #endif +diff --git a/fs/xfs/scrub/agheader.c b/fs/xfs/scrub/agheader.c +index fd97552..05c66e0 100644 +--- a/fs/xfs/scrub/agheader.c ++++ b/fs/xfs/scrub/agheader.c +@@ -767,7 +767,7 @@ int + xfs_scrub_agfl( + struct xfs_scrub_context *sc) + { +- struct xfs_scrub_agfl_info sai = { 0 }; ++ struct xfs_scrub_agfl_info sai; + struct xfs_agf *agf; + xfs_agnumber_t agno; + unsigned int agflcount; +@@ -795,6 +795,7 @@ xfs_scrub_agfl( + xfs_scrub_block_set_corrupt(sc, sc->sa.agf_bp); + goto out; + } ++ memset(&sai, 0, sizeof(sai)); + sai.sz_entries = agflcount; + sai.entries = kmem_zalloc(sizeof(xfs_agblock_t) * agflcount, KM_NOFS); + if (!sai.entries) { +diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c +index 66e1edb..046469f 100644 +--- a/fs/xfs/xfs_iomap.c ++++ b/fs/xfs/xfs_iomap.c +@@ -955,15 +955,29 @@ static inline bool imap_needs_alloc(struct inode *inode, + (IS_DAX(inode) && imap->br_state == XFS_EXT_UNWRITTEN); + } + ++static inline bool needs_cow_for_zeroing(struct xfs_bmbt_irec *imap, int nimaps) ++{ ++ return nimaps && ++ imap->br_startblock != HOLESTARTBLOCK && ++ imap->br_state != XFS_EXT_UNWRITTEN; ++} ++ + static inline bool need_excl_ilock(struct xfs_inode *ip, unsigned flags) + { + /* +- * COW writes will allocate delalloc space, so we need to make sure +- * to take the lock exclusively here. ++ * COW writes may allocate delalloc space or convert unwritten COW ++ * extents, so we need to make sure to take the lock exclusively here. + */ + if (xfs_is_reflink_inode(ip) && (flags & (IOMAP_WRITE | IOMAP_ZERO))) + return true; +- if ((flags & IOMAP_DIRECT) && (flags & IOMAP_WRITE)) ++ ++ /* ++ * Extents not yet cached requires exclusive access, don't block. ++ * This is an opencoded xfs_ilock_data_map_shared() to cater for the ++ * non-blocking behaviour. ++ */ ++ if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE && ++ !(ip->i_df.if_flags & XFS_IFEXTENTS)) + return true; + return false; + } +@@ -993,16 +1007,18 @@ xfs_file_iomap_begin( + return xfs_file_iomap_begin_delay(inode, offset, length, iomap); + } + +- if (need_excl_ilock(ip, flags)) { ++ if (need_excl_ilock(ip, flags)) + lockmode = XFS_ILOCK_EXCL; +- xfs_ilock(ip, XFS_ILOCK_EXCL); +- } else { +- lockmode = xfs_ilock_data_map_shared(ip); +- } ++ else ++ lockmode = XFS_ILOCK_SHARED; + +- if ((flags & IOMAP_NOWAIT) && !(ip->i_df.if_flags & XFS_IFEXTENTS)) { +- error = -EAGAIN; +- goto out_unlock; ++ if (flags & IOMAP_NOWAIT) { ++ if (!(ip->i_df.if_flags & XFS_IFEXTENTS)) ++ return -EAGAIN; ++ if (!xfs_ilock_nowait(ip, lockmode)) ++ return -EAGAIN; ++ } else { ++ xfs_ilock(ip, lockmode); + } + + ASSERT(offset <= mp->m_super->s_maxbytes); +@@ -1024,7 +1040,9 @@ xfs_file_iomap_begin( + goto out_unlock; + } + +- if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { ++ if (xfs_is_reflink_inode(ip) && ++ ((flags & IOMAP_WRITE) || ++ ((flags & IOMAP_ZERO) && needs_cow_for_zeroing(&imap, nimaps)))) { + if (flags & IOMAP_DIRECT) { + /* + * A reflinked inode will result in CoW alloc. +diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c +index 3a55d6f..7a39f40 100644 +--- a/fs/xfs/xfs_refcount_item.c ++++ b/fs/xfs/xfs_refcount_item.c +@@ -23,6 +23,7 @@ + #include "xfs_log_format.h" + #include "xfs_trans_resv.h" + #include "xfs_bit.h" ++#include "xfs_shared.h" + #include "xfs_mount.h" + #include "xfs_defer.h" + #include "xfs_trans.h" +@@ -456,10 +457,12 @@ xfs_cui_recover( + * transaction. Normally, any work that needs to be deferred + * gets attached to the same defer_ops that scheduled the + * refcount update. However, we're in log recovery here, so we +- * we create our own defer_ops and use that to finish up any +- * work that doesn't fit. ++ * we use the passed in defer_ops and to finish up any work that ++ * doesn't fit. We need to reserve enough blocks to handle a ++ * full btree split on either end of the refcount range. + */ +- error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); ++ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, ++ mp->m_refc_maxlevels * 2, 0, XFS_TRANS_RESERVE, &tp); + if (error) + return error; + cudp = xfs_trans_get_cud(tp, cuip); +diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c +index f3b139c..49d3124 100644 +--- a/fs/xfs/xfs_rmap_item.c ++++ b/fs/xfs/xfs_rmap_item.c +@@ -23,6 +23,7 @@ + #include "xfs_log_format.h" + #include "xfs_trans_resv.h" + #include "xfs_bit.h" ++#include "xfs_shared.h" + #include "xfs_mount.h" + #include "xfs_defer.h" + #include "xfs_trans.h" +@@ -470,7 +471,8 @@ xfs_rui_recover( + } + } + +- error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); ++ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, ++ mp->m_rmap_maxlevels, 0, XFS_TRANS_RESERVE, &tp); + if (error) + return error; + rudp = xfs_trans_get_rud(tp, ruip); +diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c +index 7aba628..93588ea 100644 +--- a/fs/xfs/xfs_super.c ++++ b/fs/xfs/xfs_super.c +@@ -250,6 +250,7 @@ xfs_parseargs( + return -EINVAL; + break; + case Opt_logdev: ++ kfree(mp->m_logname); + mp->m_logname = match_strdup(args); + if (!mp->m_logname) + return -ENOMEM; +@@ -258,6 +259,7 @@ xfs_parseargs( + xfs_warn(mp, "%s option not allowed on this system", p); + return -EINVAL; + case Opt_rtdev: ++ kfree(mp->m_rtname); + mp->m_rtname = match_strdup(args); + if (!mp->m_rtname) + return -ENOMEM; +diff --git a/include/asm-generic/bitops/lock.h b/include/asm-generic/bitops/lock.h +index bc39757..67ab280 100644 +--- a/include/asm-generic/bitops/lock.h ++++ b/include/asm-generic/bitops/lock.h +@@ -7,7 +7,8 @@ + * @nr: Bit to set + * @addr: Address to count from + * +- * This operation is atomic and provides acquire barrier semantics. ++ * This operation is atomic and provides acquire barrier semantics if ++ * the returned value is 0. + * It can be used to implement bit locks. + */ + #define test_and_set_bit_lock(nr, addr) test_and_set_bit(nr, addr) +diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h +index 963b755..a7613e1 100644 +--- a/include/asm-generic/bug.h ++++ b/include/asm-generic/bug.h +@@ -52,6 +52,7 @@ struct bug_entry { + #ifndef HAVE_ARCH_BUG + #define BUG() do { \ + printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \ ++ barrier_before_unreachable(); \ + panic("BUG!"); \ + } while (0) + #endif +diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h +index 1c27526..cf13842 100644 +--- a/include/drm/drm_atomic.h ++++ b/include/drm/drm_atomic.h +@@ -134,6 +134,15 @@ struct drm_crtc_commit { + * &drm_pending_vblank_event pointer to clean up private events. + */ + struct drm_pending_vblank_event *event; ++ ++ /** ++ * @abort_completion: ++ * ++ * A flag that's set after drm_atomic_helper_setup_commit takes a second ++ * reference for the completion of $drm_crtc_state.event. It's used by ++ * the free code to remove the second reference if commit fails. ++ */ ++ bool abort_completion; + }; + + struct __drm_planes_state { +diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h +index 76e237b..6914633 100644 +--- a/include/drm/drm_crtc_helper.h ++++ b/include/drm/drm_crtc_helper.h +@@ -77,5 +77,6 @@ void drm_kms_helper_hotplug_event(struct drm_device *dev); + + void drm_kms_helper_poll_disable(struct drm_device *dev); + void drm_kms_helper_poll_enable(struct drm_device *dev); ++bool drm_kms_helper_is_poll_worker(void); + + #endif +diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h +index d32b688..d23dcdd 100644 +--- a/include/drm/drm_drv.h ++++ b/include/drm/drm_drv.h +@@ -56,6 +56,7 @@ struct drm_printer; + #define DRIVER_ATOMIC 0x10000 + #define DRIVER_KMS_LEGACY_CONTEXT 0x20000 + #define DRIVER_SYNCOBJ 0x40000 ++#define DRIVER_PREFER_XBGR_30BPP 0x80000 + + /** + * struct drm_driver - DRM driver structure +diff --git a/include/linux/acpi.h b/include/linux/acpi.h +index 64e1074..968173e 100644 +--- a/include/linux/acpi.h ++++ b/include/linux/acpi.h +@@ -587,7 +587,7 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *), + const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, + const struct device *dev); + +-void *acpi_get_match_data(const struct device *dev); ++const void *acpi_device_get_match_data(const struct device *dev); + extern bool acpi_driver_match_device(struct device *dev, + const struct device_driver *drv); + int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *); +@@ -766,7 +766,7 @@ static inline const struct acpi_device_id *acpi_match_device( + return NULL; + } + +-static inline void *acpi_get_match_data(const struct device *dev) ++static inline const void *acpi_device_get_match_data(const struct device *dev) + { + return NULL; + } +diff --git a/include/linux/bio.h b/include/linux/bio.h +index d0eb659..ce547a2 100644 +--- a/include/linux/bio.h ++++ b/include/linux/bio.h +@@ -511,6 +511,7 @@ void zero_fill_bio(struct bio *bio); + extern struct bio_vec *bvec_alloc(gfp_t, int, unsigned long *, mempool_t *); + extern void bvec_free(mempool_t *, struct bio_vec *, unsigned int); + extern unsigned int bvec_nr_vecs(unsigned short idx); ++extern const char *bio_devname(struct bio *bio, char *buffer); + + #define bio_set_dev(bio, bdev) \ + do { \ +@@ -529,9 +530,6 @@ do { \ + #define bio_dev(bio) \ + disk_devt((bio)->bi_disk) + +-#define bio_devname(bio, buf) \ +- __bdevname(bio_dev(bio), (buf)) +- + #ifdef CONFIG_BLK_CGROUP + int bio_associate_blkcg(struct bio *bio, struct cgroup_subsys_state *blkcg_css); + void bio_disassociate_task(struct bio *bio); +diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h +index 4f3df80..ed63f3b 100644 +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -49,7 +49,7 @@ struct blk_stat_callback; + #define BLKDEV_MIN_RQ 4 + #define BLKDEV_MAX_RQ 128 /* Default maximum */ + +-/* Must be consisitent with blk_mq_poll_stats_bkt() */ ++/* Must be consistent with blk_mq_poll_stats_bkt() */ + #define BLK_MQ_POLL_STATS_BKTS 16 + + /* +diff --git a/include/linux/compat.h b/include/linux/compat.h +index 8a96438..16c3027 100644 +--- a/include/linux/compat.h ++++ b/include/linux/compat.h +@@ -17,6 +17,7 @@ + #include + #include + #include /* for aio_context_t */ ++#include + #include + + #include +@@ -229,13 +230,13 @@ typedef struct compat_siginfo { + short int _addr_lsb; /* Valid LSB of the reported address. */ + /* used when si_code=SEGV_BNDERR */ + struct { +- short _dummy_bnd; ++ compat_uptr_t _dummy_bnd; + compat_uptr_t _lower; + compat_uptr_t _upper; + } _addr_bnd; + /* used when si_code=SEGV_PKUERR */ + struct { +- short _dummy_pkey; ++ compat_uptr_t _dummy_pkey; + u32 _pkey; + } _addr_pkey; + }; +@@ -550,8 +551,29 @@ asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, + asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp); + + extern int get_compat_sigset(sigset_t *set, const compat_sigset_t __user *compat); +-extern int put_compat_sigset(compat_sigset_t __user *compat, +- const sigset_t *set, unsigned int size); ++ ++/* ++ * Defined inline such that size can be compile time constant, which avoids ++ * CONFIG_HARDENED_USERCOPY complaining about copies from task_struct ++ */ ++static inline int ++put_compat_sigset(compat_sigset_t __user *compat, const sigset_t *set, ++ unsigned int size) ++{ ++ /* size <= sizeof(compat_sigset_t) <= sizeof(sigset_t) */ ++#ifdef __BIG_ENDIAN ++ compat_sigset_t v; ++ switch (_NSIG_WORDS) { ++ case 4: v.sig[7] = (set->sig[3] >> 32); v.sig[6] = set->sig[3]; ++ case 3: v.sig[5] = (set->sig[2] >> 32); v.sig[4] = set->sig[2]; ++ case 2: v.sig[3] = (set->sig[1] >> 32); v.sig[2] = set->sig[1]; ++ case 1: v.sig[1] = (set->sig[0] >> 32); v.sig[0] = set->sig[0]; ++ } ++ return copy_to_user(compat, &v, size) ? -EFAULT : 0; ++#else ++ return copy_to_user(compat, set, size) ? -EFAULT : 0; ++#endif ++} + + asmlinkage long compat_sys_migrate_pages(compat_pid_t pid, + compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes, +diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h +index d02a4df..d3f264a 100644 +--- a/include/linux/compiler-clang.h ++++ b/include/linux/compiler-clang.h +@@ -27,3 +27,8 @@ + #if __has_feature(address_sanitizer) + #define __SANITIZE_ADDRESS__ + #endif ++ ++/* Clang doesn't have a way to turn it off per-function, yet. */ ++#ifdef __noretpoline ++#undef __noretpoline ++#endif +diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h +index 631354a..e2c7f43 100644 +--- a/include/linux/compiler-gcc.h ++++ b/include/linux/compiler-gcc.h +@@ -93,6 +93,10 @@ + #define __weak __attribute__((weak)) + #define __alias(symbol) __attribute__((alias(#symbol))) + ++#ifdef RETPOLINE ++#define __noretpoline __attribute__((indirect_branch("keep"))) ++#endif ++ + /* + * it doesn't make sense on ARM (currently the only user of __naked) + * to trace naked functions because then mcount is called without +@@ -167,8 +171,6 @@ + + #if GCC_VERSION >= 40100 + # define __compiletime_object_size(obj) __builtin_object_size(obj, 0) +- +-#define __nostackprotector __attribute__((__optimize__("no-stack-protector"))) + #endif + + #if GCC_VERSION >= 40300 +@@ -196,6 +198,11 @@ + #endif /* __CHECKER__ */ + #endif /* GCC_VERSION >= 40300 */ + ++#if GCC_VERSION >= 40400 ++#define __optimize(level) __attribute__((__optimize__(level))) ++#define __nostackprotector __optimize("no-stack-protector") ++#endif /* GCC_VERSION >= 40400 */ ++ + #if GCC_VERSION >= 40500 + + #ifndef __CHECKER__ +@@ -205,6 +212,15 @@ + #endif + + /* ++ * calling noreturn functions, __builtin_unreachable() and __builtin_trap() ++ * confuse the stack allocation in gcc, leading to overly large stack ++ * frames, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82365 ++ * ++ * Adding an empty inline assembly before it works around the problem ++ */ ++#define barrier_before_unreachable() asm volatile("") ++ ++/* + * Mark a position in code as unreachable. This can be used to + * suppress control flow warnings after asm blocks that transfer + * control elsewhere. +@@ -214,7 +230,11 @@ + * unreleased. Really, we need to have autoconf for the kernel. + */ + #define unreachable() \ +- do { annotate_unreachable(); __builtin_unreachable(); } while (0) ++ do { \ ++ annotate_unreachable(); \ ++ barrier_before_unreachable(); \ ++ __builtin_unreachable(); \ ++ } while (0) + + /* Mark a function definition as prohibited from being cloned. */ + #define __noclone __attribute__((__noclone__, __optimize__("no-tracer"))) +diff --git a/include/linux/compiler.h b/include/linux/compiler.h +index c2cc57a..ab4711c 100644 +--- a/include/linux/compiler.h ++++ b/include/linux/compiler.h +@@ -86,6 +86,11 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, + # define barrier_data(ptr) barrier() + #endif + ++/* workaround for GCC PR82365 if needed */ ++#ifndef barrier_before_unreachable ++# define barrier_before_unreachable() do { } while (0) ++#endif ++ + /* Unreachable code */ + #ifdef CONFIG_STACK_VALIDATION + /* +@@ -277,6 +282,10 @@ unsigned long read_word_at_a_time(const void *addr) + + #endif /* __ASSEMBLY__ */ + ++#ifndef __optimize ++# define __optimize(level) ++#endif ++ + /* Compile time object size, -1 for unknown */ + #ifndef __compiletime_object_size + # define __compiletime_object_size(obj) -1 +diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h +index 871f9e2..0b3fc22 100644 +--- a/include/linux/cpuidle.h ++++ b/include/linux/cpuidle.h +@@ -225,7 +225,7 @@ static inline void cpuidle_coupled_parallel_barrier(struct cpuidle_device *dev, + } + #endif + +-#ifdef CONFIG_ARCH_HAS_CPU_RELAX ++#if defined(CONFIG_CPU_IDLE) && defined(CONFIG_ARCH_HAS_CPU_RELAX) + void cpuidle_poll_state_init(struct cpuidle_driver *drv); + #else + static inline void cpuidle_poll_state_init(struct cpuidle_driver *drv) {} +diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h +index d4a2a7d..bf53d89 100644 +--- a/include/linux/cpumask.h ++++ b/include/linux/cpumask.h +@@ -170,6 +170,8 @@ static inline unsigned int cpumask_local_spread(unsigned int i, int node) + for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask) + #define for_each_cpu_not(cpu, mask) \ + for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask) ++#define for_each_cpu_wrap(cpu, mask, start) \ ++ for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)(start)) + #define for_each_cpu_and(cpu, mask, and) \ + for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)and) + #else +diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h +index 34fe846..eb9eab4 100644 +--- a/include/linux/dma-mapping.h ++++ b/include/linux/dma-mapping.h +@@ -578,7 +578,7 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) + + /* + * This is a hack for the legacy x86 forbid_dac and iommu_sac_force. Please +- * don't use this is new code. ++ * don't use this in new code. + */ + #ifndef arch_dma_supported + #define arch_dma_supported(dev, mask) (1) +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 2a81556..79c4139 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -3198,7 +3198,7 @@ static inline bool vma_is_fsdax(struct vm_area_struct *vma) + if (!vma_is_dax(vma)) + return false; + inode = file_inode(vma->vm_file); +- if (inode->i_mode == S_IFCHR) ++ if (S_ISCHR(inode->i_mode)) + return false; /* device-dax */ + return true; + } +diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h +index 4fa1a48..4fe8f28 100644 +--- a/include/linux/fwnode.h ++++ b/include/linux/fwnode.h +@@ -73,8 +73,8 @@ struct fwnode_operations { + struct fwnode_handle *(*get)(struct fwnode_handle *fwnode); + void (*put)(struct fwnode_handle *fwnode); + bool (*device_is_available)(const struct fwnode_handle *fwnode); +- void *(*device_get_match_data)(const struct fwnode_handle *fwnode, +- const struct device *dev); ++ const void *(*device_get_match_data)(const struct fwnode_handle *fwnode, ++ const struct device *dev); + bool (*property_present)(const struct fwnode_handle *fwnode, + const char *propname); + int (*property_read_int_array)(const struct fwnode_handle *fwnode, +diff --git a/include/linux/genhd.h b/include/linux/genhd.h +index 5e35310..c826b0b 100644 +--- a/include/linux/genhd.h ++++ b/include/linux/genhd.h +@@ -198,6 +198,7 @@ struct gendisk { + void *private_data; + + int flags; ++ struct rw_semaphore lookup_sem; + struct kobject *slave_dir; + + struct timer_rand_state *random; +@@ -600,8 +601,9 @@ extern void delete_partition(struct gendisk *, int); + extern void printk_all_partitions(void); + + extern struct gendisk *__alloc_disk_node(int minors, int node_id); +-extern struct kobject *get_disk(struct gendisk *disk); ++extern struct kobject *get_disk_and_module(struct gendisk *disk); + extern void put_disk(struct gendisk *disk); ++extern void put_disk_and_module(struct gendisk *disk); + extern void blk_register_region(dev_t devt, unsigned long range, + struct module *module, + struct kobject *(*probe)(dev_t, int *, void *), +diff --git a/include/linux/init.h b/include/linux/init.h +index 506a981..bc27cf0 100644 +--- a/include/linux/init.h ++++ b/include/linux/init.h +@@ -6,10 +6,10 @@ + #include + + /* Built-in __init functions needn't be compiled with retpoline */ +-#if defined(RETPOLINE) && !defined(MODULE) +-#define __noretpoline __attribute__((indirect_branch("keep"))) ++#if defined(__noretpoline) && !defined(MODULE) ++#define __noinitretpoline __noretpoline + #else +-#define __noretpoline ++#define __noinitretpoline + #endif + + /* These macros are used to mark some functions or +@@ -47,7 +47,7 @@ + + /* These are for everybody (although not all archs will actually + discard it in modules) */ +-#define __init __section(.init.text) __cold __latent_entropy __noretpoline ++#define __init __section(.init.text) __cold __latent_entropy __noinitretpoline + #define __initdata __section(.init.data) + #define __initconst __section(.init.rodata) + #define __exitdata __section(.exit.data) +diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h +index b6a29c1..2168cc6 100644 +--- a/include/linux/jump_label.h ++++ b/include/linux/jump_label.h +@@ -151,6 +151,7 @@ extern struct jump_entry __start___jump_table[]; + extern struct jump_entry __stop___jump_table[]; + + extern void jump_label_init(void); ++extern void jump_label_invalidate_init(void); + extern void jump_label_lock(void); + extern void jump_label_unlock(void); + extern void arch_jump_label_transform(struct jump_entry *entry, +@@ -198,6 +199,8 @@ static __always_inline void jump_label_init(void) + static_key_initialized = true; + } + ++static inline void jump_label_invalidate_init(void) {} ++ + static __always_inline bool static_key_false(struct static_key *key) + { + if (unlikely(static_key_count(key) > 0)) +diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h +index fec5076..dcde947 100644 +--- a/include/linux/kconfig.h ++++ b/include/linux/kconfig.h +@@ -4,6 +4,12 @@ + + #include + ++#ifdef CONFIG_CPU_BIG_ENDIAN ++#define __BIG_ENDIAN 4321 ++#else ++#define __LITTLE_ENDIAN 1234 ++#endif ++ + #define __ARG_PLACEHOLDER_1 0, + #define __take_second_arg(__ignored, val, ...) val + +@@ -64,4 +70,7 @@ + */ + #define IS_ENABLED(option) __or(IS_BUILTIN(option), IS_MODULE(option)) + ++/* Make sure we always have all types and struct attributes defined. */ ++#include ++ + #endif /* __LINUX_KCONFIG_H */ +diff --git a/include/linux/kcore.h b/include/linux/kcore.h +index 7ff25a8..80db19d 100644 +--- a/include/linux/kcore.h ++++ b/include/linux/kcore.h +@@ -10,6 +10,7 @@ enum kcore_type { + KCORE_VMALLOC, + KCORE_RAM, + KCORE_VMEMMAP, ++ KCORE_USER, + KCORE_OTHER, + }; + +diff --git a/include/linux/kernel.h b/include/linux/kernel.h +index ce51455..3fd2915 100644 +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -472,6 +472,7 @@ extern bool parse_option_str(const char *str, const char *option); + extern char *next_arg(char *args, char **param, char **val); + + extern int core_kernel_text(unsigned long addr); ++extern int init_kernel_text(unsigned long addr); + extern int core_kernel_data(unsigned long addr); + extern int __kernel_text_address(unsigned long addr); + extern int kernel_text_address(unsigned long addr); +diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h +index ac0062b..6930c63 100644 +--- a/include/linux/kvm_host.h ++++ b/include/linux/kvm_host.h +@@ -1105,7 +1105,6 @@ static inline void kvm_irq_routing_update(struct kvm *kvm) + { + } + #endif +-void kvm_arch_irq_routing_update(struct kvm *kvm); + + static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) + { +@@ -1114,6 +1113,8 @@ static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) + + #endif /* CONFIG_HAVE_KVM_EVENTFD */ + ++void kvm_arch_irq_routing_update(struct kvm *kvm); ++ + static inline void kvm_make_request(int req, struct kvm_vcpu *vcpu) + { + /* +@@ -1272,4 +1273,7 @@ static inline long kvm_arch_vcpu_async_ioctl(struct file *filp, + } + #endif /* CONFIG_HAVE_KVM_VCPU_ASYNC_IOCTL */ + ++void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm, ++ unsigned long start, unsigned long end); ++ + #endif +diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h +index 8820468..c46016b 100644 +--- a/include/linux/memcontrol.h ++++ b/include/linux/memcontrol.h +@@ -523,9 +523,11 @@ static inline void __mod_memcg_state(struct mem_cgroup *memcg, + static inline void mod_memcg_state(struct mem_cgroup *memcg, + int idx, int val) + { +- preempt_disable(); ++ unsigned long flags; ++ ++ local_irq_save(flags); + __mod_memcg_state(memcg, idx, val); +- preempt_enable(); ++ local_irq_restore(flags); + } + + /** +@@ -606,9 +608,11 @@ static inline void __mod_lruvec_state(struct lruvec *lruvec, + static inline void mod_lruvec_state(struct lruvec *lruvec, + enum node_stat_item idx, int val) + { +- preempt_disable(); ++ unsigned long flags; ++ ++ local_irq_save(flags); + __mod_lruvec_state(lruvec, idx, val); +- preempt_enable(); ++ local_irq_restore(flags); + } + + static inline void __mod_lruvec_page_state(struct page *page, +@@ -630,9 +634,11 @@ static inline void __mod_lruvec_page_state(struct page *page, + static inline void mod_lruvec_page_state(struct page *page, + enum node_stat_item idx, int val) + { +- preempt_disable(); ++ unsigned long flags; ++ ++ local_irq_save(flags); + __mod_lruvec_page_state(page, idx, val); +- preempt_enable(); ++ local_irq_restore(flags); + } + + unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order, +@@ -659,9 +665,11 @@ static inline void __count_memcg_events(struct mem_cgroup *memcg, + static inline void count_memcg_events(struct mem_cgroup *memcg, + int idx, unsigned long count) + { +- preempt_disable(); ++ unsigned long flags; ++ ++ local_irq_save(flags); + __count_memcg_events(memcg, idx, count); +- preempt_enable(); ++ local_irq_restore(flags); + } + + /* idx can be of type enum memcg_event_item or vm_event_item */ +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index c30b32e..10191c2 100644 +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -127,10 +127,4 @@ static __always_inline enum lru_list page_lru(struct page *page) + + #define lru_to_page(head) (list_entry((head)->prev, struct page, lru)) + +-#ifdef arch_unmap_kpfn +-extern void arch_unmap_kpfn(unsigned long pfn); +-#else +-static __always_inline void arch_unmap_kpfn(unsigned long pfn) { } +-#endif +- + #endif +diff --git a/include/linux/mutex.h b/include/linux/mutex.h +index f25c134..cb3bbed 100644 +--- a/include/linux/mutex.h ++++ b/include/linux/mutex.h +@@ -66,6 +66,11 @@ struct mutex { + #endif + }; + ++/* ++ * Internal helper function; C doesn't allow us to hide it :/ ++ * ++ * DO NOT USE (outside of mutex code). ++ */ + static inline struct task_struct *__mutex_owner(struct mutex *lock) + { + return (struct task_struct *)(atomic_long_read(&lock->owner) & ~0x07); +diff --git a/include/linux/nospec.h b/include/linux/nospec.h +index b99bced..e791ebc 100644 +--- a/include/linux/nospec.h ++++ b/include/linux/nospec.h +@@ -5,6 +5,7 @@ + + #ifndef _LINUX_NOSPEC_H + #define _LINUX_NOSPEC_H ++#include + + /** + * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise +@@ -20,20 +21,6 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, + unsigned long size) + { + /* +- * Warn developers about inappropriate array_index_nospec() usage. +- * +- * Even if the CPU speculates past the WARN_ONCE branch, the +- * sign bit of @index is taken into account when generating the +- * mask. +- * +- * This warning is compiled out when the compiler can infer that +- * @index and @size are less than LONG_MAX. +- */ +- if (WARN_ONCE(index > LONG_MAX || size > LONG_MAX, +- "array_index_nospec() limited to range of [0, LONG_MAX]\n")) +- return 0; +- +- /* + * Always calculate and emit the mask even if the compiler + * thinks the mask is not needed. The compiler does not take + * into account the value of @index under speculation. +@@ -66,7 +53,6 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, + BUILD_BUG_ON(sizeof(_i) > sizeof(long)); \ + BUILD_BUG_ON(sizeof(_s) > sizeof(long)); \ + \ +- _i &= _mask; \ +- _i; \ ++ (typeof(_i)) (_i & _mask); \ + }) + #endif /* _LINUX_NOSPEC_H */ +diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h +index 88865e0..091033a 100644 +--- a/include/linux/of_pci.h ++++ b/include/linux/of_pci.h +@@ -13,7 +13,6 @@ struct device_node; + struct device_node *of_pci_find_child_device(struct device_node *parent, + unsigned int devfn); + int of_pci_get_devfn(struct device_node *np); +-int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin); + int of_pci_parse_bus_range(struct device_node *node, struct resource *res); + int of_get_pci_domain_nr(struct device_node *node); + int of_pci_get_max_link_speed(struct device_node *node); +@@ -34,12 +33,6 @@ static inline int of_pci_get_devfn(struct device_node *np) + } + + static inline int +-of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin) +-{ +- return 0; +-} +- +-static inline int + of_pci_parse_bus_range(struct device_node *node, struct resource *res) + { + return -EINVAL; +@@ -67,6 +60,16 @@ of_pci_get_max_link_speed(struct device_node *node) + static inline void of_pci_check_probe_only(void) { } + #endif + ++#if IS_ENABLED(CONFIG_OF_IRQ) ++int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin); ++#else ++static inline int ++of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ return 0; ++} ++#endif ++ + #if defined(CONFIG_OF_ADDRESS) + int of_pci_get_host_bridge_resources(struct device_node *dev, + unsigned char busno, unsigned char bus_max, +diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h +index af0f44ef..40036a5 100644 +--- a/include/linux/perf/arm_pmu.h ++++ b/include/linux/perf/arm_pmu.h +@@ -14,26 +14,10 @@ + + #include + #include ++#include + #include + #include + +-/* +- * struct arm_pmu_platdata - ARM PMU platform data +- * +- * @handle_irq: an optional handler which will be called from the +- * interrupt and passed the address of the low level handler, +- * and can be used to implement any platform specific handling +- * before or after calling it. +- * +- * @irq_flags: if non-zero, these flags will be passed to request_irq +- * when requesting interrupts for this PMU device. +- */ +-struct arm_pmu_platdata { +- irqreturn_t (*handle_irq)(int irq, void *dev, +- irq_handler_t pmu_handler); +- unsigned long irq_flags; +-}; +- + #ifdef CONFIG_ARM_PMU + + /* +@@ -92,7 +76,6 @@ enum armpmu_attr_groups { + + struct arm_pmu { + struct pmu pmu; +- cpumask_t active_irqs; + cpumask_t supported_cpus; + char *name; + irqreturn_t (*handle_irq)(int irq_num, void *dev); +@@ -174,12 +157,11 @@ static inline int arm_pmu_acpi_probe(armpmu_init_fn init_fn) { return 0; } + + /* Internal functions only for core arm_pmu code */ + struct arm_pmu *armpmu_alloc(void); ++struct arm_pmu *armpmu_alloc_atomic(void); + void armpmu_free(struct arm_pmu *pmu); + int armpmu_register(struct arm_pmu *pmu); +-int armpmu_request_irqs(struct arm_pmu *armpmu); +-void armpmu_free_irqs(struct arm_pmu *armpmu); +-int armpmu_request_irq(struct arm_pmu *armpmu, int cpu); +-void armpmu_free_irq(struct arm_pmu *armpmu, int cpu); ++int armpmu_request_irq(int irq, int cpu); ++void armpmu_free_irq(int irq, int cpu); + + #define ARMV8_PMU_PDEV_NAME "armv8-pmu" + +diff --git a/include/linux/phy.h b/include/linux/phy.h +index 5a0c3e5..d706953 100644 +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -924,6 +924,7 @@ void phy_device_remove(struct phy_device *phydev); + int phy_init_hw(struct phy_device *phydev); + int phy_suspend(struct phy_device *phydev); + int phy_resume(struct phy_device *phydev); ++int __phy_resume(struct phy_device *phydev); + int phy_loopback(struct phy_device *phydev, bool enable); + struct phy_device *phy_attach(struct net_device *dev, const char *bus_id, + phy_interface_t interface); +diff --git a/include/linux/property.h b/include/linux/property.h +index 769d372..2eea4b3 100644 +--- a/include/linux/property.h ++++ b/include/linux/property.h +@@ -283,7 +283,7 @@ bool device_dma_supported(struct device *dev); + + enum dev_dma_attr device_get_dma_attr(struct device *dev); + +-void *device_get_match_data(struct device *dev); ++const void *device_get_match_data(struct device *dev); + + int device_get_phy_mode(struct device *dev); + +diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h +index b884b77..e633522 100644 +--- a/include/linux/ptr_ring.h ++++ b/include/linux/ptr_ring.h +@@ -469,7 +469,7 @@ static inline int ptr_ring_consume_batched_bh(struct ptr_ring *r, + */ + static inline void **__ptr_ring_init_queue_alloc(unsigned int size, gfp_t gfp) + { +- if (size * sizeof(void *) > KMALLOC_MAX_SIZE) ++ if (size > KMALLOC_MAX_SIZE / sizeof(void *)) + return NULL; + return kvmalloc_array(size, sizeof(void *), gfp | __GFP_ZERO); + } +diff --git a/include/linux/sched/mm.h b/include/linux/sched/mm.h +index 1149533..9806184 100644 +--- a/include/linux/sched/mm.h ++++ b/include/linux/sched/mm.h +@@ -36,7 +36,18 @@ static inline void mmgrab(struct mm_struct *mm) + atomic_inc(&mm->mm_count); + } + +-extern void mmdrop(struct mm_struct *mm); ++extern void __mmdrop(struct mm_struct *mm); ++ ++static inline void mmdrop(struct mm_struct *mm) ++{ ++ /* ++ * The implicit full barrier implied by atomic_dec_and_test() is ++ * required by the membarrier system call before returning to ++ * user-space, after storing to rq->curr. ++ */ ++ if (unlikely(atomic_dec_and_test(&mm->mm_count))) ++ __mmdrop(mm); ++} + + /** + * mmget() - Pin the address space associated with a &struct mm_struct. +diff --git a/include/linux/sched/user.h b/include/linux/sched/user.h +index 0dcf4e4..96fe289 100644 +--- a/include/linux/sched/user.h ++++ b/include/linux/sched/user.h +@@ -4,6 +4,7 @@ + + #include + #include ++#include + + struct key; + +@@ -41,6 +42,9 @@ struct user_struct { + defined(CONFIG_NET) + atomic_long_t locked_vm; + #endif ++ ++ /* Miscellaneous per-user rate limit */ ++ struct ratelimit_state ratelimit; + }; + + extern int uids_sysfs_init(void); +diff --git a/include/linux/semaphore.h b/include/linux/semaphore.h +index dc368b8..11c86fb 100644 +--- a/include/linux/semaphore.h ++++ b/include/linux/semaphore.h +@@ -4,7 +4,7 @@ + * + * Distributed under the terms of the GNU GPL, version 2 + * +- * Please see kernel/semaphore.c for documentation of these functions ++ * Please see kernel/locking/semaphore.c for documentation of these functions + */ + #ifndef __LINUX_SEMAPHORE_H + #define __LINUX_SEMAPHORE_H +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index 5ebc0f8..ddf77cf 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -3285,8 +3285,7 @@ int skb_zerocopy(struct sk_buff *to, struct sk_buff *from, + void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len); + int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen); + void skb_scrub_packet(struct sk_buff *skb, bool xnet); +-unsigned int skb_gso_transport_seglen(const struct sk_buff *skb); +-bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu); ++bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu); + bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len); + struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); + struct sk_buff *skb_vlan_untag(struct sk_buff *skb); +@@ -3646,7 +3645,7 @@ static inline bool __skb_checksum_validate_needed(struct sk_buff *skb, + return true; + } + +-/* For small packets <= CHECKSUM_BREAK peform checksum complete directly ++/* For small packets <= CHECKSUM_BREAK perform checksum complete directly + * in checksum_init. + */ + #define CHECKSUM_BREAK 76 +@@ -4104,38 +4103,6 @@ static inline bool skb_head_is_locked(const struct sk_buff *skb) + return !skb->head_frag || skb_cloned(skb); + } + +-/** +- * skb_gso_network_seglen - Return length of individual segments of a gso packet +- * +- * @skb: GSO skb +- * +- * skb_gso_network_seglen is used to determine the real size of the +- * individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP). +- * +- * The MAC/L2 header is not accounted for. +- */ +-static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb) +-{ +- unsigned int hdr_len = skb_transport_header(skb) - +- skb_network_header(skb); +- return hdr_len + skb_gso_transport_seglen(skb); +-} +- +-/** +- * skb_gso_mac_seglen - Return length of individual segments of a gso packet +- * +- * @skb: GSO skb +- * +- * skb_gso_mac_seglen is used to determine the real size of the +- * individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4 +- * headers (TCP/UDP). +- */ +-static inline unsigned int skb_gso_mac_seglen(const struct sk_buff *skb) +-{ +- unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb); +- return hdr_len + skb_gso_transport_seglen(skb); +-} +- + /* Local Checksum Offload. + * Compute outer checksum based on the assumption that the + * inner checksum will be offloaded later. +diff --git a/include/linux/swap.h b/include/linux/swap.h +index 7b6a59f..a1a3f4e 100644 +--- a/include/linux/swap.h ++++ b/include/linux/swap.h +@@ -337,8 +337,6 @@ extern void deactivate_file_page(struct page *page); + extern void mark_page_lazyfree(struct page *page); + extern void swap_setup(void); + +-extern void add_page_to_unevictable_list(struct page *page); +- + extern void lru_cache_add_active_or_unevictable(struct page *page, + struct vm_area_struct *vma); + +diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h +index 4a54ef9..bc0cda1 100644 +--- a/include/linux/workqueue.h ++++ b/include/linux/workqueue.h +@@ -465,6 +465,7 @@ extern bool cancel_delayed_work_sync(struct delayed_work *dwork); + + extern void workqueue_set_max_active(struct workqueue_struct *wq, + int max_active); ++extern struct work_struct *current_work(void); + extern bool current_is_workqueue_rescuer(void); + extern bool workqueue_congested(int cpu, struct workqueue_struct *wq); + extern unsigned int work_busy(struct work_struct *work); +diff --git a/include/media/demux.h b/include/media/demux.h +index c4df6ce..bf00a5a 100644 +--- a/include/media/demux.h ++++ b/include/media/demux.h +@@ -117,7 +117,7 @@ struct dmx_ts_feed { + * specified by @filter_value that will be used on the filter + * match logic. + * @filter_mode: Contains a 16 bytes (128 bits) filter mode. +- * @parent: Pointer to struct dmx_section_feed. ++ * @parent: Back-pointer to struct dmx_section_feed. + * @priv: Pointer to private data of the API client. + * + * +@@ -130,8 +130,9 @@ struct dmx_section_filter { + u8 filter_value[DMX_MAX_FILTER_SIZE]; + u8 filter_mask[DMX_MAX_FILTER_SIZE]; + u8 filter_mode[DMX_MAX_FILTER_SIZE]; +- struct dmx_section_feed *parent; /* Back-pointer */ +- void *priv; /* Pointer to private data of the API client */ ++ struct dmx_section_feed *parent; ++ ++ void *priv; + }; + + /** +@@ -193,6 +194,10 @@ struct dmx_section_feed { + * @buffer2: Pointer to the tail of the filtered TS packets, or NULL. + * @buffer2_length: Length of the TS data in buffer2. + * @source: Indicates which TS feed is the source of the callback. ++ * @buffer_flags: Address where buffer flags are stored. Those are ++ * used to report discontinuity users via DVB ++ * memory mapped API, as defined by ++ * &enum dmx_buffer_flags. + * + * This function callback prototype, provided by the client of the demux API, + * is called from the demux code. The function is only called when filtering +@@ -245,7 +250,8 @@ typedef int (*dmx_ts_cb)(const u8 *buffer1, + size_t buffer1_length, + const u8 *buffer2, + size_t buffer2_length, +- struct dmx_ts_feed *source); ++ struct dmx_ts_feed *source, ++ u32 *buffer_flags); + + /** + * typedef dmx_section_cb - DVB demux TS filter callback function prototype +@@ -261,6 +267,10 @@ typedef int (*dmx_ts_cb)(const u8 *buffer1, + * including headers and CRC. + * @source: Indicates which section feed is the source of the + * callback. ++ * @buffer_flags: Address where buffer flags are stored. Those are ++ * used to report discontinuity users via DVB ++ * memory mapped API, as defined by ++ * &enum dmx_buffer_flags. + * + * This function callback prototype, provided by the client of the demux API, + * is called from the demux code. The function is only called when +@@ -286,7 +296,8 @@ typedef int (*dmx_section_cb)(const u8 *buffer1, + size_t buffer1_len, + const u8 *buffer2, + size_t buffer2_len, +- struct dmx_section_filter *source); ++ struct dmx_section_filter *source, ++ u32 *buffer_flags); + + /* + * DVB Front-End +diff --git a/include/media/dmxdev.h b/include/media/dmxdev.h +index 2f5cb2c..baafa3b 100644 +--- a/include/media/dmxdev.h ++++ b/include/media/dmxdev.h +@@ -163,6 +163,7 @@ struct dmxdev_filter { + * @demux: pointer to &struct dmx_demux. + * @filternum: number of filters. + * @capabilities: demux capabilities as defined by &enum dmx_demux_caps. ++ * @may_do_mmap: flag used to indicate if the device may do mmap. + * @exit: flag to indicate that the demux is being released. + * @dvr_orig_fe: pointer to &struct dmx_frontend. + * @dvr_buffer: embedded &struct dvb_ringbuffer for DVB output. +@@ -180,6 +181,7 @@ struct dmxdev { + int filternum; + int capabilities; + ++ unsigned int may_do_mmap:1; + unsigned int exit:1; + #define DMXDEV_CAP_DUPLEX 1 + struct dmx_frontend *dvr_orig_fe; +diff --git a/include/media/dvb_demux.h b/include/media/dvb_demux.h +index b070920..3b6aeca 100644 +--- a/include/media/dvb_demux.h ++++ b/include/media/dvb_demux.h +@@ -115,6 +115,8 @@ struct dvb_demux_filter { + * @pid: PID to be filtered. + * @timeout: feed timeout. + * @filter: pointer to &struct dvb_demux_filter. ++ * @buffer_flags: Buffer flags used to report discontinuity users via DVB ++ * memory mapped API, as defined by &enum dmx_buffer_flags. + * @ts_type: type of TS, as defined by &enum ts_filter_type. + * @pes_type: type of PES, as defined by &enum dmx_ts_pes. + * @cc: MPEG-TS packet continuity counter +@@ -145,6 +147,8 @@ struct dvb_demux_feed { + ktime_t timeout; + struct dvb_demux_filter *filter; + ++ u32 buffer_flags; ++ + enum ts_filter_type ts_type; + enum dmx_ts_pes pes_type; + +diff --git a/include/media/dvb_vb2.h b/include/media/dvb_vb2.h +index 01d1202..8cb8845 100644 +--- a/include/media/dvb_vb2.h ++++ b/include/media/dvb_vb2.h +@@ -85,6 +85,12 @@ struct dvb_buffer { + * @nonblocking: + * If different than zero, device is operating on non-blocking + * mode. ++ * @flags: buffer flags as defined by &enum dmx_buffer_flags. ++ * Filled only at &DMX_DQBUF. &DMX_QBUF should zero this field. ++ * @count: monotonic counter for filled buffers. Helps to identify ++ * data stream loses. Filled only at &DMX_DQBUF. &DMX_QBUF should ++ * zero this field. ++ * + * @name: name of the device type. Currently, it can either be + * "dvr" or "demux_filter". + */ +@@ -100,10 +106,14 @@ struct dvb_vb2_ctx { + int buf_siz; + int buf_cnt; + int nonblocking; ++ ++ enum dmx_buffer_flags flags; ++ u32 count; ++ + char name[DVB_VB2_NAME_MAX + 1]; + }; + +-#ifndef DVB_MMAP ++#ifndef CONFIG_DVB_MMAP + static inline int dvb_vb2_init(struct dvb_vb2_ctx *ctx, + const char *name, int non_blocking) + { +@@ -114,7 +124,7 @@ static inline int dvb_vb2_release(struct dvb_vb2_ctx *ctx) + return 0; + }; + #define dvb_vb2_is_streaming(ctx) (0) +-#define dvb_vb2_fill_buffer(ctx, file, wait) (0) ++#define dvb_vb2_fill_buffer(ctx, file, wait, flags) (0) + + static inline __poll_t dvb_vb2_poll(struct dvb_vb2_ctx *ctx, + struct file *file, +@@ -153,9 +163,13 @@ int dvb_vb2_is_streaming(struct dvb_vb2_ctx *ctx); + * @ctx: control struct for VB2 handler + * @src: place where the data is stored + * @len: number of bytes to be copied from @src ++ * @buffer_flags: ++ * pointer to buffer flags as defined by &enum dmx_buffer_flags. ++ * can be NULL. + */ + int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx, +- const unsigned char *src, int len); ++ const unsigned char *src, int len, ++ enum dmx_buffer_flags *buffer_flags); + + /** + * dvb_vb2_poll - Wrapper to vb2_core_streamon() for Digital TV +diff --git a/include/net/devlink.h b/include/net/devlink.h +index 6545b03..4de35ed 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -257,6 +257,18 @@ struct devlink_resource_size_params { + enum devlink_resource_unit unit; + }; + ++static inline void ++devlink_resource_size_params_init(struct devlink_resource_size_params *size_params, ++ u64 size_min, u64 size_max, ++ u64 size_granularity, ++ enum devlink_resource_unit unit) ++{ ++ size_params->size_min = size_min; ++ size_params->size_max = size_max; ++ size_params->size_granularity = size_granularity; ++ size_params->unit = unit; ++} ++ + /** + * struct devlink_resource - devlink resource + * @name: name of the resource +@@ -278,7 +290,7 @@ struct devlink_resource { + u64 size_new; + bool size_valid; + struct devlink_resource *parent; +- struct devlink_resource_size_params *size_params; ++ struct devlink_resource_size_params size_params; + struct list_head list; + struct list_head resource_list; + const struct devlink_resource_ops *resource_ops; +@@ -402,7 +414,7 @@ int devlink_resource_register(struct devlink *devlink, + u64 resource_size, + u64 resource_id, + u64 parent_resource_id, +- struct devlink_resource_size_params *size_params, ++ const struct devlink_resource_size_params *size_params, + const struct devlink_resource_ops *resource_ops); + void devlink_resources_unregister(struct devlink *devlink, + struct devlink_resource *resource); +@@ -556,7 +568,7 @@ devlink_resource_register(struct devlink *devlink, + u64 resource_size, + u64 resource_id, + u64 parent_resource_id, +- struct devlink_resource_size_params *size_params, ++ const struct devlink_resource_size_params *size_params, + const struct devlink_resource_ops *resource_ops) + { + return 0; +diff --git a/include/net/mac80211.h b/include/net/mac80211.h +index 906e902..c96511f 100644 +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -4149,7 +4149,7 @@ void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *sta, u8 tid); + * The TX headroom reserved by mac80211 for its own tx_status functions. + * This is enough for the radiotap header. + */ +-#define IEEE80211_TX_STATUS_HEADROOM 14 ++#define IEEE80211_TX_STATUS_HEADROOM ALIGN(14, 4) + + /** + * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames +diff --git a/include/net/regulatory.h b/include/net/regulatory.h +index ebc5a2e..f83cacc 100644 +--- a/include/net/regulatory.h ++++ b/include/net/regulatory.h +@@ -78,7 +78,7 @@ struct regulatory_request { + int wiphy_idx; + enum nl80211_reg_initiator initiator; + enum nl80211_user_reg_hint_type user_reg_hint_type; +- char alpha2[2]; ++ char alpha2[3]; + enum nl80211_dfs_regions dfs_region; + bool intersect; + bool processed; +diff --git a/include/net/udplite.h b/include/net/udplite.h +index 81bdbf9..9185e45 100644 +--- a/include/net/udplite.h ++++ b/include/net/udplite.h +@@ -64,6 +64,7 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) + UDP_SKB_CB(skb)->cscov = cscov; + if (skb->ip_summed == CHECKSUM_COMPLETE) + skb->ip_summed = CHECKSUM_NONE; ++ skb->csum_valid = 0; + } + + return 0; +diff --git a/include/rdma/restrack.h b/include/rdma/restrack.h +index c2d8116..2cdf8dc 100644 +--- a/include/rdma/restrack.h ++++ b/include/rdma/restrack.h +@@ -29,10 +29,6 @@ enum rdma_restrack_type { + */ + RDMA_RESTRACK_QP, + /** +- * @RDMA_RESTRACK_XRCD: XRC domain (XRCD) +- */ +- RDMA_RESTRACK_XRCD, +- /** + * @RDMA_RESTRACK_MAX: Last entry, used for array dclarations + */ + RDMA_RESTRACK_MAX +diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h +index 6da4407..38287d9 100644 +--- a/include/rdma/uverbs_ioctl.h ++++ b/include/rdma/uverbs_ioctl.h +@@ -276,10 +276,7 @@ struct uverbs_object_tree_def { + */ + + struct uverbs_ptr_attr { +- union { +- u64 data; +- void __user *ptr; +- }; ++ u64 data; + u16 len; + /* Combination of bits from enum UVERBS_ATTR_F_XXXX */ + u16 flags; +@@ -351,38 +348,60 @@ static inline const struct uverbs_attr *uverbs_attr_get(const struct uverbs_attr + } + + static inline int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle, +- size_t idx, const void *from) ++ size_t idx, const void *from, size_t size) + { + const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); + u16 flags; ++ size_t min_size; + + if (IS_ERR(attr)) + return PTR_ERR(attr); + ++ min_size = min_t(size_t, attr->ptr_attr.len, size); ++ if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size)) ++ return -EFAULT; ++ + flags = attr->ptr_attr.flags | UVERBS_ATTR_F_VALID_OUTPUT; +- return (!copy_to_user(attr->ptr_attr.ptr, from, attr->ptr_attr.len) && +- !put_user(flags, &attr->uattr->flags)) ? 0 : -EFAULT; ++ if (put_user(flags, &attr->uattr->flags)) ++ return -EFAULT; ++ ++ return 0; + } + +-static inline int _uverbs_copy_from(void *to, size_t to_size, ++static inline bool uverbs_attr_ptr_is_inline(const struct uverbs_attr *attr) ++{ ++ return attr->ptr_attr.len <= sizeof(attr->ptr_attr.data); ++} ++ ++static inline int _uverbs_copy_from(void *to, + const struct uverbs_attr_bundle *attrs_bundle, +- size_t idx) ++ size_t idx, ++ size_t size) + { + const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); + + if (IS_ERR(attr)) + return PTR_ERR(attr); + +- if (to_size <= sizeof(((struct ib_uverbs_attr *)0)->data)) ++ /* ++ * Validation ensures attr->ptr_attr.len >= size. If the caller is ++ * using UVERBS_ATTR_SPEC_F_MIN_SZ then it must call copy_from with ++ * the right size. ++ */ ++ if (unlikely(size < attr->ptr_attr.len)) ++ return -EINVAL; ++ ++ if (uverbs_attr_ptr_is_inline(attr)) + memcpy(to, &attr->ptr_attr.data, attr->ptr_attr.len); +- else if (copy_from_user(to, attr->ptr_attr.ptr, attr->ptr_attr.len)) ++ else if (copy_from_user(to, u64_to_user_ptr(attr->ptr_attr.data), ++ attr->ptr_attr.len)) + return -EFAULT; + + return 0; + } + + #define uverbs_copy_from(to, attrs_bundle, idx) \ +- _uverbs_copy_from(to, sizeof(*(to)), attrs_bundle, idx) ++ _uverbs_copy_from(to, attrs_bundle, idx, sizeof(*to)) + + /* ================================================= + * Definitions -> Specs infrastructure +diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h +index d8d4a90..2280b23 100644 +--- a/include/scsi/scsi_cmnd.h ++++ b/include/scsi/scsi_cmnd.h +@@ -68,6 +68,9 @@ struct scsi_cmnd { + struct list_head list; /* scsi_cmnd participates in queue lists */ + struct list_head eh_entry; /* entry for the host eh_cmd_q */ + struct delayed_work abort_work; ++ ++ struct rcu_head rcu; ++ + int eh_eflags; /* Used by error handlr */ + + /* +diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h +index 1a1df0d..a8b7bf8 100644 +--- a/include/scsi/scsi_host.h ++++ b/include/scsi/scsi_host.h +@@ -571,8 +571,6 @@ struct Scsi_Host { + struct blk_mq_tag_set tag_set; + }; + +- struct rcu_head rcu; +- + atomic_t host_busy; /* commands actually active on low-level */ + atomic_t host_blocked; + +diff --git a/include/soc/arc/mcip.h b/include/soc/arc/mcip.h +index c2d1b15..a91f251 100644 +--- a/include/soc/arc/mcip.h ++++ b/include/soc/arc/mcip.h +@@ -15,6 +15,7 @@ + + #define ARC_REG_MCIP_BCR 0x0d0 + #define ARC_REG_MCIP_IDU_BCR 0x0D5 ++#define ARC_REG_GFRC_BUILD 0x0D6 + #define ARC_REG_MCIP_CMD 0x600 + #define ARC_REG_MCIP_WDATA 0x601 + #define ARC_REG_MCIP_READBACK 0x602 +@@ -36,10 +37,14 @@ struct mcip_cmd { + #define CMD_SEMA_RELEASE 0x12 + + #define CMD_DEBUG_SET_MASK 0x34 ++#define CMD_DEBUG_READ_MASK 0x35 + #define CMD_DEBUG_SET_SELECT 0x36 ++#define CMD_DEBUG_READ_SELECT 0x37 + + #define CMD_GFRC_READ_LO 0x42 + #define CMD_GFRC_READ_HI 0x43 ++#define CMD_GFRC_SET_CORE 0x47 ++#define CMD_GFRC_READ_CORE 0x48 + + #define CMD_IDU_ENABLE 0x71 + #define CMD_IDU_DISABLE 0x72 +diff --git a/include/sound/ac97/regs.h b/include/sound/ac97/regs.h +index 4bb86d3..9a4fa0c 100644 +--- a/include/sound/ac97/regs.h ++++ b/include/sound/ac97/regs.h +@@ -31,7 +31,7 @@ + #define AC97_HEADPHONE 0x04 /* Headphone Volume (optional) */ + #define AC97_MASTER_MONO 0x06 /* Master Volume Mono (optional) */ + #define AC97_MASTER_TONE 0x08 /* Master Tone (Bass & Treble) (optional) */ +-#define AC97_PC_BEEP 0x0a /* PC Beep Volume (optinal) */ ++#define AC97_PC_BEEP 0x0a /* PC Beep Volume (optional) */ + #define AC97_PHONE 0x0c /* Phone Volume (optional) */ + #define AC97_MIC 0x0e /* MIC Volume */ + #define AC97_LINE 0x10 /* Line In Volume */ +diff --git a/include/trace/events/xen.h b/include/trace/events/xen.h +index b8adf05..7dd8f34 100644 +--- a/include/trace/events/xen.h ++++ b/include/trace/events/xen.h +@@ -368,7 +368,7 @@ TRACE_EVENT(xen_mmu_flush_tlb, + TP_printk("%s", "") + ); + +-TRACE_EVENT(xen_mmu_flush_tlb_single, ++TRACE_EVENT(xen_mmu_flush_tlb_one_user, + TP_PROTO(unsigned long addr), + TP_ARGS(addr), + TP_STRUCT__entry( +diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h +index 85dc965..99c902e 100644 +--- a/include/uapi/asm-generic/siginfo.h ++++ b/include/uapi/asm-generic/siginfo.h +@@ -102,13 +102,13 @@ typedef struct siginfo { + short _addr_lsb; /* LSB of the reported address */ + /* used when si_code=SEGV_BNDERR */ + struct { +- short _dummy_bnd; ++ void *_dummy_bnd; + void __user *_lower; + void __user *_upper; + } _addr_bnd; + /* used when si_code=SEGV_PKUERR */ + struct { +- short _dummy_pkey; ++ void *_dummy_pkey; + __u32 _pkey; + } _addr_pkey; + }; +diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h +index 91a31ff..9a781f0 100644 +--- a/include/uapi/drm/virtgpu_drm.h ++++ b/include/uapi/drm/virtgpu_drm.h +@@ -63,6 +63,7 @@ struct drm_virtgpu_execbuffer { + }; + + #define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */ ++#define VIRTGPU_PARAM_CAPSET_QUERY_FIX 2 /* do we have the capset fix */ + + struct drm_virtgpu_getparam { + __u64 param; +diff --git a/include/uapi/linux/blktrace_api.h b/include/uapi/linux/blktrace_api.h +index 20d1490d..3c50e07 100644 +--- a/include/uapi/linux/blktrace_api.h ++++ b/include/uapi/linux/blktrace_api.h +@@ -131,7 +131,7 @@ enum { + #define BLKTRACE_BDEV_SIZE 32 + + /* +- * User setup structure passed with BLKTRACESTART ++ * User setup structure passed with BLKTRACESETUP + */ + struct blk_user_trace_setup { + char name[BLKTRACE_BDEV_SIZE]; /* output */ +diff --git a/include/uapi/linux/dvb/dmx.h b/include/uapi/linux/dvb/dmx.h +index 5f3c5a9..b4112f0 100644 +--- a/include/uapi/linux/dvb/dmx.h ++++ b/include/uapi/linux/dvb/dmx.h +@@ -212,6 +212,32 @@ struct dmx_stc { + }; + + /** ++ * enum dmx_buffer_flags - DMX memory-mapped buffer flags ++ * ++ * @DMX_BUFFER_FLAG_HAD_CRC32_DISCARD: ++ * Indicates that the Kernel discarded one or more frames due to wrong ++ * CRC32 checksum. ++ * @DMX_BUFFER_FLAG_TEI: ++ * Indicates that the Kernel has detected a Transport Error indicator ++ * (TEI) on a filtered pid. ++ * @DMX_BUFFER_PKT_COUNTER_MISMATCH: ++ * Indicates that the Kernel has detected a packet counter mismatch ++ * on a filtered pid. ++ * @DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED: ++ * Indicates that the Kernel has detected one or more frame discontinuity. ++ * @DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR: ++ * Received at least one packet with a frame discontinuity indicator. ++ */ ++ ++enum dmx_buffer_flags { ++ DMX_BUFFER_FLAG_HAD_CRC32_DISCARD = 1 << 0, ++ DMX_BUFFER_FLAG_TEI = 1 << 1, ++ DMX_BUFFER_PKT_COUNTER_MISMATCH = 1 << 2, ++ DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED = 1 << 3, ++ DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR = 1 << 4, ++}; ++ ++/** + * struct dmx_buffer - dmx buffer info + * + * @index: id number of the buffer +@@ -220,15 +246,24 @@ struct dmx_stc { + * offset from the start of the device memory for this plane, + * (or a "cookie" that should be passed to mmap() as offset) + * @length: size in bytes of the buffer ++ * @flags: bit array of buffer flags as defined by &enum dmx_buffer_flags. ++ * Filled only at &DMX_DQBUF. ++ * @count: monotonic counter for filled buffers. Helps to identify ++ * data stream loses. Filled only at &DMX_DQBUF. + * + * Contains data exchanged by application and driver using one of the streaming + * I/O methods. ++ * ++ * Please notice that, for &DMX_QBUF, only @index should be filled. ++ * On &DMX_DQBUF calls, all fields will be filled by the Kernel. + */ + struct dmx_buffer { + __u32 index; + __u32 bytesused; + __u32 offset; + __u32 length; ++ __u32 flags; ++ __u32 count; + }; + + /** +diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h +index f8cb576..8bbbcb5 100644 +--- a/include/uapi/linux/if_ether.h ++++ b/include/uapi/linux/if_ether.h +@@ -23,7 +23,6 @@ + #define _UAPI_LINUX_IF_ETHER_H + + #include +-#include + + /* + * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble +@@ -151,6 +150,11 @@ + * This is an Ethernet frame header. + */ + ++/* allow libcs like musl to deactivate this, glibc does not implement this. */ ++#ifndef __UAPI_DEF_ETHHDR ++#define __UAPI_DEF_ETHHDR 1 ++#endif ++ + #if __UAPI_DEF_ETHHDR + struct ethhdr { + unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ +diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h +index 0fb5ef9..7b26d4b 100644 +--- a/include/uapi/linux/kvm.h ++++ b/include/uapi/linux/kvm.h +@@ -761,6 +761,7 @@ struct kvm_ppc_resize_hpt { + #define KVM_TRACE_PAUSE __KVM_DEPRECATED_MAIN_0x07 + #define KVM_TRACE_DISABLE __KVM_DEPRECATED_MAIN_0x08 + #define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2) ++#define KVM_GET_MSR_FEATURE_INDEX_LIST _IOWR(KVMIO, 0x0a, struct kvm_msr_list) + + /* + * Extension capability list. +@@ -934,6 +935,7 @@ struct kvm_ppc_resize_hpt { + #define KVM_CAP_S390_AIS_MIGRATION 150 + #define KVM_CAP_PPC_GET_CPU_CHAR 151 + #define KVM_CAP_S390_BPB 152 ++#define KVM_CAP_GET_MSR_FEATURES 153 + + #ifdef KVM_CAP_IRQ_ROUTING + +diff --git a/include/uapi/linux/libc-compat.h b/include/uapi/linux/libc-compat.h +index fc29efaa..8254c93 100644 +--- a/include/uapi/linux/libc-compat.h ++++ b/include/uapi/linux/libc-compat.h +@@ -264,10 +264,4 @@ + + #endif /* __GLIBC__ */ + +-/* Definitions for if_ether.h */ +-/* allow libcs like musl to deactivate this, glibc does not implement this. */ +-#ifndef __UAPI_DEF_ETHHDR +-#define __UAPI_DEF_ETHHDR 1 +-#endif +- + #endif /* _UAPI_LIBC_COMPAT_H */ +diff --git a/include/uapi/linux/psp-sev.h b/include/uapi/linux/psp-sev.h +index 3d77fe9..9008f31 100644 +--- a/include/uapi/linux/psp-sev.h ++++ b/include/uapi/linux/psp-sev.h +@@ -42,7 +42,7 @@ typedef enum { + SEV_RET_INVALID_PLATFORM_STATE, + SEV_RET_INVALID_GUEST_STATE, + SEV_RET_INAVLID_CONFIG, +- SEV_RET_INVALID_len, ++ SEV_RET_INVALID_LEN, + SEV_RET_ALREADY_OWNED, + SEV_RET_INVALID_CERTIFICATE, + SEV_RET_POLICY_FAILURE, +diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h +index e46d82b..d5a1b8a 100644 +--- a/include/uapi/linux/ptrace.h ++++ b/include/uapi/linux/ptrace.h +@@ -69,8 +69,8 @@ struct ptrace_peeksiginfo_args { + #define PTRACE_SECCOMP_GET_METADATA 0x420d + + struct seccomp_metadata { +- unsigned long filter_off; /* Input: which filter */ +- unsigned int flags; /* Output: filter's flags */ ++ __u64 filter_off; /* Input: which filter */ ++ __u64 flags; /* Output: filter's flags */ + }; + + /* Read signals from a shared (process wide) queue */ +diff --git a/include/uapi/misc/ocxl.h b/include/uapi/misc/ocxl.h +index 4b0b0b7..0af83d8 100644 +--- a/include/uapi/misc/ocxl.h ++++ b/include/uapi/misc/ocxl.h +@@ -32,6 +32,22 @@ struct ocxl_ioctl_attach { + __u64 reserved3; + }; + ++struct ocxl_ioctl_metadata { ++ __u16 version; // struct version, always backwards compatible ++ ++ // Version 0 fields ++ __u8 afu_version_major; ++ __u8 afu_version_minor; ++ __u32 pasid; // PASID assigned to the current context ++ ++ __u64 pp_mmio_size; // Per PASID MMIO size ++ __u64 global_mmio_size; ++ ++ // End version 0 fields ++ ++ __u64 reserved[13]; // Total of 16*u64 ++}; ++ + struct ocxl_ioctl_irq_fd { + __u64 irq_offset; + __s32 eventfd; +@@ -45,5 +61,6 @@ struct ocxl_ioctl_irq_fd { + #define OCXL_IOCTL_IRQ_ALLOC _IOR(OCXL_MAGIC, 0x11, __u64) + #define OCXL_IOCTL_IRQ_FREE _IOW(OCXL_MAGIC, 0x12, __u64) + #define OCXL_IOCTL_IRQ_SET_FD _IOW(OCXL_MAGIC, 0x13, struct ocxl_ioctl_irq_fd) ++#define OCXL_IOCTL_GET_METADATA _IOR(OCXL_MAGIC, 0x14, struct ocxl_ioctl_metadata) + + #endif /* _UAPI_MISC_OCXL_H */ +diff --git a/include/uapi/rdma/rdma_user_ioctl.h b/include/uapi/rdma/rdma_user_ioctl.h +index 03557b5..46de088 100644 +--- a/include/uapi/rdma/rdma_user_ioctl.h ++++ b/include/uapi/rdma/rdma_user_ioctl.h +@@ -65,7 +65,7 @@ struct ib_uverbs_attr { + __u16 len; /* only for pointers */ + __u16 flags; /* combination of UVERBS_ATTR_F_XXXX */ + __u16 reserved; +- __u64 data; /* ptr to command, inline data or idr/fd */ ++ __aligned_u64 data; /* ptr to command, inline data or idr/fd */ + }; + + struct ib_uverbs_ioctl_hdr { +@@ -73,7 +73,7 @@ struct ib_uverbs_ioctl_hdr { + __u16 object_id; + __u16 method_id; + __u16 num_attrs; +- __u64 reserved; ++ __aligned_u64 reserved; + struct ib_uverbs_attr attrs[0]; + }; + +diff --git a/init/main.c b/init/main.c +index a8100b9..969eaf1 100644 +--- a/init/main.c ++++ b/init/main.c +@@ -89,6 +89,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1000,6 +1001,7 @@ static int __ref kernel_init(void *unused) + /* need to finish all async __init code before freeing the memory */ + async_synchronize_full(); + ftrace_free_init_mem(); ++ jump_label_invalidate_init(); + free_initmem(); + mark_readonly(); + system_state = SYSTEM_RUNNING; +diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c +index b1f6648..14750e7 100644 +--- a/kernel/bpf/arraymap.c ++++ b/kernel/bpf/arraymap.c +@@ -26,8 +26,10 @@ static void bpf_array_free_percpu(struct bpf_array *array) + { + int i; + +- for (i = 0; i < array->map.max_entries; i++) ++ for (i = 0; i < array->map.max_entries; i++) { + free_percpu(array->pptrs[i]); ++ cond_resched(); ++ } + } + + static int bpf_array_alloc_percpu(struct bpf_array *array) +@@ -43,6 +45,7 @@ static int bpf_array_alloc_percpu(struct bpf_array *array) + return -ENOMEM; + } + array->pptrs[i] = ptr; ++ cond_resched(); + } + + return 0; +@@ -73,11 +76,11 @@ static int array_map_alloc_check(union bpf_attr *attr) + static struct bpf_map *array_map_alloc(union bpf_attr *attr) + { + bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY; +- int numa_node = bpf_map_attr_numa_node(attr); ++ int ret, numa_node = bpf_map_attr_numa_node(attr); + u32 elem_size, index_mask, max_entries; + bool unpriv = !capable(CAP_SYS_ADMIN); ++ u64 cost, array_size, mask64; + struct bpf_array *array; +- u64 array_size, mask64; + + elem_size = round_up(attr->value_size, 8); + +@@ -109,8 +112,19 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) + array_size += (u64) max_entries * elem_size; + + /* make sure there is no u32 overflow later in round_up() */ +- if (array_size >= U32_MAX - PAGE_SIZE) ++ cost = array_size; ++ if (cost >= U32_MAX - PAGE_SIZE) + return ERR_PTR(-ENOMEM); ++ if (percpu) { ++ cost += (u64)attr->max_entries * elem_size * num_possible_cpus(); ++ if (cost >= U32_MAX - PAGE_SIZE) ++ return ERR_PTR(-ENOMEM); ++ } ++ cost = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT; ++ ++ ret = bpf_map_precharge_memlock(cost); ++ if (ret < 0) ++ return ERR_PTR(ret); + + /* allocate all map elements and zero-initialize them */ + array = bpf_map_area_alloc(array_size, numa_node); +@@ -121,20 +135,13 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) + + /* copy mandatory map attributes */ + bpf_map_init_from_attr(&array->map, attr); ++ array->map.pages = cost; + array->elem_size = elem_size; + +- if (!percpu) +- goto out; +- +- array_size += (u64) attr->max_entries * elem_size * num_possible_cpus(); +- +- if (array_size >= U32_MAX - PAGE_SIZE || +- bpf_array_alloc_percpu(array)) { ++ if (percpu && bpf_array_alloc_percpu(array)) { + bpf_map_area_free(array); + return ERR_PTR(-ENOMEM); + } +-out: +- array->map.pages = round_up(array_size, PAGE_SIZE) >> PAGE_SHIFT; + + return &array->map; + } +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 29ca920..d315b39 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -1590,7 +1590,7 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs, + * so always copy 'cnt' prog_ids to the user. + * In a rare race the user will see zero prog_ids + */ +- ids = kcalloc(cnt, sizeof(u32), GFP_USER); ++ ids = kcalloc(cnt, sizeof(u32), GFP_USER | __GFP_NOWARN); + if (!ids) + return -ENOMEM; + rcu_read_lock(); +diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c +index fbfdada6..a4bb0b3 100644 +--- a/kernel/bpf/cpumap.c ++++ b/kernel/bpf/cpumap.c +@@ -334,7 +334,7 @@ static int cpu_map_kthread_run(void *data) + static struct bpf_cpu_map_entry *__cpu_map_entry_alloc(u32 qsize, u32 cpu, + int map_id) + { +- gfp_t gfp = GFP_ATOMIC|__GFP_NOWARN; ++ gfp_t gfp = GFP_KERNEL | __GFP_NOWARN; + struct bpf_cpu_map_entry *rcpu; + int numa, err; + +diff --git a/kernel/bpf/lpm_trie.c b/kernel/bpf/lpm_trie.c +index 7b469d1..b4b5b81 100644 +--- a/kernel/bpf/lpm_trie.c ++++ b/kernel/bpf/lpm_trie.c +@@ -555,7 +555,10 @@ static void trie_free(struct bpf_map *map) + struct lpm_trie_node __rcu **slot; + struct lpm_trie_node *node; + +- raw_spin_lock(&trie->lock); ++ /* Wait for outstanding programs to complete ++ * update/lookup/delete/get_next_key and free the trie. ++ */ ++ synchronize_rcu(); + + /* Always start at the root and walk down to a node that has no + * children. Then free that node, nullify its reference in the parent +@@ -566,10 +569,9 @@ static void trie_free(struct bpf_map *map) + slot = &trie->root; + + for (;;) { +- node = rcu_dereference_protected(*slot, +- lockdep_is_held(&trie->lock)); ++ node = rcu_dereference_protected(*slot, 1); + if (!node) +- goto unlock; ++ goto out; + + if (rcu_access_pointer(node->child[0])) { + slot = &node->child[0]; +@@ -587,8 +589,8 @@ static void trie_free(struct bpf_map *map) + } + } + +-unlock: +- raw_spin_unlock(&trie->lock); ++out: ++ kfree(trie); + } + + static int trie_get_next_key(struct bpf_map *map, void *_key, void *_next_key) +diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c +index 48c3341..a927e89 100644 +--- a/kernel/bpf/sockmap.c ++++ b/kernel/bpf/sockmap.c +@@ -521,8 +521,8 @@ static struct smap_psock *smap_init_psock(struct sock *sock, + static struct bpf_map *sock_map_alloc(union bpf_attr *attr) + { + struct bpf_stab *stab; +- int err = -EINVAL; + u64 cost; ++ int err; + + if (!capable(CAP_NET_ADMIN)) + return ERR_PTR(-EPERM); +@@ -547,6 +547,7 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr) + + /* make sure page count doesn't overflow */ + cost = (u64) stab->map.max_entries * sizeof(struct sock *); ++ err = -EINVAL; + if (cost >= U32_MAX - PAGE_SIZE) + goto free_stab; + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 5fb69a8..c6eff10 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -1356,6 +1356,13 @@ static bool is_ctx_reg(struct bpf_verifier_env *env, int regno) + return reg->type == PTR_TO_CTX; + } + ++static bool is_pkt_reg(struct bpf_verifier_env *env, int regno) ++{ ++ const struct bpf_reg_state *reg = cur_regs(env) + regno; ++ ++ return type_is_pkt_pointer(reg->type); ++} ++ + static int check_pkt_ptr_alignment(struct bpf_verifier_env *env, + const struct bpf_reg_state *reg, + int off, int size, bool strict) +@@ -1416,10 +1423,10 @@ static int check_generic_ptr_alignment(struct bpf_verifier_env *env, + } + + static int check_ptr_alignment(struct bpf_verifier_env *env, +- const struct bpf_reg_state *reg, +- int off, int size) ++ const struct bpf_reg_state *reg, int off, ++ int size, bool strict_alignment_once) + { +- bool strict = env->strict_alignment; ++ bool strict = env->strict_alignment || strict_alignment_once; + const char *pointer_desc = ""; + + switch (reg->type) { +@@ -1576,9 +1583,9 @@ static void coerce_reg_to_size(struct bpf_reg_state *reg, int size) + * if t==write && value_regno==-1, some unknown value is stored into memory + * if t==read && value_regno==-1, don't care what we read from memory + */ +-static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regno, int off, +- int bpf_size, enum bpf_access_type t, +- int value_regno) ++static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regno, ++ int off, int bpf_size, enum bpf_access_type t, ++ int value_regno, bool strict_alignment_once) + { + struct bpf_reg_state *regs = cur_regs(env); + struct bpf_reg_state *reg = regs + regno; +@@ -1590,7 +1597,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn + return size; + + /* alignment checks will add in reg->off themselves */ +- err = check_ptr_alignment(env, reg, off, size); ++ err = check_ptr_alignment(env, reg, off, size, strict_alignment_once); + if (err) + return err; + +@@ -1735,21 +1742,23 @@ static int check_xadd(struct bpf_verifier_env *env, int insn_idx, struct bpf_ins + return -EACCES; + } + +- if (is_ctx_reg(env, insn->dst_reg)) { +- verbose(env, "BPF_XADD stores into R%d context is not allowed\n", +- insn->dst_reg); ++ if (is_ctx_reg(env, insn->dst_reg) || ++ is_pkt_reg(env, insn->dst_reg)) { ++ verbose(env, "BPF_XADD stores into R%d %s is not allowed\n", ++ insn->dst_reg, is_ctx_reg(env, insn->dst_reg) ? ++ "context" : "packet"); + return -EACCES; + } + + /* check whether atomic_add can read the memory */ + err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, +- BPF_SIZE(insn->code), BPF_READ, -1); ++ BPF_SIZE(insn->code), BPF_READ, -1, true); + if (err) + return err; + + /* check whether atomic_add can write into the same memory */ + return check_mem_access(env, insn_idx, insn->dst_reg, insn->off, +- BPF_SIZE(insn->code), BPF_WRITE, -1); ++ BPF_SIZE(insn->code), BPF_WRITE, -1, true); + } + + /* when register 'regno' is passed into function that will read 'access_size' +@@ -2388,7 +2397,8 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn + * is inferred from register state. + */ + for (i = 0; i < meta.access_size; i++) { +- err = check_mem_access(env, insn_idx, meta.regno, i, BPF_B, BPF_WRITE, -1); ++ err = check_mem_access(env, insn_idx, meta.regno, i, BPF_B, ++ BPF_WRITE, -1, false); + if (err) + return err; + } +@@ -4632,7 +4642,7 @@ static int do_check(struct bpf_verifier_env *env) + */ + err = check_mem_access(env, insn_idx, insn->src_reg, insn->off, + BPF_SIZE(insn->code), BPF_READ, +- insn->dst_reg); ++ insn->dst_reg, false); + if (err) + return err; + +@@ -4684,7 +4694,7 @@ static int do_check(struct bpf_verifier_env *env) + /* check that memory (dst_reg + off) is writeable */ + err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, + BPF_SIZE(insn->code), BPF_WRITE, +- insn->src_reg); ++ insn->src_reg, false); + if (err) + return err; + +@@ -4719,7 +4729,7 @@ static int do_check(struct bpf_verifier_env *env) + /* check that memory (dst_reg + off) is writeable */ + err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, + BPF_SIZE(insn->code), BPF_WRITE, +- -1); ++ -1, false); + if (err) + return err; + +diff --git a/kernel/compat.c b/kernel/compat.c +index 3247fe7..3f5fa89 100644 +--- a/kernel/compat.c ++++ b/kernel/compat.c +@@ -488,25 +488,6 @@ get_compat_sigset(sigset_t *set, const compat_sigset_t __user *compat) + } + EXPORT_SYMBOL_GPL(get_compat_sigset); + +-int +-put_compat_sigset(compat_sigset_t __user *compat, const sigset_t *set, +- unsigned int size) +-{ +- /* size <= sizeof(compat_sigset_t) <= sizeof(sigset_t) */ +-#ifdef __BIG_ENDIAN +- compat_sigset_t v; +- switch (_NSIG_WORDS) { +- case 4: v.sig[7] = (set->sig[3] >> 32); v.sig[6] = set->sig[3]; +- case 3: v.sig[5] = (set->sig[2] >> 32); v.sig[4] = set->sig[2]; +- case 2: v.sig[3] = (set->sig[1] >> 32); v.sig[2] = set->sig[1]; +- case 1: v.sig[1] = (set->sig[0] >> 32); v.sig[0] = set->sig[0]; +- } +- return copy_to_user(compat, &v, size) ? -EFAULT : 0; +-#else +- return copy_to_user(compat, set, size) ? -EFAULT : 0; +-#endif +-} +- + #ifdef CONFIG_NUMA + COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages, + compat_uptr_t __user *, pages32, +diff --git a/kernel/events/core.c b/kernel/events/core.c +index 96db9ae..4b83847 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -2246,7 +2246,7 @@ static void ctx_resched(struct perf_cpu_context *cpuctx, + struct perf_event_context *task_ctx, + enum event_type_t event_type) + { +- enum event_type_t ctx_event_type = event_type & EVENT_ALL; ++ enum event_type_t ctx_event_type; + bool cpu_event = !!(event_type & EVENT_CPU); + + /* +@@ -2256,6 +2256,8 @@ static void ctx_resched(struct perf_cpu_context *cpuctx, + if (event_type & EVENT_PINNED) + event_type |= EVENT_FLEXIBLE; + ++ ctx_event_type = event_type & EVENT_ALL; ++ + perf_pmu_disable(cpuctx->ctx.pmu); + if (task_ctx) + task_ctx_sched_out(cpuctx, task_ctx, event_type); +diff --git a/kernel/extable.c b/kernel/extable.c +index a17fdb6..6a5b61e 100644 +--- a/kernel/extable.c ++++ b/kernel/extable.c +@@ -64,7 +64,7 @@ const struct exception_table_entry *search_exception_tables(unsigned long addr) + return e; + } + +-static inline int init_kernel_text(unsigned long addr) ++int init_kernel_text(unsigned long addr) + { + if (addr >= (unsigned long)_sinittext && + addr < (unsigned long)_einittext) +diff --git a/kernel/fork.c b/kernel/fork.c +index be8aa5b..e5d9d40 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -592,7 +592,7 @@ static void check_mm(struct mm_struct *mm) + * is dropped: either by a lazy thread or by + * mmput. Free the page directory and the mm. + */ +-static void __mmdrop(struct mm_struct *mm) ++void __mmdrop(struct mm_struct *mm) + { + BUG_ON(mm == &init_mm); + mm_free_pgd(mm); +@@ -603,18 +603,7 @@ static void __mmdrop(struct mm_struct *mm) + put_user_ns(mm->user_ns); + free_mm(mm); + } +- +-void mmdrop(struct mm_struct *mm) +-{ +- /* +- * The implicit full barrier implied by atomic_dec_and_test() is +- * required by the membarrier system call before returning to +- * user-space, after storing to rq->curr. +- */ +- if (unlikely(atomic_dec_and_test(&mm->mm_count))) +- __mmdrop(mm); +-} +-EXPORT_SYMBOL_GPL(mmdrop); ++EXPORT_SYMBOL_GPL(__mmdrop); + + static void mmdrop_async_fn(struct work_struct *work) + { +diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c +index e6a9c36..82b8b18 100644 +--- a/kernel/irq/irqdomain.c ++++ b/kernel/irq/irqdomain.c +@@ -1726,25 +1726,14 @@ static int irq_domain_debug_show(struct seq_file *m, void *p) + irq_domain_debug_show_one(m, d, 0); + return 0; + } +- +-static int irq_domain_debug_open(struct inode *inode, struct file *file) +-{ +- return single_open(file, irq_domain_debug_show, inode->i_private); +-} +- +-static const struct file_operations dfs_domain_ops = { +- .open = irq_domain_debug_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = single_release, +-}; ++DEFINE_SHOW_ATTRIBUTE(irq_domain_debug); + + static void debugfs_add_domain_dir(struct irq_domain *d) + { + if (!d->name || !domain_dir || d->debugfs_file) + return; + d->debugfs_file = debugfs_create_file(d->name, 0444, domain_dir, d, +- &dfs_domain_ops); ++ &irq_domain_debug_fops); + } + + static void debugfs_remove_domain_dir(struct irq_domain *d) +@@ -1760,7 +1749,8 @@ void __init irq_domain_debugfs_init(struct dentry *root) + if (!domain_dir) + return; + +- debugfs_create_file("default", 0444, domain_dir, NULL, &dfs_domain_ops); ++ debugfs_create_file("default", 0444, domain_dir, NULL, ++ &irq_domain_debug_fops); + mutex_lock(&irq_domain_mutex); + list_for_each_entry(d, &irq_domain_list, link) + debugfs_add_domain_dir(d); +diff --git a/kernel/irq/matrix.c b/kernel/irq/matrix.c +index 5187dfe..4c57704 100644 +--- a/kernel/irq/matrix.c ++++ b/kernel/irq/matrix.c +@@ -16,6 +16,7 @@ struct cpumap { + unsigned int available; + unsigned int allocated; + unsigned int managed; ++ bool initialized; + bool online; + unsigned long alloc_map[IRQ_MATRIX_SIZE]; + unsigned long managed_map[IRQ_MATRIX_SIZE]; +@@ -81,9 +82,11 @@ void irq_matrix_online(struct irq_matrix *m) + + BUG_ON(cm->online); + +- bitmap_zero(cm->alloc_map, m->matrix_bits); +- cm->available = m->alloc_size - (cm->managed + m->systembits_inalloc); +- cm->allocated = 0; ++ if (!cm->initialized) { ++ cm->available = m->alloc_size; ++ cm->available -= cm->managed + m->systembits_inalloc; ++ cm->initialized = true; ++ } + m->global_available += cm->available; + cm->online = true; + m->online_maps++; +@@ -370,14 +373,16 @@ void irq_matrix_free(struct irq_matrix *m, unsigned int cpu, + if (WARN_ON_ONCE(bit < m->alloc_start || bit >= m->alloc_end)) + return; + +- if (cm->online) { +- clear_bit(bit, cm->alloc_map); +- cm->allocated--; ++ clear_bit(bit, cm->alloc_map); ++ cm->allocated--; ++ ++ if (cm->online) + m->total_allocated--; +- if (!managed) { +- cm->available++; ++ ++ if (!managed) { ++ cm->available++; ++ if (cm->online) + m->global_available++; +- } + } + trace_irq_matrix_free(bit, cpu, m, cm); + } +diff --git a/kernel/jump_label.c b/kernel/jump_label.c +index b451709..52a0a7a 100644 +--- a/kernel/jump_label.c ++++ b/kernel/jump_label.c +@@ -366,12 +366,15 @@ static void __jump_label_update(struct static_key *key, + { + for (; (entry < stop) && (jump_entry_key(entry) == key); entry++) { + /* +- * entry->code set to 0 invalidates module init text sections +- * kernel_text_address() verifies we are not in core kernel +- * init code, see jump_label_invalidate_module_init(). ++ * An entry->code of 0 indicates an entry which has been ++ * disabled because it was in an init text area. + */ +- if (entry->code && kernel_text_address(entry->code)) +- arch_jump_label_transform(entry, jump_label_type(entry)); ++ if (entry->code) { ++ if (kernel_text_address(entry->code)) ++ arch_jump_label_transform(entry, jump_label_type(entry)); ++ else ++ WARN_ONCE(1, "can't patch jump_label at %pS", (void *)entry->code); ++ } + } + } + +@@ -417,6 +420,19 @@ void __init jump_label_init(void) + cpus_read_unlock(); + } + ++/* Disable any jump label entries in __init code */ ++void __init jump_label_invalidate_init(void) ++{ ++ struct jump_entry *iter_start = __start___jump_table; ++ struct jump_entry *iter_stop = __stop___jump_table; ++ struct jump_entry *iter; ++ ++ for (iter = iter_start; iter < iter_stop; iter++) { ++ if (init_kernel_text(iter->code)) ++ iter->code = 0; ++ } ++} ++ + #ifdef CONFIG_MODULES + + static enum jump_label_type jump_label_init_type(struct jump_entry *entry) +@@ -633,6 +649,7 @@ static void jump_label_del_module(struct module *mod) + } + } + ++/* Disable any jump label entries in module init code */ + static void jump_label_invalidate_module_init(struct module *mod) + { + struct jump_entry *iter_start = mod->jump_entries; +diff --git a/kernel/kprobes.c b/kernel/kprobes.c +index da2ccf1..102160f 100644 +--- a/kernel/kprobes.c ++++ b/kernel/kprobes.c +@@ -978,67 +978,90 @@ static int prepare_kprobe(struct kprobe *p) + } + + /* Caller must lock kprobe_mutex */ +-static void arm_kprobe_ftrace(struct kprobe *p) ++static int arm_kprobe_ftrace(struct kprobe *p) + { +- int ret; ++ int ret = 0; + + ret = ftrace_set_filter_ip(&kprobe_ftrace_ops, + (unsigned long)p->addr, 0, 0); +- WARN(ret < 0, "Failed to arm kprobe-ftrace at %p (%d)\n", p->addr, ret); +- kprobe_ftrace_enabled++; +- if (kprobe_ftrace_enabled == 1) { ++ if (ret) { ++ pr_debug("Failed to arm kprobe-ftrace at %p (%d)\n", p->addr, ret); ++ return ret; ++ } ++ ++ if (kprobe_ftrace_enabled == 0) { + ret = register_ftrace_function(&kprobe_ftrace_ops); +- WARN(ret < 0, "Failed to init kprobe-ftrace (%d)\n", ret); ++ if (ret) { ++ pr_debug("Failed to init kprobe-ftrace (%d)\n", ret); ++ goto err_ftrace; ++ } + } ++ ++ kprobe_ftrace_enabled++; ++ return ret; ++ ++err_ftrace: ++ /* ++ * Note: Since kprobe_ftrace_ops has IPMODIFY set, and ftrace requires a ++ * non-empty filter_hash for IPMODIFY ops, we're safe from an accidental ++ * empty filter_hash which would undesirably trace all functions. ++ */ ++ ftrace_set_filter_ip(&kprobe_ftrace_ops, (unsigned long)p->addr, 1, 0); ++ return ret; + } + + /* Caller must lock kprobe_mutex */ +-static void disarm_kprobe_ftrace(struct kprobe *p) ++static int disarm_kprobe_ftrace(struct kprobe *p) + { +- int ret; ++ int ret = 0; + +- kprobe_ftrace_enabled--; +- if (kprobe_ftrace_enabled == 0) { ++ if (kprobe_ftrace_enabled == 1) { + ret = unregister_ftrace_function(&kprobe_ftrace_ops); +- WARN(ret < 0, "Failed to init kprobe-ftrace (%d)\n", ret); ++ if (WARN(ret < 0, "Failed to unregister kprobe-ftrace (%d)\n", ret)) ++ return ret; + } ++ ++ kprobe_ftrace_enabled--; ++ + ret = ftrace_set_filter_ip(&kprobe_ftrace_ops, + (unsigned long)p->addr, 1, 0); + WARN(ret < 0, "Failed to disarm kprobe-ftrace at %p (%d)\n", p->addr, ret); ++ return ret; + } + #else /* !CONFIG_KPROBES_ON_FTRACE */ + #define prepare_kprobe(p) arch_prepare_kprobe(p) +-#define arm_kprobe_ftrace(p) do {} while (0) +-#define disarm_kprobe_ftrace(p) do {} while (0) ++#define arm_kprobe_ftrace(p) (-ENODEV) ++#define disarm_kprobe_ftrace(p) (-ENODEV) + #endif + + /* Arm a kprobe with text_mutex */ +-static void arm_kprobe(struct kprobe *kp) ++static int arm_kprobe(struct kprobe *kp) + { +- if (unlikely(kprobe_ftrace(kp))) { +- arm_kprobe_ftrace(kp); +- return; +- } ++ if (unlikely(kprobe_ftrace(kp))) ++ return arm_kprobe_ftrace(kp); ++ + cpus_read_lock(); + mutex_lock(&text_mutex); + __arm_kprobe(kp); + mutex_unlock(&text_mutex); + cpus_read_unlock(); ++ ++ return 0; + } + + /* Disarm a kprobe with text_mutex */ +-static void disarm_kprobe(struct kprobe *kp, bool reopt) ++static int disarm_kprobe(struct kprobe *kp, bool reopt) + { +- if (unlikely(kprobe_ftrace(kp))) { +- disarm_kprobe_ftrace(kp); +- return; +- } ++ if (unlikely(kprobe_ftrace(kp))) ++ return disarm_kprobe_ftrace(kp); + + cpus_read_lock(); + mutex_lock(&text_mutex); + __disarm_kprobe(kp, reopt); + mutex_unlock(&text_mutex); + cpus_read_unlock(); ++ ++ return 0; + } + + /* +@@ -1362,9 +1385,15 @@ static int register_aggr_kprobe(struct kprobe *orig_p, struct kprobe *p) + + if (ret == 0 && kprobe_disabled(ap) && !kprobe_disabled(p)) { + ap->flags &= ~KPROBE_FLAG_DISABLED; +- if (!kprobes_all_disarmed) ++ if (!kprobes_all_disarmed) { + /* Arm the breakpoint again. */ +- arm_kprobe(ap); ++ ret = arm_kprobe(ap); ++ if (ret) { ++ ap->flags |= KPROBE_FLAG_DISABLED; ++ list_del_rcu(&p->list); ++ synchronize_sched(); ++ } ++ } + } + return ret; + } +@@ -1573,8 +1602,14 @@ int register_kprobe(struct kprobe *p) + hlist_add_head_rcu(&p->hlist, + &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]); + +- if (!kprobes_all_disarmed && !kprobe_disabled(p)) +- arm_kprobe(p); ++ if (!kprobes_all_disarmed && !kprobe_disabled(p)) { ++ ret = arm_kprobe(p); ++ if (ret) { ++ hlist_del_rcu(&p->hlist); ++ synchronize_sched(); ++ goto out; ++ } ++ } + + /* Try to optimize kprobe */ + try_to_optimize_kprobe(p); +@@ -1608,11 +1643,12 @@ static int aggr_kprobe_disabled(struct kprobe *ap) + static struct kprobe *__disable_kprobe(struct kprobe *p) + { + struct kprobe *orig_p; ++ int ret; + + /* Get an original kprobe for return */ + orig_p = __get_valid_kprobe(p); + if (unlikely(orig_p == NULL)) +- return NULL; ++ return ERR_PTR(-EINVAL); + + if (!kprobe_disabled(p)) { + /* Disable probe if it is a child probe */ +@@ -1626,8 +1662,13 @@ static struct kprobe *__disable_kprobe(struct kprobe *p) + * should have already been disarmed, so + * skip unneed disarming process. + */ +- if (!kprobes_all_disarmed) +- disarm_kprobe(orig_p, true); ++ if (!kprobes_all_disarmed) { ++ ret = disarm_kprobe(orig_p, true); ++ if (ret) { ++ p->flags &= ~KPROBE_FLAG_DISABLED; ++ return ERR_PTR(ret); ++ } ++ } + orig_p->flags |= KPROBE_FLAG_DISABLED; + } + } +@@ -1644,8 +1685,8 @@ static int __unregister_kprobe_top(struct kprobe *p) + + /* Disable kprobe. This will disarm it if needed. */ + ap = __disable_kprobe(p); +- if (ap == NULL) +- return -EINVAL; ++ if (IS_ERR(ap)) ++ return PTR_ERR(ap); + + if (ap == p) + /* +@@ -2078,12 +2119,14 @@ static void kill_kprobe(struct kprobe *p) + int disable_kprobe(struct kprobe *kp) + { + int ret = 0; ++ struct kprobe *p; + + mutex_lock(&kprobe_mutex); + + /* Disable this kprobe */ +- if (__disable_kprobe(kp) == NULL) +- ret = -EINVAL; ++ p = __disable_kprobe(kp); ++ if (IS_ERR(p)) ++ ret = PTR_ERR(p); + + mutex_unlock(&kprobe_mutex); + return ret; +@@ -2116,7 +2159,9 @@ int enable_kprobe(struct kprobe *kp) + + if (!kprobes_all_disarmed && kprobe_disabled(p)) { + p->flags &= ~KPROBE_FLAG_DISABLED; +- arm_kprobe(p); ++ ret = arm_kprobe(p); ++ if (ret) ++ p->flags |= KPROBE_FLAG_DISABLED; + } + out: + mutex_unlock(&kprobe_mutex); +@@ -2407,11 +2452,12 @@ static const struct file_operations debugfs_kprobe_blacklist_ops = { + .release = seq_release, + }; + +-static void arm_all_kprobes(void) ++static int arm_all_kprobes(void) + { + struct hlist_head *head; + struct kprobe *p; +- unsigned int i; ++ unsigned int i, total = 0, errors = 0; ++ int err, ret = 0; + + mutex_lock(&kprobe_mutex); + +@@ -2428,46 +2474,74 @@ static void arm_all_kprobes(void) + /* Arming kprobes doesn't optimize kprobe itself */ + for (i = 0; i < KPROBE_TABLE_SIZE; i++) { + head = &kprobe_table[i]; +- hlist_for_each_entry_rcu(p, head, hlist) +- if (!kprobe_disabled(p)) +- arm_kprobe(p); ++ /* Arm all kprobes on a best-effort basis */ ++ hlist_for_each_entry_rcu(p, head, hlist) { ++ if (!kprobe_disabled(p)) { ++ err = arm_kprobe(p); ++ if (err) { ++ errors++; ++ ret = err; ++ } ++ total++; ++ } ++ } + } + +- printk(KERN_INFO "Kprobes globally enabled\n"); ++ if (errors) ++ pr_warn("Kprobes globally enabled, but failed to arm %d out of %d probes\n", ++ errors, total); ++ else ++ pr_info("Kprobes globally enabled\n"); + + already_enabled: + mutex_unlock(&kprobe_mutex); +- return; ++ return ret; + } + +-static void disarm_all_kprobes(void) ++static int disarm_all_kprobes(void) + { + struct hlist_head *head; + struct kprobe *p; +- unsigned int i; ++ unsigned int i, total = 0, errors = 0; ++ int err, ret = 0; + + mutex_lock(&kprobe_mutex); + + /* If kprobes are already disarmed, just return */ + if (kprobes_all_disarmed) { + mutex_unlock(&kprobe_mutex); +- return; ++ return 0; + } + + kprobes_all_disarmed = true; +- printk(KERN_INFO "Kprobes globally disabled\n"); + + for (i = 0; i < KPROBE_TABLE_SIZE; i++) { + head = &kprobe_table[i]; ++ /* Disarm all kprobes on a best-effort basis */ + hlist_for_each_entry_rcu(p, head, hlist) { +- if (!arch_trampoline_kprobe(p) && !kprobe_disabled(p)) +- disarm_kprobe(p, false); ++ if (!arch_trampoline_kprobe(p) && !kprobe_disabled(p)) { ++ err = disarm_kprobe(p, false); ++ if (err) { ++ errors++; ++ ret = err; ++ } ++ total++; ++ } + } + } ++ ++ if (errors) ++ pr_warn("Kprobes globally disabled, but failed to disarm %d out of %d probes\n", ++ errors, total); ++ else ++ pr_info("Kprobes globally disabled\n"); ++ + mutex_unlock(&kprobe_mutex); + + /* Wait for disarming all kprobes by optimizer */ + wait_for_kprobe_optimizer(); ++ ++ return ret; + } + + /* +@@ -2494,6 +2568,7 @@ static ssize_t write_enabled_file_bool(struct file *file, + { + char buf[32]; + size_t buf_size; ++ int ret = 0; + + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) +@@ -2504,17 +2579,20 @@ static ssize_t write_enabled_file_bool(struct file *file, + case 'y': + case 'Y': + case '1': +- arm_all_kprobes(); ++ ret = arm_all_kprobes(); + break; + case 'n': + case 'N': + case '0': +- disarm_all_kprobes(); ++ ret = disarm_all_kprobes(); + break; + default: + return -EINVAL; + } + ++ if (ret) ++ return ret; ++ + return count; + } + +diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c +index 38ece03..d880296 100644 +--- a/kernel/locking/qspinlock.c ++++ b/kernel/locking/qspinlock.c +@@ -379,6 +379,14 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val) + tail = encode_tail(smp_processor_id(), idx); + + node += idx; ++ ++ /* ++ * Ensure that we increment the head node->count before initialising ++ * the actual node. If the compiler is kind enough to reorder these ++ * stores, then an IRQ could overwrite our assignments. ++ */ ++ barrier(); ++ + node->locked = 0; + node->next = NULL; + pv_init_node(node); +@@ -408,14 +416,15 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val) + */ + if (old & _Q_TAIL_MASK) { + prev = decode_tail(old); ++ + /* +- * The above xchg_tail() is also a load of @lock which +- * generates, through decode_tail(), a pointer. The address +- * dependency matches the RELEASE of xchg_tail() such that +- * the subsequent access to @prev happens after. ++ * We must ensure that the stores to @node are observed before ++ * the write to prev->next. The address dependency from ++ * xchg_tail is not sufficient to ensure this because the read ++ * component of xchg_tail is unordered with respect to the ++ * initialisation of @node. + */ +- +- WRITE_ONCE(prev->next, node); ++ smp_store_release(&prev->next, node); + + pv_wait_node(node, prev); + arch_mcs_spin_lock_contended(&node->locked); +diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c +index 65cc0cb..940633c 100644 +--- a/kernel/locking/rtmutex.c ++++ b/kernel/locking/rtmutex.c +@@ -1616,11 +1616,12 @@ bool __sched __rt_mutex_futex_unlock(struct rt_mutex *lock, + void __sched rt_mutex_futex_unlock(struct rt_mutex *lock) + { + DEFINE_WAKE_Q(wake_q); ++ unsigned long flags; + bool postunlock; + +- raw_spin_lock_irq(&lock->wait_lock); ++ raw_spin_lock_irqsave(&lock->wait_lock, flags); + postunlock = __rt_mutex_futex_unlock(lock, &wake_q); +- raw_spin_unlock_irq(&lock->wait_lock); ++ raw_spin_unlock_irqrestore(&lock->wait_lock, flags); + + if (postunlock) + rt_mutex_postunlock(&wake_q); +diff --git a/kernel/memremap.c b/kernel/memremap.c +index 4849be5..4dd4274 100644 +--- a/kernel/memremap.c ++++ b/kernel/memremap.c +@@ -275,8 +275,15 @@ static unsigned long pfn_end(struct dev_pagemap *pgmap) + return (res->start + resource_size(res)) >> PAGE_SHIFT; + } + ++static unsigned long pfn_next(unsigned long pfn) ++{ ++ if (pfn % 1024 == 0) ++ cond_resched(); ++ return pfn + 1; ++} ++ + #define for_each_device_pfn(pfn, map) \ +- for (pfn = pfn_first(map); pfn < pfn_end(map); pfn++) ++ for (pfn = pfn_first(map); pfn < pfn_end(map); pfn = pfn_next(pfn)) + + static void devm_memremap_pages_release(void *data) + { +@@ -337,10 +344,10 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap) + resource_size_t align_start, align_size, align_end; + struct vmem_altmap *altmap = pgmap->altmap_valid ? + &pgmap->altmap : NULL; ++ struct resource *res = &pgmap->res; + unsigned long pfn, pgoff, order; + pgprot_t pgprot = PAGE_KERNEL; +- int error, nid, is_ram, i = 0; +- struct resource *res = &pgmap->res; ++ int error, nid, is_ram; + + align_start = res->start & ~(SECTION_SIZE - 1); + align_size = ALIGN(res->start + resource_size(res), SECTION_SIZE) +@@ -409,8 +416,6 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap) + list_del(&page->lru); + page->pgmap = pgmap; + percpu_ref_get(pgmap->ref); +- if (!(++i % 1024)) +- cond_resched(); + } + + devm_add_action(dev, devm_memremap_pages_release, pgmap); +diff --git a/kernel/panic.c b/kernel/panic.c +index 2cfef40..4b794f1 100644 +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -640,7 +640,7 @@ device_initcall(register_warn_debugfs); + */ + __visible void __stack_chk_fail(void) + { +- panic("stack-protector: Kernel stack is corrupted in: %p\n", ++ panic("stack-protector: Kernel stack is corrupted in: %pB\n", + __builtin_return_address(0)); + } + EXPORT_SYMBOL(__stack_chk_fail); +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index fc11235..f274fbe 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -2397,7 +2397,7 @@ void console_unlock(void) + + if (console_lock_spinning_disable_and_check()) { + printk_safe_exit_irqrestore(flags); +- return; ++ goto out; + } + + printk_safe_exit_irqrestore(flags); +@@ -2430,6 +2430,7 @@ void console_unlock(void) + if (retry && console_trylock()) + goto again; + ++out: + if (wake_klogd) + wake_up_klogd(); + } +diff --git a/kernel/relay.c b/kernel/relay.c +index c302940..c955b10 100644 +--- a/kernel/relay.c ++++ b/kernel/relay.c +@@ -163,7 +163,7 @@ static struct rchan_buf *relay_create_buf(struct rchan *chan) + { + struct rchan_buf *buf; + +- if (chan->n_subbufs > UINT_MAX / sizeof(size_t *)) ++ if (chan->n_subbufs > KMALLOC_MAX_SIZE / sizeof(size_t *)) + return NULL; + + buf = kzalloc(sizeof(struct rchan_buf), GFP_KERNEL); +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index bf724c1..e7c535e 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -2601,19 +2601,31 @@ static inline void finish_task(struct task_struct *prev) + #endif + } + +-static inline void finish_lock_switch(struct rq *rq) ++static inline void ++prepare_lock_switch(struct rq *rq, struct task_struct *next, struct rq_flags *rf) + { ++ /* ++ * Since the runqueue lock will be released by the next ++ * task (which is an invalid locking op but in the case ++ * of the scheduler it's an obvious special-case), so we ++ * do an early lockdep release here: ++ */ ++ rq_unpin_lock(rq, rf); ++ spin_release(&rq->lock.dep_map, 1, _THIS_IP_); + #ifdef CONFIG_DEBUG_SPINLOCK + /* this is a valid case when another task releases the spinlock */ +- rq->lock.owner = current; ++ rq->lock.owner = next; + #endif ++} ++ ++static inline void finish_lock_switch(struct rq *rq) ++{ + /* + * If we are tracking spinlock dependencies then we have to + * fix up the runqueue lock - which gets 'carried over' from + * prev into current: + */ + spin_acquire(&rq->lock.dep_map, 0, 0, _THIS_IP_); +- + raw_spin_unlock_irq(&rq->lock); + } + +@@ -2844,14 +2856,7 @@ context_switch(struct rq *rq, struct task_struct *prev, + + rq->clock_update_flags &= ~(RQCF_ACT_SKIP|RQCF_REQ_SKIP); + +- /* +- * Since the runqueue lock will be released by the next +- * task (which is an invalid locking op but in the case +- * of the scheduler it's an obvious special-case), so we +- * do an early lockdep release here: +- */ +- rq_unpin_lock(rq, rf); +- spin_release(&rq->lock.dep_map, 1, _THIS_IP_); ++ prepare_lock_switch(rq, next, rf); + + /* Here we just switch the register state and the stack. */ + switch_to(prev, next, prev); +diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c +index dd062a1..7936f54 100644 +--- a/kernel/sched/cpufreq_schedutil.c ++++ b/kernel/sched/cpufreq_schedutil.c +@@ -19,8 +19,6 @@ + + #include "sched.h" + +-#define SUGOV_KTHREAD_PRIORITY 50 +- + struct sugov_tunables { + struct gov_attr_set attr_set; + unsigned int rate_limit_us; +diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c +index 9bb0e0c..9df0978 100644 +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -1153,6 +1153,7 @@ static void update_curr_dl(struct rq *rq) + struct sched_dl_entity *dl_se = &curr->dl; + u64 delta_exec, scaled_delta_exec; + int cpu = cpu_of(rq); ++ u64 now; + + if (!dl_task(curr) || !on_dl_rq(dl_se)) + return; +@@ -1165,7 +1166,8 @@ static void update_curr_dl(struct rq *rq) + * natural solution, but the full ramifications of this + * approach need further study. + */ +- delta_exec = rq_clock_task(rq) - curr->se.exec_start; ++ now = rq_clock_task(rq); ++ delta_exec = now - curr->se.exec_start; + if (unlikely((s64)delta_exec <= 0)) { + if (unlikely(dl_se->dl_yielded)) + goto throttle; +@@ -1178,7 +1180,7 @@ static void update_curr_dl(struct rq *rq) + curr->se.sum_exec_runtime += delta_exec; + account_group_exec_runtime(curr, delta_exec); + +- curr->se.exec_start = rq_clock_task(rq); ++ curr->se.exec_start = now; + cgroup_account_cputime(curr, delta_exec); + + sched_rt_avg_update(rq, delta_exec); +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index 663b235..aad49451 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -950,12 +950,13 @@ static void update_curr_rt(struct rq *rq) + { + struct task_struct *curr = rq->curr; + struct sched_rt_entity *rt_se = &curr->rt; +- u64 now = rq_clock_task(rq); + u64 delta_exec; ++ u64 now; + + if (curr->sched_class != &rt_sched_class) + return; + ++ now = rq_clock_task(rq); + delta_exec = now - curr->se.exec_start; + if (unlikely((s64)delta_exec <= 0)) + return; +diff --git a/kernel/seccomp.c b/kernel/seccomp.c +index 940fa40..dc77548 100644 +--- a/kernel/seccomp.c ++++ b/kernel/seccomp.c +@@ -1076,14 +1076,16 @@ long seccomp_get_metadata(struct task_struct *task, + + size = min_t(unsigned long, size, sizeof(kmd)); + +- if (copy_from_user(&kmd, data, size)) ++ if (size < sizeof(kmd.filter_off)) ++ return -EINVAL; ++ ++ if (copy_from_user(&kmd.filter_off, data, sizeof(kmd.filter_off))) + return -EFAULT; + + filter = get_nth_filter(task, kmd.filter_off); + if (IS_ERR(filter)) + return PTR_ERR(filter); + +- memset(&kmd, 0, sizeof(kmd)); + if (filter->log) + kmd.flags |= SECCOMP_FILTER_FLAG_LOG; + +diff --git a/kernel/time/timer.c b/kernel/time/timer.c +index 48150ab..4a4fd56 100644 +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -1894,6 +1894,12 @@ int timers_dead_cpu(unsigned int cpu) + raw_spin_lock_irq(&new_base->lock); + raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); + ++ /* ++ * The current CPUs base clock might be stale. Update it ++ * before moving the timers over. ++ */ ++ forward_timer_base(new_base); ++ + BUG_ON(old_base->running_timer); + + for (i = 0; i < WHEEL_SIZE; i++) +diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c +index fc2838a..c0a9e31 100644 +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -872,6 +872,8 @@ int perf_event_query_prog_array(struct perf_event *event, void __user *info) + return -EINVAL; + if (copy_from_user(&query, uquery, sizeof(query))) + return -EFAULT; ++ if (query.ids_len > BPF_TRACE_MAX_PROGS) ++ return -E2BIG; + + mutex_lock(&bpf_event_mutex); + ret = bpf_prog_array_copy_info(event->tp_event->prog_array, +diff --git a/kernel/user.c b/kernel/user.c +index 9a20acc..36288d8 100644 +--- a/kernel/user.c ++++ b/kernel/user.c +@@ -101,6 +101,7 @@ struct user_struct root_user = { + .sigpending = ATOMIC_INIT(0), + .locked_shm = 0, + .uid = GLOBAL_ROOT_UID, ++ .ratelimit = RATELIMIT_STATE_INIT(root_user.ratelimit, 0, 0), + }; + + /* +@@ -191,6 +192,8 @@ struct user_struct *alloc_uid(kuid_t uid) + + new->uid = uid; + atomic_set(&new->__count, 1); ++ ratelimit_state_init(&new->ratelimit, HZ, 100); ++ ratelimit_set_flags(&new->ratelimit, RATELIMIT_MSG_ON_RELEASE); + + /* + * Before adding this, check whether we raced +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index 017044c..bb9a519 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -4180,6 +4180,22 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active) + EXPORT_SYMBOL_GPL(workqueue_set_max_active); + + /** ++ * current_work - retrieve %current task's work struct ++ * ++ * Determine if %current task is a workqueue worker and what it's working on. ++ * Useful to find out the context that the %current task is running in. ++ * ++ * Return: work struct if %current task is a workqueue worker, %NULL otherwise. ++ */ ++struct work_struct *current_work(void) ++{ ++ struct worker *worker = current_wq_worker(); ++ ++ return worker ? worker->current_work : NULL; ++} ++EXPORT_SYMBOL(current_work); ++ ++/** + * current_is_workqueue_rescuer - is %current workqueue rescuer? + * + * Determine whether %current is a workqueue rescuer. Can be used from +diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug +index 6088408..64155e3 100644 +--- a/lib/Kconfig.debug ++++ b/lib/Kconfig.debug +@@ -1642,6 +1642,7 @@ config DMA_API_DEBUG + + menuconfig RUNTIME_TESTING_MENU + bool "Runtime Testing" ++ def_bool y + + if RUNTIME_TESTING_MENU + +diff --git a/lib/bug.c b/lib/bug.c +index c1b0fad..1077366 100644 +--- a/lib/bug.c ++++ b/lib/bug.c +@@ -150,6 +150,8 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) + return BUG_TRAP_TYPE_NONE; + + bug = find_bug(bugaddr); ++ if (!bug) ++ return BUG_TRAP_TYPE_NONE; + + file = NULL; + line = 0; +@@ -191,7 +193,7 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) + if (file) + pr_crit("kernel BUG at %s:%u!\n", file, line); + else +- pr_crit("Kernel BUG at %p [verbose debug info unavailable]\n", ++ pr_crit("Kernel BUG at %pB [verbose debug info unavailable]\n", + (void *)bugaddr); + + return BUG_TRAP_TYPE_BUG; +diff --git a/lib/dma-debug.c b/lib/dma-debug.c +index 1b34d21..7f5cdc1 100644 +--- a/lib/dma-debug.c ++++ b/lib/dma-debug.c +@@ -1491,12 +1491,12 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size, + if (unlikely(virt == NULL)) + return; + +- entry = dma_entry_alloc(); +- if (!entry) ++ /* handle vmalloc and linear addresses */ ++ if (!is_vmalloc_addr(virt) && !virt_addr_valid(virt)) + return; + +- /* handle vmalloc and linear addresses */ +- if (!is_vmalloc_addr(virt) && !virt_to_page(virt)) ++ entry = dma_entry_alloc(); ++ if (!entry) + return; + + entry->type = dma_debug_coherent; +@@ -1528,7 +1528,7 @@ void debug_dma_free_coherent(struct device *dev, size_t size, + }; + + /* handle vmalloc and linear addresses */ +- if (!is_vmalloc_addr(virt) && !virt_to_page(virt)) ++ if (!is_vmalloc_addr(virt) && !virt_addr_valid(virt)) + return; + + if (is_vmalloc_addr(virt)) +diff --git a/lib/dma-direct.c b/lib/dma-direct.c +index 40b1f92..c9e8e21 100644 +--- a/lib/dma-direct.c ++++ b/lib/dma-direct.c +@@ -84,6 +84,10 @@ void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, + return page_address(page); + } + ++/* ++ * NOTE: this function must never look at the dma_addr argument, because we want ++ * to be able to use it as a helper for iommu implementations as well. ++ */ + void dma_direct_free(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t dma_addr, unsigned long attrs) + { +@@ -152,5 +156,6 @@ const struct dma_map_ops dma_direct_ops = { + .map_sg = dma_direct_map_sg, + .dma_supported = dma_direct_supported, + .mapping_error = dma_direct_mapping_error, ++ .is_phys = 1, + }; + EXPORT_SYMBOL(dma_direct_ops); +diff --git a/lib/idr.c b/lib/idr.c +index c98d77f..823b813 100644 +--- a/lib/idr.c ++++ b/lib/idr.c +@@ -36,8 +36,8 @@ int idr_alloc_u32(struct idr *idr, void *ptr, u32 *nextid, + { + struct radix_tree_iter iter; + void __rcu **slot; +- int base = idr->idr_base; +- int id = *nextid; ++ unsigned int base = idr->idr_base; ++ unsigned int id = *nextid; + + if (WARN_ON_ONCE(radix_tree_is_internal_node(ptr))) + return -EINVAL; +@@ -204,10 +204,11 @@ int idr_for_each(const struct idr *idr, + + radix_tree_for_each_slot(slot, &idr->idr_rt, &iter, 0) { + int ret; ++ unsigned long id = iter.index + base; + +- if (WARN_ON_ONCE(iter.index > INT_MAX)) ++ if (WARN_ON_ONCE(id > INT_MAX)) + break; +- ret = fn(iter.index + base, rcu_dereference_raw(*slot), data); ++ ret = fn(id, rcu_dereference_raw(*slot), data); + if (ret) + return ret; + } +@@ -230,8 +231,8 @@ void *idr_get_next(struct idr *idr, int *nextid) + { + struct radix_tree_iter iter; + void __rcu **slot; +- int base = idr->idr_base; +- int id = *nextid; ++ unsigned long base = idr->idr_base; ++ unsigned long id = *nextid; + + id = (id < base) ? 0 : id - base; + slot = radix_tree_iter_find(&idr->idr_rt, &iter, id); +@@ -431,7 +432,6 @@ int ida_get_new_above(struct ida *ida, int start, int *id) + bitmap = this_cpu_xchg(ida_bitmap, NULL); + if (!bitmap) + return -EAGAIN; +- memset(bitmap, 0, sizeof(*bitmap)); + bitmap->bitmap[0] = tmp >> RADIX_TREE_EXCEPTIONAL_SHIFT; + rcu_assign_pointer(*slot, bitmap); + } +@@ -464,7 +464,6 @@ int ida_get_new_above(struct ida *ida, int start, int *id) + bitmap = this_cpu_xchg(ida_bitmap, NULL); + if (!bitmap) + return -EAGAIN; +- memset(bitmap, 0, sizeof(*bitmap)); + __set_bit(bit, bitmap->bitmap); + radix_tree_iter_replace(root, &iter, slot, bitmap); + } +diff --git a/lib/radix-tree.c b/lib/radix-tree.c +index 0a7ae32..8e00138 100644 +--- a/lib/radix-tree.c ++++ b/lib/radix-tree.c +@@ -2125,7 +2125,7 @@ int ida_pre_get(struct ida *ida, gfp_t gfp) + preempt_enable(); + + if (!this_cpu_read(ida_bitmap)) { +- struct ida_bitmap *bitmap = kmalloc(sizeof(*bitmap), gfp); ++ struct ida_bitmap *bitmap = kzalloc(sizeof(*bitmap), gfp); + if (!bitmap) + return 0; + if (this_cpu_cmpxchg(ida_bitmap, NULL, bitmap)) +diff --git a/lib/test_bpf.c b/lib/test_bpf.c +index b4e2234..2efb213 100644 +--- a/lib/test_bpf.c ++++ b/lib/test_bpf.c +@@ -24,10 +24,11 @@ + #include + #include + #include ++#include + + /* General test specific settings */ + #define MAX_SUBTESTS 3 +-#define MAX_TESTRUNS 10000 ++#define MAX_TESTRUNS 1000 + #define MAX_DATA 128 + #define MAX_INSNS 512 + #define MAX_K 0xffffFFFF +@@ -6582,6 +6583,7 @@ static __init int test_bpf(void) + struct bpf_prog *fp; + int err; + ++ cond_resched(); + if (exclude_test(i)) + continue; + +diff --git a/lib/test_kmod.c b/lib/test_kmod.c +index e372b97..0e5b7a6 100644 +--- a/lib/test_kmod.c ++++ b/lib/test_kmod.c +@@ -1141,7 +1141,7 @@ static struct kmod_test_device *register_test_dev_kmod(void) + mutex_lock(®_dev_mutex); + + /* int should suffice for number of devices, test for wrap */ +- if (unlikely(num_test_devs + 1) < 0) { ++ if (num_test_devs + 1 == INT_MAX) { + pr_err("reached limit of number of test devices\n"); + goto out; + } +diff --git a/lib/vsprintf.c b/lib/vsprintf.c +index 77ee6ce..d7a708f 100644 +--- a/lib/vsprintf.c ++++ b/lib/vsprintf.c +@@ -1849,7 +1849,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, + { + const int default_width = 2 * sizeof(void *); + +- if (!ptr && *fmt != 'K') { ++ if (!ptr && *fmt != 'K' && *fmt != 'x') { + /* + * Print (null) with the same width as a pointer so it makes + * tabular output look nice. +diff --git a/mm/gup.c b/mm/gup.c +index 1b46e6e..6afae32 100644 +--- a/mm/gup.c ++++ b/mm/gup.c +@@ -516,7 +516,7 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma, + } + + if (ret & VM_FAULT_RETRY) { +- if (nonblocking) ++ if (nonblocking && !(fault_flags & FAULT_FLAG_RETRY_NOWAIT)) + *nonblocking = 0; + return -EBUSY; + } +@@ -890,7 +890,10 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk, + break; + } + if (*locked) { +- /* VM_FAULT_RETRY didn't trigger */ ++ /* ++ * VM_FAULT_RETRY didn't trigger or it was a ++ * FOLL_NOWAIT. ++ */ + if (!pages_done) + pages_done = ret; + break; +diff --git a/mm/hugetlb.c b/mm/hugetlb.c +index 7c204e3..a963f20 100644 +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -1583,7 +1583,7 @@ static struct page *alloc_surplus_huge_page(struct hstate *h, gfp_t gfp_mask, + page = NULL; + } else { + h->surplus_huge_pages++; +- h->nr_huge_pages_node[page_to_nid(page)]++; ++ h->surplus_huge_pages_node[page_to_nid(page)]++; + } + + out_unlock: +diff --git a/mm/memblock.c b/mm/memblock.c +index 5a9ca2a..b6ba6b7 100644 +--- a/mm/memblock.c ++++ b/mm/memblock.c +@@ -1107,7 +1107,7 @@ unsigned long __init_memblock memblock_next_valid_pfn(unsigned long pfn, + struct memblock_type *type = &memblock.memory; + unsigned int right = type->cnt; + unsigned int mid, left = 0; +- phys_addr_t addr = PFN_PHYS(pfn + 1); ++ phys_addr_t addr = PFN_PHYS(++pfn); + + do { + mid = (right + left) / 2; +@@ -1118,15 +1118,15 @@ unsigned long __init_memblock memblock_next_valid_pfn(unsigned long pfn, + type->regions[mid].size)) + left = mid + 1; + else { +- /* addr is within the region, so pfn + 1 is valid */ +- return min(pfn + 1, max_pfn); ++ /* addr is within the region, so pfn is valid */ ++ return pfn; + } + } while (left < right); + + if (right == type->cnt) +- return max_pfn; ++ return -1UL; + else +- return min(PHYS_PFN(type->regions[right].base), max_pfn); ++ return PHYS_PFN(type->regions[right].base); + } + + /** +diff --git a/mm/memory-failure.c b/mm/memory-failure.c +index 4b80cce..8291b75 100644 +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -1139,8 +1139,6 @@ int memory_failure(unsigned long pfn, int flags) + return 0; + } + +- arch_unmap_kpfn(pfn); +- + orig_head = hpage = compound_head(p); + num_poisoned_pages_inc(); + +diff --git a/mm/memory.c b/mm/memory.c +index dd8de96..5fcfc24 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -80,7 +80,7 @@ + + #include "internal.h" + +-#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS ++#if defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS) && !defined(CONFIG_COMPILE_TEST) + #warning Unfortunate NUMA and NUMA Balancing config, growing page-frame for last_cpupid. + #endif + +diff --git a/mm/mlock.c b/mm/mlock.c +index 7939820..74e5a65 100644 +--- a/mm/mlock.c ++++ b/mm/mlock.c +@@ -64,6 +64,12 @@ void clear_page_mlock(struct page *page) + mod_zone_page_state(page_zone(page), NR_MLOCK, + -hpage_nr_pages(page)); + count_vm_event(UNEVICTABLE_PGCLEARED); ++ /* ++ * The previous TestClearPageMlocked() corresponds to the smp_mb() ++ * in __pagevec_lru_add_fn(). ++ * ++ * See __pagevec_lru_add_fn for more explanation. ++ */ + if (!isolate_lru_page(page)) { + putback_lru_page(page); + } else { +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index 81e18ce..3d974cb 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -46,6 +46,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -347,6 +348,9 @@ static inline bool update_defer_init(pg_data_t *pgdat, + /* Always populate low zones for address-constrained allocations */ + if (zone_end < pgdat_end_pfn(pgdat)) + return true; ++ /* Xen PV domains need page structures early */ ++ if (xen_pv_domain()) ++ return true; + (*nr_initialised)++; + if ((*nr_initialised > pgdat->static_init_pgcnt) && + (pfn & (PAGES_PER_SECTION - 1)) == 0) { +@@ -5355,9 +5359,14 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone, + /* + * Skip to the pfn preceding the next valid one (or + * end_pfn), such that we hit a valid pfn (or end_pfn) +- * on our next iteration of the loop. ++ * on our next iteration of the loop. Note that it needs ++ * to be pageblock aligned even when the region itself ++ * is not. move_freepages_block() can shift ahead of ++ * the valid region but still depends on correct page ++ * metadata. + */ +- pfn = memblock_next_valid_pfn(pfn, end_pfn) - 1; ++ pfn = (memblock_next_valid_pfn(pfn, end_pfn) & ++ ~(pageblock_nr_pages-1)) - 1; + #endif + continue; + } +diff --git a/mm/swap.c b/mm/swap.c +index 567a7b9..0f17330 100644 +--- a/mm/swap.c ++++ b/mm/swap.c +@@ -446,30 +446,6 @@ void lru_cache_add(struct page *page) + } + + /** +- * add_page_to_unevictable_list - add a page to the unevictable list +- * @page: the page to be added to the unevictable list +- * +- * Add page directly to its zone's unevictable list. To avoid races with +- * tasks that might be making the page evictable, through eg. munlock, +- * munmap or exit, while it's not on the lru, we want to add the page +- * while it's locked or otherwise "invisible" to other tasks. This is +- * difficult to do when using the pagevec cache, so bypass that. +- */ +-void add_page_to_unevictable_list(struct page *page) +-{ +- struct pglist_data *pgdat = page_pgdat(page); +- struct lruvec *lruvec; +- +- spin_lock_irq(&pgdat->lru_lock); +- lruvec = mem_cgroup_page_lruvec(page, pgdat); +- ClearPageActive(page); +- SetPageUnevictable(page); +- SetPageLRU(page); +- add_page_to_lru_list(page, lruvec, LRU_UNEVICTABLE); +- spin_unlock_irq(&pgdat->lru_lock); +-} +- +-/** + * lru_cache_add_active_or_unevictable + * @page: the page to be added to LRU + * @vma: vma in which page is mapped for determining reclaimability +@@ -484,13 +460,9 @@ void lru_cache_add_active_or_unevictable(struct page *page, + { + VM_BUG_ON_PAGE(PageLRU(page), page); + +- if (likely((vma->vm_flags & (VM_LOCKED | VM_SPECIAL)) != VM_LOCKED)) { ++ if (likely((vma->vm_flags & (VM_LOCKED | VM_SPECIAL)) != VM_LOCKED)) + SetPageActive(page); +- lru_cache_add(page); +- return; +- } +- +- if (!TestSetPageMlocked(page)) { ++ else if (!TestSetPageMlocked(page)) { + /* + * We use the irq-unsafe __mod_zone_page_stat because this + * counter is not modified from interrupt context, and the pte +@@ -500,7 +472,7 @@ void lru_cache_add_active_or_unevictable(struct page *page, + hpage_nr_pages(page)); + count_vm_event(UNEVICTABLE_PGMLOCKED); + } +- add_page_to_unevictable_list(page); ++ lru_cache_add(page); + } + + /* +@@ -886,15 +858,55 @@ void lru_add_page_tail(struct page *page, struct page *page_tail, + static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec, + void *arg) + { +- int file = page_is_file_cache(page); +- int active = PageActive(page); +- enum lru_list lru = page_lru(page); ++ enum lru_list lru; ++ int was_unevictable = TestClearPageUnevictable(page); + + VM_BUG_ON_PAGE(PageLRU(page), page); + + SetPageLRU(page); ++ /* ++ * Page becomes evictable in two ways: ++ * 1) Within LRU lock [munlock_vma_pages() and __munlock_pagevec()]. ++ * 2) Before acquiring LRU lock to put the page to correct LRU and then ++ * a) do PageLRU check with lock [check_move_unevictable_pages] ++ * b) do PageLRU check before lock [clear_page_mlock] ++ * ++ * (1) & (2a) are ok as LRU lock will serialize them. For (2b), we need ++ * following strict ordering: ++ * ++ * #0: __pagevec_lru_add_fn #1: clear_page_mlock ++ * ++ * SetPageLRU() TestClearPageMlocked() ++ * smp_mb() // explicit ordering // above provides strict ++ * // ordering ++ * PageMlocked() PageLRU() ++ * ++ * ++ * if '#1' does not observe setting of PG_lru by '#0' and fails ++ * isolation, the explicit barrier will make sure that page_evictable ++ * check will put the page in correct LRU. Without smp_mb(), SetPageLRU ++ * can be reordered after PageMlocked check and can make '#1' to fail ++ * the isolation of the page whose Mlocked bit is cleared (#0 is also ++ * looking at the same page) and the evictable page will be stranded ++ * in an unevictable LRU. ++ */ ++ smp_mb(); ++ ++ if (page_evictable(page)) { ++ lru = page_lru(page); ++ update_page_reclaim_stat(lruvec, page_is_file_cache(page), ++ PageActive(page)); ++ if (was_unevictable) ++ count_vm_event(UNEVICTABLE_PGRESCUED); ++ } else { ++ lru = LRU_UNEVICTABLE; ++ ClearPageActive(page); ++ SetPageUnevictable(page); ++ if (!was_unevictable) ++ count_vm_event(UNEVICTABLE_PGCULLED); ++ } ++ + add_page_to_lru_list(page, lruvec, lru); +- update_page_reclaim_stat(lruvec, file, active); + trace_mm_lru_insertion(page, lru); + } + +@@ -913,7 +925,7 @@ EXPORT_SYMBOL(__pagevec_lru_add); + * @pvec: Where the resulting entries are placed + * @mapping: The address_space to search + * @start: The starting entry index +- * @nr_pages: The maximum number of pages ++ * @nr_entries: The maximum number of pages + * @indices: The cache indices corresponding to the entries in @pvec + * + * pagevec_lookup_entries() will search for and return a group of up +diff --git a/mm/vmalloc.c b/mm/vmalloc.c +index 6739420..ebff729 100644 +--- a/mm/vmalloc.c ++++ b/mm/vmalloc.c +@@ -1943,11 +1943,15 @@ void *vmalloc_exec(unsigned long size) + } + + #if defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA32) +-#define GFP_VMALLOC32 GFP_DMA32 | GFP_KERNEL ++#define GFP_VMALLOC32 (GFP_DMA32 | GFP_KERNEL) + #elif defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA) +-#define GFP_VMALLOC32 GFP_DMA | GFP_KERNEL ++#define GFP_VMALLOC32 (GFP_DMA | GFP_KERNEL) + #else +-#define GFP_VMALLOC32 GFP_KERNEL ++/* ++ * 64b systems should always have either DMA or DMA32 zones. For others ++ * GFP_DMA32 should do the right thing and use the normal zone. ++ */ ++#define GFP_VMALLOC32 GFP_DMA32 | GFP_KERNEL + #endif + + /** +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 4447496..bee5349 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -769,64 +769,7 @@ int remove_mapping(struct address_space *mapping, struct page *page) + */ + void putback_lru_page(struct page *page) + { +- bool is_unevictable; +- int was_unevictable = PageUnevictable(page); +- +- VM_BUG_ON_PAGE(PageLRU(page), page); +- +-redo: +- ClearPageUnevictable(page); +- +- if (page_evictable(page)) { +- /* +- * For evictable pages, we can use the cache. +- * In event of a race, worst case is we end up with an +- * unevictable page on [in]active list. +- * We know how to handle that. +- */ +- is_unevictable = false; +- lru_cache_add(page); +- } else { +- /* +- * Put unevictable pages directly on zone's unevictable +- * list. +- */ +- is_unevictable = true; +- add_page_to_unevictable_list(page); +- /* +- * When racing with an mlock or AS_UNEVICTABLE clearing +- * (page is unlocked) make sure that if the other thread +- * does not observe our setting of PG_lru and fails +- * isolation/check_move_unevictable_pages, +- * we see PG_mlocked/AS_UNEVICTABLE cleared below and move +- * the page back to the evictable list. +- * +- * The other side is TestClearPageMlocked() or shmem_lock(). +- */ +- smp_mb(); +- } +- +- /* +- * page's status can change while we move it among lru. If an evictable +- * page is on unevictable list, it never be freed. To avoid that, +- * check after we added it to the list, again. +- */ +- if (is_unevictable && page_evictable(page)) { +- if (!isolate_lru_page(page)) { +- put_page(page); +- goto redo; +- } +- /* This means someone else dropped this page from LRU +- * So, it will be freed or putback to LRU again. There is +- * nothing to do here. +- */ +- } +- +- if (was_unevictable && !is_unevictable) +- count_vm_event(UNEVICTABLE_PGRESCUED); +- else if (!was_unevictable && is_unevictable) +- count_vm_event(UNEVICTABLE_PGCULLED); +- ++ lru_cache_add(page); + put_page(page); /* drop ref from isolate */ + } + +diff --git a/mm/zpool.c b/mm/zpool.c +index f8cb83e..01a771e 100644 +--- a/mm/zpool.c ++++ b/mm/zpool.c +@@ -360,7 +360,7 @@ u64 zpool_get_total_size(struct zpool *zpool) + + /** + * zpool_evictable() - Test if zpool is potentially evictable +- * @pool The zpool to test ++ * @zpool: The zpool to test + * + * Zpool is only potentially evictable when it's created with struct + * zpool_ops.evict and its driver implements struct zpool_driver.shrink. +diff --git a/mm/zswap.c b/mm/zswap.c +index c004aa4..61a5c41 100644 +--- a/mm/zswap.c ++++ b/mm/zswap.c +@@ -1007,6 +1007,12 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset, + u8 *src, *dst; + struct zswap_header zhdr = { .swpentry = swp_entry(type, offset) }; + ++ /* THP isn't supported */ ++ if (PageTransHuge(page)) { ++ ret = -EINVAL; ++ goto reject; ++ } ++ + if (!zswap_enabled || !tree) { + ret = -ENODEV; + goto reject; +diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c +index f3a4efc..3aa5a93 100644 +--- a/net/9p/trans_virtio.c ++++ b/net/9p/trans_virtio.c +@@ -160,7 +160,8 @@ static void req_done(struct virtqueue *vq) + spin_unlock_irqrestore(&chan->lock, flags); + /* Wakeup if anyone waiting for VirtIO ring space. */ + wake_up(chan->vc_wq); +- p9_client_cb(chan->client, req, REQ_STATUS_RCVD); ++ if (len) ++ p9_client_cb(chan->client, req, REQ_STATUS_RCVD); + } + } + +diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c +index 79e3263..99abead 100644 +--- a/net/batman-adv/bat_iv_ogm.c ++++ b/net/batman-adv/bat_iv_ogm.c +@@ -157,7 +157,7 @@ static void batadv_iv_ogm_orig_free(struct batadv_orig_node *orig_node) + * Return: 0 on success, a negative error code otherwise. + */ + static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node, +- int max_if_num) ++ unsigned int max_if_num) + { + void *data_ptr; + size_t old_size; +@@ -201,7 +201,8 @@ static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node, + */ + static void + batadv_iv_ogm_drop_bcast_own_entry(struct batadv_orig_node *orig_node, +- int max_if_num, int del_if_num) ++ unsigned int max_if_num, ++ unsigned int del_if_num) + { + size_t chunk_size; + size_t if_offset; +@@ -239,7 +240,8 @@ batadv_iv_ogm_drop_bcast_own_entry(struct batadv_orig_node *orig_node, + */ + static void + batadv_iv_ogm_drop_bcast_own_sum_entry(struct batadv_orig_node *orig_node, +- int max_if_num, int del_if_num) ++ unsigned int max_if_num, ++ unsigned int del_if_num) + { + size_t if_offset; + void *data_ptr; +@@ -276,7 +278,8 @@ batadv_iv_ogm_drop_bcast_own_sum_entry(struct batadv_orig_node *orig_node, + * Return: 0 on success, a negative error code otherwise. + */ + static int batadv_iv_ogm_orig_del_if(struct batadv_orig_node *orig_node, +- int max_if_num, int del_if_num) ++ unsigned int max_if_num, ++ unsigned int del_if_num) + { + spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); + +@@ -311,7 +314,8 @@ static struct batadv_orig_node * + batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr) + { + struct batadv_orig_node *orig_node; +- int size, hash_added; ++ int hash_added; ++ size_t size; + + orig_node = batadv_orig_hash_find(bat_priv, addr); + if (orig_node) +@@ -893,7 +897,7 @@ batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface) + u32 i; + size_t word_index; + u8 *w; +- int if_num; ++ unsigned int if_num; + + for (i = 0; i < hash->size; i++) { + head = &hash->table[i]; +@@ -1023,7 +1027,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, + struct batadv_neigh_node *tmp_neigh_node = NULL; + struct batadv_neigh_node *router = NULL; + struct batadv_orig_node *orig_node_tmp; +- int if_num; ++ unsigned int if_num; + u8 sum_orig, sum_neigh; + u8 *neigh_addr; + u8 tq_avg; +@@ -1182,7 +1186,7 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, + u8 total_count; + u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; + unsigned int neigh_rq_inv_cube, neigh_rq_max_cube; +- int if_num; ++ unsigned int if_num; + unsigned int tq_asym_penalty, inv_asym_penalty; + unsigned int combined_tq; + unsigned int tq_iface_penalty; +@@ -1702,9 +1706,9 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset, + + if (is_my_orig) { + unsigned long *word; +- int offset; ++ size_t offset; + s32 bit_pos; +- s16 if_num; ++ unsigned int if_num; + u8 *weight; + + orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv, +@@ -2729,7 +2733,7 @@ static int batadv_iv_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_neigh_ifinfo *router_ifinfo = NULL; + struct batadv_neigh_node *router; + struct batadv_gw_node *curr_gw; +- int ret = -EINVAL; ++ int ret = 0; + void *hdr; + + router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); +diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c +index 27e165a..c74f813 100644 +--- a/net/batman-adv/bat_v.c ++++ b/net/batman-adv/bat_v.c +@@ -928,7 +928,7 @@ static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_neigh_ifinfo *router_ifinfo = NULL; + struct batadv_neigh_node *router; + struct batadv_gw_node *curr_gw; +- int ret = -EINVAL; ++ int ret = 0; + void *hdr; + + router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); +diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c +index fad4785..b1a0837 100644 +--- a/net/batman-adv/bridge_loop_avoidance.c ++++ b/net/batman-adv/bridge_loop_avoidance.c +@@ -2161,22 +2161,25 @@ batadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, + { + struct batadv_bla_claim *claim; + int idx = 0; ++ int ret = 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(claim, head, hash_entry) { + if (idx++ < *idx_skip) + continue; +- if (batadv_bla_claim_dump_entry(msg, portid, seq, +- primary_if, claim)) { ++ ++ ret = batadv_bla_claim_dump_entry(msg, portid, seq, ++ primary_if, claim); ++ if (ret) { + *idx_skip = idx - 1; + goto unlock; + } + } + +- *idx_skip = idx; ++ *idx_skip = 0; + unlock: + rcu_read_unlock(); +- return 0; ++ return ret; + } + + /** +@@ -2391,22 +2394,25 @@ batadv_bla_backbone_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, + { + struct batadv_bla_backbone_gw *backbone_gw; + int idx = 0; ++ int ret = 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) { + if (idx++ < *idx_skip) + continue; +- if (batadv_bla_backbone_dump_entry(msg, portid, seq, +- primary_if, backbone_gw)) { ++ ++ ret = batadv_bla_backbone_dump_entry(msg, portid, seq, ++ primary_if, backbone_gw); ++ if (ret) { + *idx_skip = idx - 1; + goto unlock; + } + } + +- *idx_skip = idx; ++ *idx_skip = 0; + unlock: + rcu_read_unlock(); +- return 0; ++ return ret; + } + + /** +diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c +index 22dde42..5afe641 100644 +--- a/net/batman-adv/fragmentation.c ++++ b/net/batman-adv/fragmentation.c +@@ -288,7 +288,8 @@ batadv_frag_merge_packets(struct hlist_head *chain) + /* Move the existing MAC header to just before the payload. (Override + * the fragment header.) + */ +- skb_pull_rcsum(skb_out, hdr_size); ++ skb_pull(skb_out, hdr_size); ++ skb_out->ip_summed = CHECKSUM_NONE; + memmove(skb_out->data - ETH_HLEN, skb_mac_header(skb_out), ETH_HLEN); + skb_set_mac_header(skb_out, -ETH_HLEN); + skb_reset_network_header(skb_out); +diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c +index 5f186bf..68b54a3 100644 +--- a/net/batman-adv/hard-interface.c ++++ b/net/batman-adv/hard-interface.c +@@ -763,6 +763,11 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, + hard_iface->soft_iface = soft_iface; + bat_priv = netdev_priv(hard_iface->soft_iface); + ++ if (bat_priv->num_ifaces >= UINT_MAX) { ++ ret = -ENOSPC; ++ goto err_dev; ++ } ++ + ret = netdev_master_upper_dev_link(hard_iface->net_dev, + soft_iface, NULL, NULL, NULL); + if (ret) +@@ -876,7 +881,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, + batadv_hardif_recalc_extra_skbroom(hard_iface->soft_iface); + + /* nobody uses this interface anymore */ +- if (!bat_priv->num_ifaces) { ++ if (bat_priv->num_ifaces == 0) { + batadv_gw_check_client_stop(bat_priv); + + if (autodel == BATADV_IF_CLEANUP_AUTO) +@@ -912,7 +917,7 @@ batadv_hardif_add_interface(struct net_device *net_dev) + if (ret) + goto free_if; + +- hard_iface->if_num = -1; ++ hard_iface->if_num = 0; + hard_iface->net_dev = net_dev; + hard_iface->soft_iface = NULL; + hard_iface->if_status = BATADV_IF_NOT_IN_USE; +diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c +index 58a7d92..7478242 100644 +--- a/net/batman-adv/originator.c ++++ b/net/batman-adv/originator.c +@@ -1569,7 +1569,7 @@ int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb) + * Return: 0 on success or negative error number in case of failure + */ + int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, +- int max_if_num) ++ unsigned int max_if_num) + { + struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); + struct batadv_algo_ops *bao = bat_priv->algo_ops; +@@ -1611,7 +1611,7 @@ int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, + * Return: 0 on success or negative error number in case of failure + */ + int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, +- int max_if_num) ++ unsigned int max_if_num) + { + struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); + struct batadv_hashtable *hash = bat_priv->orig_hash; +diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h +index 8e543a3..15d896b 100644 +--- a/net/batman-adv/originator.h ++++ b/net/batman-adv/originator.h +@@ -73,9 +73,9 @@ int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); + int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb); + int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset); + int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, +- int max_if_num); ++ unsigned int max_if_num); + int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, +- int max_if_num); ++ unsigned int max_if_num); + struct batadv_orig_node_vlan * + batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node, + unsigned short vid); +diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c +index 900c5ce..367a81f 100644 +--- a/net/batman-adv/soft-interface.c ++++ b/net/batman-adv/soft-interface.c +@@ -459,13 +459,7 @@ void batadv_interface_rx(struct net_device *soft_iface, + + /* skb->dev & skb->pkt_type are set here */ + skb->protocol = eth_type_trans(skb, soft_iface); +- +- /* should not be necessary anymore as we use skb_pull_rcsum() +- * TODO: please verify this and remove this TODO +- * -- Dec 21st 2009, Simon Wunderlich +- */ +- +- /* skb->ip_summed = CHECKSUM_UNNECESSARY; */ ++ skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); + + batadv_inc_counter(bat_priv, BATADV_CNT_RX); + batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES, +diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h +index bb15784..a5aa6d6 100644 +--- a/net/batman-adv/types.h ++++ b/net/batman-adv/types.h +@@ -167,7 +167,7 @@ struct batadv_hard_iface { + struct list_head list; + + /** @if_num: identificator of the interface */ +- s16 if_num; ++ unsigned int if_num; + + /** @if_status: status of the interface for batman-adv */ + char if_status; +@@ -1596,7 +1596,7 @@ struct batadv_priv { + atomic_t batman_queue_left; + + /** @num_ifaces: number of interfaces assigned to this mesh interface */ +- char num_ifaces; ++ unsigned int num_ifaces; + + /** @mesh_obj: kobject for sysfs mesh subdirectory */ + struct kobject *mesh_obj; +@@ -2186,15 +2186,16 @@ struct batadv_algo_orig_ops { + * orig_node due to a new hard-interface being added into the mesh + * (optional) + */ +- int (*add_if)(struct batadv_orig_node *orig_node, int max_if_num); ++ int (*add_if)(struct batadv_orig_node *orig_node, ++ unsigned int max_if_num); + + /** + * @del_if: ask the routing algorithm to apply the needed changes to the + * orig_node due to an hard-interface being removed from the mesh + * (optional) + */ +- int (*del_if)(struct batadv_orig_node *orig_node, int max_if_num, +- int del_if_num); ++ int (*del_if)(struct batadv_orig_node *orig_node, ++ unsigned int max_if_num, unsigned int del_if_num); + + #ifdef CONFIG_BATMAN_ADV_DEBUGFS + /** @print: print the originator table (optional) */ +diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c +index 27f1d4f..9b16eaf 100644 +--- a/net/bridge/br_netfilter_hooks.c ++++ b/net/bridge/br_netfilter_hooks.c +@@ -214,7 +214,7 @@ static int br_validate_ipv4(struct net *net, struct sk_buff *skb) + + iph = ip_hdr(skb); + if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) +- goto inhdr_error; ++ goto csum_error; + + len = ntohs(iph->tot_len); + if (skb->len < len) { +@@ -236,6 +236,8 @@ static int br_validate_ipv4(struct net *net, struct sk_buff *skb) + */ + return 0; + ++csum_error: ++ __IP_INC_STATS(net, IPSTATS_MIB_CSUMERRORS); + inhdr_error: + __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS); + drop: +diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c +index 0254c35..126a8ea 100644 +--- a/net/bridge/br_sysfs_if.c ++++ b/net/bridge/br_sysfs_if.c +@@ -255,6 +255,9 @@ static ssize_t brport_show(struct kobject *kobj, + struct brport_attribute *brport_attr = to_brport_attr(attr); + struct net_bridge_port *p = to_brport(kobj); + ++ if (!brport_attr->show) ++ return -EINVAL; ++ + return brport_attr->show(p, buf); + } + +diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c +index 5193527..9896f49 100644 +--- a/net/bridge/br_vlan.c ++++ b/net/bridge/br_vlan.c +@@ -168,6 +168,8 @@ static struct net_bridge_vlan *br_vlan_get_master(struct net_bridge *br, u16 vid + masterv = br_vlan_find(vg, vid); + if (WARN_ON(!masterv)) + return NULL; ++ refcount_set(&masterv->refcnt, 1); ++ return masterv; + } + refcount_inc(&masterv->refcnt); + +diff --git a/net/bridge/netfilter/ebt_among.c b/net/bridge/netfilter/ebt_among.c +index 279527f..c5afb42 100644 +--- a/net/bridge/netfilter/ebt_among.c ++++ b/net/bridge/netfilter/ebt_among.c +@@ -172,32 +172,49 @@ ebt_among_mt(const struct sk_buff *skb, struct xt_action_param *par) + return true; + } + ++static bool poolsize_invalid(const struct ebt_mac_wormhash *w) ++{ ++ return w && w->poolsize >= (INT_MAX / sizeof(struct ebt_mac_wormhash_tuple)); ++} ++ + static int ebt_among_mt_check(const struct xt_mtchk_param *par) + { + const struct ebt_among_info *info = par->matchinfo; + const struct ebt_entry_match *em = + container_of(par->matchinfo, const struct ebt_entry_match, data); +- int expected_length = sizeof(struct ebt_among_info); ++ unsigned int expected_length = sizeof(struct ebt_among_info); + const struct ebt_mac_wormhash *wh_dst, *wh_src; + int err; + ++ if (expected_length > em->match_size) ++ return -EINVAL; ++ + wh_dst = ebt_among_wh_dst(info); +- wh_src = ebt_among_wh_src(info); ++ if (poolsize_invalid(wh_dst)) ++ return -EINVAL; ++ + expected_length += ebt_mac_wormhash_size(wh_dst); ++ if (expected_length > em->match_size) ++ return -EINVAL; ++ ++ wh_src = ebt_among_wh_src(info); ++ if (poolsize_invalid(wh_src)) ++ return -EINVAL; ++ + expected_length += ebt_mac_wormhash_size(wh_src); + + if (em->match_size != EBT_ALIGN(expected_length)) { +- pr_info("wrong size: %d against expected %d, rounded to %zd\n", +- em->match_size, expected_length, +- EBT_ALIGN(expected_length)); ++ pr_err_ratelimited("wrong size: %d against expected %d, rounded to %zd\n", ++ em->match_size, expected_length, ++ EBT_ALIGN(expected_length)); + return -EINVAL; + } + if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) { +- pr_info("dst integrity fail: %x\n", -err); ++ pr_err_ratelimited("dst integrity fail: %x\n", -err); + return -EINVAL; + } + if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) { +- pr_info("src integrity fail: %x\n", -err); ++ pr_err_ratelimited("src integrity fail: %x\n", -err); + return -EINVAL; + } + return 0; +diff --git a/net/bridge/netfilter/ebt_limit.c b/net/bridge/netfilter/ebt_limit.c +index 61a9f1b..165b9d6 100644 +--- a/net/bridge/netfilter/ebt_limit.c ++++ b/net/bridge/netfilter/ebt_limit.c +@@ -72,8 +72,8 @@ static int ebt_limit_mt_check(const struct xt_mtchk_param *par) + /* Check for overflow. */ + if (info->burst == 0 || + user2credits(info->avg * info->burst) < user2credits(info->avg)) { +- pr_info("overflow, try lower: %u/%u\n", +- info->avg, info->burst); ++ pr_info_ratelimited("overflow, try lower: %u/%u\n", ++ info->avg, info->burst); + return -EINVAL; + } + +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index 02c4b40..254ef9f 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -1641,7 +1641,8 @@ static int compat_match_to_user(struct ebt_entry_match *m, void __user **dstptr, + int off = ebt_compat_match_offset(match, m->match_size); + compat_uint_t msize = m->match_size - off; + +- BUG_ON(off >= m->match_size); ++ if (WARN_ON(off >= m->match_size)) ++ return -EINVAL; + + if (copy_to_user(cm->u.name, match->name, + strlen(match->name) + 1) || put_user(msize, &cm->match_size)) +@@ -1671,7 +1672,8 @@ static int compat_target_to_user(struct ebt_entry_target *t, + int off = xt_compat_target_offset(target); + compat_uint_t tsize = t->target_size - off; + +- BUG_ON(off >= t->target_size); ++ if (WARN_ON(off >= t->target_size)) ++ return -EINVAL; + + if (copy_to_user(cm->u.name, target->name, + strlen(target->name) + 1) || put_user(tsize, &cm->match_size)) +@@ -1902,7 +1904,8 @@ static int ebt_buf_add(struct ebt_entries_buf_state *state, + if (state->buf_kern_start == NULL) + goto count_only; + +- BUG_ON(state->buf_kern_offset + sz > state->buf_kern_len); ++ if (WARN_ON(state->buf_kern_offset + sz > state->buf_kern_len)) ++ return -EINVAL; + + memcpy(state->buf_kern_start + state->buf_kern_offset, data, sz); + +@@ -1915,7 +1918,8 @@ static int ebt_buf_add_pad(struct ebt_entries_buf_state *state, unsigned int sz) + { + char *b = state->buf_kern_start; + +- BUG_ON(b && state->buf_kern_offset > state->buf_kern_len); ++ if (WARN_ON(b && state->buf_kern_offset > state->buf_kern_len)) ++ return -EINVAL; + + if (b != NULL && sz > 0) + memset(b + state->buf_kern_offset, 0, sz); +@@ -1992,8 +1996,10 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, + pad = XT_ALIGN(size_kern) - size_kern; + + if (pad > 0 && dst) { +- BUG_ON(state->buf_kern_len <= pad); +- BUG_ON(state->buf_kern_offset - (match_size + off) + size_kern > state->buf_kern_len - pad); ++ if (WARN_ON(state->buf_kern_len <= pad)) ++ return -EINVAL; ++ if (WARN_ON(state->buf_kern_offset - (match_size + off) + size_kern > state->buf_kern_len - pad)) ++ return -EINVAL; + memset(dst + size_kern, 0, pad); + } + return off + match_size; +@@ -2043,7 +2049,8 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32, + if (ret < 0) + return ret; + +- BUG_ON(ret < match32->match_size); ++ if (WARN_ON(ret < match32->match_size)) ++ return -EINVAL; + growth += ret - match32->match_size; + growth += ebt_compat_entry_padsize(); + +@@ -2053,7 +2060,9 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32, + if (match_kern) + match_kern->match_size = ret; + +- WARN_ON(type == EBT_COMPAT_TARGET && size_left); ++ if (WARN_ON(type == EBT_COMPAT_TARGET && size_left)) ++ return -EINVAL; ++ + match32 = (struct compat_ebt_entry_mwt *) buf; + } + +@@ -2109,6 +2118,15 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, + * + * offsets are relative to beginning of struct ebt_entry (i.e., 0). + */ ++ for (i = 0; i < 4 ; ++i) { ++ if (offsets[i] >= *total) ++ return -EINVAL; ++ if (i == 0) ++ continue; ++ if (offsets[i-1] > offsets[i]) ++ return -EINVAL; ++ } ++ + for (i = 0, j = 1 ; j < 4 ; j++, i++) { + struct compat_ebt_entry_mwt *match32; + unsigned int size; +@@ -2140,7 +2158,8 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, + + startoff = state->buf_user_offset - startoff; + +- BUG_ON(*total < startoff); ++ if (WARN_ON(*total < startoff)) ++ return -EINVAL; + *total -= startoff; + return 0; + } +@@ -2267,7 +2286,8 @@ static int compat_do_replace(struct net *net, void __user *user, + state.buf_kern_len = size64; + + ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state); +- BUG_ON(ret < 0); /* parses same data again */ ++ if (WARN_ON(ret < 0)) ++ goto out_unlock; + + vfree(entries_tmp); + tmp.entries_size = size64; +diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c +index 1e492ef..4d4c822 100644 +--- a/net/ceph/ceph_common.c ++++ b/net/ceph/ceph_common.c +@@ -418,6 +418,7 @@ ceph_parse_options(char *options, const char *dev_name, + opt->flags |= CEPH_OPT_FSID; + break; + case Opt_name: ++ kfree(opt->name); + opt->name = kstrndup(argstr[0].from, + argstr[0].to-argstr[0].from, + GFP_KERNEL); +@@ -427,6 +428,9 @@ ceph_parse_options(char *options, const char *dev_name, + } + break; + case Opt_secret: ++ ceph_crypto_key_destroy(opt->key); ++ kfree(opt->key); ++ + opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL); + if (!opt->key) { + err = -ENOMEM; +@@ -437,6 +441,9 @@ ceph_parse_options(char *options, const char *dev_name, + goto out; + break; + case Opt_key: ++ ceph_crypto_key_destroy(opt->key); ++ kfree(opt->key); ++ + opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL); + if (!opt->key) { + err = -ENOMEM; +diff --git a/net/core/dev.c b/net/core/dev.c +index dda9d7b..2cedf52 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -2382,8 +2382,11 @@ EXPORT_SYMBOL(netdev_set_num_tc); + */ + int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) + { ++ bool disabling; + int rc; + ++ disabling = txq < dev->real_num_tx_queues; ++ + if (txq < 1 || txq > dev->num_tx_queues) + return -EINVAL; + +@@ -2399,15 +2402,19 @@ int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) + if (dev->num_tc) + netif_setup_tc(dev, txq); + +- if (txq < dev->real_num_tx_queues) { ++ dev->real_num_tx_queues = txq; ++ ++ if (disabling) { ++ synchronize_net(); + qdisc_reset_all_tx_gt(dev, txq); + #ifdef CONFIG_XPS + netif_reset_xps_queues_gt(dev, txq); + #endif + } ++ } else { ++ dev->real_num_tx_queues = txq; + } + +- dev->real_num_tx_queues = txq; + return 0; + } + EXPORT_SYMBOL(netif_set_real_num_tx_queues); +@@ -6389,6 +6396,7 @@ static int __netdev_upper_dev_link(struct net_device *dev, + .linking = true, + .upper_info = upper_info, + }; ++ struct net_device *master_dev; + int ret = 0; + + ASSERT_RTNL(); +@@ -6400,11 +6408,14 @@ static int __netdev_upper_dev_link(struct net_device *dev, + if (netdev_has_upper_dev(upper_dev, dev)) + return -EBUSY; + +- if (netdev_has_upper_dev(dev, upper_dev)) +- return -EEXIST; +- +- if (master && netdev_master_upper_dev_get(dev)) +- return -EBUSY; ++ if (!master) { ++ if (netdev_has_upper_dev(dev, upper_dev)) ++ return -EEXIST; ++ } else { ++ master_dev = netdev_master_upper_dev_get(dev); ++ if (master_dev) ++ return master_dev == upper_dev ? -EEXIST : -EBUSY; ++ } + + ret = call_netdevice_notifiers_info(NETDEV_PRECHANGEUPPER, + &changeupper_info.info); +diff --git a/net/core/devlink.c b/net/core/devlink.c +index 18d385e..2f2307d9 100644 +--- a/net/core/devlink.c ++++ b/net/core/devlink.c +@@ -1695,10 +1695,11 @@ static int devlink_dpipe_table_put(struct sk_buff *skb, + goto nla_put_failure; + + if (table->resource_valid) { +- nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID, +- table->resource_id, DEVLINK_ATTR_PAD); +- nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS, +- table->resource_units, DEVLINK_ATTR_PAD); ++ if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID, ++ table->resource_id, DEVLINK_ATTR_PAD) || ++ nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS, ++ table->resource_units, DEVLINK_ATTR_PAD)) ++ goto nla_put_failure; + } + if (devlink_dpipe_matches_put(table, skb)) + goto nla_put_failure; +@@ -2332,7 +2333,7 @@ devlink_resource_validate_children(struct devlink_resource *resource) + list_for_each_entry(child_resource, &resource->resource_list, list) + parts_size += child_resource->size_new; + +- if (parts_size > resource->size) ++ if (parts_size > resource->size_new) + size_valid = false; + out: + resource->size_valid = size_valid; +@@ -2372,20 +2373,22 @@ static int devlink_nl_cmd_resource_set(struct sk_buff *skb, + return 0; + } + +-static void ++static int + devlink_resource_size_params_put(struct devlink_resource *resource, + struct sk_buff *skb) + { + struct devlink_resource_size_params *size_params; + +- size_params = resource->size_params; +- nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN, +- size_params->size_granularity, DEVLINK_ATTR_PAD); +- nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX, +- size_params->size_max, DEVLINK_ATTR_PAD); +- nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN, +- size_params->size_min, DEVLINK_ATTR_PAD); +- nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit); ++ size_params = &resource->size_params; ++ if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN, ++ size_params->size_granularity, DEVLINK_ATTR_PAD) || ++ nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX, ++ size_params->size_max, DEVLINK_ATTR_PAD) || ++ nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN, ++ size_params->size_min, DEVLINK_ATTR_PAD) || ++ nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit)) ++ return -EMSGSIZE; ++ return 0; + } + + static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb, +@@ -2409,10 +2412,12 @@ static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb, + nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW, + resource->size_new, DEVLINK_ATTR_PAD); + if (resource->resource_ops && resource->resource_ops->occ_get) +- nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC, +- resource->resource_ops->occ_get(devlink), +- DEVLINK_ATTR_PAD); +- devlink_resource_size_params_put(resource, skb); ++ if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC, ++ resource->resource_ops->occ_get(devlink), ++ DEVLINK_ATTR_PAD)) ++ goto nla_put_failure; ++ if (devlink_resource_size_params_put(resource, skb)) ++ goto nla_put_failure; + if (list_empty(&resource->resource_list)) + goto out; + +@@ -3151,7 +3156,7 @@ int devlink_resource_register(struct devlink *devlink, + u64 resource_size, + u64 resource_id, + u64 parent_resource_id, +- struct devlink_resource_size_params *size_params, ++ const struct devlink_resource_size_params *size_params, + const struct devlink_resource_ops *resource_ops) + { + struct devlink_resource *resource; +@@ -3194,7 +3199,8 @@ int devlink_resource_register(struct devlink *devlink, + resource->id = resource_id; + resource->resource_ops = resource_ops; + resource->size_valid = true; +- resource->size_params = size_params; ++ memcpy(&resource->size_params, size_params, ++ sizeof(resource->size_params)); + INIT_LIST_HEAD(&resource->resource_list); + list_add_tail(&resource->list, resource_list); + out: +diff --git a/net/core/ethtool.c b/net/core/ethtool.c +index 494e6a5..3f89c76 100644 +--- a/net/core/ethtool.c ++++ b/net/core/ethtool.c +@@ -2520,11 +2520,14 @@ static int set_phy_tunable(struct net_device *dev, void __user *useraddr) + static int ethtool_get_fecparam(struct net_device *dev, void __user *useraddr) + { + struct ethtool_fecparam fecparam = { ETHTOOL_GFECPARAM }; ++ int rc; + + if (!dev->ethtool_ops->get_fecparam) + return -EOPNOTSUPP; + +- dev->ethtool_ops->get_fecparam(dev, &fecparam); ++ rc = dev->ethtool_ops->get_fecparam(dev, &fecparam); ++ if (rc) ++ return rc; + + if (copy_to_user(useraddr, &fecparam, sizeof(fecparam))) + return -EFAULT; +diff --git a/net/core/filter.c b/net/core/filter.c +index 08ab4c6..0c121ad 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -3381,17 +3381,13 @@ BPF_CALL_2(bpf_sock_ops_cb_flags_set, struct bpf_sock_ops_kern *, bpf_sock, + struct sock *sk = bpf_sock->sk; + int val = argval & BPF_SOCK_OPS_ALL_CB_FLAGS; + +- if (!sk_fullsock(sk)) ++ if (!IS_ENABLED(CONFIG_INET) || !sk_fullsock(sk)) + return -EINVAL; + +-#ifdef CONFIG_INET + if (val) + tcp_sk(sk)->bpf_sock_ops_cb_flags = val; + + return argval & (~BPF_SOCK_OPS_ALL_CB_FLAGS); +-#else +- return -EINVAL; +-#endif + } + + static const struct bpf_func_proto bpf_sock_ops_cb_flags_set_proto = { +diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c +index 0a3f88f..98fd127 100644 +--- a/net/core/gen_estimator.c ++++ b/net/core/gen_estimator.c +@@ -66,6 +66,7 @@ struct net_rate_estimator { + static void est_fetch_counters(struct net_rate_estimator *e, + struct gnet_stats_basic_packed *b) + { ++ memset(b, 0, sizeof(*b)); + if (e->stats_lock) + spin_lock(e->stats_lock); + +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 09bd89c..0bb0d88 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -4891,7 +4891,7 @@ EXPORT_SYMBOL_GPL(skb_scrub_packet); + * + * The MAC/L2 or network (IP, IPv6) headers are not accounted for. + */ +-unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) ++static unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) + { + const struct skb_shared_info *shinfo = skb_shinfo(skb); + unsigned int thlen = 0; +@@ -4913,7 +4913,40 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) + */ + return thlen + shinfo->gso_size; + } +-EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); ++ ++/** ++ * skb_gso_network_seglen - Return length of individual segments of a gso packet ++ * ++ * @skb: GSO skb ++ * ++ * skb_gso_network_seglen is used to determine the real size of the ++ * individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP). ++ * ++ * The MAC/L2 header is not accounted for. ++ */ ++static unsigned int skb_gso_network_seglen(const struct sk_buff *skb) ++{ ++ unsigned int hdr_len = skb_transport_header(skb) - ++ skb_network_header(skb); ++ ++ return hdr_len + skb_gso_transport_seglen(skb); ++} ++ ++/** ++ * skb_gso_mac_seglen - Return length of individual segments of a gso packet ++ * ++ * @skb: GSO skb ++ * ++ * skb_gso_mac_seglen is used to determine the real size of the ++ * individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4 ++ * headers (TCP/UDP). ++ */ ++static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb) ++{ ++ unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb); ++ ++ return hdr_len + skb_gso_transport_seglen(skb); ++} + + /** + * skb_gso_size_check - check the skb size, considering GSO_BY_FRAGS +@@ -4955,19 +4988,20 @@ static inline bool skb_gso_size_check(const struct sk_buff *skb, + } + + /** +- * skb_gso_validate_mtu - Return in case such skb fits a given MTU ++ * skb_gso_validate_network_len - Will a split GSO skb fit into a given MTU? + * + * @skb: GSO skb + * @mtu: MTU to validate against + * +- * skb_gso_validate_mtu validates if a given skb will fit a wanted MTU +- * once split. ++ * skb_gso_validate_network_len validates if a given skb will fit a ++ * wanted MTU once split. It considers L3 headers, L4 headers, and the ++ * payload. + */ +-bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu) ++bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu) + { + return skb_gso_size_check(skb, skb_gso_network_seglen(skb), mtu); + } +-EXPORT_SYMBOL_GPL(skb_gso_validate_mtu); ++EXPORT_SYMBOL_GPL(skb_gso_validate_network_len); + + /** + * skb_gso_validate_mac_len - Will a split GSO skb fit in a given length? +diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c +index 91dd09f..791aff6 100644 +--- a/net/decnet/af_decnet.c ++++ b/net/decnet/af_decnet.c +@@ -1338,6 +1338,12 @@ static int dn_setsockopt(struct socket *sock, int level, int optname, char __use + lock_sock(sk); + err = __dn_setsockopt(sock, level, optname, optval, optlen, 0); + release_sock(sk); ++#ifdef CONFIG_NETFILTER ++ /* we need to exclude all possible ENOPROTOOPTs except default case */ ++ if (err == -ENOPROTOOPT && optname != DSO_LINKINFO && ++ optname != DSO_STREAM && optname != DSO_SEQPACKET) ++ err = nf_setsockopt(sk, PF_DECnet, optname, optval, optlen); ++#endif + + return err; + } +@@ -1445,15 +1451,6 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us + dn_nsp_send_disc(sk, 0x38, 0, sk->sk_allocation); + break; + +- default: +-#ifdef CONFIG_NETFILTER +- return nf_setsockopt(sk, PF_DECnet, optname, optval, optlen); +-#endif +- case DSO_LINKINFO: +- case DSO_STREAM: +- case DSO_SEQPACKET: +- return -ENOPROTOOPT; +- + case DSO_MAXWINDOW: + if (optlen != sizeof(unsigned long)) + return -EINVAL; +@@ -1501,6 +1498,12 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us + return -EINVAL; + scp->info_loc = u.info; + break; ++ ++ case DSO_LINKINFO: ++ case DSO_STREAM: ++ case DSO_SEQPACKET: ++ default: ++ return -ENOPROTOOPT; + } + + return 0; +@@ -1514,6 +1517,20 @@ static int dn_getsockopt(struct socket *sock, int level, int optname, char __use + lock_sock(sk); + err = __dn_getsockopt(sock, level, optname, optval, optlen, 0); + release_sock(sk); ++#ifdef CONFIG_NETFILTER ++ if (err == -ENOPROTOOPT && optname != DSO_STREAM && ++ optname != DSO_SEQPACKET && optname != DSO_CONACCEPT && ++ optname != DSO_CONREJECT) { ++ int len; ++ ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ ++ err = nf_getsockopt(sk, PF_DECnet, optname, optval, &len); ++ if (err >= 0) ++ err = put_user(len, optlen); ++ } ++#endif + + return err; + } +@@ -1579,26 +1596,6 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us + r_data = &link; + break; + +- default: +-#ifdef CONFIG_NETFILTER +- { +- int ret, len; +- +- if (get_user(len, optlen)) +- return -EFAULT; +- +- ret = nf_getsockopt(sk, PF_DECnet, optname, optval, &len); +- if (ret >= 0) +- ret = put_user(len, optlen); +- return ret; +- } +-#endif +- case DSO_STREAM: +- case DSO_SEQPACKET: +- case DSO_CONACCEPT: +- case DSO_CONREJECT: +- return -ENOPROTOOPT; +- + case DSO_MAXWINDOW: + if (r_len > sizeof(unsigned long)) + r_len = sizeof(unsigned long); +@@ -1630,6 +1627,13 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us + r_len = sizeof(unsigned char); + r_data = &scp->info_rem; + break; ++ ++ case DSO_STREAM: ++ case DSO_SEQPACKET: ++ case DSO_CONACCEPT: ++ case DSO_CONREJECT: ++ default: ++ return -ENOPROTOOPT; + } + + if (r_data) { +diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c +index c586597..7d36a95 100644 +--- a/net/ipv4/fib_semantics.c ++++ b/net/ipv4/fib_semantics.c +@@ -646,6 +646,11 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi, + fi->fib_nh, cfg, extack)) + return 1; + } ++#ifdef CONFIG_IP_ROUTE_CLASSID ++ if (cfg->fc_flow && ++ cfg->fc_flow != fi->fib_nh->nh_tclassid) ++ return 1; ++#endif + if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) && + (!cfg->fc_gw || cfg->fc_gw == fi->fib_nh->nh_gw)) + return 0; +diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c +index 2dd21c3..b54b948 100644 +--- a/net/ipv4/ip_forward.c ++++ b/net/ipv4/ip_forward.c +@@ -55,7 +55,7 @@ static bool ip_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) + if (skb->ignore_df) + return false; + +- if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) + return false; + + return true; +diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c +index 45d97e9..0901de4 100644 +--- a/net/ipv4/ip_gre.c ++++ b/net/ipv4/ip_gre.c +@@ -970,9 +970,6 @@ static void __gre_tunnel_init(struct net_device *dev) + + t_hlen = tunnel->hlen + sizeof(struct iphdr); + +- dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; +- dev->mtu = ETH_DATA_LEN - t_hlen - 4; +- + dev->features |= GRE_FEATURES; + dev->hw_features |= GRE_FEATURES; + +@@ -1290,8 +1287,6 @@ static int erspan_tunnel_init(struct net_device *dev) + erspan_hdr_len(tunnel->erspan_ver); + t_hlen = tunnel->hlen + sizeof(struct iphdr); + +- dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; +- dev->mtu = ETH_DATA_LEN - t_hlen - 4; + dev->features |= GRE_FEATURES; + dev->hw_features |= GRE_FEATURES; + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +index e8e675b..66340ab 100644 +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -248,7 +248,7 @@ static int ip_finish_output_gso(struct net *net, struct sock *sk, + + /* common case: seglen is <= mtu + */ +- if (skb_gso_validate_mtu(skb, mtu)) ++ if (skb_gso_validate_network_len(skb, mtu)) + return ip_finish_output2(net, sk, skb); + + /* Slowpath - GSO segment length exceeds the egress MTU. +diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c +index 008be04..9c41a0c 100644 +--- a/net/ipv4/ip_sockglue.c ++++ b/net/ipv4/ip_sockglue.c +@@ -1567,10 +1567,7 @@ int ip_getsockopt(struct sock *sk, int level, + if (get_user(len, optlen)) + return -EFAULT; + +- lock_sock(sk); +- err = nf_getsockopt(sk, PF_INET, optname, optval, +- &len); +- release_sock(sk); ++ err = nf_getsockopt(sk, PF_INET, optname, optval, &len); + if (err >= 0) + err = put_user(len, optlen); + return err; +@@ -1602,9 +1599,7 @@ int compat_ip_getsockopt(struct sock *sk, int level, int optname, + if (get_user(len, optlen)) + return -EFAULT; + +- lock_sock(sk); + err = compat_nf_getsockopt(sk, PF_INET, optname, optval, &len); +- release_sock(sk); + if (err >= 0) + err = put_user(len, optlen); + return err; +diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c +index d786a84..6d21068 100644 +--- a/net/ipv4/ip_tunnel.c ++++ b/net/ipv4/ip_tunnel.c +@@ -710,16 +710,9 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, + } + } + +- if (tunnel->fwmark) { +- init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, +- tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link, +- tunnel->fwmark); +- } +- else { +- init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, +- tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link, +- skb->mark); +- } ++ init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, ++ tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link, ++ tunnel->fwmark); + + if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0) + goto tx_error; +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 4ffe302..e3e420f 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -252,6 +252,10 @@ unsigned int arpt_do_table(struct sk_buff *skb, + } + if (table_base + v + != arpt_next_entry(e)) { ++ if (unlikely(stackidx >= private->stacksize)) { ++ verdict = NF_DROP; ++ break; ++ } + jumpstack[stackidx++] = e; + } + +diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c +index 9a71f31..e38395a 100644 +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -330,8 +330,13 @@ ipt_do_table(struct sk_buff *skb, + continue; + } + if (table_base + v != ipt_next_entry(e) && +- !(e->ip.flags & IPT_F_GOTO)) ++ !(e->ip.flags & IPT_F_GOTO)) { ++ if (unlikely(stackidx >= private->stacksize)) { ++ verdict = NF_DROP; ++ break; ++ } + jumpstack[stackidx++] = e; ++ } + + e = get_entry(table_base, v); + continue; +diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c +index 3a84a60..8a8ae61 100644 +--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c ++++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c +@@ -107,12 +107,6 @@ clusterip_config_entry_put(struct net *net, struct clusterip_config *c) + + local_bh_disable(); + if (refcount_dec_and_lock(&c->entries, &cn->lock)) { +- list_del_rcu(&c->list); +- spin_unlock(&cn->lock); +- local_bh_enable(); +- +- unregister_netdevice_notifier(&c->notifier); +- + /* In case anyone still accesses the file, the open/close + * functions are also incrementing the refcount on their own, + * so it's safe to remove the entry even if it's in use. */ +@@ -120,6 +114,12 @@ clusterip_config_entry_put(struct net *net, struct clusterip_config *c) + if (cn->procdir) + proc_remove(c->pde); + #endif ++ list_del_rcu(&c->list); ++ spin_unlock(&cn->lock); ++ local_bh_enable(); ++ ++ unregister_netdevice_notifier(&c->notifier); ++ + return; + } + local_bh_enable(); +@@ -154,8 +154,12 @@ clusterip_config_find_get(struct net *net, __be32 clusterip, int entry) + #endif + if (unlikely(!refcount_inc_not_zero(&c->refcount))) + c = NULL; +- else if (entry) +- refcount_inc(&c->entries); ++ else if (entry) { ++ if (unlikely(!refcount_inc_not_zero(&c->entries))) { ++ clusterip_config_put(c); ++ c = NULL; ++ } ++ } + } + rcu_read_unlock_bh(); + +@@ -228,7 +232,6 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i, + c->hash_mode = i->hash_mode; + c->hash_initval = i->hash_initval; + refcount_set(&c->refcount, 1); +- refcount_set(&c->entries, 1); + + spin_lock_bh(&cn->lock); + if (__clusterip_config_find(net, ip)) { +@@ -259,8 +262,10 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i, + + c->notifier.notifier_call = clusterip_netdev_event; + err = register_netdevice_notifier(&c->notifier); +- if (!err) ++ if (!err) { ++ refcount_set(&c->entries, 1); + return c; ++ } + + #ifdef CONFIG_PROC_FS + proc_remove(c->pde); +@@ -269,7 +274,7 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i, + spin_lock_bh(&cn->lock); + list_del_rcu(&c->list); + spin_unlock_bh(&cn->lock); +- kfree(c); ++ clusterip_config_put(c); + + return ERR_PTR(err); + } +@@ -492,12 +497,15 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) + return PTR_ERR(config); + } + } +- cipinfo->config = config; + + ret = nf_ct_netns_get(par->net, par->family); +- if (ret < 0) ++ if (ret < 0) { + pr_info("cannot load conntrack support for proto=%u\n", + par->family); ++ clusterip_config_entry_put(par->net, config); ++ clusterip_config_put(config); ++ return ret; ++ } + + if (!par->net->xt.clusterip_deprecated_warning) { + pr_info("ipt_CLUSTERIP is deprecated and it will removed soon, " +@@ -505,6 +513,7 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) + par->net->xt.clusterip_deprecated_warning = true; + } + ++ cipinfo->config = config; + return ret; + } + +diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c +index 2707652..aaaf9a8 100644 +--- a/net/ipv4/netfilter/ipt_ECN.c ++++ b/net/ipv4/netfilter/ipt_ECN.c +@@ -98,17 +98,15 @@ static int ecn_tg_check(const struct xt_tgchk_param *par) + const struct ipt_ECN_info *einfo = par->targinfo; + const struct ipt_entry *e = par->entryinfo; + +- if (einfo->operation & IPT_ECN_OP_MASK) { +- pr_info("unsupported ECN operation %x\n", einfo->operation); ++ if (einfo->operation & IPT_ECN_OP_MASK) + return -EINVAL; +- } +- if (einfo->ip_ect & ~IPT_ECN_IP_MASK) { +- pr_info("new ECT codepoint %x out of mask\n", einfo->ip_ect); ++ ++ if (einfo->ip_ect & ~IPT_ECN_IP_MASK) + return -EINVAL; +- } ++ + if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)) && + (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & XT_INV_PROTO))) { +- pr_info("cannot use TCP operations on a non-tcp rule\n"); ++ pr_info_ratelimited("cannot use operation on non-tcp rule\n"); + return -EINVAL; + } + return 0; +diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c +index 8bd0d7b..e8bed33 100644 +--- a/net/ipv4/netfilter/ipt_REJECT.c ++++ b/net/ipv4/netfilter/ipt_REJECT.c +@@ -74,13 +74,13 @@ static int reject_tg_check(const struct xt_tgchk_param *par) + const struct ipt_entry *e = par->entryinfo; + + if (rejinfo->with == IPT_ICMP_ECHOREPLY) { +- pr_info("ECHOREPLY no longer supported.\n"); ++ pr_info_ratelimited("ECHOREPLY no longer supported.\n"); + return -EINVAL; + } else if (rejinfo->with == IPT_TCP_RESET) { + /* Must specify that it's a TCP packet */ + if (e->ip.proto != IPPROTO_TCP || + (e->ip.invflags & XT_INV_PROTO)) { +- pr_info("TCP_RESET invalid for non-tcp\n"); ++ pr_info_ratelimited("TCP_RESET invalid for non-tcp\n"); + return -EINVAL; + } + } +diff --git a/net/ipv4/netfilter/ipt_rpfilter.c b/net/ipv4/netfilter/ipt_rpfilter.c +index 37fb955..fd01f13 100644 +--- a/net/ipv4/netfilter/ipt_rpfilter.c ++++ b/net/ipv4/netfilter/ipt_rpfilter.c +@@ -105,14 +105,14 @@ static int rpfilter_check(const struct xt_mtchk_param *par) + const struct xt_rpfilter_info *info = par->matchinfo; + unsigned int options = ~XT_RPFILTER_OPTION_MASK; + if (info->flags & options) { +- pr_info("unknown options encountered"); ++ pr_info_ratelimited("unknown options\n"); + return -EINVAL; + } + + if (strcmp(par->table, "mangle") != 0 && + strcmp(par->table, "raw") != 0) { +- pr_info("match only valid in the \'raw\' " +- "or \'mangle\' tables, not \'%s\'.\n", par->table); ++ pr_info_ratelimited("only valid in \'raw\' or \'mangle\' table, not \'%s\'\n", ++ par->table); + return -EINVAL; + } + +diff --git a/net/ipv4/netfilter/nf_flow_table_ipv4.c b/net/ipv4/netfilter/nf_flow_table_ipv4.c +index 25d2975..0cd46bf 100644 +--- a/net/ipv4/netfilter/nf_flow_table_ipv4.c ++++ b/net/ipv4/netfilter/nf_flow_table_ipv4.c +@@ -111,6 +111,7 @@ static int nf_flow_dnat_ip(const struct flow_offload *flow, struct sk_buff *skb, + default: + return -1; + } ++ csum_replace4(&iph->check, addr, new_addr); + + return nf_flow_nat_ip_l4proto(skb, iph, thoff, addr, new_addr); + } +@@ -185,7 +186,7 @@ static bool __nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) + if ((ip_hdr(skb)->frag_off & htons(IP_DF)) == 0) + return false; + +- if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) + return false; + + return true; +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index 49cc1c1..860b3fd 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -128,10 +128,11 @@ static int ip_rt_redirect_silence __read_mostly = ((HZ / 50) << (9 + 1)); + static int ip_rt_error_cost __read_mostly = HZ; + static int ip_rt_error_burst __read_mostly = 5 * HZ; + static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ; +-static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; ++static u32 ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; + static int ip_rt_min_advmss __read_mostly = 256; + + static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT; ++ + /* + * Interface to generic destination cache. + */ +@@ -930,14 +931,23 @@ void ip_rt_send_redirect(struct sk_buff *skb) + + static int ip_error(struct sk_buff *skb) + { +- struct in_device *in_dev = __in_dev_get_rcu(skb->dev); + struct rtable *rt = skb_rtable(skb); ++ struct net_device *dev = skb->dev; ++ struct in_device *in_dev; + struct inet_peer *peer; + unsigned long now; + struct net *net; + bool send; + int code; + ++ if (netif_is_l3_master(skb->dev)) { ++ dev = __dev_get_by_index(dev_net(skb->dev), IPCB(skb)->iif); ++ if (!dev) ++ goto out; ++ } ++ ++ in_dev = __in_dev_get_rcu(dev); ++ + /* IP on this device is disabled. */ + if (!in_dev) + goto out; +@@ -1826,6 +1836,8 @@ int fib_multipath_hash(const struct fib_info *fi, const struct flowi4 *fl4, + return skb_get_hash_raw(skb) >> 1; + memset(&hash_keys, 0, sizeof(hash_keys)); + skb_flow_dissect_flow_keys(skb, &keys, flag); ++ ++ hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; + hash_keys.addrs.v4addrs.src = keys.addrs.v4addrs.src; + hash_keys.addrs.v4addrs.dst = keys.addrs.v4addrs.dst; + hash_keys.ports.src = keys.ports.src; +@@ -2816,6 +2828,7 @@ void ip_rt_multicast_event(struct in_device *in_dev) + static int ip_rt_gc_interval __read_mostly = 60 * HZ; + static int ip_rt_gc_min_interval __read_mostly = HZ / 2; + static int ip_rt_gc_elasticity __read_mostly = 8; ++static int ip_min_valid_pmtu __read_mostly = IPV4_MIN_MTU; + + static int ipv4_sysctl_rtcache_flush(struct ctl_table *__ctl, int write, + void __user *buffer, +@@ -2931,7 +2944,8 @@ static struct ctl_table ipv4_route_table[] = { + .data = &ip_rt_min_pmtu, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = proc_dointvec, ++ .proc_handler = proc_dointvec_minmax, ++ .extra1 = &ip_min_valid_pmtu, + }, + { + .procname = "min_adv_mss", +diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c +index 7c84357..faddf4f 100644 +--- a/net/ipv4/tcp_illinois.c ++++ b/net/ipv4/tcp_illinois.c +@@ -6,7 +6,7 @@ + * The algorithm is described in: + * "TCP-Illinois: A Loss and Delay-Based Congestion Control Algorithm + * for High-Speed Networks" +- * http://www.ifp.illinois.edu/~srikant/Papers/liubassri06perf.pdf ++ * http://tamerbasar.csl.illinois.edu/LiuBasarSrikantPerfEvalArtJun2008.pdf + * + * Implemented from description in paper and ns-2 simulation. + * Copyright (C) 2007 Stephen Hemminger +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 575d3c1..9a1b3c1 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1971,11 +1971,6 @@ void tcp_enter_loss(struct sock *sk) + /* F-RTO RFC5682 sec 3.1 step 1: retransmit SND.UNA if no previous + * loss recovery is underway except recurring timeout(s) on + * the same SND.UNA (sec 3.2). Disable F-RTO on path MTU probing +- * +- * In theory F-RTO can be used repeatedly during loss recovery. +- * In practice this interacts badly with broken middle-boxes that +- * falsely raise the receive window, which results in repeated +- * timeouts and stop-and-go behavior. + */ + tp->frto = net->ipv4.sysctl_tcp_frto && + (new_recovery || icsk->icsk_retransmits) && +@@ -2631,18 +2626,14 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack, + tcp_try_undo_loss(sk, false)) + return; + +- /* The ACK (s)acks some never-retransmitted data meaning not all +- * the data packets before the timeout were lost. Therefore we +- * undo the congestion window and state. This is essentially +- * the operation in F-RTO (RFC5682 section 3.1 step 3.b). Since +- * a retransmitted skb is permantly marked, we can apply such an +- * operation even if F-RTO was not used. +- */ +- if ((flag & FLAG_ORIG_SACK_ACKED) && +- tcp_try_undo_loss(sk, tp->undo_marker)) +- return; +- + if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */ ++ /* Step 3.b. A timeout is spurious if not all data are ++ * lost, i.e., never-retransmitted data are (s)acked. ++ */ ++ if ((flag & FLAG_ORIG_SACK_ACKED) && ++ tcp_try_undo_loss(sk, true)) ++ return; ++ + if (after(tp->snd_nxt, tp->high_seq)) { + if (flag & FLAG_DATA_SACKED || is_dupack) + tp->frto = 0; /* Step 3.a. loss was real */ +@@ -4001,6 +3992,7 @@ void tcp_reset(struct sock *sk) + /* This barrier is coupled with smp_rmb() in tcp_poll() */ + smp_wmb(); + ++ tcp_write_queue_purge(sk); + tcp_done(sk); + + if (!sock_flag(sk, SOCK_DEAD)) +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index e9f985e..6818042 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1730,7 +1730,7 @@ u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now, + */ + segs = max_t(u32, bytes / mss_now, min_tso_segs); + +- return min_t(u32, segs, sk->sk_gso_max_segs); ++ return segs; + } + EXPORT_SYMBOL(tcp_tso_autosize); + +@@ -1742,9 +1742,10 @@ static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now) + const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; + u32 tso_segs = ca_ops->tso_segs_goal ? ca_ops->tso_segs_goal(sk) : 0; + +- return tso_segs ? : +- tcp_tso_autosize(sk, mss_now, +- sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs); ++ if (!tso_segs) ++ tso_segs = tcp_tso_autosize(sk, mss_now, ++ sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs); ++ return min_t(u32, tso_segs, sk->sk_gso_max_segs); + } + + /* Returns the portion of skb which can be sent right away */ +@@ -2027,6 +2028,24 @@ static inline void tcp_mtu_check_reprobe(struct sock *sk) + } + } + ++static bool tcp_can_coalesce_send_queue_head(struct sock *sk, int len) ++{ ++ struct sk_buff *skb, *next; ++ ++ skb = tcp_send_head(sk); ++ tcp_for_write_queue_from_safe(skb, next, sk) { ++ if (len <= skb->len) ++ break; ++ ++ if (unlikely(TCP_SKB_CB(skb)->eor)) ++ return false; ++ ++ len -= skb->len; ++ } ++ ++ return true; ++} ++ + /* Create a new MTU probe if we are ready. + * MTU probe is regularly attempting to increase the path MTU by + * deliberately sending larger packets. This discovers routing +@@ -2099,6 +2118,9 @@ static int tcp_mtu_probe(struct sock *sk) + return 0; + } + ++ if (!tcp_can_coalesce_send_queue_head(sk, probe_size)) ++ return -1; ++ + /* We're allowed to probe. Build it now. */ + nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC, false); + if (!nskb) +@@ -2134,6 +2156,10 @@ static int tcp_mtu_probe(struct sock *sk) + /* We've eaten all the data from this skb. + * Throw it away. */ + TCP_SKB_CB(nskb)->tcp_flags |= TCP_SKB_CB(skb)->tcp_flags; ++ /* If this is the last SKB we copy and eor is set ++ * we need to propagate it to the new skb. ++ */ ++ TCP_SKB_CB(nskb)->eor = TCP_SKB_CB(skb)->eor; + tcp_unlink_write_queue(skb, sk); + sk_wmem_free_skb(sk, skb); + } else { +diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c +index bfaefe5..e5ef7c3 100644 +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -2024,6 +2024,11 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, + err = udplite_checksum_init(skb, uh); + if (err) + return err; ++ ++ if (UDP_SKB_CB(skb)->partial_cov) { ++ skb->csum = inet_compute_pseudo(skb, proto); ++ return 0; ++ } + } + + /* Note, we are only interested in != 0 or == 0, thus the +diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c +index 94b8702..be980c1 100644 +--- a/net/ipv4/xfrm4_output.c ++++ b/net/ipv4/xfrm4_output.c +@@ -30,7 +30,8 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb) + + mtu = dst_mtu(skb_dst(skb)); + if ((!skb_is_gso(skb) && skb->len > mtu) || +- (skb_is_gso(skb) && skb_gso_network_seglen(skb) > ip_skb_dst_mtu(skb->sk, skb))) { ++ (skb_is_gso(skb) && ++ !skb_gso_validate_network_len(skb, ip_skb_dst_mtu(skb->sk, skb)))) { + skb->protocol = htons(ETH_P_IP); + + if (skb->sk) +diff --git a/net/ipv6/ip6_checksum.c b/net/ipv6/ip6_checksum.c +index ec43d18..547515e 100644 +--- a/net/ipv6/ip6_checksum.c ++++ b/net/ipv6/ip6_checksum.c +@@ -73,6 +73,11 @@ int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto) + err = udplite_checksum_init(skb, uh); + if (err) + return err; ++ ++ if (UDP_SKB_CB(skb)->partial_cov) { ++ skb->csum = ip6_compute_pseudo(skb, proto); ++ return 0; ++ } + } + + /* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels) +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index 997c7f1..a8a9195 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -412,7 +412,7 @@ static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) + if (skb->ignore_df) + return false; + +- if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) + return false; + + return true; +diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c +index 4b15fe9..6e0f21e 100644 +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -1982,14 +1982,14 @@ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev, + { + struct net *net = dev_net(dev); + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); +- struct ip6_tnl *nt, *t; + struct ip_tunnel_encap ipencap; ++ struct ip6_tnl *nt, *t; ++ int err; + + nt = netdev_priv(dev); + + if (ip6_tnl_netlink_encap_parms(data, &ipencap)) { +- int err = ip6_tnl_encap_setup(nt, &ipencap); +- ++ err = ip6_tnl_encap_setup(nt, &ipencap); + if (err < 0) + return err; + } +@@ -2005,7 +2005,11 @@ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev, + return -EEXIST; + } + +- return ip6_tnl_create2(dev); ++ err = ip6_tnl_create2(dev); ++ if (!err && tb[IFLA_MTU]) ++ ip6_tnl_change_mtu(dev, nla_get_u32(tb[IFLA_MTU])); ++ ++ return err; + } + + static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[], +diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c +index d78d41f..2453516 100644 +--- a/net/ipv6/ipv6_sockglue.c ++++ b/net/ipv6/ipv6_sockglue.c +@@ -1367,10 +1367,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, + if (get_user(len, optlen)) + return -EFAULT; + +- lock_sock(sk); +- err = nf_getsockopt(sk, PF_INET6, optname, optval, +- &len); +- release_sock(sk); ++ err = nf_getsockopt(sk, PF_INET6, optname, optval, &len); + if (err >= 0) + err = put_user(len, optlen); + } +@@ -1409,10 +1406,7 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, + if (get_user(len, optlen)) + return -EFAULT; + +- lock_sock(sk); +- err = compat_nf_getsockopt(sk, PF_INET6, +- optname, optval, &len); +- release_sock(sk); ++ err = compat_nf_getsockopt(sk, PF_INET6, optname, optval, &len); + if (err >= 0) + err = put_user(len, optlen); + } +diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c +index d95ceca..531d695 100644 +--- a/net/ipv6/netfilter.c ++++ b/net/ipv6/netfilter.c +@@ -21,18 +21,19 @@ + int ip6_route_me_harder(struct net *net, struct sk_buff *skb) + { + const struct ipv6hdr *iph = ipv6_hdr(skb); ++ struct sock *sk = sk_to_full_sk(skb->sk); + unsigned int hh_len; + struct dst_entry *dst; + struct flowi6 fl6 = { +- .flowi6_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0, ++ .flowi6_oif = sk ? sk->sk_bound_dev_if : 0, + .flowi6_mark = skb->mark, +- .flowi6_uid = sock_net_uid(net, skb->sk), ++ .flowi6_uid = sock_net_uid(net, sk), + .daddr = iph->daddr, + .saddr = iph->saddr, + }; + int err; + +- dst = ip6_route_output(net, skb->sk, &fl6); ++ dst = ip6_route_output(net, sk, &fl6); + err = dst->error; + if (err) { + IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); +@@ -50,7 +51,7 @@ int ip6_route_me_harder(struct net *net, struct sk_buff *skb) + if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && + xfrm_decode_session(skb, flowi6_to_flowi(&fl6), AF_INET6) == 0) { + skb_dst_set(skb, NULL); +- dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), skb->sk, 0); ++ dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0); + if (IS_ERR(dst)) + return PTR_ERR(dst); + skb_dst_set(skb, dst); +diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c +index af4c917..62358b9 100644 +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -352,6 +352,10 @@ ip6t_do_table(struct sk_buff *skb, + } + if (table_base + v != ip6t_next_entry(e) && + !(e->ipv6.flags & IP6T_F_GOTO)) { ++ if (unlikely(stackidx >= private->stacksize)) { ++ verdict = NF_DROP; ++ break; ++ } + jumpstack[stackidx++] = e; + } + +diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c +index fa51a20..38dea8f 100644 +--- a/net/ipv6/netfilter/ip6t_REJECT.c ++++ b/net/ipv6/netfilter/ip6t_REJECT.c +@@ -85,14 +85,14 @@ static int reject_tg6_check(const struct xt_tgchk_param *par) + const struct ip6t_entry *e = par->entryinfo; + + if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) { +- pr_info("ECHOREPLY is not supported.\n"); ++ pr_info_ratelimited("ECHOREPLY is not supported\n"); + return -EINVAL; + } else if (rejinfo->with == IP6T_TCP_RESET) { + /* Must specify that it's a TCP packet */ + if (!(e->ipv6.flags & IP6T_F_PROTO) || + e->ipv6.proto != IPPROTO_TCP || + (e->ipv6.invflags & XT_INV_PROTO)) { +- pr_info("TCP_RESET illegal for non-tcp\n"); ++ pr_info_ratelimited("TCP_RESET illegal for non-tcp\n"); + return -EINVAL; + } + } +diff --git a/net/ipv6/netfilter/ip6t_rpfilter.c b/net/ipv6/netfilter/ip6t_rpfilter.c +index b12e61b..91ed25a 100644 +--- a/net/ipv6/netfilter/ip6t_rpfilter.c ++++ b/net/ipv6/netfilter/ip6t_rpfilter.c +@@ -48,10 +48,6 @@ static bool rpfilter_lookup_reverse6(struct net *net, const struct sk_buff *skb, + } + + fl6.flowi6_mark = flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0; +- if ((flags & XT_RPFILTER_LOOSE) == 0) { +- fl6.flowi6_oif = dev->ifindex; +- lookup_flags |= RT6_LOOKUP_F_IFACE; +- } + + rt = (void *) ip6_route_lookup(net, &fl6, lookup_flags); + if (rt->dst.error) +@@ -103,14 +99,14 @@ static int rpfilter_check(const struct xt_mtchk_param *par) + unsigned int options = ~XT_RPFILTER_OPTION_MASK; + + if (info->flags & options) { +- pr_info("unknown options encountered"); ++ pr_info_ratelimited("unknown options\n"); + return -EINVAL; + } + + if (strcmp(par->table, "mangle") != 0 && + strcmp(par->table, "raw") != 0) { +- pr_info("match only valid in the \'raw\' " +- "or \'mangle\' tables, not \'%s\'.\n", par->table); ++ pr_info_ratelimited("only valid in \'raw\' or \'mangle\' table, not \'%s\'\n", ++ par->table); + return -EINVAL; + } + +diff --git a/net/ipv6/netfilter/ip6t_srh.c b/net/ipv6/netfilter/ip6t_srh.c +index 9642164..33719d5 100644 +--- a/net/ipv6/netfilter/ip6t_srh.c ++++ b/net/ipv6/netfilter/ip6t_srh.c +@@ -122,12 +122,14 @@ static int srh_mt6_check(const struct xt_mtchk_param *par) + const struct ip6t_srh *srhinfo = par->matchinfo; + + if (srhinfo->mt_flags & ~IP6T_SRH_MASK) { +- pr_err("unknown srh match flags %X\n", srhinfo->mt_flags); ++ pr_info_ratelimited("unknown srh match flags %X\n", ++ srhinfo->mt_flags); + return -EINVAL; + } + + if (srhinfo->mt_invflags & ~IP6T_SRH_INV_MASK) { +- pr_err("unknown srh invflags %X\n", srhinfo->mt_invflags); ++ pr_info_ratelimited("unknown srh invflags %X\n", ++ srhinfo->mt_invflags); + return -EINVAL; + } + +diff --git a/net/ipv6/netfilter/nf_flow_table_ipv6.c b/net/ipv6/netfilter/nf_flow_table_ipv6.c +index d346705..207cb35 100644 +--- a/net/ipv6/netfilter/nf_flow_table_ipv6.c ++++ b/net/ipv6/netfilter/nf_flow_table_ipv6.c +@@ -178,7 +178,7 @@ static bool __nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) + if (skb->len <= mtu) + return false; + +- if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) + return false; + + return true; +diff --git a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c +index bed57ee..6b7f075 100644 +--- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c ++++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c +@@ -99,6 +99,10 @@ static bool nf_nat_ipv6_manip_pkt(struct sk_buff *skb, + !l4proto->manip_pkt(skb, &nf_nat_l3proto_ipv6, iphdroff, hdroff, + target, maniptype)) + return false; ++ ++ /* must reload, offset might have changed */ ++ ipv6h = (void *)skb->data + iphdroff; ++ + manip_addr: + if (maniptype == NF_NAT_MANIP_SRC) + ipv6h->saddr = target->src.u3.in6; +diff --git a/net/ipv6/netfilter/nft_fib_ipv6.c b/net/ipv6/netfilter/nft_fib_ipv6.c +index cc5174c..62fc84d 100644 +--- a/net/ipv6/netfilter/nft_fib_ipv6.c ++++ b/net/ipv6/netfilter/nft_fib_ipv6.c +@@ -180,7 +180,6 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs, + } + + *dest = 0; +- again: + rt = (void *)ip6_route_lookup(nft_net(pkt), &fl6, lookup_flags); + if (rt->dst.error) + goto put_rt_err; +@@ -189,15 +188,8 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs, + if (rt->rt6i_flags & (RTF_REJECT | RTF_ANYCAST | RTF_LOCAL)) + goto put_rt_err; + +- if (oif && oif != rt->rt6i_idev->dev) { +- /* multipath route? Try again with F_IFACE */ +- if ((lookup_flags & RT6_LOOKUP_F_IFACE) == 0) { +- lookup_flags |= RT6_LOOKUP_F_IFACE; +- fl6.flowi6_oif = oif->ifindex; +- ip6_rt_put(rt); +- goto again; +- } +- } ++ if (oif && oif != rt->rt6i_idev->dev) ++ goto put_rt_err; + + switch (priv->result) { + case NFT_FIB_RESULT_OIF: +diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c +index 3873d38..0195598 100644 +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -182,7 +182,7 @@ static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) + #ifdef CONFIG_IPV6_SIT_6RD + struct ip_tunnel *t = netdev_priv(dev); + +- if (t->dev == sitn->fb_tunnel_dev) { ++ if (dev == sitn->fb_tunnel_dev) { + ipv6_addr_set(&t->ip6rd.prefix, htonl(0x20020000), 0, 0, 0); + t->ip6rd.relay_prefix = 0; + t->ip6rd.prefixlen = 16; +@@ -1578,6 +1578,13 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev, + if (err < 0) + return err; + ++ if (tb[IFLA_MTU]) { ++ u32 mtu = nla_get_u32(tb[IFLA_MTU]); ++ ++ if (mtu >= IPV6_MIN_MTU && mtu <= 0xFFF8 - dev->hard_header_len) ++ dev->mtu = mtu; ++ } ++ + #ifdef CONFIG_IPV6_SIT_6RD + if (ipip6_netlink_6rd_parms(data, &ip6rd)) + err = ipip6_tunnel_update_6rd(nt, &ip6rd); +diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c +index 8ae87d4..5959ce9 100644 +--- a/net/ipv6/xfrm6_output.c ++++ b/net/ipv6/xfrm6_output.c +@@ -82,7 +82,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb) + + if ((!skb_is_gso(skb) && skb->len > mtu) || + (skb_is_gso(skb) && +- skb_gso_network_seglen(skb) > ip6_skb_dst_mtu(skb))) { ++ !skb_gso_validate_network_len(skb, ip6_skb_dst_mtu(skb)))) { + skb->dev = dst->dev; + skb->protocol = htons(ETH_P_IPV6); + +diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c +index 194a748..83421c6 100644 +--- a/net/l2tp/l2tp_core.c ++++ b/net/l2tp/l2tp_core.c +@@ -136,51 +136,6 @@ l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id) + + } + +-/* Lookup the tunnel socket, possibly involving the fs code if the socket is +- * owned by userspace. A struct sock returned from this function must be +- * released using l2tp_tunnel_sock_put once you're done with it. +- */ +-static struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel) +-{ +- int err = 0; +- struct socket *sock = NULL; +- struct sock *sk = NULL; +- +- if (!tunnel) +- goto out; +- +- if (tunnel->fd >= 0) { +- /* Socket is owned by userspace, who might be in the process +- * of closing it. Look the socket up using the fd to ensure +- * consistency. +- */ +- sock = sockfd_lookup(tunnel->fd, &err); +- if (sock) +- sk = sock->sk; +- } else { +- /* Socket is owned by kernelspace */ +- sk = tunnel->sock; +- sock_hold(sk); +- } +- +-out: +- return sk; +-} +- +-/* Drop a reference to a tunnel socket obtained via. l2tp_tunnel_sock_put */ +-static void l2tp_tunnel_sock_put(struct sock *sk) +-{ +- struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); +- if (tunnel) { +- if (tunnel->fd >= 0) { +- /* Socket is owned by userspace */ +- sockfd_put(sk->sk_socket); +- } +- sock_put(sk); +- } +- sock_put(sk); +-} +- + /* Session hash list. + * The session_id SHOULD be random according to RFC2661, but several + * L2TP implementations (Cisco and Microsoft) use incrementing +@@ -193,6 +148,13 @@ l2tp_session_id_hash(struct l2tp_tunnel *tunnel, u32 session_id) + return &tunnel->session_hlist[hash_32(session_id, L2TP_HASH_BITS)]; + } + ++void l2tp_tunnel_free(struct l2tp_tunnel *tunnel) ++{ ++ sock_put(tunnel->sock); ++ /* the tunnel is freed in the socket destructor */ ++} ++EXPORT_SYMBOL(l2tp_tunnel_free); ++ + /* Lookup a tunnel. A new reference is held on the returned tunnel. */ + struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id) + { +@@ -345,13 +307,11 @@ int l2tp_session_register(struct l2tp_session *session, + } + + l2tp_tunnel_inc_refcount(tunnel); +- sock_hold(tunnel->sock); + hlist_add_head_rcu(&session->global_hlist, g_head); + + spin_unlock_bh(&pn->l2tp_session_hlist_lock); + } else { + l2tp_tunnel_inc_refcount(tunnel); +- sock_hold(tunnel->sock); + } + + hlist_add_head(&session->hlist, head); +@@ -969,7 +929,7 @@ int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) + { + struct l2tp_tunnel *tunnel; + +- tunnel = l2tp_sock_to_tunnel(sk); ++ tunnel = l2tp_tunnel(sk); + if (tunnel == NULL) + goto pass_up; + +@@ -977,13 +937,10 @@ int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) + tunnel->name, skb->len); + + if (l2tp_udp_recv_core(tunnel, skb, tunnel->recv_payload_hook)) +- goto pass_up_put; ++ goto pass_up; + +- sock_put(sk); + return 0; + +-pass_up_put: +- sock_put(sk); + pass_up: + return 1; + } +@@ -1207,14 +1164,12 @@ EXPORT_SYMBOL_GPL(l2tp_xmit_skb); + static void l2tp_tunnel_destruct(struct sock *sk) + { + struct l2tp_tunnel *tunnel = l2tp_tunnel(sk); +- struct l2tp_net *pn; + + if (tunnel == NULL) + goto end; + + l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: closing...\n", tunnel->name); + +- + /* Disable udp encapsulation */ + switch (tunnel->encap) { + case L2TP_ENCAPTYPE_UDP: +@@ -1231,18 +1186,11 @@ static void l2tp_tunnel_destruct(struct sock *sk) + sk->sk_destruct = tunnel->old_sk_destruct; + sk->sk_user_data = NULL; + +- /* Remove the tunnel struct from the tunnel list */ +- pn = l2tp_pernet(tunnel->l2tp_net); +- spin_lock_bh(&pn->l2tp_tunnel_list_lock); +- list_del_rcu(&tunnel->list); +- spin_unlock_bh(&pn->l2tp_tunnel_list_lock); +- +- tunnel->sock = NULL; +- l2tp_tunnel_dec_refcount(tunnel); +- + /* Call the original destructor */ + if (sk->sk_destruct) + (*sk->sk_destruct)(sk); ++ ++ kfree_rcu(tunnel, rcu); + end: + return; + } +@@ -1303,49 +1251,43 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_closeall); + /* Tunnel socket destroy hook for UDP encapsulation */ + static void l2tp_udp_encap_destroy(struct sock *sk) + { +- struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); +- if (tunnel) { +- l2tp_tunnel_closeall(tunnel); +- sock_put(sk); +- } ++ struct l2tp_tunnel *tunnel = l2tp_tunnel(sk); ++ ++ if (tunnel) ++ l2tp_tunnel_delete(tunnel); + } + + /* Workqueue tunnel deletion function */ + static void l2tp_tunnel_del_work(struct work_struct *work) + { +- struct l2tp_tunnel *tunnel = NULL; +- struct socket *sock = NULL; +- struct sock *sk = NULL; +- +- tunnel = container_of(work, struct l2tp_tunnel, del_work); ++ struct l2tp_tunnel *tunnel = container_of(work, struct l2tp_tunnel, ++ del_work); ++ struct sock *sk = tunnel->sock; ++ struct socket *sock = sk->sk_socket; ++ struct l2tp_net *pn; + + l2tp_tunnel_closeall(tunnel); + +- sk = l2tp_tunnel_sock_lookup(tunnel); +- if (!sk) +- goto out; +- +- sock = sk->sk_socket; +- +- /* If the tunnel socket was created by userspace, then go through the +- * inet layer to shut the socket down, and let userspace close it. +- * Otherwise, if we created the socket directly within the kernel, use ++ /* If the tunnel socket was created within the kernel, use + * the sk API to release it here. +- * In either case the tunnel resources are freed in the socket +- * destructor when the tunnel socket goes away. + */ +- if (tunnel->fd >= 0) { +- if (sock) +- inet_shutdown(sock, 2); +- } else { ++ if (tunnel->fd < 0) { + if (sock) { + kernel_sock_shutdown(sock, SHUT_RDWR); + sock_release(sock); + } + } + +- l2tp_tunnel_sock_put(sk); +-out: ++ /* Remove the tunnel struct from the tunnel list */ ++ pn = l2tp_pernet(tunnel->l2tp_net); ++ spin_lock_bh(&pn->l2tp_tunnel_list_lock); ++ list_del_rcu(&tunnel->list); ++ spin_unlock_bh(&pn->l2tp_tunnel_list_lock); ++ ++ /* drop initial ref */ ++ l2tp_tunnel_dec_refcount(tunnel); ++ ++ /* drop workqueue ref */ + l2tp_tunnel_dec_refcount(tunnel); + } + +@@ -1598,13 +1540,22 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 + sk->sk_user_data = tunnel; + } + ++ /* Bump the reference count. The tunnel context is deleted ++ * only when this drops to zero. A reference is also held on ++ * the tunnel socket to ensure that it is not released while ++ * the tunnel is extant. Must be done before sk_destruct is ++ * set. ++ */ ++ refcount_set(&tunnel->ref_count, 1); ++ sock_hold(sk); ++ tunnel->sock = sk; ++ tunnel->fd = fd; ++ + /* Hook on the tunnel socket destructor so that we can cleanup + * if the tunnel socket goes away. + */ + tunnel->old_sk_destruct = sk->sk_destruct; + sk->sk_destruct = &l2tp_tunnel_destruct; +- tunnel->sock = sk; +- tunnel->fd = fd; + lockdep_set_class_and_name(&sk->sk_lock.slock, &l2tp_socket_class, "l2tp_sock"); + + sk->sk_allocation = GFP_ATOMIC; +@@ -1614,11 +1565,6 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 + + /* Add tunnel to our list */ + INIT_LIST_HEAD(&tunnel->list); +- +- /* Bump the reference count. The tunnel context is deleted +- * only when this drops to zero. Must be done before list insertion +- */ +- refcount_set(&tunnel->ref_count, 1); + spin_lock_bh(&pn->l2tp_tunnel_list_lock); + list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list); + spin_unlock_bh(&pn->l2tp_tunnel_list_lock); +@@ -1659,8 +1605,6 @@ void l2tp_session_free(struct l2tp_session *session) + + if (tunnel) { + BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC); +- sock_put(tunnel->sock); +- session->tunnel = NULL; + l2tp_tunnel_dec_refcount(tunnel); + } + +diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h +index 9bbee90..a1aa955 100644 +--- a/net/l2tp/l2tp_core.h ++++ b/net/l2tp/l2tp_core.h +@@ -214,27 +214,8 @@ static inline void *l2tp_session_priv(struct l2tp_session *session) + return &session->priv[0]; + } + +-static inline struct l2tp_tunnel *l2tp_sock_to_tunnel(struct sock *sk) +-{ +- struct l2tp_tunnel *tunnel; +- +- if (sk == NULL) +- return NULL; +- +- sock_hold(sk); +- tunnel = (struct l2tp_tunnel *)(sk->sk_user_data); +- if (tunnel == NULL) { +- sock_put(sk); +- goto out; +- } +- +- BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC); +- +-out: +- return tunnel; +-} +- + struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id); ++void l2tp_tunnel_free(struct l2tp_tunnel *tunnel); + + struct l2tp_session *l2tp_session_get(const struct net *net, + struct l2tp_tunnel *tunnel, +@@ -283,7 +264,7 @@ static inline void l2tp_tunnel_inc_refcount(struct l2tp_tunnel *tunnel) + static inline void l2tp_tunnel_dec_refcount(struct l2tp_tunnel *tunnel) + { + if (refcount_dec_and_test(&tunnel->ref_count)) +- kfree_rcu(tunnel, rcu); ++ l2tp_tunnel_free(tunnel); + } + + /* Session reference counts. Incremented when code obtains a reference +diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c +index ff61124..3428fba 100644 +--- a/net/l2tp/l2tp_ip.c ++++ b/net/l2tp/l2tp_ip.c +@@ -234,17 +234,13 @@ static void l2tp_ip_close(struct sock *sk, long timeout) + static void l2tp_ip_destroy_sock(struct sock *sk) + { + struct sk_buff *skb; +- struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); ++ struct l2tp_tunnel *tunnel = sk->sk_user_data; + + while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) + kfree_skb(skb); + +- if (tunnel) { +- l2tp_tunnel_closeall(tunnel); +- sock_put(sk); +- } +- +- sk_refcnt_debug_dec(sk); ++ if (tunnel) ++ l2tp_tunnel_delete(tunnel); + } + + static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) +diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c +index 1923446..6f009ea 100644 +--- a/net/l2tp/l2tp_ip6.c ++++ b/net/l2tp/l2tp_ip6.c +@@ -248,16 +248,14 @@ static void l2tp_ip6_close(struct sock *sk, long timeout) + + static void l2tp_ip6_destroy_sock(struct sock *sk) + { +- struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); ++ struct l2tp_tunnel *tunnel = sk->sk_user_data; + + lock_sock(sk); + ip6_flush_pending_frames(sk); + release_sock(sk); + +- if (tunnel) { +- l2tp_tunnel_closeall(tunnel); +- sock_put(sk); +- } ++ if (tunnel) ++ l2tp_tunnel_delete(tunnel); + + inet6_destroy_sock(sk); + } +diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c +index 59f246d..3b02f24 100644 +--- a/net/l2tp/l2tp_ppp.c ++++ b/net/l2tp/l2tp_ppp.c +@@ -416,20 +416,28 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) + * Session (and tunnel control) socket create/destroy. + *****************************************************************************/ + ++static void pppol2tp_put_sk(struct rcu_head *head) ++{ ++ struct pppol2tp_session *ps; ++ ++ ps = container_of(head, typeof(*ps), rcu); ++ sock_put(ps->__sk); ++} ++ + /* Called by l2tp_core when a session socket is being closed. + */ + static void pppol2tp_session_close(struct l2tp_session *session) + { +- struct sock *sk; +- +- BUG_ON(session->magic != L2TP_SESSION_MAGIC); ++ struct pppol2tp_session *ps; + +- sk = pppol2tp_session_get_sock(session); +- if (sk) { +- if (sk->sk_socket) +- inet_shutdown(sk->sk_socket, SEND_SHUTDOWN); +- sock_put(sk); +- } ++ ps = l2tp_session_priv(session); ++ mutex_lock(&ps->sk_lock); ++ ps->__sk = rcu_dereference_protected(ps->sk, ++ lockdep_is_held(&ps->sk_lock)); ++ RCU_INIT_POINTER(ps->sk, NULL); ++ if (ps->__sk) ++ call_rcu(&ps->rcu, pppol2tp_put_sk); ++ mutex_unlock(&ps->sk_lock); + } + + /* Really kill the session socket. (Called from sock_put() if +@@ -449,14 +457,6 @@ static void pppol2tp_session_destruct(struct sock *sk) + } + } + +-static void pppol2tp_put_sk(struct rcu_head *head) +-{ +- struct pppol2tp_session *ps; +- +- ps = container_of(head, typeof(*ps), rcu); +- sock_put(ps->__sk); +-} +- + /* Called when the PPPoX socket (session) is closed. + */ + static int pppol2tp_release(struct socket *sock) +@@ -480,26 +480,17 @@ static int pppol2tp_release(struct socket *sock) + sock_orphan(sk); + sock->sk = NULL; + ++ /* If the socket is associated with a session, ++ * l2tp_session_delete will call pppol2tp_session_close which ++ * will drop the session's ref on the socket. ++ */ + session = pppol2tp_sock_to_session(sk); +- +- if (session != NULL) { +- struct pppol2tp_session *ps; +- ++ if (session) { + l2tp_session_delete(session); +- +- ps = l2tp_session_priv(session); +- mutex_lock(&ps->sk_lock); +- ps->__sk = rcu_dereference_protected(ps->sk, +- lockdep_is_held(&ps->sk_lock)); +- RCU_INIT_POINTER(ps->sk, NULL); +- mutex_unlock(&ps->sk_lock); +- call_rcu(&ps->rcu, pppol2tp_put_sk); +- +- /* Rely on the sock_put() call at the end of the function for +- * dropping the reference held by pppol2tp_sock_to_session(). +- * The last reference will be dropped by pppol2tp_put_sk(). +- */ ++ /* drop the ref obtained by pppol2tp_sock_to_session */ ++ sock_put(sk); + } ++ + release_sock(sk); + + /* This will delete the session context via +@@ -796,6 +787,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, + + out_no_ppp: + /* This is how we get the session context from the socket. */ ++ sock_hold(sk); + sk->sk_user_data = session; + rcu_assign_pointer(ps->sk, sk); + mutex_unlock(&ps->sk_lock); +diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c +index a8b1616..1f3188d 100644 +--- a/net/mac80211/agg-rx.c ++++ b/net/mac80211/agg-rx.c +@@ -8,6 +8,7 @@ + * Copyright 2007, Michael Wu + * Copyright 2007-2010, Intel Corporation + * Copyright(c) 2015-2017 Intel Deutschland GmbH ++ * Copyright (C) 2018 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -304,9 +305,6 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta, + * driver so reject the timeout update. + */ + status = WLAN_STATUS_REQUEST_DECLINED; +- ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, +- tid, dialog_token, status, +- 1, buf_size, timeout); + goto end; + } + +diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c +index 46028e1..f4195a0 100644 +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -2892,7 +2892,7 @@ cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon) + } + if (beacon->probe_resp_len) { + new_beacon->probe_resp_len = beacon->probe_resp_len; +- beacon->probe_resp = pos; ++ new_beacon->probe_resp = pos; + memcpy(pos, beacon->probe_resp, beacon->probe_resp_len); + pos += beacon->probe_resp_len; + } +diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h +index 2690002..ae9c33c 100644 +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1467,7 +1467,7 @@ struct ieee802_11_elems { + const struct ieee80211_timeout_interval_ie *timeout_int; + const u8 *opmode_notif; + const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; +- const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie; ++ struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie; + const struct ieee80211_bss_max_idle_period_ie *max_idle_period_ie; + + /* length of them, respectively */ +diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c +index 73ac607..6a381cb 100644 +--- a/net/mac80211/mesh.c ++++ b/net/mac80211/mesh.c +@@ -1255,13 +1255,12 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, + } + + static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata, +- struct ieee80211_mgmt *mgmt, size_t len) ++ struct ieee80211_mgmt *mgmt, size_t len, ++ struct ieee802_11_elems *elems) + { + struct ieee80211_mgmt *mgmt_fwd; + struct sk_buff *skb; + struct ieee80211_local *local = sdata->local; +- u8 *pos = mgmt->u.action.u.chan_switch.variable; +- size_t offset_ttl; + + skb = dev_alloc_skb(local->tx_headroom + len); + if (!skb) +@@ -1269,13 +1268,9 @@ static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata, + skb_reserve(skb, local->tx_headroom); + mgmt_fwd = skb_put(skb, len); + +- /* offset_ttl is based on whether the secondary channel +- * offset is available or not. Subtract 1 from the mesh TTL +- * and disable the initiator flag before forwarding. +- */ +- offset_ttl = (len < 42) ? 7 : 10; +- *(pos + offset_ttl) -= 1; +- *(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR; ++ elems->mesh_chansw_params_ie->mesh_ttl--; ++ elems->mesh_chansw_params_ie->mesh_flags &= ++ ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR; + + memcpy(mgmt_fwd, mgmt, len); + eth_broadcast_addr(mgmt_fwd->da); +@@ -1323,7 +1318,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata, + + /* forward or re-broadcast the CSA frame */ + if (fwd_csa) { +- if (mesh_fwd_csa_frame(sdata, mgmt, len) < 0) ++ if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0) + mcsa_dbg(sdata, "Failed to forward the CSA frame"); + } + } +diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c +index fd58061..56fe16b 100644 +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -3921,7 +3921,7 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, + if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FROMDS | + IEEE80211_FCTL_TODS)) != + fast_rx->expected_ds_bits) +- goto drop; ++ return false; + + /* assign the key to drop unencrypted frames (later) + * and strip the IV/MIC if necessary +diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c +index ee01817..0293348 100644 +--- a/net/mac80211/spectmgmt.c ++++ b/net/mac80211/spectmgmt.c +@@ -8,6 +8,7 @@ + * Copyright 2007, Michael Wu + * Copyright 2007-2008, Intel Corporation + * Copyright 2008, Johannes Berg ++ * Copyright (C) 2018 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -27,7 +28,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, + u32 sta_flags, u8 *bssid, + struct ieee80211_csa_ie *csa_ie) + { +- enum nl80211_band new_band; ++ enum nl80211_band new_band = current_band; + int new_freq; + u8 new_chan_no; + struct ieee80211_channel *new_chan; +@@ -55,15 +56,13 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, + elems->ext_chansw_ie->new_operating_class, + &new_band)) { + sdata_info(sdata, +- "cannot understand ECSA IE operating class %d, disconnecting\n", ++ "cannot understand ECSA IE operating class, %d, ignoring\n", + elems->ext_chansw_ie->new_operating_class); +- return -EINVAL; + } + new_chan_no = elems->ext_chansw_ie->new_ch_num; + csa_ie->count = elems->ext_chansw_ie->count; + csa_ie->mode = elems->ext_chansw_ie->mode; + } else if (elems->ch_switch_ie) { +- new_band = current_band; + new_chan_no = elems->ch_switch_ie->new_ch_num; + csa_ie->count = elems->ch_switch_ie->count; + csa_ie->mode = elems->ch_switch_ie->mode; +diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c +index 0c5627f..af0b608 100644 +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -314,7 +314,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, + + if (ieee80211_hw_check(hw, USES_RSS)) { + sta->pcpu_rx_stats = +- alloc_percpu(struct ieee80211_sta_rx_stats); ++ alloc_percpu_gfp(struct ieee80211_sta_rx_stats, gfp); + if (!sta->pcpu_rx_stats) + goto free; + } +@@ -433,6 +433,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, + if (sta->sta.txq[0]) + kfree(to_txq_info(sta->sta.txq[0])); + free: ++ free_percpu(sta->pcpu_rx_stats); + #ifdef CONFIG_MAC80211_MESH + kfree(sta->mesh); + #endif +diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c +index 25904af..6972250 100644 +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3574,6 +3574,14 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb, + if (!IS_ERR_OR_NULL(sta)) { + struct ieee80211_fast_tx *fast_tx; + ++ /* We need a bit of data queued to build aggregates properly, so ++ * instruct the TCP stack to allow more than a single ms of data ++ * to be queued in the stack. The value is a bit-shift of 1 ++ * second, so 8 is ~4ms of queued data. Only affects local TCP ++ * sockets. ++ */ ++ sk_pacing_shift_update(skb->sk, 8); ++ + fast_tx = rcu_dereference(sta->fast_tx); + + if (fast_tx && +diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c +index e545a3c..7a4de6d 100644 +--- a/net/mpls/af_mpls.c ++++ b/net/mpls/af_mpls.c +@@ -122,7 +122,7 @@ bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) + if (skb->len <= mtu) + return false; + +- if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) + return false; + + return true; +diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c +index 3e17d32..58d5d05 100644 +--- a/net/netfilter/ipvs/ip_vs_ftp.c ++++ b/net/netfilter/ipvs/ip_vs_ftp.c +@@ -260,7 +260,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, + buf_len = strlen(buf); + + ct = nf_ct_get(skb, &ctinfo); +- if (ct && (ct->status & IPS_NAT_MASK)) { ++ if (ct) { + bool mangled; + + /* If mangling fails this function will return 0 +diff --git a/net/netfilter/nf_nat_proto_common.c b/net/netfilter/nf_nat_proto_common.c +index fbce552..7d7466d 100644 +--- a/net/netfilter/nf_nat_proto_common.c ++++ b/net/netfilter/nf_nat_proto_common.c +@@ -41,7 +41,7 @@ void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto, + const struct nf_conn *ct, + u16 *rover) + { +- unsigned int range_size, min, i; ++ unsigned int range_size, min, max, i; + __be16 *portptr; + u_int16_t off; + +@@ -71,7 +71,10 @@ void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto, + } + } else { + min = ntohs(range->min_proto.all); +- range_size = ntohs(range->max_proto.all) - min + 1; ++ max = ntohs(range->max_proto.all); ++ if (unlikely(max < min)) ++ swap(max, min); ++ range_size = max - min + 1; + } + + if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) { +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 8b9fe30..558593e 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -5037,9 +5037,9 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk, + { + const struct nfgenmsg *nfmsg = nlmsg_data(nlh); + const struct nf_flowtable_type *type; ++ struct nft_flowtable *flowtable, *ft; + u8 genmask = nft_genmask_next(net); + int family = nfmsg->nfgen_family; +- struct nft_flowtable *flowtable; + struct nft_table *table; + struct nft_ctx ctx; + int err, i, k; +@@ -5099,6 +5099,22 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk, + goto err3; + + for (i = 0; i < flowtable->ops_len; i++) { ++ if (!flowtable->ops[i].dev) ++ continue; ++ ++ list_for_each_entry(ft, &table->flowtables, list) { ++ for (k = 0; k < ft->ops_len; k++) { ++ if (!ft->ops[k].dev) ++ continue; ++ ++ if (flowtable->ops[i].dev == ft->ops[k].dev && ++ flowtable->ops[i].pf == ft->ops[k].pf) { ++ err = -EBUSY; ++ goto err4; ++ } ++ } ++ } ++ + err = nf_register_net_hook(net, &flowtable->ops[i]); + if (err < 0) + goto err4; +@@ -5120,7 +5136,7 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk, + i = flowtable->ops_len; + err4: + for (k = i - 1; k >= 0; k--) +- nf_unregister_net_hook(net, &flowtable->ops[i]); ++ nf_unregister_net_hook(net, &flowtable->ops[k]); + + kfree(flowtable->ops); + err3: +@@ -5145,6 +5161,11 @@ static int nf_tables_delflowtable(struct net *net, struct sock *nlsk, + struct nft_table *table; + struct nft_ctx ctx; + ++ if (!nla[NFTA_FLOWTABLE_TABLE] || ++ (!nla[NFTA_FLOWTABLE_NAME] && ++ !nla[NFTA_FLOWTABLE_HANDLE])) ++ return -EINVAL; ++ + table = nf_tables_table_lookup(net, nla[NFTA_FLOWTABLE_TABLE], + family, genmask); + if (IS_ERR(table)) +diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c +index 2f685ee..fa1655a 100644 +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -434,36 +434,35 @@ int xt_check_match(struct xt_mtchk_param *par, + * ebt_among is exempt from centralized matchsize checking + * because it uses a dynamic-size data set. + */ +- pr_err("%s_tables: %s.%u match: invalid size " +- "%u (kernel) != (user) %u\n", +- xt_prefix[par->family], par->match->name, +- par->match->revision, +- XT_ALIGN(par->match->matchsize), size); ++ pr_err_ratelimited("%s_tables: %s.%u match: invalid size %u (kernel) != (user) %u\n", ++ xt_prefix[par->family], par->match->name, ++ par->match->revision, ++ XT_ALIGN(par->match->matchsize), size); + return -EINVAL; + } + if (par->match->table != NULL && + strcmp(par->match->table, par->table) != 0) { +- pr_err("%s_tables: %s match: only valid in %s table, not %s\n", +- xt_prefix[par->family], par->match->name, +- par->match->table, par->table); ++ pr_info_ratelimited("%s_tables: %s match: only valid in %s table, not %s\n", ++ xt_prefix[par->family], par->match->name, ++ par->match->table, par->table); + return -EINVAL; + } + if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) { + char used[64], allow[64]; + +- pr_err("%s_tables: %s match: used from hooks %s, but only " +- "valid from %s\n", +- xt_prefix[par->family], par->match->name, +- textify_hooks(used, sizeof(used), par->hook_mask, +- par->family), +- textify_hooks(allow, sizeof(allow), par->match->hooks, +- par->family)); ++ pr_info_ratelimited("%s_tables: %s match: used from hooks %s, but only valid from %s\n", ++ xt_prefix[par->family], par->match->name, ++ textify_hooks(used, sizeof(used), ++ par->hook_mask, par->family), ++ textify_hooks(allow, sizeof(allow), ++ par->match->hooks, ++ par->family)); + return -EINVAL; + } + if (par->match->proto && (par->match->proto != proto || inv_proto)) { +- pr_err("%s_tables: %s match: only valid for protocol %u\n", +- xt_prefix[par->family], par->match->name, +- par->match->proto); ++ pr_info_ratelimited("%s_tables: %s match: only valid for protocol %u\n", ++ xt_prefix[par->family], par->match->name, ++ par->match->proto); + return -EINVAL; + } + if (par->match->checkentry != NULL) { +@@ -814,36 +813,35 @@ int xt_check_target(struct xt_tgchk_param *par, + int ret; + + if (XT_ALIGN(par->target->targetsize) != size) { +- pr_err("%s_tables: %s.%u target: invalid size " +- "%u (kernel) != (user) %u\n", +- xt_prefix[par->family], par->target->name, +- par->target->revision, +- XT_ALIGN(par->target->targetsize), size); ++ pr_err_ratelimited("%s_tables: %s.%u target: invalid size %u (kernel) != (user) %u\n", ++ xt_prefix[par->family], par->target->name, ++ par->target->revision, ++ XT_ALIGN(par->target->targetsize), size); + return -EINVAL; + } + if (par->target->table != NULL && + strcmp(par->target->table, par->table) != 0) { +- pr_err("%s_tables: %s target: only valid in %s table, not %s\n", +- xt_prefix[par->family], par->target->name, +- par->target->table, par->table); ++ pr_info_ratelimited("%s_tables: %s target: only valid in %s table, not %s\n", ++ xt_prefix[par->family], par->target->name, ++ par->target->table, par->table); + return -EINVAL; + } + if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) { + char used[64], allow[64]; + +- pr_err("%s_tables: %s target: used from hooks %s, but only " +- "usable from %s\n", +- xt_prefix[par->family], par->target->name, +- textify_hooks(used, sizeof(used), par->hook_mask, +- par->family), +- textify_hooks(allow, sizeof(allow), par->target->hooks, +- par->family)); ++ pr_info_ratelimited("%s_tables: %s target: used from hooks %s, but only usable from %s\n", ++ xt_prefix[par->family], par->target->name, ++ textify_hooks(used, sizeof(used), ++ par->hook_mask, par->family), ++ textify_hooks(allow, sizeof(allow), ++ par->target->hooks, ++ par->family)); + return -EINVAL; + } + if (par->target->proto && (par->target->proto != proto || inv_proto)) { +- pr_err("%s_tables: %s target: only valid for protocol %u\n", +- xt_prefix[par->family], par->target->name, +- par->target->proto); ++ pr_info_ratelimited("%s_tables: %s target: only valid for protocol %u\n", ++ xt_prefix[par->family], par->target->name, ++ par->target->proto); + return -EINVAL; + } + if (par->target->checkentry != NULL) { +@@ -1004,10 +1002,6 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size) + if (sz < sizeof(*info)) + return NULL; + +- /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */ +- if ((size >> PAGE_SHIFT) + 2 > totalram_pages) +- return NULL; +- + /* __GFP_NORETRY is not fully supported by kvmalloc but it should + * work reasonably well if sz is too large and bail out rather + * than shoot all processes down before realizing there is nothing +diff --git a/net/netfilter/xt_AUDIT.c b/net/netfilter/xt_AUDIT.c +index c502419..f368ee6 100644 +--- a/net/netfilter/xt_AUDIT.c ++++ b/net/netfilter/xt_AUDIT.c +@@ -120,8 +120,8 @@ static int audit_tg_check(const struct xt_tgchk_param *par) + const struct xt_audit_info *info = par->targinfo; + + if (info->type > XT_AUDIT_TYPE_MAX) { +- pr_info("Audit type out of range (valid range: 0..%hhu)\n", +- XT_AUDIT_TYPE_MAX); ++ pr_info_ratelimited("Audit type out of range (valid range: 0..%hhu)\n", ++ XT_AUDIT_TYPE_MAX); + return -ERANGE; + } + +diff --git a/net/netfilter/xt_CHECKSUM.c b/net/netfilter/xt_CHECKSUM.c +index 0f642ef..9f4151e 100644 +--- a/net/netfilter/xt_CHECKSUM.c ++++ b/net/netfilter/xt_CHECKSUM.c +@@ -36,13 +36,13 @@ static int checksum_tg_check(const struct xt_tgchk_param *par) + const struct xt_CHECKSUM_info *einfo = par->targinfo; + + if (einfo->operation & ~XT_CHECKSUM_OP_FILL) { +- pr_info("unsupported CHECKSUM operation %x\n", einfo->operation); ++ pr_info_ratelimited("unsupported CHECKSUM operation %x\n", ++ einfo->operation); + return -EINVAL; + } +- if (!einfo->operation) { +- pr_info("no CHECKSUM operation enabled\n"); ++ if (!einfo->operation) + return -EINVAL; +- } ++ + return 0; + } + +diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c +index da56c06..f3f1caa 100644 +--- a/net/netfilter/xt_CONNSECMARK.c ++++ b/net/netfilter/xt_CONNSECMARK.c +@@ -91,8 +91,8 @@ static int connsecmark_tg_check(const struct xt_tgchk_param *par) + + if (strcmp(par->table, "mangle") != 0 && + strcmp(par->table, "security") != 0) { +- pr_info("target only valid in the \'mangle\' " +- "or \'security\' tables, not \'%s\'.\n", par->table); ++ pr_info_ratelimited("only valid in \'mangle\' or \'security\' table, not \'%s\'\n", ++ par->table); + return -EINVAL; + } + +@@ -102,14 +102,14 @@ static int connsecmark_tg_check(const struct xt_tgchk_param *par) + break; + + default: +- pr_info("invalid mode: %hu\n", info->mode); ++ pr_info_ratelimited("invalid mode: %hu\n", info->mode); + return -EINVAL; + } + + ret = nf_ct_netns_get(par->net, par->family); + if (ret < 0) +- pr_info("cannot load conntrack support for proto=%u\n", +- par->family); ++ pr_info_ratelimited("cannot load conntrack support for proto=%u\n", ++ par->family); + return ret; + } + +diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c +index 5a152e2..8790190 100644 +--- a/net/netfilter/xt_CT.c ++++ b/net/netfilter/xt_CT.c +@@ -82,15 +82,14 @@ xt_ct_set_helper(struct nf_conn *ct, const char *helper_name, + + proto = xt_ct_find_proto(par); + if (!proto) { +- pr_info("You must specify a L4 protocol, and not use " +- "inversions on it.\n"); ++ pr_info_ratelimited("You must specify a L4 protocol and not use inversions on it\n"); + return -ENOENT; + } + + helper = nf_conntrack_helper_try_module_get(helper_name, par->family, + proto); + if (helper == NULL) { +- pr_info("No such helper \"%s\"\n", helper_name); ++ pr_info_ratelimited("No such helper \"%s\"\n", helper_name); + return -ENOENT; + } + +@@ -124,6 +123,7 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par, + const struct nf_conntrack_l4proto *l4proto; + struct ctnl_timeout *timeout; + struct nf_conn_timeout *timeout_ext; ++ const char *errmsg = NULL; + int ret = 0; + u8 proto; + +@@ -131,29 +131,29 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par, + timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook); + if (timeout_find_get == NULL) { + ret = -ENOENT; +- pr_info("Timeout policy base is empty\n"); ++ errmsg = "Timeout policy base is empty"; + goto out; + } + + proto = xt_ct_find_proto(par); + if (!proto) { + ret = -EINVAL; +- pr_info("You must specify a L4 protocol, and not use " +- "inversions on it.\n"); ++ errmsg = "You must specify a L4 protocol and not use inversions on it"; + goto out; + } + + timeout = timeout_find_get(par->net, timeout_name); + if (timeout == NULL) { + ret = -ENOENT; +- pr_info("No such timeout policy \"%s\"\n", timeout_name); ++ pr_info_ratelimited("No such timeout policy \"%s\"\n", ++ timeout_name); + goto out; + } + + if (timeout->l3num != par->family) { + ret = -EINVAL; +- pr_info("Timeout policy `%s' can only be used by L3 protocol " +- "number %d\n", timeout_name, timeout->l3num); ++ pr_info_ratelimited("Timeout policy `%s' can only be used by L%d protocol number %d\n", ++ timeout_name, 3, timeout->l3num); + goto err_put_timeout; + } + /* Make sure the timeout policy matches any existing protocol tracker, +@@ -162,9 +162,8 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par, + l4proto = __nf_ct_l4proto_find(par->family, proto); + if (timeout->l4proto->l4proto != l4proto->l4proto) { + ret = -EINVAL; +- pr_info("Timeout policy `%s' can only be used by L4 protocol " +- "number %d\n", +- timeout_name, timeout->l4proto->l4proto); ++ pr_info_ratelimited("Timeout policy `%s' can only be used by L%d protocol number %d\n", ++ timeout_name, 4, timeout->l4proto->l4proto); + goto err_put_timeout; + } + timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_ATOMIC); +@@ -180,6 +179,8 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par, + __xt_ct_tg_timeout_put(timeout); + out: + rcu_read_unlock(); ++ if (errmsg) ++ pr_info_ratelimited("%s\n", errmsg); + return ret; + #else + return -EOPNOTSUPP; +diff --git a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c +index 3f83d38..098ed85 100644 +--- a/net/netfilter/xt_DSCP.c ++++ b/net/netfilter/xt_DSCP.c +@@ -66,10 +66,8 @@ static int dscp_tg_check(const struct xt_tgchk_param *par) + { + const struct xt_DSCP_info *info = par->targinfo; + +- if (info->dscp > XT_DSCP_MAX) { +- pr_info("dscp %x out of range\n", info->dscp); ++ if (info->dscp > XT_DSCP_MAX) + return -EDOM; +- } + return 0; + } + +diff --git a/net/netfilter/xt_HL.c b/net/netfilter/xt_HL.c +index 1535e87..4653b07 100644 +--- a/net/netfilter/xt_HL.c ++++ b/net/netfilter/xt_HL.c +@@ -105,10 +105,8 @@ static int ttl_tg_check(const struct xt_tgchk_param *par) + { + const struct ipt_TTL_info *info = par->targinfo; + +- if (info->mode > IPT_TTL_MAXMODE) { +- pr_info("TTL: invalid or unknown mode %u\n", info->mode); ++ if (info->mode > IPT_TTL_MAXMODE) + return -EINVAL; +- } + if (info->mode != IPT_TTL_SET && info->ttl == 0) + return -EINVAL; + return 0; +@@ -118,15 +116,10 @@ static int hl_tg6_check(const struct xt_tgchk_param *par) + { + const struct ip6t_HL_info *info = par->targinfo; + +- if (info->mode > IP6T_HL_MAXMODE) { +- pr_info("invalid or unknown mode %u\n", info->mode); ++ if (info->mode > IP6T_HL_MAXMODE) + return -EINVAL; +- } +- if (info->mode != IP6T_HL_SET && info->hop_limit == 0) { +- pr_info("increment/decrement does not " +- "make sense with value 0\n"); ++ if (info->mode != IP6T_HL_SET && info->hop_limit == 0) + return -EINVAL; +- } + return 0; + } + +diff --git a/net/netfilter/xt_HMARK.c b/net/netfilter/xt_HMARK.c +index 60e6dbe..9c75f41 100644 +--- a/net/netfilter/xt_HMARK.c ++++ b/net/netfilter/xt_HMARK.c +@@ -9,6 +9,8 @@ + * the Free Software Foundation. + */ + ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ + #include + #include + #include +@@ -312,29 +314,30 @@ hmark_tg_v4(struct sk_buff *skb, const struct xt_action_param *par) + static int hmark_tg_check(const struct xt_tgchk_param *par) + { + const struct xt_hmark_info *info = par->targinfo; ++ const char *errmsg = "proto mask must be zero with L3 mode"; + +- if (!info->hmodulus) { +- pr_info("xt_HMARK: hash modulus can't be zero\n"); ++ if (!info->hmodulus) + return -EINVAL; +- } ++ + if (info->proto_mask && +- (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3))) { +- pr_info("xt_HMARK: proto mask must be zero with L3 mode\n"); +- return -EINVAL; +- } ++ (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3))) ++ goto err; ++ + if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI_MASK) && + (info->flags & (XT_HMARK_FLAG(XT_HMARK_SPORT_MASK) | +- XT_HMARK_FLAG(XT_HMARK_DPORT_MASK)))) { +- pr_info("xt_HMARK: spi-mask and port-mask can't be combined\n"); ++ XT_HMARK_FLAG(XT_HMARK_DPORT_MASK)))) + return -EINVAL; +- } ++ + if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI) && + (info->flags & (XT_HMARK_FLAG(XT_HMARK_SPORT) | + XT_HMARK_FLAG(XT_HMARK_DPORT)))) { +- pr_info("xt_HMARK: spi-set and port-set can't be combined\n"); +- return -EINVAL; ++ errmsg = "spi-set and port-set can't be combined"; ++ goto err; + } + return 0; ++err: ++ pr_info_ratelimited("%s\n", errmsg); ++ return -EINVAL; + } + + static struct xt_target hmark_tg_reg[] __read_mostly = { +diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c +index 6c2482b..1ac6600 100644 +--- a/net/netfilter/xt_IDLETIMER.c ++++ b/net/netfilter/xt_IDLETIMER.c +@@ -146,11 +146,11 @@ static int idletimer_tg_create(struct idletimer_tg_info *info) + timer_setup(&info->timer->timer, idletimer_tg_expired, 0); + info->timer->refcnt = 1; + ++ INIT_WORK(&info->timer->work, idletimer_tg_work); ++ + mod_timer(&info->timer->timer, + msecs_to_jiffies(info->timeout * 1000) + jiffies); + +- INIT_WORK(&info->timer->work, idletimer_tg_work); +- + return 0; + + out_free_attr: +@@ -191,7 +191,10 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par) + pr_debug("timeout value is zero\n"); + return -EINVAL; + } +- ++ if (info->timeout >= INT_MAX / 1000) { ++ pr_debug("timeout value is too big\n"); ++ return -EINVAL; ++ } + if (info->label[0] == '\0' || + strnlen(info->label, + MAX_IDLETIMER_LABEL_SIZE) == MAX_IDLETIMER_LABEL_SIZE) { +diff --git a/net/netfilter/xt_LED.c b/net/netfilter/xt_LED.c +index 1dcad89..1984644 100644 +--- a/net/netfilter/xt_LED.c ++++ b/net/netfilter/xt_LED.c +@@ -111,10 +111,8 @@ static int led_tg_check(const struct xt_tgchk_param *par) + struct xt_led_info_internal *ledinternal; + int err; + +- if (ledinfo->id[0] == '\0') { +- pr_info("No 'id' parameter given.\n"); ++ if (ledinfo->id[0] == '\0') + return -EINVAL; +- } + + mutex_lock(&xt_led_mutex); + +@@ -138,13 +136,14 @@ static int led_tg_check(const struct xt_tgchk_param *par) + + err = led_trigger_register(&ledinternal->netfilter_led_trigger); + if (err) { +- pr_err("Trigger name is already in use.\n"); ++ pr_info_ratelimited("Trigger name is already in use.\n"); + goto exit_alloc; + } + +- /* See if we need to set up a timer */ +- if (ledinfo->delay > 0) +- timer_setup(&ledinternal->timer, led_timeout_callback, 0); ++ /* Since the letinternal timer can be shared between multiple targets, ++ * always set it up, even if the current target does not need it ++ */ ++ timer_setup(&ledinternal->timer, led_timeout_callback, 0); + + list_add_tail(&ledinternal->list, &xt_led_triggers); + +@@ -181,8 +180,7 @@ static void led_tg_destroy(const struct xt_tgdtor_param *par) + + list_del(&ledinternal->list); + +- if (ledinfo->delay > 0) +- del_timer_sync(&ledinternal->timer); ++ del_timer_sync(&ledinternal->timer); + + led_trigger_unregister(&ledinternal->netfilter_led_trigger); + +diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c +index a360b99..a9aca80 100644 +--- a/net/netfilter/xt_NFQUEUE.c ++++ b/net/netfilter/xt_NFQUEUE.c +@@ -8,6 +8,8 @@ + * + */ + ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ + #include + #include + +@@ -67,13 +69,13 @@ static int nfqueue_tg_check(const struct xt_tgchk_param *par) + init_hashrandom(&jhash_initval); + + if (info->queues_total == 0) { +- pr_err("NFQUEUE: number of total queues is 0\n"); ++ pr_info_ratelimited("number of total queues is 0\n"); + return -EINVAL; + } + maxid = info->queues_total - 1 + info->queuenum; + if (maxid > 0xffff) { +- pr_err("NFQUEUE: number of queues (%u) out of range (got %u)\n", +- info->queues_total, maxid); ++ pr_info_ratelimited("number of queues (%u) out of range (got %u)\n", ++ info->queues_total, maxid); + return -ERANGE; + } + if (par->target->revision == 2 && info->flags > 1) +diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c +index 9faf5e0..4ad5fe2 100644 +--- a/net/netfilter/xt_SECMARK.c ++++ b/net/netfilter/xt_SECMARK.c +@@ -60,18 +60,20 @@ static int checkentry_lsm(struct xt_secmark_target_info *info) + &info->secid); + if (err) { + if (err == -EINVAL) +- pr_info("invalid security context \'%s\'\n", info->secctx); ++ pr_info_ratelimited("invalid security context \'%s\'\n", ++ info->secctx); + return err; + } + + if (!info->secid) { +- pr_info("unable to map security context \'%s\'\n", info->secctx); ++ pr_info_ratelimited("unable to map security context \'%s\'\n", ++ info->secctx); + return -ENOENT; + } + + err = security_secmark_relabel_packet(info->secid); + if (err) { +- pr_info("unable to obtain relabeling permission\n"); ++ pr_info_ratelimited("unable to obtain relabeling permission\n"); + return err; + } + +@@ -86,14 +88,14 @@ static int secmark_tg_check(const struct xt_tgchk_param *par) + + if (strcmp(par->table, "mangle") != 0 && + strcmp(par->table, "security") != 0) { +- pr_info("target only valid in the \'mangle\' " +- "or \'security\' tables, not \'%s\'.\n", par->table); ++ pr_info_ratelimited("only valid in \'mangle\' or \'security\' table, not \'%s\'\n", ++ par->table); + return -EINVAL; + } + + if (mode && mode != info->mode) { +- pr_info("mode already set to %hu cannot mix with " +- "rules for mode %hu\n", mode, info->mode); ++ pr_info_ratelimited("mode already set to %hu cannot mix with rules for mode %hu\n", ++ mode, info->mode); + return -EINVAL; + } + +@@ -101,7 +103,7 @@ static int secmark_tg_check(const struct xt_tgchk_param *par) + case SECMARK_MODE_SEL: + break; + default: +- pr_info("invalid mode: %hu\n", info->mode); ++ pr_info_ratelimited("invalid mode: %hu\n", info->mode); + return -EINVAL; + } + +diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c +index 99bb8e4..98efb20 100644 +--- a/net/netfilter/xt_TCPMSS.c ++++ b/net/netfilter/xt_TCPMSS.c +@@ -273,8 +273,7 @@ static int tcpmss_tg4_check(const struct xt_tgchk_param *par) + (par->hook_mask & ~((1 << NF_INET_FORWARD) | + (1 << NF_INET_LOCAL_OUT) | + (1 << NF_INET_POST_ROUTING))) != 0) { +- pr_info("path-MTU clamping only supported in " +- "FORWARD, OUTPUT and POSTROUTING hooks\n"); ++ pr_info_ratelimited("path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n"); + return -EINVAL; + } + if (par->nft_compat) +@@ -283,7 +282,7 @@ static int tcpmss_tg4_check(const struct xt_tgchk_param *par) + xt_ematch_foreach(ematch, e) + if (find_syn_match(ematch)) + return 0; +- pr_info("Only works on TCP SYN packets\n"); ++ pr_info_ratelimited("Only works on TCP SYN packets\n"); + return -EINVAL; + } + +@@ -298,8 +297,7 @@ static int tcpmss_tg6_check(const struct xt_tgchk_param *par) + (par->hook_mask & ~((1 << NF_INET_FORWARD) | + (1 << NF_INET_LOCAL_OUT) | + (1 << NF_INET_POST_ROUTING))) != 0) { +- pr_info("path-MTU clamping only supported in " +- "FORWARD, OUTPUT and POSTROUTING hooks\n"); ++ pr_info_ratelimited("path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n"); + return -EINVAL; + } + if (par->nft_compat) +@@ -308,7 +306,7 @@ static int tcpmss_tg6_check(const struct xt_tgchk_param *par) + xt_ematch_foreach(ematch, e) + if (find_syn_match(ematch)) + return 0; +- pr_info("Only works on TCP SYN packets\n"); ++ pr_info_ratelimited("Only works on TCP SYN packets\n"); + return -EINVAL; + } + #endif +diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c +index 17d7705..8c89323 100644 +--- a/net/netfilter/xt_TPROXY.c ++++ b/net/netfilter/xt_TPROXY.c +@@ -540,8 +540,7 @@ static int tproxy_tg6_check(const struct xt_tgchk_param *par) + !(i->invflags & IP6T_INV_PROTO)) + return 0; + +- pr_info("Can be used only in combination with " +- "either -p tcp or -p udp\n"); ++ pr_info_ratelimited("Can be used only with -p tcp or -p udp\n"); + return -EINVAL; + } + #endif +@@ -559,8 +558,7 @@ static int tproxy_tg4_check(const struct xt_tgchk_param *par) + && !(i->invflags & IPT_INV_PROTO)) + return 0; + +- pr_info("Can be used only in combination with " +- "either -p tcp or -p udp\n"); ++ pr_info_ratelimited("Can be used only with -p tcp or -p udp\n"); + return -EINVAL; + } + +diff --git a/net/netfilter/xt_addrtype.c b/net/netfilter/xt_addrtype.c +index 911a7c0..89e281b 100644 +--- a/net/netfilter/xt_addrtype.c ++++ b/net/netfilter/xt_addrtype.c +@@ -164,48 +164,47 @@ addrtype_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) + + static int addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par) + { ++ const char *errmsg = "both incoming and outgoing interface limitation cannot be selected"; + struct xt_addrtype_info_v1 *info = par->matchinfo; + + if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN && +- info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) { +- pr_info("both incoming and outgoing " +- "interface limitation cannot be selected\n"); +- return -EINVAL; +- } ++ info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) ++ goto err; + + if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) | + (1 << NF_INET_LOCAL_IN)) && + info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) { +- pr_info("output interface limitation " +- "not valid in PREROUTING and INPUT\n"); +- return -EINVAL; ++ errmsg = "output interface limitation not valid in PREROUTING and INPUT"; ++ goto err; + } + + if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) | + (1 << NF_INET_LOCAL_OUT)) && + info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) { +- pr_info("input interface limitation " +- "not valid in POSTROUTING and OUTPUT\n"); +- return -EINVAL; ++ errmsg = "input interface limitation not valid in POSTROUTING and OUTPUT"; ++ goto err; + } + + #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) + if (par->family == NFPROTO_IPV6) { + if ((info->source | info->dest) & XT_ADDRTYPE_BLACKHOLE) { +- pr_err("ipv6 BLACKHOLE matching not supported\n"); +- return -EINVAL; ++ errmsg = "ipv6 BLACKHOLE matching not supported"; ++ goto err; + } + if ((info->source | info->dest) >= XT_ADDRTYPE_PROHIBIT) { +- pr_err("ipv6 PROHIBIT (THROW, NAT ..) matching not supported\n"); +- return -EINVAL; ++ errmsg = "ipv6 PROHIBIT (THROW, NAT ..) matching not supported"; ++ goto err; + } + if ((info->source | info->dest) & XT_ADDRTYPE_BROADCAST) { +- pr_err("ipv6 does not support BROADCAST matching\n"); +- return -EINVAL; ++ errmsg = "ipv6 does not support BROADCAST matching"; ++ goto err; + } + } + #endif + return 0; ++err: ++ pr_info_ratelimited("%s\n", errmsg); ++ return -EINVAL; + } + + static struct xt_match addrtype_mt_reg[] __read_mostly = { +diff --git a/net/netfilter/xt_bpf.c b/net/netfilter/xt_bpf.c +index 06b090d..a2cf8a62 100644 +--- a/net/netfilter/xt_bpf.c ++++ b/net/netfilter/xt_bpf.c +@@ -7,6 +7,8 @@ + * published by the Free Software Foundation. + */ + ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ + #include + #include + #include +@@ -34,7 +36,7 @@ static int __bpf_mt_check_bytecode(struct sock_filter *insns, __u16 len, + program.filter = insns; + + if (bpf_prog_create(ret, &program)) { +- pr_info("bpf: check failed: parse error\n"); ++ pr_info_ratelimited("check failed: parse error\n"); + return -EINVAL; + } + +diff --git a/net/netfilter/xt_cgroup.c b/net/netfilter/xt_cgroup.c +index 891f4e7..7df2dec 100644 +--- a/net/netfilter/xt_cgroup.c ++++ b/net/netfilter/xt_cgroup.c +@@ -12,6 +12,8 @@ + * published by the Free Software Foundation. + */ + ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ + #include + #include + #include +@@ -48,7 +50,7 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par) + } + + if (info->has_path && info->has_classid) { +- pr_info("xt_cgroup: both path and classid specified\n"); ++ pr_info_ratelimited("path and classid specified\n"); + return -EINVAL; + } + +@@ -56,8 +58,8 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par) + if (info->has_path) { + cgrp = cgroup_get_from_path(info->path); + if (IS_ERR(cgrp)) { +- pr_info("xt_cgroup: invalid path, errno=%ld\n", +- PTR_ERR(cgrp)); ++ pr_info_ratelimited("invalid path, errno=%ld\n", ++ PTR_ERR(cgrp)); + return -EINVAL; + } + info->priv = cgrp; +diff --git a/net/netfilter/xt_cluster.c b/net/netfilter/xt_cluster.c +index 57ef175..00686889 100644 +--- a/net/netfilter/xt_cluster.c ++++ b/net/netfilter/xt_cluster.c +@@ -135,14 +135,12 @@ static int xt_cluster_mt_checkentry(const struct xt_mtchk_param *par) + struct xt_cluster_match_info *info = par->matchinfo; + + if (info->total_nodes > XT_CLUSTER_NODES_MAX) { +- pr_info("you have exceeded the maximum " +- "number of cluster nodes (%u > %u)\n", +- info->total_nodes, XT_CLUSTER_NODES_MAX); ++ pr_info_ratelimited("you have exceeded the maximum number of cluster nodes (%u > %u)\n", ++ info->total_nodes, XT_CLUSTER_NODES_MAX); + return -EINVAL; + } + if (info->node_mask >= (1ULL << info->total_nodes)) { +- pr_info("this node mask cannot be " +- "higher than the total number of nodes\n"); ++ pr_info_ratelimited("node mask cannot exceed total number of nodes\n"); + return -EDOM; + } + return 0; +diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c +index cad0b7b..93cb018 100644 +--- a/net/netfilter/xt_connbytes.c ++++ b/net/netfilter/xt_connbytes.c +@@ -112,8 +112,8 @@ static int connbytes_mt_check(const struct xt_mtchk_param *par) + + ret = nf_ct_netns_get(par->net, par->family); + if (ret < 0) +- pr_info("cannot load conntrack support for proto=%u\n", +- par->family); ++ pr_info_ratelimited("cannot load conntrack support for proto=%u\n", ++ par->family); + + /* + * This filter cannot function correctly unless connection tracking +diff --git a/net/netfilter/xt_connlabel.c b/net/netfilter/xt_connlabel.c +index 2337287..4fa4efd 100644 +--- a/net/netfilter/xt_connlabel.c ++++ b/net/netfilter/xt_connlabel.c +@@ -57,14 +57,15 @@ static int connlabel_mt_check(const struct xt_mtchk_param *par) + int ret; + + if (info->options & ~options) { +- pr_err("Unknown options in mask %x\n", info->options); ++ pr_info_ratelimited("Unknown options in mask %x\n", ++ info->options); + return -EINVAL; + } + + ret = nf_ct_netns_get(par->net, par->family); + if (ret < 0) { +- pr_info("cannot load conntrack support for proto=%u\n", +- par->family); ++ pr_info_ratelimited("cannot load conntrack support for proto=%u\n", ++ par->family); + return ret; + } + +diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c +index ec377cc..809639c 100644 +--- a/net/netfilter/xt_connmark.c ++++ b/net/netfilter/xt_connmark.c +@@ -79,8 +79,8 @@ static int connmark_tg_check(const struct xt_tgchk_param *par) + + ret = nf_ct_netns_get(par->net, par->family); + if (ret < 0) +- pr_info("cannot load conntrack support for proto=%u\n", +- par->family); ++ pr_info_ratelimited("cannot load conntrack support for proto=%u\n", ++ par->family); + return ret; + } + +@@ -109,8 +109,8 @@ static int connmark_mt_check(const struct xt_mtchk_param *par) + + ret = nf_ct_netns_get(par->net, par->family); + if (ret < 0) +- pr_info("cannot load conntrack support for proto=%u\n", +- par->family); ++ pr_info_ratelimited("cannot load conntrack support for proto=%u\n", ++ par->family); + return ret; + } + +diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c +index 39cf1d0..df80fe7 100644 +--- a/net/netfilter/xt_conntrack.c ++++ b/net/netfilter/xt_conntrack.c +@@ -272,8 +272,8 @@ static int conntrack_mt_check(const struct xt_mtchk_param *par) + + ret = nf_ct_netns_get(par->net, par->family); + if (ret < 0) +- pr_info("cannot load conntrack support for proto=%u\n", +- par->family); ++ pr_info_ratelimited("cannot load conntrack support for proto=%u\n", ++ par->family); + return ret; + } + +diff --git a/net/netfilter/xt_dscp.c b/net/netfilter/xt_dscp.c +index 236ac80..a4c2b86 100644 +--- a/net/netfilter/xt_dscp.c ++++ b/net/netfilter/xt_dscp.c +@@ -46,10 +46,8 @@ static int dscp_mt_check(const struct xt_mtchk_param *par) + { + const struct xt_dscp_info *info = par->matchinfo; + +- if (info->dscp > XT_DSCP_MAX) { +- pr_info("dscp %x out of range\n", info->dscp); ++ if (info->dscp > XT_DSCP_MAX) + return -EDOM; +- } + + return 0; + } +diff --git a/net/netfilter/xt_ecn.c b/net/netfilter/xt_ecn.c +index 3c831a8..c7ad4af 100644 +--- a/net/netfilter/xt_ecn.c ++++ b/net/netfilter/xt_ecn.c +@@ -97,7 +97,7 @@ static int ecn_mt_check4(const struct xt_mtchk_param *par) + + if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) && + (ip->proto != IPPROTO_TCP || ip->invflags & IPT_INV_PROTO)) { +- pr_info("cannot match TCP bits in rule for non-tcp packets\n"); ++ pr_info_ratelimited("cannot match TCP bits for non-tcp packets\n"); + return -EINVAL; + } + +@@ -139,7 +139,7 @@ static int ecn_mt_check6(const struct xt_mtchk_param *par) + + if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) && + (ip->proto != IPPROTO_TCP || ip->invflags & IP6T_INV_PROTO)) { +- pr_info("cannot match TCP bits in rule for non-tcp packets\n"); ++ pr_info_ratelimited("cannot match TCP bits for non-tcp packets\n"); + return -EINVAL; + } + +diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c +index ca68474..66f5aca 100644 +--- a/net/netfilter/xt_hashlimit.c ++++ b/net/netfilter/xt_hashlimit.c +@@ -523,7 +523,8 @@ static u64 user2rate(u64 user) + if (user != 0) { + return div64_u64(XT_HASHLIMIT_SCALE_v2, user); + } else { +- pr_warn("invalid rate from userspace: %llu\n", user); ++ pr_info_ratelimited("invalid rate from userspace: %llu\n", ++ user); + return 0; + } + } +@@ -774,7 +775,7 @@ hashlimit_mt_common(const struct sk_buff *skb, struct xt_action_param *par, + if (!dh->rateinfo.prev_window && + (dh->rateinfo.current_rate <= dh->rateinfo.burst)) { + spin_unlock(&dh->lock); +- rcu_read_unlock_bh(); ++ local_bh_enable(); + return !(cfg->mode & XT_HASHLIMIT_INVERT); + } else { + goto overlimit; +@@ -865,33 +866,34 @@ static int hashlimit_mt_check_common(const struct xt_mtchk_param *par, + } + + if (cfg->mode & ~XT_HASHLIMIT_ALL) { +- pr_info("Unknown mode mask %X, kernel too old?\n", +- cfg->mode); ++ pr_info_ratelimited("Unknown mode mask %X, kernel too old?\n", ++ cfg->mode); + return -EINVAL; + } + + /* Check for overflow. */ + if (revision >= 3 && cfg->mode & XT_HASHLIMIT_RATE_MATCH) { + if (cfg->avg == 0 || cfg->avg > U32_MAX) { +- pr_info("hashlimit invalid rate\n"); ++ pr_info_ratelimited("invalid rate\n"); + return -ERANGE; + } + + if (cfg->interval == 0) { +- pr_info("hashlimit invalid interval\n"); ++ pr_info_ratelimited("invalid interval\n"); + return -EINVAL; + } + } else if (cfg->mode & XT_HASHLIMIT_BYTES) { + if (user2credits_byte(cfg->avg) == 0) { +- pr_info("overflow, rate too high: %llu\n", cfg->avg); ++ pr_info_ratelimited("overflow, rate too high: %llu\n", ++ cfg->avg); + return -EINVAL; + } + } else if (cfg->burst == 0 || +- user2credits(cfg->avg * cfg->burst, revision) < +- user2credits(cfg->avg, revision)) { +- pr_info("overflow, try lower: %llu/%llu\n", +- cfg->avg, cfg->burst); +- return -ERANGE; ++ user2credits(cfg->avg * cfg->burst, revision) < ++ user2credits(cfg->avg, revision)) { ++ pr_info_ratelimited("overflow, try lower: %llu/%llu\n", ++ cfg->avg, cfg->burst); ++ return -ERANGE; + } + + mutex_lock(&hashlimit_mutex); +diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c +index 38a7815..fd077ae 100644 +--- a/net/netfilter/xt_helper.c ++++ b/net/netfilter/xt_helper.c +@@ -61,8 +61,8 @@ static int helper_mt_check(const struct xt_mtchk_param *par) + + ret = nf_ct_netns_get(par->net, par->family); + if (ret < 0) { +- pr_info("cannot load conntrack support for proto=%u\n", +- par->family); ++ pr_info_ratelimited("cannot load conntrack support for proto=%u\n", ++ par->family); + return ret; + } + info->name[sizeof(info->name) - 1] = '\0'; +diff --git a/net/netfilter/xt_ipcomp.c b/net/netfilter/xt_ipcomp.c +index 7ca64a5..57f1df5 100644 +--- a/net/netfilter/xt_ipcomp.c ++++ b/net/netfilter/xt_ipcomp.c +@@ -72,7 +72,7 @@ static int comp_mt_check(const struct xt_mtchk_param *par) + + /* Must specify no unknown invflags */ + if (compinfo->invflags & ~XT_IPCOMP_INV_MASK) { +- pr_err("unknown flags %X\n", compinfo->invflags); ++ pr_info_ratelimited("unknown flags %X\n", compinfo->invflags); + return -EINVAL; + } + return 0; +diff --git a/net/netfilter/xt_ipvs.c b/net/netfilter/xt_ipvs.c +index 42540d2..1d950a6 100644 +--- a/net/netfilter/xt_ipvs.c ++++ b/net/netfilter/xt_ipvs.c +@@ -158,7 +158,8 @@ static int ipvs_mt_check(const struct xt_mtchk_param *par) + && par->family != NFPROTO_IPV6 + #endif + ) { +- pr_info("protocol family %u not supported\n", par->family); ++ pr_info_ratelimited("protocol family %u not supported\n", ++ par->family); + return -EINVAL; + } + +diff --git a/net/netfilter/xt_l2tp.c b/net/netfilter/xt_l2tp.c +index 8aee572..c43482b 100644 +--- a/net/netfilter/xt_l2tp.c ++++ b/net/netfilter/xt_l2tp.c +@@ -216,7 +216,7 @@ static int l2tp_mt_check(const struct xt_mtchk_param *par) + /* Check for invalid flags */ + if (info->flags & ~(XT_L2TP_TID | XT_L2TP_SID | XT_L2TP_VERSION | + XT_L2TP_TYPE)) { +- pr_info("unknown flags: %x\n", info->flags); ++ pr_info_ratelimited("unknown flags: %x\n", info->flags); + return -EINVAL; + } + +@@ -225,7 +225,8 @@ static int l2tp_mt_check(const struct xt_mtchk_param *par) + (!(info->flags & XT_L2TP_SID)) && + ((!(info->flags & XT_L2TP_TYPE)) || + (info->type != XT_L2TP_TYPE_CONTROL))) { +- pr_info("invalid flags combination: %x\n", info->flags); ++ pr_info_ratelimited("invalid flags combination: %x\n", ++ info->flags); + return -EINVAL; + } + +@@ -234,19 +235,22 @@ static int l2tp_mt_check(const struct xt_mtchk_param *par) + */ + if (info->flags & XT_L2TP_VERSION) { + if ((info->version < 2) || (info->version > 3)) { +- pr_info("wrong L2TP version: %u\n", info->version); ++ pr_info_ratelimited("wrong L2TP version: %u\n", ++ info->version); + return -EINVAL; + } + + if (info->version == 2) { + if ((info->flags & XT_L2TP_TID) && + (info->tid > 0xffff)) { +- pr_info("v2 tid > 0xffff: %u\n", info->tid); ++ pr_info_ratelimited("v2 tid > 0xffff: %u\n", ++ info->tid); + return -EINVAL; + } + if ((info->flags & XT_L2TP_SID) && + (info->sid > 0xffff)) { +- pr_info("v2 sid > 0xffff: %u\n", info->sid); ++ pr_info_ratelimited("v2 sid > 0xffff: %u\n", ++ info->sid); + return -EINVAL; + } + } +@@ -268,13 +272,13 @@ static int l2tp_mt_check4(const struct xt_mtchk_param *par) + + if ((ip->proto != IPPROTO_UDP) && + (ip->proto != IPPROTO_L2TP)) { +- pr_info("missing protocol rule (udp|l2tpip)\n"); ++ pr_info_ratelimited("missing protocol rule (udp|l2tpip)\n"); + return -EINVAL; + } + + if ((ip->proto == IPPROTO_L2TP) && + (info->version == 2)) { +- pr_info("v2 doesn't support IP mode\n"); ++ pr_info_ratelimited("v2 doesn't support IP mode\n"); + return -EINVAL; + } + +@@ -295,13 +299,13 @@ static int l2tp_mt_check6(const struct xt_mtchk_param *par) + + if ((ip->proto != IPPROTO_UDP) && + (ip->proto != IPPROTO_L2TP)) { +- pr_info("missing protocol rule (udp|l2tpip)\n"); ++ pr_info_ratelimited("missing protocol rule (udp|l2tpip)\n"); + return -EINVAL; + } + + if ((ip->proto == IPPROTO_L2TP) && + (info->version == 2)) { +- pr_info("v2 doesn't support IP mode\n"); ++ pr_info_ratelimited("v2 doesn't support IP mode\n"); + return -EINVAL; + } + +diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c +index 61403b7..55d18cd 100644 +--- a/net/netfilter/xt_limit.c ++++ b/net/netfilter/xt_limit.c +@@ -106,8 +106,8 @@ static int limit_mt_check(const struct xt_mtchk_param *par) + /* Check for overflow. */ + if (r->burst == 0 + || user2credits(r->avg * r->burst) < user2credits(r->avg)) { +- pr_info("Overflow, try lower: %u/%u\n", +- r->avg, r->burst); ++ pr_info_ratelimited("Overflow, try lower: %u/%u\n", ++ r->avg, r->burst); + return -ERANGE; + } + +diff --git a/net/netfilter/xt_nat.c b/net/netfilter/xt_nat.c +index 0fd14d1..bdb689c 100644 +--- a/net/netfilter/xt_nat.c ++++ b/net/netfilter/xt_nat.c +@@ -8,6 +8,8 @@ + * published by the Free Software Foundation. + */ + ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ + #include + #include + #include +@@ -19,8 +21,7 @@ static int xt_nat_checkentry_v0(const struct xt_tgchk_param *par) + const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo; + + if (mr->rangesize != 1) { +- pr_info("%s: multiple ranges no longer supported\n", +- par->target->name); ++ pr_info_ratelimited("multiple ranges no longer supported\n"); + return -EINVAL; + } + return nf_ct_netns_get(par->net, par->family); +diff --git a/net/netfilter/xt_nfacct.c b/net/netfilter/xt_nfacct.c +index 6f92d25..c8674de 100644 +--- a/net/netfilter/xt_nfacct.c ++++ b/net/netfilter/xt_nfacct.c +@@ -6,6 +6,8 @@ + * it under the terms of the GNU General Public License version 2 (or any + * later at your option) as published by the Free Software Foundation. + */ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ + #include + #include + +@@ -39,8 +41,8 @@ nfacct_mt_checkentry(const struct xt_mtchk_param *par) + + nfacct = nfnl_acct_find_get(par->net, info->name); + if (nfacct == NULL) { +- pr_info("xt_nfacct: accounting object with name `%s' " +- "does not exists\n", info->name); ++ pr_info_ratelimited("accounting object `%s' does not exists\n", ++ info->name); + return -ENOENT; + } + info->nfacct = nfacct; +diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c +index bb33598..9d6d67b 100644 +--- a/net/netfilter/xt_physdev.c ++++ b/net/netfilter/xt_physdev.c +@@ -107,9 +107,7 @@ static int physdev_mt_check(const struct xt_mtchk_param *par) + info->invert & XT_PHYSDEV_OP_BRIDGED) && + par->hook_mask & ((1 << NF_INET_LOCAL_OUT) | + (1 << NF_INET_FORWARD) | (1 << NF_INET_POST_ROUTING))) { +- pr_info("using --physdev-out and --physdev-is-out are only " +- "supported in the FORWARD and POSTROUTING chains with " +- "bridged traffic.\n"); ++ pr_info_ratelimited("--physdev-out and --physdev-is-out only supported in the FORWARD and POSTROUTING chains with bridged traffic\n"); + if (par->hook_mask & (1 << NF_INET_LOCAL_OUT)) + return -EINVAL; + } +diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c +index 5639fb0..13f8ccf 100644 +--- a/net/netfilter/xt_policy.c ++++ b/net/netfilter/xt_policy.c +@@ -132,26 +132,29 @@ policy_mt(const struct sk_buff *skb, struct xt_action_param *par) + static int policy_mt_check(const struct xt_mtchk_param *par) + { + const struct xt_policy_info *info = par->matchinfo; ++ const char *errmsg = "neither incoming nor outgoing policy selected"; ++ ++ if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT))) ++ goto err; + +- if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT))) { +- pr_info("neither incoming nor outgoing policy selected\n"); +- return -EINVAL; +- } + if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) | + (1 << NF_INET_LOCAL_IN)) && info->flags & XT_POLICY_MATCH_OUT) { +- pr_info("output policy not valid in PREROUTING and INPUT\n"); +- return -EINVAL; ++ errmsg = "output policy not valid in PREROUTING and INPUT"; ++ goto err; + } + if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) | + (1 << NF_INET_LOCAL_OUT)) && info->flags & XT_POLICY_MATCH_IN) { +- pr_info("input policy not valid in POSTROUTING and OUTPUT\n"); +- return -EINVAL; ++ errmsg = "input policy not valid in POSTROUTING and OUTPUT"; ++ goto err; + } + if (info->len > XT_POLICY_MAX_ELEM) { +- pr_info("too many policy elements\n"); +- return -EINVAL; ++ errmsg = "too many policy elements"; ++ goto err; + } + return 0; ++err: ++ pr_info_ratelimited("%s\n", errmsg); ++ return -EINVAL; + } + + static struct xt_match policy_mt_reg[] __read_mostly = { +diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c +index 245fa35..6d232d1 100644 +--- a/net/netfilter/xt_recent.c ++++ b/net/netfilter/xt_recent.c +@@ -342,8 +342,8 @@ static int recent_mt_check(const struct xt_mtchk_param *par, + net_get_random_once(&hash_rnd, sizeof(hash_rnd)); + + if (info->check_set & ~XT_RECENT_VALID_FLAGS) { +- pr_info("Unsupported user space flags (%08x)\n", +- info->check_set); ++ pr_info_ratelimited("Unsupported userspace flags (%08x)\n", ++ info->check_set); + return -EINVAL; + } + if (hweight8(info->check_set & +@@ -357,8 +357,8 @@ static int recent_mt_check(const struct xt_mtchk_param *par, + if ((info->check_set & XT_RECENT_REAP) && !info->seconds) + return -EINVAL; + if (info->hit_count >= XT_RECENT_MAX_NSTAMPS) { +- pr_info("hitcount (%u) is larger than allowed maximum (%u)\n", +- info->hit_count, XT_RECENT_MAX_NSTAMPS - 1); ++ pr_info_ratelimited("hitcount (%u) is larger than allowed maximum (%u)\n", ++ info->hit_count, XT_RECENT_MAX_NSTAMPS - 1); + return -EINVAL; + } + if (info->name[0] == '\0' || +@@ -587,7 +587,7 @@ recent_mt_proc_write(struct file *file, const char __user *input, + add = true; + break; + default: +- pr_info("Need \"+ip\", \"-ip\" or \"/\"\n"); ++ pr_info_ratelimited("Need \"+ip\", \"-ip\" or \"/\"\n"); + return -EINVAL; + } + +@@ -601,10 +601,8 @@ recent_mt_proc_write(struct file *file, const char __user *input, + succ = in4_pton(c, size, (void *)&addr, '\n', NULL); + } + +- if (!succ) { +- pr_info("illegal address written to procfs\n"); ++ if (!succ) + return -EINVAL; +- } + + spin_lock_bh(&recent_lock); + e = recent_entry_lookup(t, &addr, family, 0); +diff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c +index 16b6b11..6f4c521 100644 +--- a/net/netfilter/xt_set.c ++++ b/net/netfilter/xt_set.c +@@ -92,12 +92,12 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par) + index = ip_set_nfnl_get_byindex(par->net, info->match_set.index); + + if (index == IPSET_INVALID_ID) { +- pr_warn("Cannot find set identified by id %u to match\n", +- info->match_set.index); ++ pr_info_ratelimited("Cannot find set identified by id %u to match\n", ++ info->match_set.index); + return -ENOENT; + } + if (info->match_set.u.flags[IPSET_DIM_MAX - 1] != 0) { +- pr_warn("Protocol error: set match dimension is over the limit!\n"); ++ pr_info_ratelimited("set match dimension is over the limit!\n"); + ip_set_nfnl_put(par->net, info->match_set.index); + return -ERANGE; + } +@@ -143,12 +143,12 @@ set_match_v1_checkentry(const struct xt_mtchk_param *par) + index = ip_set_nfnl_get_byindex(par->net, info->match_set.index); + + if (index == IPSET_INVALID_ID) { +- pr_warn("Cannot find set identified by id %u to match\n", +- info->match_set.index); ++ pr_info_ratelimited("Cannot find set identified by id %u to match\n", ++ info->match_set.index); + return -ENOENT; + } + if (info->match_set.dim > IPSET_DIM_MAX) { +- pr_warn("Protocol error: set match dimension is over the limit!\n"); ++ pr_info_ratelimited("set match dimension is over the limit!\n"); + ip_set_nfnl_put(par->net, info->match_set.index); + return -ERANGE; + } +@@ -241,8 +241,8 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) + if (info->add_set.index != IPSET_INVALID_ID) { + index = ip_set_nfnl_get_byindex(par->net, info->add_set.index); + if (index == IPSET_INVALID_ID) { +- pr_warn("Cannot find add_set index %u as target\n", +- info->add_set.index); ++ pr_info_ratelimited("Cannot find add_set index %u as target\n", ++ info->add_set.index); + return -ENOENT; + } + } +@@ -250,8 +250,8 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) + if (info->del_set.index != IPSET_INVALID_ID) { + index = ip_set_nfnl_get_byindex(par->net, info->del_set.index); + if (index == IPSET_INVALID_ID) { +- pr_warn("Cannot find del_set index %u as target\n", +- info->del_set.index); ++ pr_info_ratelimited("Cannot find del_set index %u as target\n", ++ info->del_set.index); + if (info->add_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(par->net, info->add_set.index); + return -ENOENT; +@@ -259,7 +259,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) + } + if (info->add_set.u.flags[IPSET_DIM_MAX - 1] != 0 || + info->del_set.u.flags[IPSET_DIM_MAX - 1] != 0) { +- pr_warn("Protocol error: SET target dimension is over the limit!\n"); ++ pr_info_ratelimited("SET target dimension over the limit!\n"); + if (info->add_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(par->net, info->add_set.index); + if (info->del_set.index != IPSET_INVALID_ID) +@@ -316,8 +316,8 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par) + if (info->add_set.index != IPSET_INVALID_ID) { + index = ip_set_nfnl_get_byindex(par->net, info->add_set.index); + if (index == IPSET_INVALID_ID) { +- pr_warn("Cannot find add_set index %u as target\n", +- info->add_set.index); ++ pr_info_ratelimited("Cannot find add_set index %u as target\n", ++ info->add_set.index); + return -ENOENT; + } + } +@@ -325,8 +325,8 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par) + if (info->del_set.index != IPSET_INVALID_ID) { + index = ip_set_nfnl_get_byindex(par->net, info->del_set.index); + if (index == IPSET_INVALID_ID) { +- pr_warn("Cannot find del_set index %u as target\n", +- info->del_set.index); ++ pr_info_ratelimited("Cannot find del_set index %u as target\n", ++ info->del_set.index); + if (info->add_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(par->net, info->add_set.index); + return -ENOENT; +@@ -334,7 +334,7 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par) + } + if (info->add_set.dim > IPSET_DIM_MAX || + info->del_set.dim > IPSET_DIM_MAX) { +- pr_warn("Protocol error: SET target dimension is over the limit!\n"); ++ pr_info_ratelimited("SET target dimension over the limit!\n"); + if (info->add_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(par->net, info->add_set.index); + if (info->del_set.index != IPSET_INVALID_ID) +@@ -444,8 +444,8 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par) + index = ip_set_nfnl_get_byindex(par->net, + info->add_set.index); + if (index == IPSET_INVALID_ID) { +- pr_warn("Cannot find add_set index %u as target\n", +- info->add_set.index); ++ pr_info_ratelimited("Cannot find add_set index %u as target\n", ++ info->add_set.index); + return -ENOENT; + } + } +@@ -454,8 +454,8 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par) + index = ip_set_nfnl_get_byindex(par->net, + info->del_set.index); + if (index == IPSET_INVALID_ID) { +- pr_warn("Cannot find del_set index %u as target\n", +- info->del_set.index); ++ pr_info_ratelimited("Cannot find del_set index %u as target\n", ++ info->del_set.index); + if (info->add_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(par->net, + info->add_set.index); +@@ -465,7 +465,7 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par) + + if (info->map_set.index != IPSET_INVALID_ID) { + if (strncmp(par->table, "mangle", 7)) { +- pr_warn("--map-set only usable from mangle table\n"); ++ pr_info_ratelimited("--map-set only usable from mangle table\n"); + return -EINVAL; + } + if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) | +@@ -473,14 +473,14 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par) + !(par->hook_mask & (1 << NF_INET_FORWARD | + 1 << NF_INET_LOCAL_OUT | + 1 << NF_INET_POST_ROUTING))) { +- pr_warn("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n"); ++ pr_info_ratelimited("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n"); + return -EINVAL; + } + index = ip_set_nfnl_get_byindex(par->net, + info->map_set.index); + if (index == IPSET_INVALID_ID) { +- pr_warn("Cannot find map_set index %u as target\n", +- info->map_set.index); ++ pr_info_ratelimited("Cannot find map_set index %u as target\n", ++ info->map_set.index); + if (info->add_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(par->net, + info->add_set.index); +@@ -494,7 +494,7 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par) + if (info->add_set.dim > IPSET_DIM_MAX || + info->del_set.dim > IPSET_DIM_MAX || + info->map_set.dim > IPSET_DIM_MAX) { +- pr_warn("Protocol error: SET target dimension is over the limit!\n"); ++ pr_info_ratelimited("SET target dimension over the limit!\n"); + if (info->add_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(par->net, info->add_set.index); + if (info->del_set.index != IPSET_INVALID_ID) +diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c +index 575d215..2ac7f67 100644 +--- a/net/netfilter/xt_socket.c ++++ b/net/netfilter/xt_socket.c +@@ -171,7 +171,8 @@ static int socket_mt_v1_check(const struct xt_mtchk_param *par) + return err; + + if (info->flags & ~XT_SOCKET_FLAGS_V1) { +- pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V1); ++ pr_info_ratelimited("unknown flags 0x%x\n", ++ info->flags & ~XT_SOCKET_FLAGS_V1); + return -EINVAL; + } + return 0; +@@ -187,7 +188,8 @@ static int socket_mt_v2_check(const struct xt_mtchk_param *par) + return err; + + if (info->flags & ~XT_SOCKET_FLAGS_V2) { +- pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V2); ++ pr_info_ratelimited("unknown flags 0x%x\n", ++ info->flags & ~XT_SOCKET_FLAGS_V2); + return -EINVAL; + } + return 0; +@@ -203,8 +205,8 @@ static int socket_mt_v3_check(const struct xt_mtchk_param *par) + if (err) + return err; + if (info->flags & ~XT_SOCKET_FLAGS_V3) { +- pr_info("unknown flags 0x%x\n", +- info->flags & ~XT_SOCKET_FLAGS_V3); ++ pr_info_ratelimited("unknown flags 0x%x\n", ++ info->flags & ~XT_SOCKET_FLAGS_V3); + return -EINVAL; + } + return 0; +diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c +index 5fbd791..0b41c0b 100644 +--- a/net/netfilter/xt_state.c ++++ b/net/netfilter/xt_state.c +@@ -44,8 +44,8 @@ static int state_mt_check(const struct xt_mtchk_param *par) + + ret = nf_ct_netns_get(par->net, par->family); + if (ret < 0) +- pr_info("cannot load conntrack support for proto=%u\n", +- par->family); ++ pr_info_ratelimited("cannot load conntrack support for proto=%u\n", ++ par->family); + return ret; + } + +diff --git a/net/netfilter/xt_time.c b/net/netfilter/xt_time.c +index 1b01eec..0160f50 100644 +--- a/net/netfilter/xt_time.c ++++ b/net/netfilter/xt_time.c +@@ -235,13 +235,13 @@ static int time_mt_check(const struct xt_mtchk_param *par) + + if (info->daytime_start > XT_TIME_MAX_DAYTIME || + info->daytime_stop > XT_TIME_MAX_DAYTIME) { +- pr_info("invalid argument - start or " +- "stop time greater than 23:59:59\n"); ++ pr_info_ratelimited("invalid argument - start or stop time greater than 23:59:59\n"); + return -EDOM; + } + + if (info->flags & ~XT_TIME_ALL_FLAGS) { +- pr_info("unknown flags 0x%x\n", info->flags & ~XT_TIME_ALL_FLAGS); ++ pr_info_ratelimited("unknown flags 0x%x\n", ++ info->flags & ~XT_TIME_ALL_FLAGS); + return -EINVAL; + } + +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 2ad445c..07e8478 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -2308,7 +2308,7 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, + if (cb->start) { + ret = cb->start(cb); + if (ret) +- goto error_unlock; ++ goto error_put; + } + + nlk->cb_running = true; +@@ -2328,6 +2328,8 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, + */ + return -EINTR; + ++error_put: ++ module_put(control->module); + error_unlock: + sock_put(sk); + mutex_unlock(nlk->cb_mutex); +diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c +index 367d8c0..2ceefa1 100644 +--- a/net/nfc/llcp_commands.c ++++ b/net/nfc/llcp_commands.c +@@ -149,6 +149,10 @@ struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri, + + pr_debug("uri: %s, len: %zu\n", uri, uri_len); + ++ /* sdreq->tlv_len is u8, takes uri_len, + 3 for header, + 1 for NULL */ ++ if (WARN_ON_ONCE(uri_len > U8_MAX - 4)) ++ return NULL; ++ + sdreq = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL); + if (sdreq == NULL) + return NULL; +diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c +index c0b83dc..f018eaf 100644 +--- a/net/nfc/netlink.c ++++ b/net/nfc/netlink.c +@@ -61,7 +61,8 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = { + }; + + static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = { +- [NFC_SDP_ATTR_URI] = { .type = NLA_STRING }, ++ [NFC_SDP_ATTR_URI] = { .type = NLA_STRING, ++ .len = U8_MAX - 4 }, + [NFC_SDP_ATTR_SAP] = { .type = NLA_U8 }, + }; + +diff --git a/net/qrtr/smd.c b/net/qrtr/smd.c +index 50615d5..9cf089b 100644 +--- a/net/qrtr/smd.c ++++ b/net/qrtr/smd.c +@@ -114,5 +114,6 @@ static struct rpmsg_driver qcom_smd_qrtr_driver = { + + module_rpmsg_driver(qcom_smd_qrtr_driver); + ++MODULE_ALIAS("rpmsg:IPCRTR"); + MODULE_DESCRIPTION("Qualcomm IPC-Router SMD interface driver"); + MODULE_LICENSE("GPL v2"); +diff --git a/net/rds/connection.c b/net/rds/connection.c +index 94e190fe..2da3176 100644 +--- a/net/rds/connection.c ++++ b/net/rds/connection.c +@@ -224,7 +224,7 @@ static struct rds_connection *__rds_conn_create(struct net *net, + if (rds_destroy_pending(conn)) + ret = -ENETDOWN; + else +- ret = trans->conn_alloc(conn, gfp); ++ ret = trans->conn_alloc(conn, GFP_ATOMIC); + if (ret) { + rcu_read_unlock(); + kfree(conn->c_path); +diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c +index c061d6e..2257118 100644 +--- a/net/rds/tcp_listen.c ++++ b/net/rds/tcp_listen.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2006 Oracle. All rights reserved. ++ * Copyright (c) 2006, 2018 Oracle. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU +@@ -142,12 +142,20 @@ int rds_tcp_accept_one(struct socket *sock) + if (ret) + goto out; + +- new_sock->type = sock->type; +- new_sock->ops = sock->ops; + ret = sock->ops->accept(sock, new_sock, O_NONBLOCK, true); + if (ret < 0) + goto out; + ++ /* sock_create_lite() does not get a hold on the owner module so we ++ * need to do it here. Note that sock_release() uses sock->ops to ++ * determine if it needs to decrement the reference count. So set ++ * sock->ops after calling accept() in case that fails. And there's ++ * no need to do try_module_get() as the listener should have a hold ++ * already. ++ */ ++ new_sock->ops = sock->ops; ++ __module_get(new_sock->ops->owner); ++ + ret = rds_tcp_keepalive(new_sock); + if (ret < 0) + goto out; +diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c +index 42410e9..cf73dc0 100644 +--- a/net/rxrpc/output.c ++++ b/net/rxrpc/output.c +@@ -445,7 +445,7 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb, + (char *)&opt, sizeof(opt)); + if (ret == 0) { + ret = kernel_sendmsg(conn->params.local->socket, &msg, +- iov, 1, iov[0].iov_len); ++ iov, 2, len); + + opt = IPV6_PMTUDISC_DO; + kernel_setsockopt(conn->params.local->socket, +diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c +index cc21e8d..9d45d8b 100644 +--- a/net/rxrpc/recvmsg.c ++++ b/net/rxrpc/recvmsg.c +@@ -517,9 +517,10 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, + ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID, + sizeof(unsigned int), &id32); + } else { ++ unsigned long idl = call->user_call_ID; ++ + ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID, +- sizeof(unsigned long), +- &call->user_call_ID); ++ sizeof(unsigned long), &idl); + } + if (ret < 0) + goto error_unlock_call; +diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c +index 2bc1bc2..247b7cc 100644 +--- a/net/sched/cls_api.c ++++ b/net/sched/cls_api.c +@@ -376,17 +376,12 @@ struct tcf_net { + static unsigned int tcf_net_id; + + static int tcf_block_insert(struct tcf_block *block, struct net *net, +- u32 block_index, struct netlink_ext_ack *extack) ++ struct netlink_ext_ack *extack) + { + struct tcf_net *tn = net_generic(net, tcf_net_id); +- int err; + +- err = idr_alloc_u32(&tn->idr, block, &block_index, block_index, +- GFP_KERNEL); +- if (err) +- return err; +- block->index = block_index; +- return 0; ++ return idr_alloc_u32(&tn->idr, block, &block->index, block->index, ++ GFP_KERNEL); + } + + static void tcf_block_remove(struct tcf_block *block, struct net *net) +@@ -397,6 +392,7 @@ static void tcf_block_remove(struct tcf_block *block, struct net *net) + } + + static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q, ++ u32 block_index, + struct netlink_ext_ack *extack) + { + struct tcf_block *block; +@@ -419,10 +415,13 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q, + err = -ENOMEM; + goto err_chain_create; + } +- block->net = qdisc_net(q); + block->refcnt = 1; + block->net = net; +- block->q = q; ++ block->index = block_index; ++ ++ /* Don't store q pointer for blocks which are shared */ ++ if (!tcf_block_shared(block)) ++ block->q = q; + return block; + + err_chain_create: +@@ -518,13 +517,12 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q, + } + + if (!block) { +- block = tcf_block_create(net, q, extack); ++ block = tcf_block_create(net, q, ei->block_index, extack); + if (IS_ERR(block)) + return PTR_ERR(block); + created = true; +- if (ei->block_index) { +- err = tcf_block_insert(block, net, +- ei->block_index, extack); ++ if (tcf_block_shared(block)) { ++ err = tcf_block_insert(block, net, extack); + if (err) + goto err_block_insert; + } +@@ -1399,13 +1397,18 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) + nla_get_u32(tca[TCA_CHAIN]) != chain->index) + continue; + if (!tcf_chain_dump(chain, q, parent, skb, cb, +- index_start, &index)) ++ index_start, &index)) { ++ err = -EMSGSIZE; + break; ++ } + } + + cb->args[0] = index; + + out: ++ /* If we did no progress, the error (EMSGSIZE) is real */ ++ if (skb->len == 0 && err) ++ return err; + return skb->len; + } + +diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c +index 6c7601a..ed8b6a2 100644 +--- a/net/sched/cls_u32.c ++++ b/net/sched/cls_u32.c +@@ -96,7 +96,7 @@ struct tc_u_hnode { + + struct tc_u_common { + struct tc_u_hnode __rcu *hlist; +- struct tcf_block *block; ++ void *ptr; + int refcnt; + struct idr handle_idr; + struct hlist_node hnode; +@@ -330,9 +330,25 @@ static struct hlist_head *tc_u_common_hash; + #define U32_HASH_SHIFT 10 + #define U32_HASH_SIZE (1 << U32_HASH_SHIFT) + ++static void *tc_u_common_ptr(const struct tcf_proto *tp) ++{ ++ struct tcf_block *block = tp->chain->block; ++ ++ /* The block sharing is currently supported only ++ * for classless qdiscs. In that case we use block ++ * for tc_u_common identification. In case the ++ * block is not shared, block->q is a valid pointer ++ * and we can use that. That works for classful qdiscs. ++ */ ++ if (tcf_block_shared(block)) ++ return block; ++ else ++ return block->q; ++} ++ + static unsigned int tc_u_hash(const struct tcf_proto *tp) + { +- return hash_ptr(tp->chain->block, U32_HASH_SHIFT); ++ return hash_ptr(tc_u_common_ptr(tp), U32_HASH_SHIFT); + } + + static struct tc_u_common *tc_u_common_find(const struct tcf_proto *tp) +@@ -342,7 +358,7 @@ static struct tc_u_common *tc_u_common_find(const struct tcf_proto *tp) + + h = tc_u_hash(tp); + hlist_for_each_entry(tc, &tc_u_common_hash[h], hnode) { +- if (tc->block == tp->chain->block) ++ if (tc->ptr == tc_u_common_ptr(tp)) + return tc; + } + return NULL; +@@ -371,7 +387,7 @@ static int u32_init(struct tcf_proto *tp) + kfree(root_ht); + return -ENOBUFS; + } +- tp_c->block = tp->chain->block; ++ tp_c->ptr = tc_u_common_ptr(tp); + INIT_HLIST_NODE(&tp_c->hnode); + idr_init(&tp_c->handle_idr); + +diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c +index 229172d..03225a8 100644 +--- a/net/sched/sch_tbf.c ++++ b/net/sched/sch_tbf.c +@@ -188,7 +188,8 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch, + int ret; + + if (qdisc_pkt_len(skb) > q->max_size) { +- if (skb_is_gso(skb) && skb_gso_mac_seglen(skb) <= q->max_size) ++ if (skb_is_gso(skb) && ++ skb_gso_validate_mac_len(skb, q->max_size)) + return tbf_segment(skb, sch, to_free); + return qdisc_drop(skb, sch, to_free); + } +diff --git a/net/sctp/debug.c b/net/sctp/debug.c +index 291c97b..8f6c2e8 100644 +--- a/net/sctp/debug.c ++++ b/net/sctp/debug.c +@@ -81,6 +81,12 @@ const char *sctp_cname(const union sctp_subtype cid) + case SCTP_CID_RECONF: + return "RECONF"; + ++ case SCTP_CID_I_DATA: ++ return "I_DATA"; ++ ++ case SCTP_CID_I_FWD_TSN: ++ return "I_FWD_TSN"; ++ + default: + break; + } +diff --git a/net/sctp/input.c b/net/sctp/input.c +index 141c9c4..0247cc4 100644 +--- a/net/sctp/input.c ++++ b/net/sctp/input.c +@@ -897,15 +897,12 @@ int sctp_hash_transport(struct sctp_transport *t) + rhl_for_each_entry_rcu(transport, tmp, list, node) + if (transport->asoc->ep == t->asoc->ep) { + rcu_read_unlock(); +- err = -EEXIST; +- goto out; ++ return -EEXIST; + } + rcu_read_unlock(); + + err = rhltable_insert_key(&sctp_transport_hashtable, &arg, + &t->node, sctp_hash_params); +- +-out: + if (err) + pr_err_once("insert transport fail, errno %d\n", err); + +diff --git a/net/sctp/stream.c b/net/sctp/stream.c +index cedf672..f799043 100644 +--- a/net/sctp/stream.c ++++ b/net/sctp/stream.c +@@ -6,7 +6,7 @@ + * + * This file is part of the SCTP kernel implementation + * +- * These functions manipulate sctp tsn mapping array. ++ * This file contains sctp stream maniuplation primitives and helpers. + * + * This SCTP implementation is free software; + * you can redistribute it and/or modify it under the terms of +diff --git a/net/sctp/stream_interleave.c b/net/sctp/stream_interleave.c +index 8c7cf8f..d3764c1 100644 +--- a/net/sctp/stream_interleave.c ++++ b/net/sctp/stream_interleave.c +@@ -3,7 +3,8 @@ + * + * This file is part of the SCTP kernel implementation + * +- * These functions manipulate sctp stream queue/scheduling. ++ * These functions implement sctp stream message interleaving, mostly ++ * including I-DATA and I-FORWARD-TSN chunks process. + * + * This SCTP implementation is free software; + * you can redistribute it and/or modify it under the terms of +@@ -954,12 +955,8 @@ static void sctp_renege_events(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, + __u32 freed = 0; + __u16 needed; + +- if (chunk) { +- needed = ntohs(chunk->chunk_hdr->length); +- needed -= sizeof(struct sctp_idata_chunk); +- } else { +- needed = SCTP_DEFAULT_MAXWINDOW; +- } ++ needed = ntohs(chunk->chunk_hdr->length) - ++ sizeof(struct sctp_idata_chunk); + + if (skb_queue_empty(&asoc->base.sk->sk_receive_queue)) { + freed = sctp_ulpq_renege_list(ulpq, &ulpq->lobby, needed); +@@ -971,9 +968,8 @@ static void sctp_renege_events(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, + needed); + } + +- if (chunk && freed >= needed) +- if (sctp_ulpevent_idata(ulpq, chunk, gfp) <= 0) +- sctp_intl_start_pd(ulpq, gfp); ++ if (freed >= needed && sctp_ulpevent_idata(ulpq, chunk, gfp) <= 0) ++ sctp_intl_start_pd(ulpq, gfp); + + sk_mem_reclaim(asoc->base.sk); + } +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index da1a5cd..8cc9783 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -1406,8 +1406,10 @@ static int smc_create(struct net *net, struct socket *sock, int protocol, + smc->use_fallback = false; /* assume rdma capability first */ + rc = sock_create_kern(net, PF_INET, SOCK_STREAM, + IPPROTO_TCP, &smc->clcsock); +- if (rc) ++ if (rc) { + sk_common_release(sk); ++ goto out; ++ } + smc->sk.sk_sndbuf = max(smc->clcsock->sk->sk_sndbuf, SMC_BUF_MIN_SIZE); + smc->sk.sk_rcvbuf = max(smc->clcsock->sk->sk_rcvbuf, SMC_BUF_MIN_SIZE); + +diff --git a/net/smc/smc_cdc.c b/net/smc/smc_cdc.c +index 3cd086e..b42395d 100644 +--- a/net/smc/smc_cdc.c ++++ b/net/smc/smc_cdc.c +@@ -269,7 +269,7 @@ static void smc_cdc_rx_handler(struct ib_wc *wc, void *buf) + + if (wc->byte_len < offsetof(struct smc_cdc_msg, reserved)) + return; /* short message */ +- if (cdc->len != sizeof(*cdc)) ++ if (cdc->len != SMC_WR_TX_SIZE) + return; /* invalid message */ + smc_cdc_msg_recv(cdc, link, wc->wr_id); + } +diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c +index 2424c71..645dd22 100644 +--- a/net/smc/smc_core.c ++++ b/net/smc/smc_core.c +@@ -177,6 +177,7 @@ static int smc_lgr_create(struct smc_sock *smc, __be32 peer_in_addr, + + lnk = &lgr->lnk[SMC_SINGLE_LINK]; + /* initialize link */ ++ lnk->link_id = SMC_SINGLE_LINK; + lnk->smcibdev = smcibdev; + lnk->ibport = ibport; + lnk->path_mtu = smcibdev->pattr[ibport - 1].active_mtu; +@@ -465,7 +466,7 @@ int smc_conn_create(struct smc_sock *smc, __be32 peer_in_addr, + rc = smc_link_determine_gid(conn->lgr); + } + conn->local_tx_ctrl.common.type = SMC_CDC_MSG_TYPE; +- conn->local_tx_ctrl.len = sizeof(struct smc_cdc_msg); ++ conn->local_tx_ctrl.len = SMC_WR_TX_SIZE; + #ifndef KERNEL_HAS_ATOMIC64 + spin_lock_init(&conn->acurs_lock); + #endif +diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c +index 92fe4cc..b4aa4fc 100644 +--- a/net/smc/smc_llc.c ++++ b/net/smc/smc_llc.c +@@ -92,7 +92,7 @@ int smc_llc_send_confirm_link(struct smc_link *link, u8 mac[], + memcpy(confllc->sender_mac, mac, ETH_ALEN); + memcpy(confllc->sender_gid, gid, SMC_GID_SIZE); + hton24(confllc->sender_qp_num, link->roce_qp->qp_num); +- /* confllc->link_num = SMC_SINGLE_LINK; already done by memset above */ ++ confllc->link_num = link->link_id; + memcpy(confllc->link_uid, lgr->id, SMC_LGR_ID_SIZE); + confllc->max_links = SMC_LINKS_PER_LGR_MAX; + /* send llc message */ +diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c +index c800147..3e3dce3 100644 +--- a/net/tipc/bearer.c ++++ b/net/tipc/bearer.c +@@ -813,7 +813,7 @@ int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info) + return err; + } + +-int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info) ++int __tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info) + { + int err; + char *name; +@@ -835,20 +835,27 @@ int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info) + + name = nla_data(attrs[TIPC_NLA_BEARER_NAME]); + +- rtnl_lock(); + bearer = tipc_bearer_find(net, name); +- if (!bearer) { +- rtnl_unlock(); ++ if (!bearer) + return -EINVAL; +- } + + bearer_disable(net, bearer); +- rtnl_unlock(); + + return 0; + } + +-int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info) ++int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info) ++{ ++ int err; ++ ++ rtnl_lock(); ++ err = __tipc_nl_bearer_disable(skb, info); ++ rtnl_unlock(); ++ ++ return err; ++} ++ ++int __tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info) + { + int err; + char *bearer; +@@ -890,15 +897,18 @@ int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info) + prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); + } + ++ return tipc_enable_bearer(net, bearer, domain, prio, attrs); ++} ++ ++int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info) ++{ ++ int err; ++ + rtnl_lock(); +- err = tipc_enable_bearer(net, bearer, domain, prio, attrs); +- if (err) { +- rtnl_unlock(); +- return err; +- } ++ err = __tipc_nl_bearer_enable(skb, info); + rtnl_unlock(); + +- return 0; ++ return err; + } + + int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info) +@@ -944,7 +954,7 @@ int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info) + return 0; + } + +-int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info) ++int __tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info) + { + int err; + char *name; +@@ -965,22 +975,17 @@ int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info) + return -EINVAL; + name = nla_data(attrs[TIPC_NLA_BEARER_NAME]); + +- rtnl_lock(); + b = tipc_bearer_find(net, name); +- if (!b) { +- rtnl_unlock(); ++ if (!b) + return -EINVAL; +- } + + if (attrs[TIPC_NLA_BEARER_PROP]) { + struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; + + err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_BEARER_PROP], + props); +- if (err) { +- rtnl_unlock(); ++ if (err) + return err; +- } + + if (props[TIPC_NLA_PROP_TOL]) + b->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]); +@@ -989,11 +994,21 @@ int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info) + if (props[TIPC_NLA_PROP_WIN]) + b->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]); + } +- rtnl_unlock(); + + return 0; + } + ++int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info) ++{ ++ int err; ++ ++ rtnl_lock(); ++ err = __tipc_nl_bearer_set(skb, info); ++ rtnl_unlock(); ++ ++ return err; ++} ++ + static int __tipc_nl_add_media(struct tipc_nl_msg *msg, + struct tipc_media *media, int nlflags) + { +@@ -1115,7 +1130,7 @@ int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info) + return err; + } + +-int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info) ++int __tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info) + { + int err; + char *name; +@@ -1133,22 +1148,17 @@ int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info) + return -EINVAL; + name = nla_data(attrs[TIPC_NLA_MEDIA_NAME]); + +- rtnl_lock(); + m = tipc_media_find(name); +- if (!m) { +- rtnl_unlock(); ++ if (!m) + return -EINVAL; +- } + + if (attrs[TIPC_NLA_MEDIA_PROP]) { + struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; + + err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_MEDIA_PROP], + props); +- if (err) { +- rtnl_unlock(); ++ if (err) + return err; +- } + + if (props[TIPC_NLA_PROP_TOL]) + m->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]); +@@ -1157,7 +1167,17 @@ int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info) + if (props[TIPC_NLA_PROP_WIN]) + m->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]); + } +- rtnl_unlock(); + + return 0; + } ++ ++int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info) ++{ ++ int err; ++ ++ rtnl_lock(); ++ err = __tipc_nl_media_set(skb, info); ++ rtnl_unlock(); ++ ++ return err; ++} +diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h +index 42d6eee..a53613d 100644 +--- a/net/tipc/bearer.h ++++ b/net/tipc/bearer.h +@@ -188,15 +188,19 @@ extern struct tipc_media udp_media_info; + #endif + + int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info); ++int __tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info); + int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info); ++int __tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info); + int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb); + int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info); + int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info); ++int __tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info); + int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info); + + int tipc_nl_media_dump(struct sk_buff *skb, struct netlink_callback *cb); + int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info); + int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info); ++int __tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info); + + int tipc_media_set_priority(const char *name, u32 new_value); + int tipc_media_set_window(const char *name, u32 new_value); +diff --git a/net/tipc/group.c b/net/tipc/group.c +index 122162a..04e516d 100644 +--- a/net/tipc/group.c ++++ b/net/tipc/group.c +@@ -189,6 +189,7 @@ struct tipc_group *tipc_group_create(struct net *net, u32 portid, + grp->loopback = mreq->flags & TIPC_GROUP_LOOPBACK; + grp->events = mreq->flags & TIPC_GROUP_MEMBER_EVTS; + grp->open = group_is_open; ++ *grp->open = false; + filter |= global ? TIPC_SUB_CLUSTER_SCOPE : TIPC_SUB_NODE_SCOPE; + if (tipc_topsrv_kern_subscr(net, portid, type, 0, ~0, + filter, &grp->subid)) +diff --git a/net/tipc/net.c b/net/tipc/net.c +index 719c592..1a2fde0 100644 +--- a/net/tipc/net.c ++++ b/net/tipc/net.c +@@ -200,7 +200,7 @@ int tipc_nl_net_dump(struct sk_buff *skb, struct netlink_callback *cb) + return skb->len; + } + +-int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info) ++int __tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info) + { + struct net *net = sock_net(skb->sk); + struct tipc_net *tn = net_generic(net, tipc_net_id); +@@ -241,10 +241,19 @@ int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info) + if (!tipc_addr_node_valid(addr)) + return -EINVAL; + +- rtnl_lock(); + tipc_net_start(net, addr); +- rtnl_unlock(); + } + + return 0; + } ++ ++int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info) ++{ ++ int err; ++ ++ rtnl_lock(); ++ err = __tipc_nl_net_set(skb, info); ++ rtnl_unlock(); ++ ++ return err; ++} +diff --git a/net/tipc/net.h b/net/tipc/net.h +index c7c2549..c0306aa 100644 +--- a/net/tipc/net.h ++++ b/net/tipc/net.h +@@ -47,5 +47,6 @@ void tipc_net_stop(struct net *net); + + int tipc_nl_net_dump(struct sk_buff *skb, struct netlink_callback *cb); + int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info); ++int __tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info); + + #endif +diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c +index e48f0b2..4492cda 100644 +--- a/net/tipc/netlink_compat.c ++++ b/net/tipc/netlink_compat.c +@@ -285,10 +285,6 @@ static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd, + if (!trans_buf) + return -ENOMEM; + +- err = (*cmd->transcode)(cmd, trans_buf, msg); +- if (err) +- goto trans_out; +- + attrbuf = kmalloc((tipc_genl_family.maxattr + 1) * + sizeof(struct nlattr *), GFP_KERNEL); + if (!attrbuf) { +@@ -296,27 +292,34 @@ static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd, + goto trans_out; + } + +- err = nla_parse(attrbuf, tipc_genl_family.maxattr, +- (const struct nlattr *)trans_buf->data, +- trans_buf->len, NULL, NULL); +- if (err) +- goto parse_out; +- + doit_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + if (!doit_buf) { + err = -ENOMEM; +- goto parse_out; ++ goto attrbuf_out; + } + +- doit_buf->sk = msg->dst_sk; +- + memset(&info, 0, sizeof(info)); + info.attrs = attrbuf; + ++ rtnl_lock(); ++ err = (*cmd->transcode)(cmd, trans_buf, msg); ++ if (err) ++ goto doit_out; ++ ++ err = nla_parse(attrbuf, tipc_genl_family.maxattr, ++ (const struct nlattr *)trans_buf->data, ++ trans_buf->len, NULL, NULL); ++ if (err) ++ goto doit_out; ++ ++ doit_buf->sk = msg->dst_sk; ++ + err = (*cmd->doit)(doit_buf, &info); ++doit_out: ++ rtnl_unlock(); + + kfree_skb(doit_buf); +-parse_out: ++attrbuf_out: + kfree(attrbuf); + trans_out: + kfree_skb(trans_buf); +@@ -722,13 +725,13 @@ static int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd, + + media = tipc_media_find(lc->name); + if (media) { +- cmd->doit = &tipc_nl_media_set; ++ cmd->doit = &__tipc_nl_media_set; + return tipc_nl_compat_media_set(skb, msg); + } + + bearer = tipc_bearer_find(msg->net, lc->name); + if (bearer) { +- cmd->doit = &tipc_nl_bearer_set; ++ cmd->doit = &__tipc_nl_bearer_set; + return tipc_nl_compat_bearer_set(skb, msg); + } + +@@ -1089,12 +1092,12 @@ static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg) + return tipc_nl_compat_dumpit(&dump, msg); + case TIPC_CMD_ENABLE_BEARER: + msg->req_type = TIPC_TLV_BEARER_CONFIG; +- doit.doit = tipc_nl_bearer_enable; ++ doit.doit = __tipc_nl_bearer_enable; + doit.transcode = tipc_nl_compat_bearer_enable; + return tipc_nl_compat_doit(&doit, msg); + case TIPC_CMD_DISABLE_BEARER: + msg->req_type = TIPC_TLV_BEARER_NAME; +- doit.doit = tipc_nl_bearer_disable; ++ doit.doit = __tipc_nl_bearer_disable; + doit.transcode = tipc_nl_compat_bearer_disable; + return tipc_nl_compat_doit(&doit, msg); + case TIPC_CMD_SHOW_LINK_STATS: +@@ -1148,12 +1151,12 @@ static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg) + return tipc_nl_compat_dumpit(&dump, msg); + case TIPC_CMD_SET_NODE_ADDR: + msg->req_type = TIPC_TLV_NET_ADDR; +- doit.doit = tipc_nl_net_set; ++ doit.doit = __tipc_nl_net_set; + doit.transcode = tipc_nl_compat_net_set; + return tipc_nl_compat_doit(&doit, msg); + case TIPC_CMD_SET_NETID: + msg->req_type = TIPC_TLV_UNSIGNED; +- doit.doit = tipc_nl_net_set; ++ doit.doit = __tipc_nl_net_set; + doit.transcode = tipc_nl_compat_net_set; + return tipc_nl_compat_doit(&doit, msg); + case TIPC_CMD_GET_NETID: +diff --git a/net/tipc/socket.c b/net/tipc/socket.c +index b0323ec..7dfa9fc 100644 +--- a/net/tipc/socket.c ++++ b/net/tipc/socket.c +@@ -473,6 +473,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock, + sk->sk_write_space = tipc_write_space; + sk->sk_destruct = tipc_sock_destruct; + tsk->conn_timeout = CONN_TIMEOUT_DEFAULT; ++ tsk->group_is_open = true; + atomic_set(&tsk->dupl_rcvcnt, 0); + + /* Start out with safe limits until we receive an advertised window */ +diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c +index b0d5fce..d824d54 100644 +--- a/net/tls/tls_main.c ++++ b/net/tls/tls_main.c +@@ -46,16 +46,26 @@ MODULE_DESCRIPTION("Transport Layer Security Support"); + MODULE_LICENSE("Dual BSD/GPL"); + + enum { ++ TLSV4, ++ TLSV6, ++ TLS_NUM_PROTS, ++}; ++ ++enum { + TLS_BASE_TX, + TLS_SW_TX, + TLS_NUM_CONFIG, + }; + +-static struct proto tls_prots[TLS_NUM_CONFIG]; ++static struct proto *saved_tcpv6_prot; ++static DEFINE_MUTEX(tcpv6_prot_mutex); ++static struct proto tls_prots[TLS_NUM_PROTS][TLS_NUM_CONFIG]; + + static inline void update_sk_prot(struct sock *sk, struct tls_context *ctx) + { +- sk->sk_prot = &tls_prots[ctx->tx_conf]; ++ int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4; ++ ++ sk->sk_prot = &tls_prots[ip_ver][ctx->tx_conf]; + } + + int wait_on_pending_writer(struct sock *sk, long *timeo) +@@ -308,8 +318,11 @@ static int do_tls_getsockopt_tx(struct sock *sk, char __user *optval, + goto out; + } + lock_sock(sk); +- memcpy(crypto_info_aes_gcm_128->iv, ctx->iv, ++ memcpy(crypto_info_aes_gcm_128->iv, ++ ctx->iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE, + TLS_CIPHER_AES_GCM_128_IV_SIZE); ++ memcpy(crypto_info_aes_gcm_128->rec_seq, ctx->rec_seq, ++ TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE); + release_sock(sk); + if (copy_to_user(optval, + crypto_info_aes_gcm_128, +@@ -375,7 +388,7 @@ static int do_tls_setsockopt_tx(struct sock *sk, char __user *optval, + rc = copy_from_user(crypto_info, optval, sizeof(*crypto_info)); + if (rc) { + rc = -EFAULT; +- goto out; ++ goto err_crypto_info; + } + + /* check version */ +@@ -450,8 +463,21 @@ static int tls_setsockopt(struct sock *sk, int level, int optname, + return do_tls_setsockopt(sk, optname, optval, optlen); + } + ++static void build_protos(struct proto *prot, struct proto *base) ++{ ++ prot[TLS_BASE_TX] = *base; ++ prot[TLS_BASE_TX].setsockopt = tls_setsockopt; ++ prot[TLS_BASE_TX].getsockopt = tls_getsockopt; ++ prot[TLS_BASE_TX].close = tls_sk_proto_close; ++ ++ prot[TLS_SW_TX] = prot[TLS_BASE_TX]; ++ prot[TLS_SW_TX].sendmsg = tls_sw_sendmsg; ++ prot[TLS_SW_TX].sendpage = tls_sw_sendpage; ++} ++ + static int tls_init(struct sock *sk) + { ++ int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4; + struct inet_connection_sock *icsk = inet_csk(sk); + struct tls_context *ctx; + int rc = 0; +@@ -476,6 +502,17 @@ static int tls_init(struct sock *sk) + ctx->getsockopt = sk->sk_prot->getsockopt; + ctx->sk_proto_close = sk->sk_prot->close; + ++ /* Build IPv6 TLS whenever the address of tcpv6_prot changes */ ++ if (ip_ver == TLSV6 && ++ unlikely(sk->sk_prot != smp_load_acquire(&saved_tcpv6_prot))) { ++ mutex_lock(&tcpv6_prot_mutex); ++ if (likely(sk->sk_prot != saved_tcpv6_prot)) { ++ build_protos(tls_prots[TLSV6], sk->sk_prot); ++ smp_store_release(&saved_tcpv6_prot, sk->sk_prot); ++ } ++ mutex_unlock(&tcpv6_prot_mutex); ++ } ++ + ctx->tx_conf = TLS_BASE_TX; + update_sk_prot(sk, ctx); + out: +@@ -490,21 +527,9 @@ static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = { + .init = tls_init, + }; + +-static void build_protos(struct proto *prot, struct proto *base) +-{ +- prot[TLS_BASE_TX] = *base; +- prot[TLS_BASE_TX].setsockopt = tls_setsockopt; +- prot[TLS_BASE_TX].getsockopt = tls_getsockopt; +- prot[TLS_BASE_TX].close = tls_sk_proto_close; +- +- prot[TLS_SW_TX] = prot[TLS_BASE_TX]; +- prot[TLS_SW_TX].sendmsg = tls_sw_sendmsg; +- prot[TLS_SW_TX].sendpage = tls_sw_sendpage; +-} +- + static int __init tls_register(void) + { +- build_protos(tls_prots, &tcp_prot); ++ build_protos(tls_prots[TLSV4], &tcp_prot); + + tcp_register_ulp(&tcp_tls_ulp_ops); + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index d545e1d..2d465bd 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -1825,7 +1825,7 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, + } + + /* We use paged skbs for stream sockets, and limit occupancy to 32768 +- * bytes, and a minimun of a full page. ++ * bytes, and a minimum of a full page. + */ + #define UNIX_SKB_FRAGS_SZ (PAGE_SIZE << get_order(32768)) + +diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig +index 1abcc4f..4172204 100644 +--- a/net/wireless/Kconfig ++++ b/net/wireless/Kconfig +@@ -34,9 +34,10 @@ config CFG80211 + + When built as a module it will be called cfg80211. + ++if CFG80211 ++ + config NL80211_TESTMODE + bool "nl80211 testmode command" +- depends on CFG80211 + help + The nl80211 testmode command helps implementing things like + factory calibration or validation tools for wireless chips. +@@ -51,7 +52,6 @@ config NL80211_TESTMODE + + config CFG80211_DEVELOPER_WARNINGS + bool "enable developer warnings" +- depends on CFG80211 + default n + help + This option enables some additional warnings that help +@@ -68,7 +68,7 @@ config CFG80211_DEVELOPER_WARNINGS + + config CFG80211_CERTIFICATION_ONUS + bool "cfg80211 certification onus" +- depends on CFG80211 && EXPERT ++ depends on EXPERT + default n + ---help--- + You should disable this option unless you are both capable +@@ -159,7 +159,6 @@ config CFG80211_REG_RELAX_NO_IR + + config CFG80211_DEFAULT_PS + bool "enable powersave by default" +- depends on CFG80211 + default y + help + This option enables powersave mode by default. +@@ -170,7 +169,6 @@ config CFG80211_DEFAULT_PS + + config CFG80211_DEBUGFS + bool "cfg80211 DebugFS entries" +- depends on CFG80211 + depends on DEBUG_FS + ---help--- + You can enable this if you want debugfs entries for cfg80211. +@@ -180,7 +178,6 @@ config CFG80211_DEBUGFS + config CFG80211_CRDA_SUPPORT + bool "support CRDA" if EXPERT + default y +- depends on CFG80211 + help + You should enable this option unless you know for sure you have no + need for it, for example when using internal regdb (above) or the +@@ -190,7 +187,6 @@ config CFG80211_CRDA_SUPPORT + + config CFG80211_WEXT + bool "cfg80211 wireless extensions compatibility" if !CFG80211_WEXT_EXPORT +- depends on CFG80211 + select WEXT_CORE + default y if CFG80211_WEXT_EXPORT + help +@@ -199,11 +195,12 @@ config CFG80211_WEXT + + config CFG80211_WEXT_EXPORT + bool +- depends on CFG80211 + help + Drivers should select this option if they require cfg80211's + wext compatibility symbols to be exported. + ++endif # CFG80211 ++ + config LIB80211 + tristate + default n +diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c +index 51aa556..b12da6e 100644 +--- a/net/wireless/mesh.c ++++ b/net/wireless/mesh.c +@@ -170,9 +170,28 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, + enum nl80211_bss_scan_width scan_width; + struct ieee80211_supported_band *sband = + rdev->wiphy.bands[setup->chandef.chan->band]; +- scan_width = cfg80211_chandef_to_scan_width(&setup->chandef); +- setup->basic_rates = ieee80211_mandatory_rates(sband, +- scan_width); ++ ++ if (setup->chandef.chan->band == NL80211_BAND_2GHZ) { ++ int i; ++ ++ /* ++ * Older versions selected the mandatory rates for ++ * 2.4 GHz as well, but were broken in that only ++ * 1 Mbps was regarded as a mandatory rate. Keep ++ * using just 1 Mbps as the default basic rate for ++ * mesh to be interoperable with older versions. ++ */ ++ for (i = 0; i < sband->n_bitrates; i++) { ++ if (sband->bitrates[i].bitrate == 10) { ++ setup->basic_rates = BIT(i); ++ break; ++ } ++ } ++ } else { ++ scan_width = cfg80211_chandef_to_scan_width(&setup->chandef); ++ setup->basic_rates = ieee80211_mandatory_rates(sband, ++ scan_width); ++ } + } + + err = cfg80211_chandef_dfs_required(&rdev->wiphy, +diff --git a/net/wireless/sme.c b/net/wireless/sme.c +index fdb3646..701cfd7 100644 +--- a/net/wireless/sme.c ++++ b/net/wireless/sme.c +@@ -1032,6 +1032,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, + wdev->current_bss = NULL; + wdev->ssid_len = 0; + wdev->conn_owner_nlportid = 0; ++ kzfree(wdev->connect_keys); ++ wdev->connect_keys = NULL; + + nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); + +diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c +index 8e70291..e87d6c4 100644 +--- a/net/xfrm/xfrm_device.c ++++ b/net/xfrm/xfrm_device.c +@@ -217,7 +217,7 @@ bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x) + if (skb->len <= mtu) + goto ok; + +- if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) + goto ok; + } + +diff --git a/samples/seccomp/Makefile b/samples/seccomp/Makefile +index 0e349b8..ba942e3 100644 +--- a/samples/seccomp/Makefile ++++ b/samples/seccomp/Makefile +@@ -1,4 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 ++ifndef CROSS_COMPILE + hostprogs-$(CONFIG_SAMPLE_SECCOMP) := bpf-fancy dropper bpf-direct + + HOSTCFLAGS_bpf-fancy.o += -I$(objtree)/usr/include +@@ -16,7 +17,6 @@ HOSTCFLAGS_bpf-direct.o += -idirafter $(objtree)/include + bpf-direct-objs := bpf-direct.o + + # Try to match the kernel target. +-ifndef CROSS_COMPILE + ifndef CONFIG_64BIT + + # s390 has -m31 flag to build 31 bit binaries +@@ -35,12 +35,4 @@ HOSTLOADLIBES_bpf-fancy += $(MFLAG) + HOSTLOADLIBES_dropper += $(MFLAG) + endif + always := $(hostprogs-m) +-else +-# MIPS system calls are defined based on the -mabi that is passed +-# to the toolchain which may or may not be a valid option +-# for the host toolchain. So disable tests if target architecture +-# is MIPS but the host isn't. +-ifndef CONFIG_MIPS +-always := $(hostprogs-m) +-endif + endif +diff --git a/scripts/Makefile.build b/scripts/Makefile.build +index 47cddf3..4f2b25d 100644 +--- a/scripts/Makefile.build ++++ b/scripts/Makefile.build +@@ -256,6 +256,8 @@ __objtool_obj := $(objtree)/tools/objtool/objtool + + objtool_args = $(if $(CONFIG_UNWINDER_ORC),orc generate,check) + ++objtool_args += $(if $(part-of-module), --module,) ++ + ifndef CONFIG_FRAME_POINTER + objtool_args += --no-fp + endif +@@ -264,6 +266,12 @@ objtool_args += --no-unreachable + else + objtool_args += $(call cc-ifversion, -lt, 0405, --no-unreachable) + endif ++ifdef CONFIG_RETPOLINE ++ifneq ($(RETPOLINE_CFLAGS),) ++ objtool_args += --retpoline ++endif ++endif ++ + + ifdef CONFIG_MODVERSIONS + objtool_o = $(@D)/.tmp_$(@F) +diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib +index 5589bae..a6f538b 100644 +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -297,11 +297,11 @@ cmd_dt_S_dtb= \ + echo '\#include '; \ + echo '.section .dtb.init.rodata,"a"'; \ + echo '.balign STRUCT_ALIGNMENT'; \ +- echo '.global __dtb_$(*F)_begin'; \ +- echo '__dtb_$(*F)_begin:'; \ ++ echo '.global __dtb_$(subst -,_,$(*F))_begin'; \ ++ echo '__dtb_$(subst -,_,$(*F))_begin:'; \ + echo '.incbin "$<" '; \ +- echo '__dtb_$(*F)_end:'; \ +- echo '.global __dtb_$(*F)_end'; \ ++ echo '__dtb_$(subst -,_,$(*F))_end:'; \ ++ echo '.global __dtb_$(subst -,_,$(*F))_end'; \ + echo '.balign STRUCT_ALIGNMENT'; \ + ) > $@ + +diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c +index fa3d39b6..449b68c 100644 +--- a/scripts/basic/fixdep.c ++++ b/scripts/basic/fixdep.c +@@ -93,14 +93,6 @@ + * (Note: it'd be easy to port over the complete mkdep state machine, + * but I don't think the added complexity is worth it) + */ +-/* +- * Note 2: if somebody writes HELLO_CONFIG_BOOM in a file, it will depend onto +- * CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not +- * fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as +- * UML_CONFIG_BOOM, to avoid conflicts with /usr/include/linux/autoconf.h, +- * through arch/um/include/uml-config.h; this fixdep "bug" makes sure that +- * those files will have correct dependencies. +- */ + + #include + #include +@@ -233,8 +225,13 @@ static int str_ends_with(const char *s, int slen, const char *sub) + static void parse_config_file(const char *p) + { + const char *q, *r; ++ const char *start = p; + + while ((p = strstr(p, "CONFIG_"))) { ++ if (p > start && (isalnum(p[-1]) || p[-1] == '_')) { ++ p += 7; ++ continue; ++ } + p += 7; + q = p; + while (*q && (isalnum(*q) || *q == '_')) +@@ -286,8 +283,6 @@ static int is_ignored_file(const char *s, int len) + { + return str_ends_with(s, len, "include/generated/autoconf.h") || + str_ends_with(s, len, "include/generated/autoksyms.h") || +- str_ends_with(s, len, "arch/um/include/uml-config.h") || +- str_ends_with(s, len, "include/linux/kconfig.h") || + str_ends_with(s, len, ".ver"); + } + +diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter +index 94b6648..d84a567 100755 +--- a/scripts/bloat-o-meter ++++ b/scripts/bloat-o-meter +@@ -15,7 +15,7 @@ signal(SIGPIPE, SIG_DFL) + if len(sys.argv) < 3: + sys.stderr.write("usage: %s [option] file1 file2\n" % sys.argv[0]) + sys.stderr.write("The options are:\n") +- sys.stderr.write("-c cateogrize output based on symbole type\n") ++ sys.stderr.write("-c categorize output based on symbol type\n") + sys.stderr.write("-d Show delta of Data Section\n") + sys.stderr.write("-t Show delta of text Section\n") + sys.exit(-1) +diff --git a/scripts/coccinelle/api/memdup.cocci b/scripts/coccinelle/api/memdup.cocci +index 1249b72..8fd6437 100644 +--- a/scripts/coccinelle/api/memdup.cocci ++++ b/scripts/coccinelle/api/memdup.cocci +@@ -56,10 +56,10 @@ statement S; + p << r.p; + @@ + +-coccilib.org.print_todo(p[0], "WARNING opportunity for kmemdep") ++coccilib.org.print_todo(p[0], "WARNING opportunity for kmemdup") + + @script:python depends on report@ + p << r.p; + @@ + +-coccilib.report.print_report(p[0], "WARNING opportunity for kmemdep") ++coccilib.report.print_report(p[0], "WARNING opportunity for kmemdup") +diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c +index 9ee9bf7..6579265 100644 +--- a/scripts/kallsyms.c ++++ b/scripts/kallsyms.c +@@ -595,7 +595,7 @@ static void optimize_result(void) + * original char code */ + if (!best_table_len[i]) { + +- /* find the token with the breates profit value */ ++ /* find the token with the best profit value */ + best = find_best_token(); + if (token_profit[best] == 0) + break; +diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c +index 5c12dc9..df26c7b 100644 +--- a/scripts/kconfig/confdata.c ++++ b/scripts/kconfig/confdata.c +@@ -178,7 +178,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) + case S_HEX: + done: + if (sym_string_valid(sym, p)) { +- sym->def[def].val = strdup(p); ++ sym->def[def].val = xstrdup(p); + sym->flags |= def_flags; + } else { + if (def != S_DEF_AUTO) +diff --git a/scripts/kconfig/kxgettext.c b/scripts/kconfig/kxgettext.c +index 2858738..240880a 100644 +--- a/scripts/kconfig/kxgettext.c ++++ b/scripts/kconfig/kxgettext.c +@@ -101,7 +101,7 @@ static struct message *message__new(const char *msg, char *option, + if (self->files == NULL) + goto out_fail; + +- self->msg = strdup(msg); ++ self->msg = xstrdup(msg); + if (self->msg == NULL) + goto out_fail_msg; + +diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h +index 4e23feb..2d5ec2d 100644 +--- a/scripts/kconfig/lkc.h ++++ b/scripts/kconfig/lkc.h +@@ -115,6 +115,7 @@ int file_write_dep(const char *name); + void *xmalloc(size_t size); + void *xcalloc(size_t nmemb, size_t size); + void *xrealloc(void *p, size_t size); ++char *xstrdup(const char *s); + + struct gstr { + size_t len; +diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh +index a10bd9d..6c0bcd9 100755 +--- a/scripts/kconfig/lxdialog/check-lxdialog.sh ++++ b/scripts/kconfig/lxdialog/check-lxdialog.sh +@@ -55,7 +55,8 @@ EOF + echo " *** required header files." 1>&2 + echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2 + echo " *** " 1>&2 +- echo " *** Install ncurses (ncurses-devel) and try again." 1>&2 ++ echo " *** Install ncurses (ncurses-devel or libncurses-dev " 1>&2 ++ echo " *** depending on your distribution) and try again." 1>&2 + echo " *** " 1>&2 + exit 1 + fi +diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c +index 9922285..36cd3e1 100644 +--- a/scripts/kconfig/menu.c ++++ b/scripts/kconfig/menu.c +@@ -212,6 +212,7 @@ void menu_add_option(int token, char *arg) + sym_defconfig_list = current_entry->sym; + else if (sym_defconfig_list != current_entry->sym) + zconf_error("trying to redefine defconfig symbol"); ++ sym_defconfig_list->flags |= SYMBOL_AUTO; + break; + case T_OPT_ENV: + prop_add_env(arg); +diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c +index cca9663..2220bc4 100644 +--- a/scripts/kconfig/symbol.c ++++ b/scripts/kconfig/symbol.c +@@ -183,7 +183,7 @@ static void sym_validate_range(struct symbol *sym) + sprintf(str, "%lld", val2); + else + sprintf(str, "0x%llx", val2); +- sym->curr.val = strdup(str); ++ sym->curr.val = xstrdup(str); + } + + static void sym_set_changed(struct symbol *sym) +@@ -849,7 +849,7 @@ struct symbol *sym_lookup(const char *name, int flags) + : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) + return symbol; + } +- new_name = strdup(name); ++ new_name = xstrdup(name); + } else { + new_name = NULL; + hash = 0; +diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c +index b98a79e..c6f6e21 100644 +--- a/scripts/kconfig/util.c ++++ b/scripts/kconfig/util.c +@@ -154,3 +154,14 @@ void *xrealloc(void *p, size_t size) + fprintf(stderr, "Out of memory.\n"); + exit(1); + } ++ ++char *xstrdup(const char *s) ++{ ++ char *p; ++ ++ p = strdup(s); ++ if (p) ++ return p; ++ fprintf(stderr, "Out of memory.\n"); ++ exit(1); ++} +diff --git a/scripts/kconfig/zconf.l b/scripts/kconfig/zconf.l +index 02de6fe..88b650e 100644 +--- a/scripts/kconfig/zconf.l ++++ b/scripts/kconfig/zconf.l +@@ -332,16 +332,12 @@ void zconf_nextfile(const char *name) + "Inclusion path:\n current file : '%s'\n", + zconf_curname(), zconf_lineno(), + zconf_curname()); +- iter = current_file->parent; +- while (iter && \ +- strcmp(iter->name,current_file->name)) { +- fprintf(stderr, " included from: '%s:%d'\n", +- iter->name, iter->lineno-1); ++ iter = current_file; ++ do { + iter = iter->parent; +- } +- if (iter) + fprintf(stderr, " included from: '%s:%d'\n", +- iter->name, iter->lineno+1); ++ iter->name, iter->lineno - 1); ++ } while (strcmp(iter->name, current_file->name)); + exit(1); + } + } +diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y +index 4be9805..ad6305b 100644 +--- a/scripts/kconfig/zconf.y ++++ b/scripts/kconfig/zconf.y +@@ -127,7 +127,7 @@ no_mainmenu_stmt: /* empty */ + * later regardless of whether it comes from the 'prompt' in + * mainmenu_stmt or here + */ +- menu_add_prompt(P_MENU, strdup("Linux Kernel Configuration"), NULL); ++ menu_add_prompt(P_MENU, xstrdup("Linux Kernel Configuration"), NULL); + }; + + +@@ -276,6 +276,7 @@ choice: T_CHOICE word_opt T_EOL + sym->flags |= SYMBOL_AUTO; + menu_add_entry(sym); + menu_add_expr(P_CHOICE, NULL, NULL); ++ free($2); + printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); + }; + +diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh +index c0d129d..be56a11 100755 +--- a/scripts/link-vmlinux.sh ++++ b/scripts/link-vmlinux.sh +@@ -246,7 +246,7 @@ else + fi; + + # final build of init/ +-${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init GCC_PLUGINS_CFLAGS="${GCC_PLUGINS_CFLAGS}" ++${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init + + archive_builtin + +diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c +index 6f9e4ce..9bb0a7f 100644 +--- a/security/integrity/digsig.c ++++ b/security/integrity/digsig.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + +diff --git a/security/keys/big_key.c b/security/keys/big_key.c +index 929e149..fa728f6 100644 +--- a/security/keys/big_key.c ++++ b/security/keys/big_key.c +@@ -22,6 +22,13 @@ + #include + #include + ++struct big_key_buf { ++ unsigned int nr_pages; ++ void *virt; ++ struct scatterlist *sg; ++ struct page *pages[]; ++}; ++ + /* + * Layout of key payload words. + */ +@@ -91,10 +98,9 @@ static DEFINE_MUTEX(big_key_aead_lock); + /* + * Encrypt/decrypt big_key data + */ +-static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) ++static int big_key_crypt(enum big_key_op op, struct big_key_buf *buf, size_t datalen, u8 *key) + { + int ret; +- struct scatterlist sgio; + struct aead_request *aead_req; + /* We always use a zero nonce. The reason we can get away with this is + * because we're using a different randomly generated key for every +@@ -109,8 +115,7 @@ static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) + return -ENOMEM; + + memset(zero_nonce, 0, sizeof(zero_nonce)); +- sg_init_one(&sgio, data, datalen + (op == BIG_KEY_ENC ? ENC_AUTHTAG_SIZE : 0)); +- aead_request_set_crypt(aead_req, &sgio, &sgio, datalen, zero_nonce); ++ aead_request_set_crypt(aead_req, buf->sg, buf->sg, datalen, zero_nonce); + aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); + aead_request_set_ad(aead_req, 0); + +@@ -130,21 +135,81 @@ static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) + } + + /* ++ * Free up the buffer. ++ */ ++static void big_key_free_buffer(struct big_key_buf *buf) ++{ ++ unsigned int i; ++ ++ if (buf->virt) { ++ memset(buf->virt, 0, buf->nr_pages * PAGE_SIZE); ++ vunmap(buf->virt); ++ } ++ ++ for (i = 0; i < buf->nr_pages; i++) ++ if (buf->pages[i]) ++ __free_page(buf->pages[i]); ++ ++ kfree(buf); ++} ++ ++/* ++ * Allocate a buffer consisting of a set of pages with a virtual mapping ++ * applied over them. ++ */ ++static void *big_key_alloc_buffer(size_t len) ++{ ++ struct big_key_buf *buf; ++ unsigned int npg = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; ++ unsigned int i, l; ++ ++ buf = kzalloc(sizeof(struct big_key_buf) + ++ sizeof(struct page) * npg + ++ sizeof(struct scatterlist) * npg, ++ GFP_KERNEL); ++ if (!buf) ++ return NULL; ++ ++ buf->nr_pages = npg; ++ buf->sg = (void *)(buf->pages + npg); ++ sg_init_table(buf->sg, npg); ++ ++ for (i = 0; i < buf->nr_pages; i++) { ++ buf->pages[i] = alloc_page(GFP_KERNEL); ++ if (!buf->pages[i]) ++ goto nomem; ++ ++ l = min_t(size_t, len, PAGE_SIZE); ++ sg_set_page(&buf->sg[i], buf->pages[i], l, 0); ++ len -= l; ++ } ++ ++ buf->virt = vmap(buf->pages, buf->nr_pages, VM_MAP, PAGE_KERNEL); ++ if (!buf->virt) ++ goto nomem; ++ ++ return buf; ++ ++nomem: ++ big_key_free_buffer(buf); ++ return NULL; ++} ++ ++/* + * Preparse a big key + */ + int big_key_preparse(struct key_preparsed_payload *prep) + { ++ struct big_key_buf *buf; + struct path *path = (struct path *)&prep->payload.data[big_key_path]; + struct file *file; + u8 *enckey; +- u8 *data = NULL; + ssize_t written; +- size_t datalen = prep->datalen; ++ size_t datalen = prep->datalen, enclen = datalen + ENC_AUTHTAG_SIZE; + int ret; + +- ret = -EINVAL; + if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data) +- goto error; ++ return -EINVAL; + + /* Set an arbitrary quota */ + prep->quotalen = 16; +@@ -157,13 +222,12 @@ int big_key_preparse(struct key_preparsed_payload *prep) + * + * File content is stored encrypted with randomly generated key. + */ +- size_t enclen = datalen + ENC_AUTHTAG_SIZE; + loff_t pos = 0; + +- data = kmalloc(enclen, GFP_KERNEL); +- if (!data) ++ buf = big_key_alloc_buffer(enclen); ++ if (!buf) + return -ENOMEM; +- memcpy(data, prep->data, datalen); ++ memcpy(buf->virt, prep->data, datalen); + + /* generate random key */ + enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL); +@@ -176,7 +240,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) + goto err_enckey; + + /* encrypt aligned data */ +- ret = big_key_crypt(BIG_KEY_ENC, data, datalen, enckey); ++ ret = big_key_crypt(BIG_KEY_ENC, buf, datalen, enckey); + if (ret) + goto err_enckey; + +@@ -187,7 +251,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) + goto err_enckey; + } + +- written = kernel_write(file, data, enclen, &pos); ++ written = kernel_write(file, buf->virt, enclen, &pos); + if (written != enclen) { + ret = written; + if (written >= 0) +@@ -202,7 +266,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) + *path = file->f_path; + path_get(path); + fput(file); +- kzfree(data); ++ big_key_free_buffer(buf); + } else { + /* Just store the data in a buffer */ + void *data = kmalloc(datalen, GFP_KERNEL); +@@ -220,7 +284,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) + err_enckey: + kzfree(enckey); + error: +- kzfree(data); ++ big_key_free_buffer(buf); + return ret; + } + +@@ -298,15 +362,15 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen) + return datalen; + + if (datalen > BIG_KEY_FILE_THRESHOLD) { ++ struct big_key_buf *buf; + struct path *path = (struct path *)&key->payload.data[big_key_path]; + struct file *file; +- u8 *data; + u8 *enckey = (u8 *)key->payload.data[big_key_data]; + size_t enclen = datalen + ENC_AUTHTAG_SIZE; + loff_t pos = 0; + +- data = kmalloc(enclen, GFP_KERNEL); +- if (!data) ++ buf = big_key_alloc_buffer(enclen); ++ if (!buf) + return -ENOMEM; + + file = dentry_open(path, O_RDONLY, current_cred()); +@@ -316,26 +380,26 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen) + } + + /* read file to kernel and decrypt */ +- ret = kernel_read(file, data, enclen, &pos); ++ ret = kernel_read(file, buf->virt, enclen, &pos); + if (ret >= 0 && ret != enclen) { + ret = -EIO; + goto err_fput; + } + +- ret = big_key_crypt(BIG_KEY_DEC, data, enclen, enckey); ++ ret = big_key_crypt(BIG_KEY_DEC, buf, enclen, enckey); + if (ret) + goto err_fput; + + ret = datalen; + + /* copy decrypted data to user */ +- if (copy_to_user(buffer, data, datalen) != 0) ++ if (copy_to_user(buffer, buf->virt, datalen) != 0) + ret = -EFAULT; + + err_fput: + fput(file); + error: +- kzfree(data); ++ big_key_free_buffer(buf); + } else { + ret = datalen; + if (copy_to_user(buffer, key->payload.data[big_key_data], +diff --git a/sound/ac97/Kconfig b/sound/ac97/Kconfig +index f8a64e1..baa5f8e 100644 +--- a/sound/ac97/Kconfig ++++ b/sound/ac97/Kconfig +@@ -5,7 +5,6 @@ + + config AC97_BUS_NEW + tristate +- select AC97 + help + This is the new AC97 bus type, successor of AC97_BUS. The ported + drivers which benefit from the AC97 automatic probing should "select" +diff --git a/sound/core/control.c b/sound/core/control.c +index 0b3026d..8a77620 100644 +--- a/sound/core/control.c ++++ b/sound/core/control.c +@@ -889,7 +889,7 @@ static int snd_ctl_elem_read(struct snd_card *card, + + index_offset = snd_ctl_get_ioff(kctl, &control->id); + vd = &kctl->vd[index_offset]; +- if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && kctl->get == NULL) ++ if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) + return -EPERM; + + snd_ctl_build_ioff(&control->id, kctl, index_offset); +diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c +index 60db327..918338d 100644 +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -910,7 +910,8 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop) + static int snd_seq_client_enqueue_event(struct snd_seq_client *client, + struct snd_seq_event *event, + struct file *file, int blocking, +- int atomic, int hop) ++ int atomic, int hop, ++ struct mutex *mutexp) + { + struct snd_seq_event_cell *cell; + int err; +@@ -948,7 +949,8 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client, + return -ENXIO; /* queue is not allocated */ + + /* allocate an event cell */ +- err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, file); ++ err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, ++ file, mutexp); + if (err < 0) + return err; + +@@ -1003,7 +1005,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, + { + struct snd_seq_client *client = file->private_data; + int written = 0, len; +- int err = -EINVAL; ++ int err; + struct snd_seq_event event; + + if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT)) +@@ -1017,12 +1019,15 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, + return -ENXIO; + + /* allocate the pool now if the pool is not allocated yet */ ++ mutex_lock(&client->ioctl_mutex); + if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) { +- if (snd_seq_pool_init(client->pool) < 0) +- return -ENOMEM; ++ err = snd_seq_pool_init(client->pool); ++ if (err < 0) ++ goto out; + } + + /* only process whole events */ ++ err = -EINVAL; + while (count >= sizeof(struct snd_seq_event)) { + /* Read in the event header from the user */ + len = sizeof(event); +@@ -1069,7 +1074,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, + /* ok, enqueue it */ + err = snd_seq_client_enqueue_event(client, &event, file, + !(file->f_flags & O_NONBLOCK), +- 0, 0); ++ 0, 0, &client->ioctl_mutex); + if (err < 0) + break; + +@@ -1080,6 +1085,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, + written += len; + } + ++ out: ++ mutex_unlock(&client->ioctl_mutex); + return written ? written : err; + } + +@@ -1834,9 +1841,11 @@ static int snd_seq_ioctl_set_client_pool(struct snd_seq_client *client, + (! snd_seq_write_pool_allocated(client) || + info->output_pool != client->pool->size)) { + if (snd_seq_write_pool_allocated(client)) { ++ /* is the pool in use? */ ++ if (atomic_read(&client->pool->counter)) ++ return -EBUSY; + /* remove all existing cells */ + snd_seq_pool_mark_closing(client->pool); +- snd_seq_queue_client_leave_cells(client->number); + snd_seq_pool_done(client->pool); + } + client->pool->size = info->output_pool; +@@ -2256,7 +2265,8 @@ static int kernel_client_enqueue(int client, struct snd_seq_event *ev, + if (! cptr->accept_output) + result = -EPERM; + else /* send it */ +- result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, atomic, hop); ++ result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, ++ atomic, hop, NULL); + + snd_seq_client_unlock(cptr); + return result; +diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c +index a8c2822..72c0302 100644 +--- a/sound/core/seq/seq_fifo.c ++++ b/sound/core/seq/seq_fifo.c +@@ -125,7 +125,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, + return -EINVAL; + + snd_use_lock_use(&f->use_lock); +- err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL); /* always non-blocking */ ++ err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL, NULL); /* always non-blocking */ + if (err < 0) { + if ((err == -ENOMEM) || (err == -EAGAIN)) + atomic_inc(&f->overflow); +diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c +index f763682..ab1112e9 100644 +--- a/sound/core/seq/seq_memory.c ++++ b/sound/core/seq/seq_memory.c +@@ -220,7 +220,8 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell) + */ + static int snd_seq_cell_alloc(struct snd_seq_pool *pool, + struct snd_seq_event_cell **cellp, +- int nonblock, struct file *file) ++ int nonblock, struct file *file, ++ struct mutex *mutexp) + { + struct snd_seq_event_cell *cell; + unsigned long flags; +@@ -244,7 +245,11 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool, + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&pool->output_sleep, &wait); + spin_unlock_irq(&pool->lock); ++ if (mutexp) ++ mutex_unlock(mutexp); + schedule(); ++ if (mutexp) ++ mutex_lock(mutexp); + spin_lock_irq(&pool->lock); + remove_wait_queue(&pool->output_sleep, &wait); + /* interrupted? */ +@@ -287,7 +292,7 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool, + */ + int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, + struct snd_seq_event_cell **cellp, int nonblock, +- struct file *file) ++ struct file *file, struct mutex *mutexp) + { + int ncells, err; + unsigned int extlen; +@@ -304,7 +309,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, + if (ncells >= pool->total_elements) + return -ENOMEM; + +- err = snd_seq_cell_alloc(pool, &cell, nonblock, file); ++ err = snd_seq_cell_alloc(pool, &cell, nonblock, file, mutexp); + if (err < 0) + return err; + +@@ -330,7 +335,8 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, + int size = sizeof(struct snd_seq_event); + if (len < size) + size = len; +- err = snd_seq_cell_alloc(pool, &tmp, nonblock, file); ++ err = snd_seq_cell_alloc(pool, &tmp, nonblock, file, ++ mutexp); + if (err < 0) + goto __error; + if (cell->event.data.ext.ptr == NULL) +diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h +index 32f959c..3abe306 100644 +--- a/sound/core/seq/seq_memory.h ++++ b/sound/core/seq/seq_memory.h +@@ -66,7 +66,8 @@ struct snd_seq_pool { + void snd_seq_cell_free(struct snd_seq_event_cell *cell); + + int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, +- struct snd_seq_event_cell **cellp, int nonblock, struct file *file); ++ struct snd_seq_event_cell **cellp, int nonblock, ++ struct file *file, struct mutex *mutexp); + + /* return number of unused (free) cells */ + static inline int snd_seq_unused_cells(struct snd_seq_pool *pool) +diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c +index c71dcac..96143df 100644 +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -181,7 +181,7 @@ static const struct kernel_param_ops param_ops_xint = { + }; + #define param_check_xint param_check_int + +-static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; ++static int power_save = -1; + module_param(power_save, xint, 0644); + MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " + "(in second, 0 = disable)."); +@@ -2186,6 +2186,24 @@ static int azx_probe(struct pci_dev *pci, + return err; + } + ++#ifdef CONFIG_PM ++/* On some boards setting power_save to a non 0 value leads to clicking / ++ * popping sounds when ever we enter/leave powersaving mode. Ideally we would ++ * figure out how to avoid these sounds, but that is not always feasible. ++ * So we keep a list of devices where we disable powersaving as its known ++ * to causes problems on these devices. ++ */ ++static struct snd_pci_quirk power_save_blacklist[] = { ++ /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ ++ SND_PCI_QUIRK(0x1849, 0x0c0c, "Asrock B85M-ITX", 0), ++ /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ ++ SND_PCI_QUIRK(0x1043, 0x8733, "Asus Prime X370-Pro", 0), ++ /* https://bugzilla.kernel.org/show_bug.cgi?id=198611 */ ++ SND_PCI_QUIRK(0x17aa, 0x2227, "Lenovo X1 Carbon 3rd Gen", 0), ++ {} ++}; ++#endif /* CONFIG_PM */ ++ + /* number of codec slots for each chipset: 0 = default slots (i.e. 4) */ + static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = { + [AZX_DRIVER_NVIDIA] = 8, +@@ -2198,6 +2216,7 @@ static int azx_probe_continue(struct azx *chip) + struct hdac_bus *bus = azx_bus(chip); + struct pci_dev *pci = chip->pci; + int dev = chip->dev_index; ++ int val; + int err; + + hda->probe_continued = 1; +@@ -2278,7 +2297,22 @@ static int azx_probe_continue(struct azx *chip) + + chip->running = 1; + azx_add_card_list(chip); +- snd_hda_set_power_save(&chip->bus, power_save * 1000); ++ ++ val = power_save; ++#ifdef CONFIG_PM ++ if (val == -1) { ++ const struct snd_pci_quirk *q; ++ ++ val = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; ++ q = snd_pci_quirk_lookup(chip->pci, power_save_blacklist); ++ if (q && val) { ++ dev_info(chip->card->dev, "device %04x:%04x is on the power_save blacklist, forcing power_save to 0\n", ++ q->subvendor, q->subdevice); ++ val = 0; ++ } ++ } ++#endif /* CONFIG_PM */ ++ snd_hda_set_power_save(&chip->bus, val * 1000); + if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo) + pm_runtime_put_autosuspend(&pci->dev); + +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index 37e1cf8..5b4dbce 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -957,6 +957,8 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { + SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC), + SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC), + SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK), ++ SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK), ++ SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), + SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), + SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO), +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 2347588..9af301c 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -3465,6 +3465,19 @@ static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec, + spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; + } + ++static void alc269_fixup_pincfg_U7x7_headset_mic(struct hda_codec *codec, ++ const struct hda_fixup *fix, ++ int action) ++{ ++ unsigned int cfg_headphone = snd_hda_codec_get_pincfg(codec, 0x21); ++ unsigned int cfg_headset_mic = snd_hda_codec_get_pincfg(codec, 0x19); ++ ++ if (cfg_headphone && cfg_headset_mic == 0x411111f0) ++ snd_hda_codec_set_pincfg(codec, 0x19, ++ (cfg_headphone & ~AC_DEFCFG_DEVICE) | ++ (AC_JACK_MIC_IN << AC_DEFCFG_DEVICE_SHIFT)); ++} ++ + static void alc269_fixup_hweq(struct hda_codec *codec, + const struct hda_fixup *fix, int action) + { +@@ -4972,6 +4985,29 @@ static void alc_fixup_tpt440_dock(struct hda_codec *codec, + } + } + ++static void alc_fixup_tpt470_dock(struct hda_codec *codec, ++ const struct hda_fixup *fix, int action) ++{ ++ static const struct hda_pintbl pincfgs[] = { ++ { 0x17, 0x21211010 }, /* dock headphone */ ++ { 0x19, 0x21a11010 }, /* dock mic */ ++ { } ++ }; ++ struct alc_spec *spec = codec->spec; ++ ++ if (action == HDA_FIXUP_ACT_PRE_PROBE) { ++ spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; ++ snd_hda_apply_pincfgs(codec, pincfgs); ++ } else if (action == HDA_FIXUP_ACT_INIT) { ++ /* Enable DOCK device */ ++ snd_hda_codec_write(codec, 0x17, 0, ++ AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0); ++ /* Enable DOCK device */ ++ snd_hda_codec_write(codec, 0x19, 0, ++ AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0); ++ } ++} ++ + static void alc_shutup_dell_xps13(struct hda_codec *codec) + { + struct alc_spec *spec = codec->spec; +@@ -5238,6 +5274,16 @@ static void alc298_fixup_speaker_volume(struct hda_codec *codec, + } + } + ++/* disable DAC3 (0x06) selection on NID 0x17 as it has no volume amp control */ ++static void alc295_fixup_disable_dac3(struct hda_codec *codec, ++ const struct hda_fixup *fix, int action) ++{ ++ if (action == HDA_FIXUP_ACT_PRE_PROBE) { ++ hda_nid_t conn[2] = { 0x02, 0x03 }; ++ snd_hda_override_conn_list(codec, 0x17, 2, conn); ++ } ++} ++ + /* Hook to update amp GPIO4 for automute */ + static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec, + struct hda_jack_callback *jack) +@@ -5351,6 +5397,7 @@ enum { + ALC269_FIXUP_LIFEBOOK_EXTMIC, + ALC269_FIXUP_LIFEBOOK_HP_PIN, + ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT, ++ ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC, + ALC269_FIXUP_AMIC, + ALC269_FIXUP_DMIC, + ALC269VB_FIXUP_AMIC, +@@ -5429,6 +5476,7 @@ enum { + ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, + ALC255_FIXUP_DELL_SPK_NOISE, + ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, ++ ALC295_FIXUP_DISABLE_DAC3, + ALC280_FIXUP_HP_HEADSET_MIC, + ALC221_FIXUP_HP_FRONT_MIC, + ALC292_FIXUP_TPT460, +@@ -5443,9 +5491,12 @@ enum { + ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE, + ALC233_FIXUP_LENOVO_MULTI_CODECS, + ALC294_FIXUP_LENOVO_MIC_LOCATION, ++ ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE, + ALC700_FIXUP_INTEL_REFERENCE, + ALC274_FIXUP_DELL_BIND_DACS, + ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, ++ ALC298_FIXUP_TPT470_DOCK, ++ ALC255_FIXUP_DUMMY_LINEOUT_VERB, + }; + + static const struct hda_fixup alc269_fixups[] = { +@@ -5556,6 +5607,10 @@ static const struct hda_fixup alc269_fixups[] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_pincfg_no_hp_to_lineout, + }, ++ [ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc269_fixup_pincfg_U7x7_headset_mic, ++ }, + [ALC269_FIXUP_AMIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { +@@ -6156,6 +6211,10 @@ static const struct hda_fixup alc269_fixups[] = { + .chained = true, + .chain_id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE, + }, ++ [ALC295_FIXUP_DISABLE_DAC3] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc295_fixup_disable_dac3, ++ }, + [ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { +@@ -6241,6 +6300,18 @@ static const struct hda_fixup alc269_fixups[] = { + { } + }, + }, ++ [ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE] = { ++ .type = HDA_FIXUP_PINS, ++ .v.pins = (const struct hda_pintbl[]) { ++ { 0x16, 0x0101102f }, /* Rear Headset HP */ ++ { 0x19, 0x02a1913c }, /* use as Front headset mic, without its own jack detect */ ++ { 0x1a, 0x01a19030 }, /* Rear Headset MIC */ ++ { 0x1b, 0x02011020 }, ++ { } ++ }, ++ .chained = true, ++ .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC ++ }, + [ALC700_FIXUP_INTEL_REFERENCE] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { +@@ -6271,6 +6342,21 @@ static const struct hda_fixup alc269_fixups[] = { + .chained = true, + .chain_id = ALC274_FIXUP_DELL_BIND_DACS + }, ++ [ALC298_FIXUP_TPT470_DOCK] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc_fixup_tpt470_dock, ++ .chained = true, ++ .chain_id = ALC293_FIXUP_LENOVO_SPK_NOISE ++ }, ++ [ALC255_FIXUP_DUMMY_LINEOUT_VERB] = { ++ .type = HDA_FIXUP_PINS, ++ .v.pins = (const struct hda_pintbl[]) { ++ { 0x14, 0x0201101f }, ++ { } ++ }, ++ .chained = true, ++ .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE ++ }, + }; + + static const struct snd_pci_quirk alc269_fixup_tbl[] = { +@@ -6319,8 +6405,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE), + SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), + SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME), ++ SND_PCI_QUIRK(0x1028, 0x07b0, "Dell Precision 7520", ALC295_FIXUP_DISABLE_DAC3), + SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER), ++ SND_PCI_QUIRK(0x1028, 0x080c, "Dell WYSE", ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x082a, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), ++ SND_PCI_QUIRK(0x1028, 0x084b, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), ++ SND_PCI_QUIRK(0x1028, 0x084e, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), ++ SND_PCI_QUIRK(0x1028, 0x0873, "Dell Precision 3930", ALC255_FIXUP_DUMMY_LINEOUT_VERB), + SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), +@@ -6422,6 +6513,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x10cf, 0x159f, "Lifebook E780", ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT), + SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN), + SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN), ++ SND_PCI_QUIRK(0x10cf, 0x1629, "Lifebook U7x7", ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC), + SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), + SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE), + SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC), +@@ -6450,8 +6542,18 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x17aa, 0x2218, "Thinkpad X1 Carbon 2nd", ALC292_FIXUP_TPT440_DOCK), + SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK), + SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK), ++ SND_PCI_QUIRK(0x17aa, 0x222d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), ++ SND_PCI_QUIRK(0x17aa, 0x222e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), + SND_PCI_QUIRK(0x17aa, 0x2231, "Thinkpad T560", ALC292_FIXUP_TPT460), + SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC292_FIXUP_TPT460), ++ SND_PCI_QUIRK(0x17aa, 0x2245, "Thinkpad T470", ALC298_FIXUP_TPT470_DOCK), ++ SND_PCI_QUIRK(0x17aa, 0x2246, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), ++ SND_PCI_QUIRK(0x17aa, 0x2247, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), ++ SND_PCI_QUIRK(0x17aa, 0x2249, "Thinkpad", ALC292_FIXUP_TPT460), ++ SND_PCI_QUIRK(0x17aa, 0x224b, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), ++ SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), ++ SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), ++ SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), + SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), + SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), +@@ -6472,7 +6574,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x17aa, 0x5050, "Thinkpad T560p", ALC292_FIXUP_TPT460), + SND_PCI_QUIRK(0x17aa, 0x5051, "Thinkpad L460", ALC292_FIXUP_TPT460), + SND_PCI_QUIRK(0x17aa, 0x5053, "Thinkpad T460", ALC292_FIXUP_TPT460), ++ SND_PCI_QUIRK(0x17aa, 0x505d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), ++ SND_PCI_QUIRK(0x17aa, 0x505f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), ++ SND_PCI_QUIRK(0x17aa, 0x5062, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), + SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), ++ SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), ++ SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), + SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), + SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), + SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ +@@ -6735,6 +6842,11 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { + {0x14, 0x90170110}, + {0x21, 0x02211020}), + SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, ++ {0x12, 0x90a60130}, ++ {0x14, 0x90170110}, ++ {0x14, 0x01011020}, ++ {0x21, 0x0221101f}), ++ SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC256_STANDARD_PINS), + SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC, + {0x14, 0x90170110}, +@@ -6803,6 +6915,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { + {0x12, 0x90a60120}, + {0x14, 0x90170110}, + {0x21, 0x0321101f}), ++ SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, ++ {0x12, 0xb7a60130}, ++ {0x14, 0x90170110}, ++ {0x21, 0x04211020}), + SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + ALC290_STANDARD_PINS, + {0x15, 0x04211040}, +diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c +index 9afb8ab..06b2262 100644 +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -347,17 +347,20 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, + int validx, int *value_ret) + { + struct snd_usb_audio *chip = cval->head.mixer->chip; +- unsigned char buf[4 + 3 * sizeof(__u32)]; /* enough space for one range */ ++ /* enough space for one range */ ++ unsigned char buf[sizeof(__u16) + 3 * sizeof(__u32)]; + unsigned char *val; +- int idx = 0, ret, size; ++ int idx = 0, ret, val_size, size; + __u8 bRequest; + ++ val_size = uac2_ctl_value_size(cval->val_type); ++ + if (request == UAC_GET_CUR) { + bRequest = UAC2_CS_CUR; +- size = uac2_ctl_value_size(cval->val_type); ++ size = val_size; + } else { + bRequest = UAC2_CS_RANGE; +- size = sizeof(buf); ++ size = sizeof(__u16) + 3 * val_size; + } + + memset(buf, 0, sizeof(buf)); +@@ -390,16 +393,17 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, + val = buf + sizeof(__u16); + break; + case UAC_GET_MAX: +- val = buf + sizeof(__u16) * 2; ++ val = buf + sizeof(__u16) + val_size; + break; + case UAC_GET_RES: +- val = buf + sizeof(__u16) * 3; ++ val = buf + sizeof(__u16) + val_size * 2; + break; + default: + return -EINVAL; + } + +- *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(val, sizeof(__u16))); ++ *value_ret = convert_signed_value(cval, ++ snd_usb_combine_bytes(val, val_size)); + + return 0; + } +diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c +index b9c9a19..3cbfae6 100644 +--- a/sound/usb/pcm.c ++++ b/sound/usb/pcm.c +@@ -357,6 +357,15 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, + + alts = &iface->altsetting[1]; + goto add_sync_ep; ++ case USB_ID(0x1397, 0x0002): ++ ep = 0x81; ++ iface = usb_ifnum_to_if(dev, 1); ++ ++ if (!iface || iface->num_altsetting == 0) ++ return -EINVAL; ++ ++ alts = &iface->altsetting[1]; ++ goto add_sync_ep; + + } + if (attr == USB_ENDPOINT_SYNC_ASYNC && +diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h +index 5025204..754e632 100644 +--- a/sound/usb/quirks-table.h ++++ b/sound/usb/quirks-table.h +@@ -3325,4 +3325,51 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), + } + }, + ++{ ++ /* ++ * Bower's & Wilkins PX headphones only support the 48 kHz sample rate ++ * even though it advertises more. The capture interface doesn't work ++ * even on windows. ++ */ ++ USB_DEVICE(0x19b5, 0x0021), ++ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ .ifnum = QUIRK_ANY_INTERFACE, ++ .type = QUIRK_COMPOSITE, ++ .data = (const struct snd_usb_audio_quirk[]) { ++ { ++ .ifnum = 0, ++ .type = QUIRK_AUDIO_STANDARD_MIXER, ++ }, ++ /* Capture */ ++ { ++ .ifnum = 1, ++ .type = QUIRK_IGNORE_INTERFACE, ++ }, ++ /* Playback */ ++ { ++ .ifnum = 2, ++ .type = QUIRK_AUDIO_FIXED_ENDPOINT, ++ .data = &(const struct audioformat) { ++ .formats = SNDRV_PCM_FMTBIT_S16_LE, ++ .channels = 2, ++ .iface = 2, ++ .altsetting = 1, ++ .altset_idx = 1, ++ .attributes = UAC_EP_CS_ATTR_FILL_MAX | ++ UAC_EP_CS_ATTR_SAMPLE_RATE, ++ .endpoint = 0x03, ++ .ep_attr = USB_ENDPOINT_XFER_ISOC, ++ .rates = SNDRV_PCM_RATE_48000, ++ .rate_min = 48000, ++ .rate_max = 48000, ++ .nr_rates = 1, ++ .rate_table = (unsigned int[]) { ++ 48000 ++ } ++ } ++ }, ++ } ++ } ++}, ++ + #undef USB_DEVICE_VENDOR_SPEC +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index a66ef57..ea8f3de 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -1363,8 +1363,11 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, + return SNDRV_PCM_FMTBIT_DSD_U32_BE; + break; + +- /* Amanero Combo384 USB interface with native DSD support */ +- case USB_ID(0x16d0, 0x071a): ++ /* Amanero Combo384 USB based DACs with native DSD support */ ++ case USB_ID(0x16d0, 0x071a): /* Amanero - Combo384 */ ++ case USB_ID(0x2ab6, 0x0004): /* T+A DAC8DSD-V2.0, MP1000E-V2.0, MP2000R-V2.0, MP2500R-V2.0, MP3100HV-V2.0 */ ++ case USB_ID(0x2ab6, 0x0005): /* T+A USB HD Audio 1 */ ++ case USB_ID(0x2ab6, 0x0006): /* T+A USB HD Audio 2 */ + if (fp->altsetting == 2) { + switch (le16_to_cpu(chip->dev->descriptor.bcdDevice)) { + case 0x199: +diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c +index a095150..4ed9d0c 100644 +--- a/sound/x86/intel_hdmi_audio.c ++++ b/sound/x86/intel_hdmi_audio.c +@@ -50,6 +50,7 @@ + /*standard module options for ALSA. This module supports only one card*/ + static int hdmi_card_index = SNDRV_DEFAULT_IDX1; + static char *hdmi_card_id = SNDRV_DEFAULT_STR1; ++static bool single_port; + + module_param_named(index, hdmi_card_index, int, 0444); + MODULE_PARM_DESC(index, +@@ -57,6 +58,9 @@ MODULE_PARM_DESC(index, + module_param_named(id, hdmi_card_id, charp, 0444); + MODULE_PARM_DESC(id, + "ID string for INTEL Intel HDMI Audio controller."); ++module_param(single_port, bool, 0444); ++MODULE_PARM_DESC(single_port, ++ "Single-port mode (for compatibility)"); + + /* + * ELD SA bits in the CEA Speaker Allocation data block +@@ -1579,7 +1583,11 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) + static void notify_audio_lpe(struct platform_device *pdev, int port) + { + struct snd_intelhad_card *card_ctx = platform_get_drvdata(pdev); +- struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port]; ++ struct snd_intelhad *ctx; ++ ++ ctx = &card_ctx->pcm_ctx[single_port ? 0 : port]; ++ if (single_port) ++ ctx->port = port; + + schedule_work(&ctx->hdmi_audio_wq); + } +@@ -1743,6 +1751,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) + { + struct snd_card *card; + struct snd_intelhad_card *card_ctx; ++ struct snd_intelhad *ctx; + struct snd_pcm *pcm; + struct intel_hdmi_lpe_audio_pdata *pdata; + int irq; +@@ -1787,6 +1796,21 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, card_ctx); + ++ card_ctx->num_pipes = pdata->num_pipes; ++ card_ctx->num_ports = single_port ? 1 : pdata->num_ports; ++ ++ for_each_port(card_ctx, port) { ++ ctx = &card_ctx->pcm_ctx[port]; ++ ctx->card_ctx = card_ctx; ++ ctx->dev = card_ctx->dev; ++ ctx->port = single_port ? -1 : port; ++ ctx->pipe = -1; ++ ++ spin_lock_init(&ctx->had_spinlock); ++ mutex_init(&ctx->mutex); ++ INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq); ++ } ++ + dev_dbg(&pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n", + __func__, (unsigned int)res_mmio->start, + (unsigned int)res_mmio->end); +@@ -1816,19 +1840,12 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) + init_channel_allocations(); + + card_ctx->num_pipes = pdata->num_pipes; +- card_ctx->num_ports = pdata->num_ports; ++ card_ctx->num_ports = single_port ? 1 : pdata->num_ports; + + for_each_port(card_ctx, port) { +- struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port]; + int i; + +- ctx->card_ctx = card_ctx; +- ctx->dev = card_ctx->dev; +- ctx->port = port; +- ctx->pipe = -1; +- +- INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq); +- ++ ctx = &card_ctx->pcm_ctx[port]; + ret = snd_pcm_new(card, INTEL_HAD, port, MAX_PB_STREAMS, + MAX_CAP_STREAMS, &pcm); + if (ret) +diff --git a/tools/arch/powerpc/include/uapi/asm/kvm.h b/tools/arch/powerpc/include/uapi/asm/kvm.h +index 637b726..833ed9a 100644 +--- a/tools/arch/powerpc/include/uapi/asm/kvm.h ++++ b/tools/arch/powerpc/include/uapi/asm/kvm.h +@@ -632,6 +632,8 @@ struct kvm_ppc_cpu_char { + #define KVM_REG_PPC_TIDR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbc) + #define KVM_REG_PPC_PSSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbd) + ++#define KVM_REG_PPC_DEC_EXPIRY (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbe) ++ + /* Transactional Memory checkpointed state: + * This is all GPRs, all VSX regs and a subset of SPRs + */ +diff --git a/tools/arch/s390/include/uapi/asm/unistd.h b/tools/arch/s390/include/uapi/asm/unistd.h +deleted file mode 100644 +index 7251209..0000000 +--- a/tools/arch/s390/include/uapi/asm/unistd.h ++++ /dev/null +@@ -1,412 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +-/* +- * S390 version +- * +- * Derived from "include/asm-i386/unistd.h" +- */ +- +-#ifndef _UAPI_ASM_S390_UNISTD_H_ +-#define _UAPI_ASM_S390_UNISTD_H_ +- +-/* +- * This file contains the system call numbers. +- */ +- +-#define __NR_exit 1 +-#define __NR_fork 2 +-#define __NR_read 3 +-#define __NR_write 4 +-#define __NR_open 5 +-#define __NR_close 6 +-#define __NR_restart_syscall 7 +-#define __NR_creat 8 +-#define __NR_link 9 +-#define __NR_unlink 10 +-#define __NR_execve 11 +-#define __NR_chdir 12 +-#define __NR_mknod 14 +-#define __NR_chmod 15 +-#define __NR_lseek 19 +-#define __NR_getpid 20 +-#define __NR_mount 21 +-#define __NR_umount 22 +-#define __NR_ptrace 26 +-#define __NR_alarm 27 +-#define __NR_pause 29 +-#define __NR_utime 30 +-#define __NR_access 33 +-#define __NR_nice 34 +-#define __NR_sync 36 +-#define __NR_kill 37 +-#define __NR_rename 38 +-#define __NR_mkdir 39 +-#define __NR_rmdir 40 +-#define __NR_dup 41 +-#define __NR_pipe 42 +-#define __NR_times 43 +-#define __NR_brk 45 +-#define __NR_signal 48 +-#define __NR_acct 51 +-#define __NR_umount2 52 +-#define __NR_ioctl 54 +-#define __NR_fcntl 55 +-#define __NR_setpgid 57 +-#define __NR_umask 60 +-#define __NR_chroot 61 +-#define __NR_ustat 62 +-#define __NR_dup2 63 +-#define __NR_getppid 64 +-#define __NR_getpgrp 65 +-#define __NR_setsid 66 +-#define __NR_sigaction 67 +-#define __NR_sigsuspend 72 +-#define __NR_sigpending 73 +-#define __NR_sethostname 74 +-#define __NR_setrlimit 75 +-#define __NR_getrusage 77 +-#define __NR_gettimeofday 78 +-#define __NR_settimeofday 79 +-#define __NR_symlink 83 +-#define __NR_readlink 85 +-#define __NR_uselib 86 +-#define __NR_swapon 87 +-#define __NR_reboot 88 +-#define __NR_readdir 89 +-#define __NR_mmap 90 +-#define __NR_munmap 91 +-#define __NR_truncate 92 +-#define __NR_ftruncate 93 +-#define __NR_fchmod 94 +-#define __NR_getpriority 96 +-#define __NR_setpriority 97 +-#define __NR_statfs 99 +-#define __NR_fstatfs 100 +-#define __NR_socketcall 102 +-#define __NR_syslog 103 +-#define __NR_setitimer 104 +-#define __NR_getitimer 105 +-#define __NR_stat 106 +-#define __NR_lstat 107 +-#define __NR_fstat 108 +-#define __NR_lookup_dcookie 110 +-#define __NR_vhangup 111 +-#define __NR_idle 112 +-#define __NR_wait4 114 +-#define __NR_swapoff 115 +-#define __NR_sysinfo 116 +-#define __NR_ipc 117 +-#define __NR_fsync 118 +-#define __NR_sigreturn 119 +-#define __NR_clone 120 +-#define __NR_setdomainname 121 +-#define __NR_uname 122 +-#define __NR_adjtimex 124 +-#define __NR_mprotect 125 +-#define __NR_sigprocmask 126 +-#define __NR_create_module 127 +-#define __NR_init_module 128 +-#define __NR_delete_module 129 +-#define __NR_get_kernel_syms 130 +-#define __NR_quotactl 131 +-#define __NR_getpgid 132 +-#define __NR_fchdir 133 +-#define __NR_bdflush 134 +-#define __NR_sysfs 135 +-#define __NR_personality 136 +-#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ +-#define __NR_getdents 141 +-#define __NR_flock 143 +-#define __NR_msync 144 +-#define __NR_readv 145 +-#define __NR_writev 146 +-#define __NR_getsid 147 +-#define __NR_fdatasync 148 +-#define __NR__sysctl 149 +-#define __NR_mlock 150 +-#define __NR_munlock 151 +-#define __NR_mlockall 152 +-#define __NR_munlockall 153 +-#define __NR_sched_setparam 154 +-#define __NR_sched_getparam 155 +-#define __NR_sched_setscheduler 156 +-#define __NR_sched_getscheduler 157 +-#define __NR_sched_yield 158 +-#define __NR_sched_get_priority_max 159 +-#define __NR_sched_get_priority_min 160 +-#define __NR_sched_rr_get_interval 161 +-#define __NR_nanosleep 162 +-#define __NR_mremap 163 +-#define __NR_query_module 167 +-#define __NR_poll 168 +-#define __NR_nfsservctl 169 +-#define __NR_prctl 172 +-#define __NR_rt_sigreturn 173 +-#define __NR_rt_sigaction 174 +-#define __NR_rt_sigprocmask 175 +-#define __NR_rt_sigpending 176 +-#define __NR_rt_sigtimedwait 177 +-#define __NR_rt_sigqueueinfo 178 +-#define __NR_rt_sigsuspend 179 +-#define __NR_pread64 180 +-#define __NR_pwrite64 181 +-#define __NR_getcwd 183 +-#define __NR_capget 184 +-#define __NR_capset 185 +-#define __NR_sigaltstack 186 +-#define __NR_sendfile 187 +-#define __NR_getpmsg 188 +-#define __NR_putpmsg 189 +-#define __NR_vfork 190 +-#define __NR_pivot_root 217 +-#define __NR_mincore 218 +-#define __NR_madvise 219 +-#define __NR_getdents64 220 +-#define __NR_readahead 222 +-#define __NR_setxattr 224 +-#define __NR_lsetxattr 225 +-#define __NR_fsetxattr 226 +-#define __NR_getxattr 227 +-#define __NR_lgetxattr 228 +-#define __NR_fgetxattr 229 +-#define __NR_listxattr 230 +-#define __NR_llistxattr 231 +-#define __NR_flistxattr 232 +-#define __NR_removexattr 233 +-#define __NR_lremovexattr 234 +-#define __NR_fremovexattr 235 +-#define __NR_gettid 236 +-#define __NR_tkill 237 +-#define __NR_futex 238 +-#define __NR_sched_setaffinity 239 +-#define __NR_sched_getaffinity 240 +-#define __NR_tgkill 241 +-/* Number 242 is reserved for tux */ +-#define __NR_io_setup 243 +-#define __NR_io_destroy 244 +-#define __NR_io_getevents 245 +-#define __NR_io_submit 246 +-#define __NR_io_cancel 247 +-#define __NR_exit_group 248 +-#define __NR_epoll_create 249 +-#define __NR_epoll_ctl 250 +-#define __NR_epoll_wait 251 +-#define __NR_set_tid_address 252 +-#define __NR_fadvise64 253 +-#define __NR_timer_create 254 +-#define __NR_timer_settime 255 +-#define __NR_timer_gettime 256 +-#define __NR_timer_getoverrun 257 +-#define __NR_timer_delete 258 +-#define __NR_clock_settime 259 +-#define __NR_clock_gettime 260 +-#define __NR_clock_getres 261 +-#define __NR_clock_nanosleep 262 +-/* Number 263 is reserved for vserver */ +-#define __NR_statfs64 265 +-#define __NR_fstatfs64 266 +-#define __NR_remap_file_pages 267 +-#define __NR_mbind 268 +-#define __NR_get_mempolicy 269 +-#define __NR_set_mempolicy 270 +-#define __NR_mq_open 271 +-#define __NR_mq_unlink 272 +-#define __NR_mq_timedsend 273 +-#define __NR_mq_timedreceive 274 +-#define __NR_mq_notify 275 +-#define __NR_mq_getsetattr 276 +-#define __NR_kexec_load 277 +-#define __NR_add_key 278 +-#define __NR_request_key 279 +-#define __NR_keyctl 280 +-#define __NR_waitid 281 +-#define __NR_ioprio_set 282 +-#define __NR_ioprio_get 283 +-#define __NR_inotify_init 284 +-#define __NR_inotify_add_watch 285 +-#define __NR_inotify_rm_watch 286 +-#define __NR_migrate_pages 287 +-#define __NR_openat 288 +-#define __NR_mkdirat 289 +-#define __NR_mknodat 290 +-#define __NR_fchownat 291 +-#define __NR_futimesat 292 +-#define __NR_unlinkat 294 +-#define __NR_renameat 295 +-#define __NR_linkat 296 +-#define __NR_symlinkat 297 +-#define __NR_readlinkat 298 +-#define __NR_fchmodat 299 +-#define __NR_faccessat 300 +-#define __NR_pselect6 301 +-#define __NR_ppoll 302 +-#define __NR_unshare 303 +-#define __NR_set_robust_list 304 +-#define __NR_get_robust_list 305 +-#define __NR_splice 306 +-#define __NR_sync_file_range 307 +-#define __NR_tee 308 +-#define __NR_vmsplice 309 +-#define __NR_move_pages 310 +-#define __NR_getcpu 311 +-#define __NR_epoll_pwait 312 +-#define __NR_utimes 313 +-#define __NR_fallocate 314 +-#define __NR_utimensat 315 +-#define __NR_signalfd 316 +-#define __NR_timerfd 317 +-#define __NR_eventfd 318 +-#define __NR_timerfd_create 319 +-#define __NR_timerfd_settime 320 +-#define __NR_timerfd_gettime 321 +-#define __NR_signalfd4 322 +-#define __NR_eventfd2 323 +-#define __NR_inotify_init1 324 +-#define __NR_pipe2 325 +-#define __NR_dup3 326 +-#define __NR_epoll_create1 327 +-#define __NR_preadv 328 +-#define __NR_pwritev 329 +-#define __NR_rt_tgsigqueueinfo 330 +-#define __NR_perf_event_open 331 +-#define __NR_fanotify_init 332 +-#define __NR_fanotify_mark 333 +-#define __NR_prlimit64 334 +-#define __NR_name_to_handle_at 335 +-#define __NR_open_by_handle_at 336 +-#define __NR_clock_adjtime 337 +-#define __NR_syncfs 338 +-#define __NR_setns 339 +-#define __NR_process_vm_readv 340 +-#define __NR_process_vm_writev 341 +-#define __NR_s390_runtime_instr 342 +-#define __NR_kcmp 343 +-#define __NR_finit_module 344 +-#define __NR_sched_setattr 345 +-#define __NR_sched_getattr 346 +-#define __NR_renameat2 347 +-#define __NR_seccomp 348 +-#define __NR_getrandom 349 +-#define __NR_memfd_create 350 +-#define __NR_bpf 351 +-#define __NR_s390_pci_mmio_write 352 +-#define __NR_s390_pci_mmio_read 353 +-#define __NR_execveat 354 +-#define __NR_userfaultfd 355 +-#define __NR_membarrier 356 +-#define __NR_recvmmsg 357 +-#define __NR_sendmmsg 358 +-#define __NR_socket 359 +-#define __NR_socketpair 360 +-#define __NR_bind 361 +-#define __NR_connect 362 +-#define __NR_listen 363 +-#define __NR_accept4 364 +-#define __NR_getsockopt 365 +-#define __NR_setsockopt 366 +-#define __NR_getsockname 367 +-#define __NR_getpeername 368 +-#define __NR_sendto 369 +-#define __NR_sendmsg 370 +-#define __NR_recvfrom 371 +-#define __NR_recvmsg 372 +-#define __NR_shutdown 373 +-#define __NR_mlock2 374 +-#define __NR_copy_file_range 375 +-#define __NR_preadv2 376 +-#define __NR_pwritev2 377 +-#define __NR_s390_guarded_storage 378 +-#define __NR_statx 379 +-#define __NR_s390_sthyi 380 +-#define NR_syscalls 381 +- +-/* +- * There are some system calls that are not present on 64 bit, some +- * have a different name although they do the same (e.g. __NR_chown32 +- * is __NR_chown on 64 bit). +- */ +-#ifndef __s390x__ +- +-#define __NR_time 13 +-#define __NR_lchown 16 +-#define __NR_setuid 23 +-#define __NR_getuid 24 +-#define __NR_stime 25 +-#define __NR_setgid 46 +-#define __NR_getgid 47 +-#define __NR_geteuid 49 +-#define __NR_getegid 50 +-#define __NR_setreuid 70 +-#define __NR_setregid 71 +-#define __NR_getrlimit 76 +-#define __NR_getgroups 80 +-#define __NR_setgroups 81 +-#define __NR_fchown 95 +-#define __NR_ioperm 101 +-#define __NR_setfsuid 138 +-#define __NR_setfsgid 139 +-#define __NR__llseek 140 +-#define __NR__newselect 142 +-#define __NR_setresuid 164 +-#define __NR_getresuid 165 +-#define __NR_setresgid 170 +-#define __NR_getresgid 171 +-#define __NR_chown 182 +-#define __NR_ugetrlimit 191 /* SuS compliant getrlimit */ +-#define __NR_mmap2 192 +-#define __NR_truncate64 193 +-#define __NR_ftruncate64 194 +-#define __NR_stat64 195 +-#define __NR_lstat64 196 +-#define __NR_fstat64 197 +-#define __NR_lchown32 198 +-#define __NR_getuid32 199 +-#define __NR_getgid32 200 +-#define __NR_geteuid32 201 +-#define __NR_getegid32 202 +-#define __NR_setreuid32 203 +-#define __NR_setregid32 204 +-#define __NR_getgroups32 205 +-#define __NR_setgroups32 206 +-#define __NR_fchown32 207 +-#define __NR_setresuid32 208 +-#define __NR_getresuid32 209 +-#define __NR_setresgid32 210 +-#define __NR_getresgid32 211 +-#define __NR_chown32 212 +-#define __NR_setuid32 213 +-#define __NR_setgid32 214 +-#define __NR_setfsuid32 215 +-#define __NR_setfsgid32 216 +-#define __NR_fcntl64 221 +-#define __NR_sendfile64 223 +-#define __NR_fadvise64_64 264 +-#define __NR_fstatat64 293 +- +-#else +- +-#define __NR_select 142 +-#define __NR_getrlimit 191 /* SuS compliant getrlimit */ +-#define __NR_lchown 198 +-#define __NR_getuid 199 +-#define __NR_getgid 200 +-#define __NR_geteuid 201 +-#define __NR_getegid 202 +-#define __NR_setreuid 203 +-#define __NR_setregid 204 +-#define __NR_getgroups 205 +-#define __NR_setgroups 206 +-#define __NR_fchown 207 +-#define __NR_setresuid 208 +-#define __NR_getresuid 209 +-#define __NR_setresgid 210 +-#define __NR_getresgid 211 +-#define __NR_chown 212 +-#define __NR_setuid 213 +-#define __NR_setgid 214 +-#define __NR_setfsuid 215 +-#define __NR_setfsgid 216 +-#define __NR_newfstatat 293 +- +-#endif +- +-#endif /* _UAPI_ASM_S390_UNISTD_H_ */ +diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h +index 1d9199e..f41079d 100644 +--- a/tools/arch/x86/include/asm/cpufeatures.h ++++ b/tools/arch/x86/include/asm/cpufeatures.h +@@ -210,8 +210,10 @@ + + #define X86_FEATURE_MBA ( 7*32+18) /* Memory Bandwidth Allocation */ + #define X86_FEATURE_RSB_CTXSW ( 7*32+19) /* "" Fill RSB on context switches */ ++#define X86_FEATURE_SEV ( 7*32+20) /* AMD Secure Encrypted Virtualization */ + + #define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */ ++#define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* "" Use IBRS during runtime firmware calls */ + + /* Virtualization flags: Linux defined, word 8 */ + #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ +diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c +index 3a0396d..185acfa 100644 +--- a/tools/bpf/bpftool/main.c ++++ b/tools/bpf/bpftool/main.c +@@ -244,7 +244,7 @@ static int do_batch(int argc, char **argv) + } + + if (errno && errno != ENOENT) { +- perror("reading batch file failed"); ++ p_err("reading batch file failed: %s", strerror(errno)); + err = -1; + } else { + p_info("processed %d lines", lines); +diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c +index e8e2baa..e549e32 100644 +--- a/tools/bpf/bpftool/prog.c ++++ b/tools/bpf/bpftool/prog.c +@@ -774,6 +774,9 @@ static int do_dump(int argc, char **argv) + n < 0 ? strerror(errno) : "short write"); + goto err_free; + } ++ ++ if (json_output) ++ jsonw_null(json_wtr); + } else { + if (member_len == &info.jited_prog_len) { + const char *name = NULL; +diff --git a/tools/cgroup/Makefile b/tools/cgroup/Makefile +index 860fa15..ffca068 100644 +--- a/tools/cgroup/Makefile ++++ b/tools/cgroup/Makefile +@@ -1,7 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 + # Makefile for cgroup tools + +-CC = $(CROSS_COMPILE)gcc + CFLAGS = -Wall -Wextra + + all: cgroup_event_listener +diff --git a/tools/gpio/Makefile b/tools/gpio/Makefile +index 805a2c0..240eda0 100644 +--- a/tools/gpio/Makefile ++++ b/tools/gpio/Makefile +@@ -12,8 +12,6 @@ endif + # (this improves performance and avoids hard-to-debug behaviour); + MAKEFLAGS += -r + +-CC = $(CROSS_COMPILE)gcc +-LD = $(CROSS_COMPILE)ld + CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include + + ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon +diff --git a/tools/hv/Makefile b/tools/hv/Makefile +index 1139d71..5db5e62 100644 +--- a/tools/hv/Makefile ++++ b/tools/hv/Makefile +@@ -1,7 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 + # Makefile for Hyper-V tools + +-CC = $(CROSS_COMPILE)gcc + WARNINGS = -Wall -Wextra + CFLAGS = $(WARNINGS) -g $(shell getconf LFS_CFLAGS) + +diff --git a/tools/iio/Makefile b/tools/iio/Makefile +index a08e7a4..332ed2f 100644 +--- a/tools/iio/Makefile ++++ b/tools/iio/Makefile +@@ -12,8 +12,6 @@ endif + # (this improves performance and avoids hard-to-debug behaviour); + MAKEFLAGS += -r + +-CC = $(CROSS_COMPILE)gcc +-LD = $(CROSS_COMPILE)ld + CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include + + ALL_TARGETS := iio_event_monitor lsiio iio_generic_buffer +diff --git a/tools/include/uapi/drm/i915_drm.h b/tools/include/uapi/drm/i915_drm.h +index ac3c6503..536ee4f 100644 +--- a/tools/include/uapi/drm/i915_drm.h ++++ b/tools/include/uapi/drm/i915_drm.h +@@ -86,6 +86,62 @@ enum i915_mocs_table_index { + I915_MOCS_CACHED, + }; + ++/* ++ * Different engines serve different roles, and there may be more than one ++ * engine serving each role. enum drm_i915_gem_engine_class provides a ++ * classification of the role of the engine, which may be used when requesting ++ * operations to be performed on a certain subset of engines, or for providing ++ * information about that group. ++ */ ++enum drm_i915_gem_engine_class { ++ I915_ENGINE_CLASS_RENDER = 0, ++ I915_ENGINE_CLASS_COPY = 1, ++ I915_ENGINE_CLASS_VIDEO = 2, ++ I915_ENGINE_CLASS_VIDEO_ENHANCE = 3, ++ ++ I915_ENGINE_CLASS_INVALID = -1 ++}; ++ ++/** ++ * DOC: perf_events exposed by i915 through /sys/bus/event_sources/drivers/i915 ++ * ++ */ ++ ++enum drm_i915_pmu_engine_sample { ++ I915_SAMPLE_BUSY = 0, ++ I915_SAMPLE_WAIT = 1, ++ I915_SAMPLE_SEMA = 2 ++}; ++ ++#define I915_PMU_SAMPLE_BITS (4) ++#define I915_PMU_SAMPLE_MASK (0xf) ++#define I915_PMU_SAMPLE_INSTANCE_BITS (8) ++#define I915_PMU_CLASS_SHIFT \ ++ (I915_PMU_SAMPLE_BITS + I915_PMU_SAMPLE_INSTANCE_BITS) ++ ++#define __I915_PMU_ENGINE(class, instance, sample) \ ++ ((class) << I915_PMU_CLASS_SHIFT | \ ++ (instance) << I915_PMU_SAMPLE_BITS | \ ++ (sample)) ++ ++#define I915_PMU_ENGINE_BUSY(class, instance) \ ++ __I915_PMU_ENGINE(class, instance, I915_SAMPLE_BUSY) ++ ++#define I915_PMU_ENGINE_WAIT(class, instance) \ ++ __I915_PMU_ENGINE(class, instance, I915_SAMPLE_WAIT) ++ ++#define I915_PMU_ENGINE_SEMA(class, instance) \ ++ __I915_PMU_ENGINE(class, instance, I915_SAMPLE_SEMA) ++ ++#define __I915_PMU_OTHER(x) (__I915_PMU_ENGINE(0xff, 0xff, 0xf) + 1 + (x)) ++ ++#define I915_PMU_ACTUAL_FREQUENCY __I915_PMU_OTHER(0) ++#define I915_PMU_REQUESTED_FREQUENCY __I915_PMU_OTHER(1) ++#define I915_PMU_INTERRUPTS __I915_PMU_OTHER(2) ++#define I915_PMU_RC6_RESIDENCY __I915_PMU_OTHER(3) ++ ++#define I915_PMU_LAST I915_PMU_RC6_RESIDENCY ++ + /* Each region is a minimum of 16k, and there are at most 255 of them. + */ + #define I915_NR_TEX_REGIONS 255 /* table size 2k - maximum due to use +@@ -450,6 +506,27 @@ typedef struct drm_i915_irq_wait { + */ + #define I915_PARAM_HAS_EXEC_FENCE_ARRAY 49 + ++/* ++ * Query whether every context (both per-file default and user created) is ++ * isolated (insofar as HW supports). If this parameter is not true, then ++ * freshly created contexts may inherit values from an existing context, ++ * rather than default HW values. If true, it also ensures (insofar as HW ++ * supports) that all state set by this context will not leak to any other ++ * context. ++ * ++ * As not every engine across every gen support contexts, the returned ++ * value reports the support of context isolation for individual engines by ++ * returning a bitmask of each engine class set to true if that class supports ++ * isolation. ++ */ ++#define I915_PARAM_HAS_CONTEXT_ISOLATION 50 ++ ++/* Frequency of the command streamer timestamps given by the *_TIMESTAMP ++ * registers. This used to be fixed per platform but from CNL onwards, this ++ * might vary depending on the parts. ++ */ ++#define I915_PARAM_CS_TIMESTAMP_FREQUENCY 51 ++ + typedef struct drm_i915_getparam { + __s32 param; + /* +diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h +index 8616131..6d94477 100644 +--- a/tools/include/uapi/linux/if_link.h ++++ b/tools/include/uapi/linux/if_link.h +@@ -163,6 +163,7 @@ enum { + IFLA_IF_NETNSID, + IFLA_CARRIER_UP_COUNT, + IFLA_CARRIER_DOWN_COUNT, ++ IFLA_NEW_IFINDEX, + __IFLA_MAX + }; + +diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h +index 8fb90a0..7b26d4b 100644 +--- a/tools/include/uapi/linux/kvm.h ++++ b/tools/include/uapi/linux/kvm.h +@@ -761,6 +761,7 @@ struct kvm_ppc_resize_hpt { + #define KVM_TRACE_PAUSE __KVM_DEPRECATED_MAIN_0x07 + #define KVM_TRACE_DISABLE __KVM_DEPRECATED_MAIN_0x08 + #define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2) ++#define KVM_GET_MSR_FEATURE_INDEX_LIST _IOWR(KVMIO, 0x0a, struct kvm_msr_list) + + /* + * Extension capability list. +@@ -934,6 +935,7 @@ struct kvm_ppc_resize_hpt { + #define KVM_CAP_S390_AIS_MIGRATION 150 + #define KVM_CAP_PPC_GET_CPU_CHAR 151 + #define KVM_CAP_S390_BPB 152 ++#define KVM_CAP_GET_MSR_FEATURES 153 + + #ifdef KVM_CAP_IRQ_ROUTING + +@@ -1362,6 +1364,96 @@ struct kvm_s390_ucas_mapping { + /* Available with KVM_CAP_S390_CMMA_MIGRATION */ + #define KVM_S390_GET_CMMA_BITS _IOWR(KVMIO, 0xb8, struct kvm_s390_cmma_log) + #define KVM_S390_SET_CMMA_BITS _IOW(KVMIO, 0xb9, struct kvm_s390_cmma_log) ++/* Memory Encryption Commands */ ++#define KVM_MEMORY_ENCRYPT_OP _IOWR(KVMIO, 0xba, unsigned long) ++ ++struct kvm_enc_region { ++ __u64 addr; ++ __u64 size; ++}; ++ ++#define KVM_MEMORY_ENCRYPT_REG_REGION _IOR(KVMIO, 0xbb, struct kvm_enc_region) ++#define KVM_MEMORY_ENCRYPT_UNREG_REGION _IOR(KVMIO, 0xbc, struct kvm_enc_region) ++ ++/* Secure Encrypted Virtualization command */ ++enum sev_cmd_id { ++ /* Guest initialization commands */ ++ KVM_SEV_INIT = 0, ++ KVM_SEV_ES_INIT, ++ /* Guest launch commands */ ++ KVM_SEV_LAUNCH_START, ++ KVM_SEV_LAUNCH_UPDATE_DATA, ++ KVM_SEV_LAUNCH_UPDATE_VMSA, ++ KVM_SEV_LAUNCH_SECRET, ++ KVM_SEV_LAUNCH_MEASURE, ++ KVM_SEV_LAUNCH_FINISH, ++ /* Guest migration commands (outgoing) */ ++ KVM_SEV_SEND_START, ++ KVM_SEV_SEND_UPDATE_DATA, ++ KVM_SEV_SEND_UPDATE_VMSA, ++ KVM_SEV_SEND_FINISH, ++ /* Guest migration commands (incoming) */ ++ KVM_SEV_RECEIVE_START, ++ KVM_SEV_RECEIVE_UPDATE_DATA, ++ KVM_SEV_RECEIVE_UPDATE_VMSA, ++ KVM_SEV_RECEIVE_FINISH, ++ /* Guest status and debug commands */ ++ KVM_SEV_GUEST_STATUS, ++ KVM_SEV_DBG_DECRYPT, ++ KVM_SEV_DBG_ENCRYPT, ++ /* Guest certificates commands */ ++ KVM_SEV_CERT_EXPORT, ++ ++ KVM_SEV_NR_MAX, ++}; ++ ++struct kvm_sev_cmd { ++ __u32 id; ++ __u64 data; ++ __u32 error; ++ __u32 sev_fd; ++}; ++ ++struct kvm_sev_launch_start { ++ __u32 handle; ++ __u32 policy; ++ __u64 dh_uaddr; ++ __u32 dh_len; ++ __u64 session_uaddr; ++ __u32 session_len; ++}; ++ ++struct kvm_sev_launch_update_data { ++ __u64 uaddr; ++ __u32 len; ++}; ++ ++ ++struct kvm_sev_launch_secret { ++ __u64 hdr_uaddr; ++ __u32 hdr_len; ++ __u64 guest_uaddr; ++ __u32 guest_len; ++ __u64 trans_uaddr; ++ __u32 trans_len; ++}; ++ ++struct kvm_sev_launch_measure { ++ __u64 uaddr; ++ __u32 len; ++}; ++ ++struct kvm_sev_guest_status { ++ __u32 handle; ++ __u32 policy; ++ __u32 state; ++}; ++ ++struct kvm_sev_dbg { ++ __u64 src_uaddr; ++ __u64 dst_uaddr; ++ __u32 len; ++}; + + #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) + #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) +diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat +index a5684d0..5898c22 100755 +--- a/tools/kvm/kvm_stat/kvm_stat ++++ b/tools/kvm/kvm_stat/kvm_stat +@@ -33,7 +33,7 @@ import resource + import struct + import re + import subprocess +-from collections import defaultdict ++from collections import defaultdict, namedtuple + + VMX_EXIT_REASONS = { + 'EXCEPTION_NMI': 0, +@@ -228,6 +228,7 @@ IOCTL_NUMBERS = { + } + + ENCODING = locale.getpreferredencoding(False) ++TRACE_FILTER = re.compile(r'^[^\(]*$') + + + class Arch(object): +@@ -260,6 +261,11 @@ class Arch(object): + return ArchX86(SVM_EXIT_REASONS) + return + ++ def tracepoint_is_child(self, field): ++ if (TRACE_FILTER.match(field)): ++ return None ++ return field.split('(', 1)[0] ++ + + class ArchX86(Arch): + def __init__(self, exit_reasons): +@@ -267,6 +273,10 @@ class ArchX86(Arch): + self.ioctl_numbers = IOCTL_NUMBERS + self.exit_reasons = exit_reasons + ++ def debugfs_is_child(self, field): ++ """ Returns name of parent if 'field' is a child, None otherwise """ ++ return None ++ + + class ArchPPC(Arch): + def __init__(self): +@@ -282,6 +292,10 @@ class ArchPPC(Arch): + self.ioctl_numbers['SET_FILTER'] = 0x80002406 | char_ptr_size << 16 + self.exit_reasons = {} + ++ def debugfs_is_child(self, field): ++ """ Returns name of parent if 'field' is a child, None otherwise """ ++ return None ++ + + class ArchA64(Arch): + def __init__(self): +@@ -289,6 +303,10 @@ class ArchA64(Arch): + self.ioctl_numbers = IOCTL_NUMBERS + self.exit_reasons = AARCH64_EXIT_REASONS + ++ def debugfs_is_child(self, field): ++ """ Returns name of parent if 'field' is a child, None otherwise """ ++ return None ++ + + class ArchS390(Arch): + def __init__(self): +@@ -296,6 +314,12 @@ class ArchS390(Arch): + self.ioctl_numbers = IOCTL_NUMBERS + self.exit_reasons = None + ++ def debugfs_is_child(self, field): ++ """ Returns name of parent if 'field' is a child, None otherwise """ ++ if field.startswith('instruction_'): ++ return 'exit_instruction' ++ ++ + ARCH = Arch.get_arch() + + +@@ -331,9 +355,6 @@ class perf_event_attr(ctypes.Structure): + PERF_TYPE_TRACEPOINT = 2 + PERF_FORMAT_GROUP = 1 << 3 + +-PATH_DEBUGFS_TRACING = '/sys/kernel/debug/tracing' +-PATH_DEBUGFS_KVM = '/sys/kernel/debug/kvm' +- + + class Group(object): + """Represents a perf event group.""" +@@ -376,8 +397,8 @@ class Event(object): + self.syscall = self.libc.syscall + self.name = name + self.fd = None +- self.setup_event(group, trace_cpu, trace_pid, trace_point, +- trace_filter, trace_set) ++ self._setup_event(group, trace_cpu, trace_pid, trace_point, ++ trace_filter, trace_set) + + def __del__(self): + """Closes the event's file descriptor. +@@ -390,7 +411,7 @@ class Event(object): + if self.fd: + os.close(self.fd) + +- def perf_event_open(self, attr, pid, cpu, group_fd, flags): ++ def _perf_event_open(self, attr, pid, cpu, group_fd, flags): + """Wrapper for the sys_perf_evt_open() syscall. + + Used to set up performance events, returns a file descriptor or -1 +@@ -409,7 +430,7 @@ class Event(object): + ctypes.c_int(pid), ctypes.c_int(cpu), + ctypes.c_int(group_fd), ctypes.c_long(flags)) + +- def setup_event_attribute(self, trace_set, trace_point): ++ def _setup_event_attribute(self, trace_set, trace_point): + """Returns an initialized ctype perf_event_attr struct.""" + + id_path = os.path.join(PATH_DEBUGFS_TRACING, 'events', trace_set, +@@ -419,8 +440,8 @@ class Event(object): + event_attr.config = int(open(id_path).read()) + return event_attr + +- def setup_event(self, group, trace_cpu, trace_pid, trace_point, +- trace_filter, trace_set): ++ def _setup_event(self, group, trace_cpu, trace_pid, trace_point, ++ trace_filter, trace_set): + """Sets up the perf event in Linux. + + Issues the syscall to register the event in the kernel and +@@ -428,7 +449,7 @@ class Event(object): + + """ + +- event_attr = self.setup_event_attribute(trace_set, trace_point) ++ event_attr = self._setup_event_attribute(trace_set, trace_point) + + # First event will be group leader. + group_leader = -1 +@@ -437,8 +458,8 @@ class Event(object): + if group.events: + group_leader = group.events[0].fd + +- fd = self.perf_event_open(event_attr, trace_pid, +- trace_cpu, group_leader, 0) ++ fd = self._perf_event_open(event_attr, trace_pid, ++ trace_cpu, group_leader, 0) + if fd == -1: + err = ctypes.get_errno() + raise OSError(err, os.strerror(err), +@@ -475,6 +496,10 @@ class Event(object): + + class Provider(object): + """Encapsulates functionalities used by all providers.""" ++ def __init__(self, pid): ++ self.child_events = False ++ self.pid = pid ++ + @staticmethod + def is_field_wanted(fields_filter, field): + """Indicate whether field is valid according to fields_filter.""" +@@ -500,12 +525,12 @@ class TracepointProvider(Provider): + """ + def __init__(self, pid, fields_filter): + self.group_leaders = [] +- self.filters = self.get_filters() ++ self.filters = self._get_filters() + self.update_fields(fields_filter) +- self.pid = pid ++ super(TracepointProvider, self).__init__(pid) + + @staticmethod +- def get_filters(): ++ def _get_filters(): + """Returns a dict of trace events, their filter ids and + the values that can be filtered. + +@@ -521,8 +546,8 @@ class TracepointProvider(Provider): + filters['kvm_exit'] = ('exit_reason', ARCH.exit_reasons) + return filters + +- def get_available_fields(self): +- """Returns a list of available event's of format 'event name(filter ++ def _get_available_fields(self): ++ """Returns a list of available events of format 'event name(filter + name)'. + + All available events have directories under +@@ -549,11 +574,12 @@ class TracepointProvider(Provider): + + def update_fields(self, fields_filter): + """Refresh fields, applying fields_filter""" +- self.fields = [field for field in self.get_available_fields() +- if self.is_field_wanted(fields_filter, field)] ++ self.fields = [field for field in self._get_available_fields() ++ if self.is_field_wanted(fields_filter, field) or ++ ARCH.tracepoint_is_child(field)] + + @staticmethod +- def get_online_cpus(): ++ def _get_online_cpus(): + """Returns a list of cpu id integers.""" + def parse_int_list(list_string): + """Returns an int list from a string of comma separated integers and +@@ -575,17 +601,17 @@ class TracepointProvider(Provider): + cpu_string = cpu_list.readline() + return parse_int_list(cpu_string) + +- def setup_traces(self): ++ def _setup_traces(self): + """Creates all event and group objects needed to be able to retrieve + data.""" +- fields = self.get_available_fields() ++ fields = self._get_available_fields() + if self._pid > 0: + # Fetch list of all threads of the monitored pid, as qemu + # starts a thread for each vcpu. + path = os.path.join('/proc', str(self._pid), 'task') + groupids = self.walkdir(path)[1] + else: +- groupids = self.get_online_cpus() ++ groupids = self._get_online_cpus() + + # The constant is needed as a buffer for python libs, std + # streams and other files that the script opens. +@@ -663,7 +689,7 @@ class TracepointProvider(Provider): + # The garbage collector will get rid of all Event/Group + # objects and open files after removing the references. + self.group_leaders = [] +- self.setup_traces() ++ self._setup_traces() + self.fields = self._fields + + def read(self, by_guest=0): +@@ -671,8 +697,12 @@ class TracepointProvider(Provider): + ret = defaultdict(int) + for group in self.group_leaders: + for name, val in group.read().items(): +- if name in self._fields: +- ret[name] += val ++ if name not in self._fields: ++ continue ++ parent = ARCH.tracepoint_is_child(name) ++ if parent: ++ name += ' ' + parent ++ ret[name] += val + return ret + + def reset(self): +@@ -690,11 +720,11 @@ class DebugfsProvider(Provider): + self._baseline = {} + self.do_read = True + self.paths = [] +- self.pid = pid ++ super(DebugfsProvider, self).__init__(pid) + if include_past: +- self.restore() ++ self._restore() + +- def get_available_fields(self): ++ def _get_available_fields(self): + """"Returns a list of available fields. + + The fields are all available KVM debugfs files +@@ -704,8 +734,9 @@ class DebugfsProvider(Provider): + + def update_fields(self, fields_filter): + """Refresh fields, applying fields_filter""" +- self._fields = [field for field in self.get_available_fields() +- if self.is_field_wanted(fields_filter, field)] ++ self._fields = [field for field in self._get_available_fields() ++ if self.is_field_wanted(fields_filter, field) or ++ ARCH.debugfs_is_child(field)] + + @property + def fields(self): +@@ -758,7 +789,7 @@ class DebugfsProvider(Provider): + paths.append(dir) + for path in paths: + for field in self._fields: +- value = self.read_field(field, path) ++ value = self._read_field(field, path) + key = path + field + if reset == 1: + self._baseline[key] = value +@@ -766,20 +797,21 @@ class DebugfsProvider(Provider): + self._baseline[key] = 0 + if self._baseline.get(key, -1) == -1: + self._baseline[key] = value +- increment = (results.get(field, 0) + value - +- self._baseline.get(key, 0)) +- if by_guest: +- pid = key.split('-')[0] +- if pid in results: +- results[pid] += increment +- else: +- results[pid] = increment ++ parent = ARCH.debugfs_is_child(field) ++ if parent: ++ field = field + ' ' + parent ++ else: ++ if by_guest: ++ field = key.split('-')[0] # set 'field' to 'pid' ++ increment = value - self._baseline.get(key, 0) ++ if field in results: ++ results[field] += increment + else: + results[field] = increment + + return results + +- def read_field(self, field, path): ++ def _read_field(self, field, path): + """Returns the value of a single field from a specific VM.""" + try: + return int(open(os.path.join(PATH_DEBUGFS_KVM, +@@ -794,12 +826,15 @@ class DebugfsProvider(Provider): + self._baseline = {} + self.read(1) + +- def restore(self): ++ def _restore(self): + """Reset field counters""" + self._baseline = {} + self.read(2) + + ++EventStat = namedtuple('EventStat', ['value', 'delta']) ++ ++ + class Stats(object): + """Manages the data providers and the data they provide. + +@@ -808,13 +843,13 @@ class Stats(object): + + """ + def __init__(self, options): +- self.providers = self.get_providers(options) ++ self.providers = self._get_providers(options) + self._pid_filter = options.pid + self._fields_filter = options.fields + self.values = {} ++ self._child_events = False + +- @staticmethod +- def get_providers(options): ++ def _get_providers(self, options): + """Returns a list of data providers depending on the passed options.""" + providers = [] + +@@ -826,7 +861,7 @@ class Stats(object): + + return providers + +- def update_provider_filters(self): ++ def _update_provider_filters(self): + """Propagates fields filters to providers.""" + # As we reset the counters when updating the fields we can + # also clear the cache of old values. +@@ -847,7 +882,7 @@ class Stats(object): + def fields_filter(self, fields_filter): + if fields_filter != self._fields_filter: + self._fields_filter = fields_filter +- self.update_provider_filters() ++ self._update_provider_filters() + + @property + def pid_filter(self): +@@ -861,16 +896,33 @@ class Stats(object): + for provider in self.providers: + provider.pid = self._pid_filter + ++ @property ++ def child_events(self): ++ return self._child_events ++ ++ @child_events.setter ++ def child_events(self, val): ++ self._child_events = val ++ for provider in self.providers: ++ provider.child_events = val ++ + def get(self, by_guest=0): + """Returns a dict with field -> (value, delta to last value) of all +- provider data.""" ++ provider data. ++ Key formats: ++ * plain: 'key' is event name ++ * child-parent: 'key' is in format ' ' ++ * pid: 'key' is the pid of the guest, and the record contains the ++ aggregated event data ++ These formats are generated by the providers, and handled in class TUI. ++ """ + for provider in self.providers: + new = provider.read(by_guest=by_guest) +- for key in new if by_guest else provider.fields: +- oldval = self.values.get(key, (0, 0))[0] ++ for key in new: ++ oldval = self.values.get(key, EventStat(0, 0)).value + newval = new.get(key, 0) + newdelta = newval - oldval +- self.values[key] = (newval, newdelta) ++ self.values[key] = EventStat(newval, newdelta) + return self.values + + def toggle_display_guests(self, to_pid): +@@ -899,10 +951,10 @@ class Stats(object): + self.get(to_pid) + return 0 + ++ + DELAY_DEFAULT = 3.0 + MAX_GUEST_NAME_LEN = 48 + MAX_REGEX_LEN = 44 +-DEFAULT_REGEX = r'^[^\(]*$' + SORT_DEFAULT = 0 + + +@@ -969,7 +1021,7 @@ class Tui(object): + + return res + +- def print_all_gnames(self, row): ++ def _print_all_gnames(self, row): + """Print a list of all running guests along with their pids.""" + self.screen.addstr(row, 2, '%8s %-60s' % + ('Pid', 'Guest Name (fuzzy list, might be ' +@@ -1032,19 +1084,13 @@ class Tui(object): + + return name + +- def update_drilldown(self): +- """Sets or removes a filter that only allows fields without braces.""" +- if not self.stats.fields_filter: +- self.stats.fields_filter = DEFAULT_REGEX +- +- elif self.stats.fields_filter == DEFAULT_REGEX: +- self.stats.fields_filter = None +- +- def update_pid(self, pid): ++ def _update_pid(self, pid): + """Propagates pid selection to stats object.""" ++ self.screen.addstr(4, 1, 'Updating pid filter...') ++ self.screen.refresh() + self.stats.pid_filter = pid + +- def refresh_header(self, pid=None): ++ def _refresh_header(self, pid=None): + """Refreshes the header.""" + if pid is None: + pid = self.stats.pid_filter +@@ -1059,8 +1105,7 @@ class Tui(object): + .format(pid, gname), curses.A_BOLD) + else: + self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD) +- if self.stats.fields_filter and self.stats.fields_filter \ +- != DEFAULT_REGEX: ++ if self.stats.fields_filter: + regex = self.stats.fields_filter + if len(regex) > MAX_REGEX_LEN: + regex = regex[:MAX_REGEX_LEN] + '...' +@@ -1075,56 +1120,99 @@ class Tui(object): + self.screen.addstr(4, 1, 'Collecting data...') + self.screen.refresh() + +- def refresh_body(self, sleeptime): ++ def _refresh_body(self, sleeptime): ++ def is_child_field(field): ++ return field.find('(') != -1 ++ ++ def insert_child(sorted_items, child, values, parent): ++ num = len(sorted_items) ++ for i in range(0, num): ++ # only add child if parent is present ++ if parent.startswith(sorted_items[i][0]): ++ sorted_items.insert(i + 1, (' ' + child, values)) ++ ++ def get_sorted_events(self, stats): ++ """ separate parent and child events """ ++ if self._sorting == SORT_DEFAULT: ++ def sortkey((_k, v)): ++ # sort by (delta value, overall value) ++ return (v.delta, v.value) ++ else: ++ def sortkey((_k, v)): ++ # sort by overall value ++ return v.value ++ ++ childs = [] ++ sorted_items = [] ++ # we can't rule out child events to appear prior to parents even ++ # when sorted - separate out all children first, and add in later ++ for key, values in sorted(stats.items(), key=sortkey, ++ reverse=True): ++ if values == (0, 0): ++ continue ++ if key.find(' ') != -1: ++ if not self.stats.child_events: ++ continue ++ childs.insert(0, (key, values)) ++ else: ++ sorted_items.append((key, values)) ++ if self.stats.child_events: ++ for key, values in childs: ++ (child, parent) = key.split(' ') ++ insert_child(sorted_items, child, values, parent) ++ ++ return sorted_items ++ + row = 3 + self.screen.move(row, 0) + self.screen.clrtobot() + stats = self.stats.get(self._display_guests) +- +- def sortCurAvg(x): +- # sort by current events if available +- if stats[x][1]: +- return (-stats[x][1], -stats[x][0]) ++ total = 0. ++ ctotal = 0. ++ for key, values in stats.items(): ++ if self._display_guests: ++ if self.get_gname_from_pid(key): ++ total += values.value ++ continue ++ if not key.find(' ') != -1: ++ total += values.value + else: +- return (0, -stats[x][0]) ++ ctotal += values.value ++ if total == 0.: ++ # we don't have any fields, or all non-child events are filtered ++ total = ctotal + +- def sortTotal(x): +- # sort by totals +- return (0, -stats[x][0]) +- total = 0. +- for key in stats.keys(): +- if key.find('(') is -1: +- total += stats[key][0] +- if self._sorting == SORT_DEFAULT: +- sortkey = sortCurAvg +- else: +- sortkey = sortTotal ++ # print events + tavg = 0 +- for key in sorted(stats.keys(), key=sortkey): +- if row >= self.screen.getmaxyx()[0] - 1: +- break +- values = stats[key] +- if not values[0] and not values[1]: ++ tcur = 0 ++ for key, values in get_sorted_events(self, stats): ++ if row >= self.screen.getmaxyx()[0] - 1 or values == (0, 0): + break +- if values[0] is not None: +- cur = int(round(values[1] / sleeptime)) if values[1] else '' +- if self._display_guests: +- key = self.get_gname_from_pid(key) +- self.screen.addstr(row, 1, '%-40s %10d%7.1f %8s' % +- (key, values[0], values[0] * 100 / total, +- cur)) +- if cur is not '' and key.find('(') is -1: +- tavg += cur ++ if self._display_guests: ++ key = self.get_gname_from_pid(key) ++ if not key: ++ continue ++ cur = int(round(values.delta / sleeptime)) if values.delta else '' ++ if key[0] != ' ': ++ if values.delta: ++ tcur += values.delta ++ ptotal = values.value ++ ltotal = total ++ else: ++ ltotal = ptotal ++ self.screen.addstr(row, 1, '%-40s %10d%7.1f %8s' % (key, ++ values.value, ++ values.value * 100 / float(ltotal), cur)) + row += 1 + if row == 3: + self.screen.addstr(4, 1, 'No matching events reported yet') +- else: ++ if row > 4: ++ tavg = int(round(tcur / sleeptime)) if tcur > 0 else '' + self.screen.addstr(row, 1, '%-40s %10d %8s' % +- ('Total', total, tavg if tavg else ''), +- curses.A_BOLD) ++ ('Total', total, tavg), curses.A_BOLD) + self.screen.refresh() + +- def show_msg(self, text): ++ def _show_msg(self, text): + """Display message centered text and exit on key press""" + hint = 'Press any key to continue' + curses.cbreak() +@@ -1139,16 +1227,16 @@ class Tui(object): + curses.A_STANDOUT) + self.screen.getkey() + +- def show_help_interactive(self): ++ def _show_help_interactive(self): + """Display help with list of interactive commands""" + msg = (' b toggle events by guests (debugfs only, honors' + ' filters)', + ' c clear filter', + ' f filter by regular expression', +- ' g filter by guest name', ++ ' g filter by guest name/PID', + ' h display interactive commands reference', + ' o toggle sorting order (Total vs CurAvg/s)', +- ' p filter by PID', ++ ' p filter by guest name/PID', + ' q quit', + ' r reset stats', + ' s set update interval', +@@ -1165,14 +1253,15 @@ class Tui(object): + self.screen.addstr(row, 0, line) + row += 1 + self.screen.getkey() +- self.refresh_header() ++ self._refresh_header() + +- def show_filter_selection(self): ++ def _show_filter_selection(self): + """Draws filter selection mask. + + Asks for a valid regex and sets the fields filter accordingly. + + """ ++ msg = '' + while True: + self.screen.erase() + self.screen.addstr(0, 0, +@@ -1181,61 +1270,25 @@ class Tui(object): + self.screen.addstr(2, 0, + "Current regex: {0}" + .format(self.stats.fields_filter)) ++ self.screen.addstr(5, 0, msg) + self.screen.addstr(3, 0, "New regex: ") + curses.echo() + regex = self.screen.getstr().decode(ENCODING) + curses.noecho() + if len(regex) == 0: +- self.stats.fields_filter = DEFAULT_REGEX +- self.refresh_header() ++ self.stats.fields_filter = '' ++ self._refresh_header() + return + try: + re.compile(regex) + self.stats.fields_filter = regex +- self.refresh_header() ++ self._refresh_header() + return + except re.error: ++ msg = '"' + regex + '": Not a valid regular expression' + continue + +- def show_vm_selection_by_pid(self): +- """Draws PID selection mask. +- +- Asks for a pid until a valid pid or 0 has been entered. +- +- """ +- msg = '' +- while True: +- self.screen.erase() +- self.screen.addstr(0, 0, +- 'Show statistics for specific pid.', +- curses.A_BOLD) +- self.screen.addstr(1, 0, +- 'This might limit the shown data to the trace ' +- 'statistics.') +- self.screen.addstr(5, 0, msg) +- self.print_all_gnames(7) +- +- curses.echo() +- self.screen.addstr(3, 0, "Pid [0 or pid]: ") +- pid = self.screen.getstr().decode(ENCODING) +- curses.noecho() +- +- try: +- if len(pid) > 0: +- pid = int(pid) +- if pid != 0 and not os.path.isdir(os.path.join('/proc/', +- str(pid))): +- msg = '"' + str(pid) + '": Not a running process' +- continue +- else: +- pid = 0 +- self.refresh_header(pid) +- self.update_pid(pid) +- break +- except ValueError: +- msg = '"' + str(pid) + '": Not a valid pid' +- +- def show_set_update_interval(self): ++ def _show_set_update_interval(self): + """Draws update interval selection mask.""" + msg = '' + while True: +@@ -1265,60 +1318,67 @@ class Tui(object): + + except ValueError: + msg = '"' + str(val) + '": Invalid value' +- self.refresh_header() ++ self._refresh_header() + +- def show_vm_selection_by_guest_name(self): ++ def _show_vm_selection_by_guest(self): + """Draws guest selection mask. + +- Asks for a guest name until a valid guest name or '' is entered. ++ Asks for a guest name or pid until a valid guest name or '' is entered. + + """ + msg = '' + while True: + self.screen.erase() + self.screen.addstr(0, 0, +- 'Show statistics for specific guest.', ++ 'Show statistics for specific guest or pid.', + curses.A_BOLD) + self.screen.addstr(1, 0, + 'This might limit the shown data to the trace ' + 'statistics.') + self.screen.addstr(5, 0, msg) +- self.print_all_gnames(7) ++ self._print_all_gnames(7) + curses.echo() +- self.screen.addstr(3, 0, "Guest [ENTER or guest]: ") +- gname = self.screen.getstr().decode(ENCODING) ++ curses.curs_set(1) ++ self.screen.addstr(3, 0, "Guest or pid [ENTER exits]: ") ++ guest = self.screen.getstr().decode(ENCODING) + curses.noecho() + +- if not gname: +- self.refresh_header(0) +- self.update_pid(0) ++ pid = 0 ++ if not guest or guest == '0': + break +- else: +- pids = [] +- try: +- pids = self.get_pid_from_gname(gname) +- except: +- msg = '"' + gname + '": Internal error while searching, ' \ +- 'use pid filter instead' +- continue +- if len(pids) == 0: +- msg = '"' + gname + '": Not an active guest' ++ if guest.isdigit(): ++ if not os.path.isdir(os.path.join('/proc/', guest)): ++ msg = '"' + guest + '": Not a running process' + continue +- if len(pids) > 1: +- msg = '"' + gname + '": Multiple matches found, use pid ' \ +- 'filter instead' +- continue +- self.refresh_header(pids[0]) +- self.update_pid(pids[0]) ++ pid = int(guest) + break ++ pids = [] ++ try: ++ pids = self.get_pid_from_gname(guest) ++ except: ++ msg = '"' + guest + '": Internal error while searching, ' \ ++ 'use pid filter instead' ++ continue ++ if len(pids) == 0: ++ msg = '"' + guest + '": Not an active guest' ++ continue ++ if len(pids) > 1: ++ msg = '"' + guest + '": Multiple matches found, use pid ' \ ++ 'filter instead' ++ continue ++ pid = pids[0] ++ break ++ curses.curs_set(0) ++ self._refresh_header(pid) ++ self._update_pid(pid) + + def show_stats(self): + """Refreshes the screen and processes user input.""" + sleeptime = self._delay_initial +- self.refresh_header() ++ self._refresh_header() + start = 0.0 # result based on init value never appears on screen + while True: +- self.refresh_body(time.time() - start) ++ self._refresh_body(time.time() - start) + curses.halfdelay(int(sleeptime * 10)) + start = time.time() + sleeptime = self._delay_regular +@@ -1327,47 +1387,39 @@ class Tui(object): + if char == 'b': + self._display_guests = not self._display_guests + if self.stats.toggle_display_guests(self._display_guests): +- self.show_msg(['Command not available with tracepoints' +- ' enabled', 'Restart with debugfs only ' +- '(see option \'-d\') and try again!']) ++ self._show_msg(['Command not available with ' ++ 'tracepoints enabled', 'Restart with ' ++ 'debugfs only (see option \'-d\') and ' ++ 'try again!']) + self._display_guests = not self._display_guests +- self.refresh_header() ++ self._refresh_header() + if char == 'c': +- self.stats.fields_filter = DEFAULT_REGEX +- self.refresh_header(0) +- self.update_pid(0) ++ self.stats.fields_filter = '' ++ self._refresh_header(0) ++ self._update_pid(0) + if char == 'f': + curses.curs_set(1) +- self.show_filter_selection() ++ self._show_filter_selection() + curses.curs_set(0) + sleeptime = self._delay_initial +- if char == 'g': +- curses.curs_set(1) +- self.show_vm_selection_by_guest_name() +- curses.curs_set(0) ++ if char == 'g' or char == 'p': ++ self._show_vm_selection_by_guest() + sleeptime = self._delay_initial + if char == 'h': +- self.show_help_interactive() ++ self._show_help_interactive() + if char == 'o': + self._sorting = not self._sorting +- if char == 'p': +- curses.curs_set(1) +- self.show_vm_selection_by_pid() +- curses.curs_set(0) +- sleeptime = self._delay_initial + if char == 'q': + break + if char == 'r': + self.stats.reset() + if char == 's': + curses.curs_set(1) +- self.show_set_update_interval() ++ self._show_set_update_interval() + curses.curs_set(0) + sleeptime = self._delay_initial + if char == 'x': +- self.update_drilldown() +- # prevents display of current values on next refresh +- self.stats.get(self._display_guests) ++ self.stats.child_events = not self.stats.child_events + except KeyboardInterrupt: + break + except curses.error: +@@ -1380,9 +1432,9 @@ def batch(stats): + s = stats.get() + time.sleep(1) + s = stats.get() +- for key in sorted(s.keys()): +- values = s[key] +- print('%-42s%10d%10d' % (key, values[0], values[1])) ++ for key, values in sorted(s.items()): ++ print('%-42s%10d%10d' % (key.split(' ')[0], values.value, ++ values.delta)) + except KeyboardInterrupt: + pass + +@@ -1392,14 +1444,14 @@ def log(stats): + keys = sorted(stats.get().keys()) + + def banner(): +- for k in keys: +- print(k, end=' ') ++ for key in keys: ++ print(key.split(' ')[0], end=' ') + print() + + def statline(): + s = stats.get() +- for k in keys: +- print(' %9d' % s[k][1], end=' ') ++ for key in keys: ++ print(' %9d' % s[key].delta, end=' ') + print() + line = 0 + banner_repeat = 20 +@@ -1504,7 +1556,7 @@ Press any other key to refresh statistics immediately. + ) + optparser.add_option('-f', '--fields', + action='store', +- default=DEFAULT_REGEX, ++ default='', + dest='fields', + help='''fields to display (regex) + "-f help" for a list of available events''', +@@ -1539,17 +1591,6 @@ Press any other key to refresh statistics immediately. + + def check_access(options): + """Exits if the current user can't access all needed directories.""" +- if not os.path.exists('/sys/kernel/debug'): +- sys.stderr.write('Please enable CONFIG_DEBUG_FS in your kernel.') +- sys.exit(1) +- +- if not os.path.exists(PATH_DEBUGFS_KVM): +- sys.stderr.write("Please make sure, that debugfs is mounted and " +- "readable by the current user:\n" +- "('mount -t debugfs debugfs /sys/kernel/debug')\n" +- "Also ensure, that the kvm modules are loaded.\n") +- sys.exit(1) +- + if not os.path.exists(PATH_DEBUGFS_TRACING) and (options.tracepoints or + not options.debugfs): + sys.stderr.write("Please enable CONFIG_TRACING in your kernel " +@@ -1567,7 +1608,33 @@ def check_access(options): + return options + + ++def assign_globals(): ++ global PATH_DEBUGFS_KVM ++ global PATH_DEBUGFS_TRACING ++ ++ debugfs = '' ++ for line in file('/proc/mounts'): ++ if line.split(' ')[0] == 'debugfs': ++ debugfs = line.split(' ')[1] ++ break ++ if debugfs == '': ++ sys.stderr.write("Please make sure that CONFIG_DEBUG_FS is enabled in " ++ "your kernel, mounted and\nreadable by the current " ++ "user:\n" ++ "('mount -t debugfs debugfs /sys/kernel/debug')\n") ++ sys.exit(1) ++ ++ PATH_DEBUGFS_KVM = os.path.join(debugfs, 'kvm') ++ PATH_DEBUGFS_TRACING = os.path.join(debugfs, 'tracing') ++ ++ if not os.path.exists(PATH_DEBUGFS_KVM): ++ sys.stderr.write("Please make sure that CONFIG_KVM is enabled in " ++ "your kernel and that the modules are loaded.\n") ++ sys.exit(1) ++ ++ + def main(): ++ assign_globals() + options = get_options() + options = check_access(options) + +diff --git a/tools/kvm/kvm_stat/kvm_stat.txt b/tools/kvm/kvm_stat/kvm_stat.txt +index b5b3810..0811d86 100644 +--- a/tools/kvm/kvm_stat/kvm_stat.txt ++++ b/tools/kvm/kvm_stat/kvm_stat.txt +@@ -35,13 +35,13 @@ INTERACTIVE COMMANDS + + *f*:: filter by regular expression + +-*g*:: filter by guest name ++*g*:: filter by guest name/PID + + *h*:: display interactive commands reference + + *o*:: toggle sorting order (Total vs CurAvg/s) + +-*p*:: filter by PID ++*p*:: filter by guest name/PID + + *q*:: quit + +diff --git a/tools/laptop/freefall/Makefile b/tools/laptop/freefall/Makefile +index 5f758c4..b572d94 100644 +--- a/tools/laptop/freefall/Makefile ++++ b/tools/laptop/freefall/Makefile +@@ -2,7 +2,6 @@ + PREFIX ?= /usr + SBINDIR ?= sbin + INSTALL ?= install +-CC = $(CROSS_COMPILE)gcc + + TARGET = freefall + +diff --git a/tools/leds/Makefile b/tools/leds/Makefile +index c379af0..7b6bed1 100644 +--- a/tools/leds/Makefile ++++ b/tools/leds/Makefile +@@ -1,7 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 + # Makefile for LEDs tools + +-CC = $(CROSS_COMPILE)gcc + CFLAGS = -Wall -Wextra -g -I../../include/uapi + + all: uledmon led_hw_brightness_mon +diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c +index 97073d6..5bbbf28 100644 +--- a/tools/lib/bpf/libbpf.c ++++ b/tools/lib/bpf/libbpf.c +@@ -1060,11 +1060,12 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj, + prog->insns = new_insn; + prog->main_prog_cnt = prog->insns_cnt; + prog->insns_cnt = new_cnt; ++ pr_debug("added %zd insn from %s to prog %s\n", ++ text->insns_cnt, text->section_name, ++ prog->section_name); + } + insn = &prog->insns[relo->insn_idx]; + insn->imm += prog->main_prog_cnt - relo->insn_idx; +- pr_debug("added %zd insn from %s to prog %s\n", +- text->insns_cnt, text->section_name, prog->section_name); + return 0; + } + +diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c +index 57254f5..694abc6 100644 +--- a/tools/objtool/builtin-check.c ++++ b/tools/objtool/builtin-check.c +@@ -29,7 +29,7 @@ + #include "builtin.h" + #include "check.h" + +-bool no_fp, no_unreachable; ++bool no_fp, no_unreachable, retpoline, module; + + static const char * const check_usage[] = { + "objtool check [] file.o", +@@ -39,6 +39,8 @@ static const char * const check_usage[] = { + const struct option check_options[] = { + OPT_BOOLEAN('f', "no-fp", &no_fp, "Skip frame pointer validation"), + OPT_BOOLEAN('u', "no-unreachable", &no_unreachable, "Skip 'unreachable instruction' warnings"), ++ OPT_BOOLEAN('r', "retpoline", &retpoline, "Validate retpoline assumptions"), ++ OPT_BOOLEAN('m', "module", &module, "Indicates the object will be part of a kernel module"), + OPT_END(), + }; + +@@ -53,5 +55,5 @@ int cmd_check(int argc, const char **argv) + + objname = argv[0]; + +- return check(objname, no_fp, no_unreachable, false); ++ return check(objname, false); + } +diff --git a/tools/objtool/builtin-orc.c b/tools/objtool/builtin-orc.c +index 91e8e19..77ea2b9 100644 +--- a/tools/objtool/builtin-orc.c ++++ b/tools/objtool/builtin-orc.c +@@ -25,7 +25,6 @@ + */ + + #include +-#include + #include "builtin.h" + #include "check.h" + +@@ -36,9 +35,6 @@ static const char *orc_usage[] = { + NULL, + }; + +-extern const struct option check_options[]; +-extern bool no_fp, no_unreachable; +- + int cmd_orc(int argc, const char **argv) + { + const char *objname; +@@ -54,7 +50,7 @@ int cmd_orc(int argc, const char **argv) + + objname = argv[0]; + +- return check(objname, no_fp, no_unreachable, true); ++ return check(objname, true); + } + + if (!strcmp(argv[0], "dump")) { +diff --git a/tools/objtool/builtin.h b/tools/objtool/builtin.h +index dd52606..28ff40e 100644 +--- a/tools/objtool/builtin.h ++++ b/tools/objtool/builtin.h +@@ -17,6 +17,11 @@ + #ifndef _BUILTIN_H + #define _BUILTIN_H + ++#include ++ ++extern const struct option check_options[]; ++extern bool no_fp, no_unreachable, retpoline, module; ++ + extern int cmd_check(int argc, const char **argv); + extern int cmd_orc(int argc, const char **argv); + +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index b00b189..92b6a2c 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -18,6 +18,7 @@ + #include + #include + ++#include "builtin.h" + #include "check.h" + #include "elf.h" + #include "special.h" +@@ -33,7 +34,6 @@ struct alternative { + }; + + const char *objname; +-static bool no_fp; + struct cfi_state initial_func_cfi; + + struct instruction *find_insn(struct objtool_file *file, +@@ -497,6 +497,7 @@ static int add_jump_destinations(struct objtool_file *file) + * disguise, so convert them accordingly. + */ + insn->type = INSN_JUMP_DYNAMIC; ++ insn->retpoline_safe = true; + continue; + } else { + /* sibling call */ +@@ -548,7 +549,8 @@ static int add_call_destinations(struct objtool_file *file) + if (!insn->call_dest && !insn->ignore) { + WARN_FUNC("unsupported intra-function call", + insn->sec, insn->offset); +- WARN("If this is a retpoline, please patch it in with alternatives and annotate it with ANNOTATE_NOSPEC_ALTERNATIVE."); ++ if (retpoline) ++ WARN("If this is a retpoline, please patch it in with alternatives and annotate it with ANNOTATE_NOSPEC_ALTERNATIVE."); + return -1; + } + +@@ -852,8 +854,14 @@ static int add_switch_table(struct objtool_file *file, struct symbol *func, + * This is a fairly uncommon pattern which is new for GCC 6. As of this + * writing, there are 11 occurrences of it in the allmodconfig kernel. + * ++ * As of GCC 7 there are quite a few more of these and the 'in between' code ++ * is significant. Esp. with KASAN enabled some of the code between the mov ++ * and jmpq uses .rodata itself, which can confuse things. ++ * + * TODO: Once we have DWARF CFI and smarter instruction decoding logic, + * ensure the same register is used in the mov and jump instructions. ++ * ++ * NOTE: RETPOLINE made it harder still to decode dynamic jumps. + */ + static struct rela *find_switch_table(struct objtool_file *file, + struct symbol *func, +@@ -875,12 +883,25 @@ static struct rela *find_switch_table(struct objtool_file *file, + text_rela->addend + 4); + if (!rodata_rela) + return NULL; ++ + file->ignore_unreachables = true; + return rodata_rela; + } + + /* case 3 */ +- func_for_each_insn_continue_reverse(file, func, insn) { ++ /* ++ * Backward search using the @first_jump_src links, these help avoid ++ * much of the 'in between' code. Which avoids us getting confused by ++ * it. ++ */ ++ for (insn = list_prev_entry(insn, list); ++ ++ &insn->list != &file->insn_list && ++ insn->sec == func->sec && ++ insn->offset >= func->offset; ++ ++ insn = insn->first_jump_src ?: list_prev_entry(insn, list)) { ++ + if (insn->type == INSN_JUMP_DYNAMIC) + break; + +@@ -904,20 +925,42 @@ static struct rela *find_switch_table(struct objtool_file *file, + if (find_symbol_containing(file->rodata, text_rela->addend)) + continue; + +- return find_rela_by_dest(file->rodata, text_rela->addend); ++ rodata_rela = find_rela_by_dest(file->rodata, text_rela->addend); ++ if (!rodata_rela) ++ continue; ++ ++ return rodata_rela; + } + + return NULL; + } + ++ + static int add_func_switch_tables(struct objtool_file *file, + struct symbol *func) + { +- struct instruction *insn, *prev_jump = NULL; ++ struct instruction *insn, *last = NULL, *prev_jump = NULL; + struct rela *rela, *prev_rela = NULL; + int ret; + + func_for_each_insn(file, func, insn) { ++ if (!last) ++ last = insn; ++ ++ /* ++ * Store back-pointers for unconditional forward jumps such ++ * that find_switch_table() can back-track using those and ++ * avoid some potentially confusing code. ++ */ ++ if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest && ++ insn->offset > last->offset && ++ insn->jump_dest->offset > insn->offset && ++ !insn->jump_dest->first_jump_src) { ++ ++ insn->jump_dest->first_jump_src = insn; ++ last = insn->jump_dest; ++ } ++ + if (insn->type != INSN_JUMP_DYNAMIC) + continue; + +@@ -1071,6 +1114,41 @@ static int read_unwind_hints(struct objtool_file *file) + return 0; + } + ++static int read_retpoline_hints(struct objtool_file *file) ++{ ++ struct section *sec; ++ struct instruction *insn; ++ struct rela *rela; ++ ++ sec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe"); ++ if (!sec) ++ return 0; ++ ++ list_for_each_entry(rela, &sec->rela_list, list) { ++ if (rela->sym->type != STT_SECTION) { ++ WARN("unexpected relocation symbol type in %s", sec->name); ++ return -1; ++ } ++ ++ insn = find_insn(file, rela->sym->sec, rela->addend); ++ if (!insn) { ++ WARN("bad .discard.retpoline_safe entry"); ++ return -1; ++ } ++ ++ if (insn->type != INSN_JUMP_DYNAMIC && ++ insn->type != INSN_CALL_DYNAMIC) { ++ WARN_FUNC("retpoline_safe hint not an indirect jump/call", ++ insn->sec, insn->offset); ++ return -1; ++ } ++ ++ insn->retpoline_safe = true; ++ } ++ ++ return 0; ++} ++ + static int decode_sections(struct objtool_file *file) + { + int ret; +@@ -1109,6 +1187,10 @@ static int decode_sections(struct objtool_file *file) + if (ret) + return ret; + ++ ret = read_retpoline_hints(file); ++ if (ret) ++ return ret; ++ + return 0; + } + +@@ -1854,6 +1936,38 @@ static int validate_unwind_hints(struct objtool_file *file) + return warnings; + } + ++static int validate_retpoline(struct objtool_file *file) ++{ ++ struct instruction *insn; ++ int warnings = 0; ++ ++ for_each_insn(file, insn) { ++ if (insn->type != INSN_JUMP_DYNAMIC && ++ insn->type != INSN_CALL_DYNAMIC) ++ continue; ++ ++ if (insn->retpoline_safe) ++ continue; ++ ++ /* ++ * .init.text code is ran before userspace and thus doesn't ++ * strictly need retpolines, except for modules which are ++ * loaded late, they very much do need retpoline in their ++ * .init.text ++ */ ++ if (!strcmp(insn->sec->name, ".init.text") && !module) ++ continue; ++ ++ WARN_FUNC("indirect %s found in RETPOLINE build", ++ insn->sec, insn->offset, ++ insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); ++ ++ warnings++; ++ } ++ ++ return warnings; ++} ++ + static bool is_kasan_insn(struct instruction *insn) + { + return (insn->type == INSN_CALL && +@@ -1899,13 +2013,19 @@ static bool ignore_unreachable_insn(struct instruction *insn) + if (is_kasan_insn(insn) || is_ubsan_insn(insn)) + return true; + +- if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest) { +- insn = insn->jump_dest; +- continue; ++ if (insn->type == INSN_JUMP_UNCONDITIONAL) { ++ if (insn->jump_dest && ++ insn->jump_dest->func == insn->func) { ++ insn = insn->jump_dest; ++ continue; ++ } ++ ++ break; + } + + if (insn->offset + insn->len >= insn->func->offset + insn->func->len) + break; ++ + insn = list_next_entry(insn, list); + } + +@@ -1979,13 +2099,12 @@ static void cleanup(struct objtool_file *file) + elf_close(file->elf); + } + +-int check(const char *_objname, bool _no_fp, bool no_unreachable, bool orc) ++int check(const char *_objname, bool orc) + { + struct objtool_file file; + int ret, warnings = 0; + + objname = _objname; +- no_fp = _no_fp; + + file.elf = elf_open(objname, orc ? O_RDWR : O_RDONLY); + if (!file.elf) +@@ -2009,6 +2128,13 @@ int check(const char *_objname, bool _no_fp, bool no_unreachable, bool orc) + if (list_empty(&file.insn_list)) + goto out; + ++ if (retpoline) { ++ ret = validate_retpoline(&file); ++ if (ret < 0) ++ return ret; ++ warnings += ret; ++ } ++ + ret = validate_functions(&file); + if (ret < 0) + goto out; +diff --git a/tools/objtool/check.h b/tools/objtool/check.h +index dbadb30..c6b68fc 100644 +--- a/tools/objtool/check.h ++++ b/tools/objtool/check.h +@@ -45,8 +45,10 @@ struct instruction { + unsigned char type; + unsigned long immediate; + bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; ++ bool retpoline_safe; + struct symbol *call_dest; + struct instruction *jump_dest; ++ struct instruction *first_jump_src; + struct list_head alts; + struct symbol *func; + struct stack_op stack_op; +@@ -62,7 +64,7 @@ struct objtool_file { + bool ignore_unreachables, c_file, hints; + }; + +-int check(const char *objname, bool no_fp, bool no_unreachable, bool orc); ++int check(const char *objname, bool orc); + + struct instruction *find_insn(struct objtool_file *file, + struct section *sec, unsigned long offset); +diff --git a/tools/perf/Documentation/perf-data.txt b/tools/perf/Documentation/perf-data.txt +index f0796a4..90bb4aa 100644 +--- a/tools/perf/Documentation/perf-data.txt ++++ b/tools/perf/Documentation/perf-data.txt +@@ -30,6 +30,10 @@ OPTIONS for 'convert' + -i:: + Specify input perf data file path. + ++-f:: ++--force:: ++ Don't complain, do it. ++ + -v:: + --verbose:: + Be more verbose (show counter open errors, etc). +diff --git a/tools/perf/Documentation/perf-kallsyms.txt b/tools/perf/Documentation/perf-kallsyms.txt +index 954ea9e..cf9f404 100644 +--- a/tools/perf/Documentation/perf-kallsyms.txt ++++ b/tools/perf/Documentation/perf-kallsyms.txt +@@ -8,7 +8,7 @@ perf-kallsyms - Searches running kernel for symbols + SYNOPSIS + -------- + [verse] +-'perf kallsyms symbol_name[,symbol_name...]' ++'perf kallsyms' [] symbol_name[,symbol_name...] + + DESCRIPTION + ----------- +diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf +index 9b0351d..0123280 100644 +--- a/tools/perf/Makefile.perf ++++ b/tools/perf/Makefile.perf +@@ -146,12 +146,6 @@ define allow-override + $(eval $(1) = $(2))) + endef + +-# Allow setting CC and AR and LD, or setting CROSS_COMPILE as a prefix. +-$(call allow-override,CC,$(CROSS_COMPILE)gcc) +-$(call allow-override,AR,$(CROSS_COMPILE)ar) +-$(call allow-override,LD,$(CROSS_COMPILE)ld) +-$(call allow-override,CXX,$(CROSS_COMPILE)g++) +- + LD += $(EXTRA_LDFLAGS) + + HOSTCC ?= gcc +diff --git a/tools/perf/arch/s390/Makefile b/tools/perf/arch/s390/Makefile +index 48228de..dfa6e31 100644 +--- a/tools/perf/arch/s390/Makefile ++++ b/tools/perf/arch/s390/Makefile +@@ -10,15 +10,19 @@ PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 + + out := $(OUTPUT)arch/s390/include/generated/asm + header := $(out)/syscalls_64.c +-sysdef := $(srctree)/tools/arch/s390/include/uapi/asm/unistd.h +-sysprf := $(srctree)/tools/perf/arch/s390/entry/syscalls/ ++syskrn := $(srctree)/arch/s390/kernel/syscalls/syscall.tbl ++sysprf := $(srctree)/tools/perf/arch/s390/entry/syscalls ++sysdef := $(sysprf)/syscall.tbl + systbl := $(sysprf)/mksyscalltbl + + # Create output directory if not already present + _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') + + $(header): $(sysdef) $(systbl) +- $(Q)$(SHELL) '$(systbl)' '$(CC)' $(sysdef) > $@ ++ @(test -d ../../kernel -a -d ../../tools -a -d ../perf && ( \ ++ (diff -B $(sysdef) $(syskrn) >/dev/null) \ ++ || echo "Warning: Kernel ABI header at '$(sysdef)' differs from latest version at '$(syskrn)'" >&2 )) || true ++ $(Q)$(SHELL) '$(systbl)' $(sysdef) > $@ + + clean:: + $(call QUIET_CLEAN, s390) $(RM) $(header) +diff --git a/tools/perf/arch/s390/entry/syscalls/mksyscalltbl b/tools/perf/arch/s390/entry/syscalls/mksyscalltbl +index 7fa0d0a..72ecbb6 100755 +--- a/tools/perf/arch/s390/entry/syscalls/mksyscalltbl ++++ b/tools/perf/arch/s390/entry/syscalls/mksyscalltbl +@@ -3,25 +3,23 @@ + # + # Generate system call table for perf + # +-# +-# Copyright IBM Corp. 2017 ++# Copyright IBM Corp. 2017, 2018 + # Author(s): Hendrik Brueckner + # + +-gcc=$1 +-input=$2 ++SYSCALL_TBL=$1 + +-if ! test -r $input; then ++if ! test -r $SYSCALL_TBL; then + echo "Could not read input file" >&2 + exit 1 + fi + + create_table() + { +- local max_nr ++ local max_nr nr abi sc discard + + echo 'static const char *syscalltbl_s390_64[] = {' +- while read sc nr; do ++ while read nr abi sc discard; do + printf '\t[%d] = "%s",\n' $nr $sc + max_nr=$nr + done +@@ -29,8 +27,6 @@ create_table() + echo "#define SYSCALLTBL_S390_64_MAX_ID $max_nr" + } + +- +-$gcc -m64 -E -dM -x c $input \ +- |sed -ne 's/^#define __NR_//p' \ +- |sort -t' ' -k2 -nu \ ++grep -E "^[[:digit:]]+[[:space:]]+(common|64)" $SYSCALL_TBL \ ++ |sort -k1 -n \ + |create_table +diff --git a/tools/perf/arch/s390/entry/syscalls/syscall.tbl b/tools/perf/arch/s390/entry/syscalls/syscall.tbl +new file mode 100644 +index 0000000..b38d484 +--- /dev/null ++++ b/tools/perf/arch/s390/entry/syscalls/syscall.tbl +@@ -0,0 +1,390 @@ ++# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note ++# ++# System call table for s390 ++# ++# Format: ++# ++# ++# ++# where can be common, 64, or 32 ++ ++1 common exit sys_exit sys_exit ++2 common fork sys_fork sys_fork ++3 common read sys_read compat_sys_s390_read ++4 common write sys_write compat_sys_s390_write ++5 common open sys_open compat_sys_open ++6 common close sys_close sys_close ++7 common restart_syscall sys_restart_syscall sys_restart_syscall ++8 common creat sys_creat compat_sys_creat ++9 common link sys_link compat_sys_link ++10 common unlink sys_unlink compat_sys_unlink ++11 common execve sys_execve compat_sys_execve ++12 common chdir sys_chdir compat_sys_chdir ++13 32 time - compat_sys_time ++14 common mknod sys_mknod compat_sys_mknod ++15 common chmod sys_chmod compat_sys_chmod ++16 32 lchown - compat_sys_s390_lchown16 ++19 common lseek sys_lseek compat_sys_lseek ++20 common getpid sys_getpid sys_getpid ++21 common mount sys_mount compat_sys_mount ++22 common umount sys_oldumount compat_sys_oldumount ++23 32 setuid - compat_sys_s390_setuid16 ++24 32 getuid - compat_sys_s390_getuid16 ++25 32 stime - compat_sys_stime ++26 common ptrace sys_ptrace compat_sys_ptrace ++27 common alarm sys_alarm sys_alarm ++29 common pause sys_pause sys_pause ++30 common utime sys_utime compat_sys_utime ++33 common access sys_access compat_sys_access ++34 common nice sys_nice sys_nice ++36 common sync sys_sync sys_sync ++37 common kill sys_kill sys_kill ++38 common rename sys_rename compat_sys_rename ++39 common mkdir sys_mkdir compat_sys_mkdir ++40 common rmdir sys_rmdir compat_sys_rmdir ++41 common dup sys_dup sys_dup ++42 common pipe sys_pipe compat_sys_pipe ++43 common times sys_times compat_sys_times ++45 common brk sys_brk compat_sys_brk ++46 32 setgid - compat_sys_s390_setgid16 ++47 32 getgid - compat_sys_s390_getgid16 ++48 common signal sys_signal compat_sys_signal ++49 32 geteuid - compat_sys_s390_geteuid16 ++50 32 getegid - compat_sys_s390_getegid16 ++51 common acct sys_acct compat_sys_acct ++52 common umount2 sys_umount compat_sys_umount ++54 common ioctl sys_ioctl compat_sys_ioctl ++55 common fcntl sys_fcntl compat_sys_fcntl ++57 common setpgid sys_setpgid sys_setpgid ++60 common umask sys_umask sys_umask ++61 common chroot sys_chroot compat_sys_chroot ++62 common ustat sys_ustat compat_sys_ustat ++63 common dup2 sys_dup2 sys_dup2 ++64 common getppid sys_getppid sys_getppid ++65 common getpgrp sys_getpgrp sys_getpgrp ++66 common setsid sys_setsid sys_setsid ++67 common sigaction sys_sigaction compat_sys_sigaction ++70 32 setreuid - compat_sys_s390_setreuid16 ++71 32 setregid - compat_sys_s390_setregid16 ++72 common sigsuspend sys_sigsuspend compat_sys_sigsuspend ++73 common sigpending sys_sigpending compat_sys_sigpending ++74 common sethostname sys_sethostname compat_sys_sethostname ++75 common setrlimit sys_setrlimit compat_sys_setrlimit ++76 32 getrlimit - compat_sys_old_getrlimit ++77 common getrusage sys_getrusage compat_sys_getrusage ++78 common gettimeofday sys_gettimeofday compat_sys_gettimeofday ++79 common settimeofday sys_settimeofday compat_sys_settimeofday ++80 32 getgroups - compat_sys_s390_getgroups16 ++81 32 setgroups - compat_sys_s390_setgroups16 ++83 common symlink sys_symlink compat_sys_symlink ++85 common readlink sys_readlink compat_sys_readlink ++86 common uselib sys_uselib compat_sys_uselib ++87 common swapon sys_swapon compat_sys_swapon ++88 common reboot sys_reboot compat_sys_reboot ++89 common readdir - compat_sys_old_readdir ++90 common mmap sys_old_mmap compat_sys_s390_old_mmap ++91 common munmap sys_munmap compat_sys_munmap ++92 common truncate sys_truncate compat_sys_truncate ++93 common ftruncate sys_ftruncate compat_sys_ftruncate ++94 common fchmod sys_fchmod sys_fchmod ++95 32 fchown - compat_sys_s390_fchown16 ++96 common getpriority sys_getpriority sys_getpriority ++97 common setpriority sys_setpriority sys_setpriority ++99 common statfs sys_statfs compat_sys_statfs ++100 common fstatfs sys_fstatfs compat_sys_fstatfs ++101 32 ioperm - - ++102 common socketcall sys_socketcall compat_sys_socketcall ++103 common syslog sys_syslog compat_sys_syslog ++104 common setitimer sys_setitimer compat_sys_setitimer ++105 common getitimer sys_getitimer compat_sys_getitimer ++106 common stat sys_newstat compat_sys_newstat ++107 common lstat sys_newlstat compat_sys_newlstat ++108 common fstat sys_newfstat compat_sys_newfstat ++110 common lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie ++111 common vhangup sys_vhangup sys_vhangup ++112 common idle - - ++114 common wait4 sys_wait4 compat_sys_wait4 ++115 common swapoff sys_swapoff compat_sys_swapoff ++116 common sysinfo sys_sysinfo compat_sys_sysinfo ++117 common ipc sys_s390_ipc compat_sys_s390_ipc ++118 common fsync sys_fsync sys_fsync ++119 common sigreturn sys_sigreturn compat_sys_sigreturn ++120 common clone sys_clone compat_sys_clone ++121 common setdomainname sys_setdomainname compat_sys_setdomainname ++122 common uname sys_newuname compat_sys_newuname ++124 common adjtimex sys_adjtimex compat_sys_adjtimex ++125 common mprotect sys_mprotect compat_sys_mprotect ++126 common sigprocmask sys_sigprocmask compat_sys_sigprocmask ++127 common create_module - - ++128 common init_module sys_init_module compat_sys_init_module ++129 common delete_module sys_delete_module compat_sys_delete_module ++130 common get_kernel_syms - - ++131 common quotactl sys_quotactl compat_sys_quotactl ++132 common getpgid sys_getpgid sys_getpgid ++133 common fchdir sys_fchdir sys_fchdir ++134 common bdflush sys_bdflush compat_sys_bdflush ++135 common sysfs sys_sysfs compat_sys_sysfs ++136 common personality sys_s390_personality sys_s390_personality ++137 common afs_syscall - - ++138 32 setfsuid - compat_sys_s390_setfsuid16 ++139 32 setfsgid - compat_sys_s390_setfsgid16 ++140 32 _llseek - compat_sys_llseek ++141 common getdents sys_getdents compat_sys_getdents ++142 32 _newselect - compat_sys_select ++142 64 select sys_select - ++143 common flock sys_flock sys_flock ++144 common msync sys_msync compat_sys_msync ++145 common readv sys_readv compat_sys_readv ++146 common writev sys_writev compat_sys_writev ++147 common getsid sys_getsid sys_getsid ++148 common fdatasync sys_fdatasync sys_fdatasync ++149 common _sysctl sys_sysctl compat_sys_sysctl ++150 common mlock sys_mlock compat_sys_mlock ++151 common munlock sys_munlock compat_sys_munlock ++152 common mlockall sys_mlockall sys_mlockall ++153 common munlockall sys_munlockall sys_munlockall ++154 common sched_setparam sys_sched_setparam compat_sys_sched_setparam ++155 common sched_getparam sys_sched_getparam compat_sys_sched_getparam ++156 common sched_setscheduler sys_sched_setscheduler compat_sys_sched_setscheduler ++157 common sched_getscheduler sys_sched_getscheduler sys_sched_getscheduler ++158 common sched_yield sys_sched_yield sys_sched_yield ++159 common sched_get_priority_max sys_sched_get_priority_max sys_sched_get_priority_max ++160 common sched_get_priority_min sys_sched_get_priority_min sys_sched_get_priority_min ++161 common sched_rr_get_interval sys_sched_rr_get_interval compat_sys_sched_rr_get_interval ++162 common nanosleep sys_nanosleep compat_sys_nanosleep ++163 common mremap sys_mremap compat_sys_mremap ++164 32 setresuid - compat_sys_s390_setresuid16 ++165 32 getresuid - compat_sys_s390_getresuid16 ++167 common query_module - - ++168 common poll sys_poll compat_sys_poll ++169 common nfsservctl - - ++170 32 setresgid - compat_sys_s390_setresgid16 ++171 32 getresgid - compat_sys_s390_getresgid16 ++172 common prctl sys_prctl compat_sys_prctl ++173 common rt_sigreturn sys_rt_sigreturn compat_sys_rt_sigreturn ++174 common rt_sigaction sys_rt_sigaction compat_sys_rt_sigaction ++175 common rt_sigprocmask sys_rt_sigprocmask compat_sys_rt_sigprocmask ++176 common rt_sigpending sys_rt_sigpending compat_sys_rt_sigpending ++177 common rt_sigtimedwait sys_rt_sigtimedwait compat_sys_rt_sigtimedwait ++178 common rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo ++179 common rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend ++180 common pread64 sys_pread64 compat_sys_s390_pread64 ++181 common pwrite64 sys_pwrite64 compat_sys_s390_pwrite64 ++182 32 chown - compat_sys_s390_chown16 ++183 common getcwd sys_getcwd compat_sys_getcwd ++184 common capget sys_capget compat_sys_capget ++185 common capset sys_capset compat_sys_capset ++186 common sigaltstack sys_sigaltstack compat_sys_sigaltstack ++187 common sendfile sys_sendfile64 compat_sys_sendfile ++188 common getpmsg - - ++189 common putpmsg - - ++190 common vfork sys_vfork sys_vfork ++191 32 ugetrlimit - compat_sys_getrlimit ++191 64 getrlimit sys_getrlimit - ++192 32 mmap2 - compat_sys_s390_mmap2 ++193 32 truncate64 - compat_sys_s390_truncate64 ++194 32 ftruncate64 - compat_sys_s390_ftruncate64 ++195 32 stat64 - compat_sys_s390_stat64 ++196 32 lstat64 - compat_sys_s390_lstat64 ++197 32 fstat64 - compat_sys_s390_fstat64 ++198 32 lchown32 - compat_sys_lchown ++198 64 lchown sys_lchown - ++199 32 getuid32 - sys_getuid ++199 64 getuid sys_getuid - ++200 32 getgid32 - sys_getgid ++200 64 getgid sys_getgid - ++201 32 geteuid32 - sys_geteuid ++201 64 geteuid sys_geteuid - ++202 32 getegid32 - sys_getegid ++202 64 getegid sys_getegid - ++203 32 setreuid32 - sys_setreuid ++203 64 setreuid sys_setreuid - ++204 32 setregid32 - sys_setregid ++204 64 setregid sys_setregid - ++205 32 getgroups32 - compat_sys_getgroups ++205 64 getgroups sys_getgroups - ++206 32 setgroups32 - compat_sys_setgroups ++206 64 setgroups sys_setgroups - ++207 32 fchown32 - sys_fchown ++207 64 fchown sys_fchown - ++208 32 setresuid32 - sys_setresuid ++208 64 setresuid sys_setresuid - ++209 32 getresuid32 - compat_sys_getresuid ++209 64 getresuid sys_getresuid - ++210 32 setresgid32 - sys_setresgid ++210 64 setresgid sys_setresgid - ++211 32 getresgid32 - compat_sys_getresgid ++211 64 getresgid sys_getresgid - ++212 32 chown32 - compat_sys_chown ++212 64 chown sys_chown - ++213 32 setuid32 - sys_setuid ++213 64 setuid sys_setuid - ++214 32 setgid32 - sys_setgid ++214 64 setgid sys_setgid - ++215 32 setfsuid32 - sys_setfsuid ++215 64 setfsuid sys_setfsuid - ++216 32 setfsgid32 - sys_setfsgid ++216 64 setfsgid sys_setfsgid - ++217 common pivot_root sys_pivot_root compat_sys_pivot_root ++218 common mincore sys_mincore compat_sys_mincore ++219 common madvise sys_madvise compat_sys_madvise ++220 common getdents64 sys_getdents64 compat_sys_getdents64 ++221 32 fcntl64 - compat_sys_fcntl64 ++222 common readahead sys_readahead compat_sys_s390_readahead ++223 32 sendfile64 - compat_sys_sendfile64 ++224 common setxattr sys_setxattr compat_sys_setxattr ++225 common lsetxattr sys_lsetxattr compat_sys_lsetxattr ++226 common fsetxattr sys_fsetxattr compat_sys_fsetxattr ++227 common getxattr sys_getxattr compat_sys_getxattr ++228 common lgetxattr sys_lgetxattr compat_sys_lgetxattr ++229 common fgetxattr sys_fgetxattr compat_sys_fgetxattr ++230 common listxattr sys_listxattr compat_sys_listxattr ++231 common llistxattr sys_llistxattr compat_sys_llistxattr ++232 common flistxattr sys_flistxattr compat_sys_flistxattr ++233 common removexattr sys_removexattr compat_sys_removexattr ++234 common lremovexattr sys_lremovexattr compat_sys_lremovexattr ++235 common fremovexattr sys_fremovexattr compat_sys_fremovexattr ++236 common gettid sys_gettid sys_gettid ++237 common tkill sys_tkill sys_tkill ++238 common futex sys_futex compat_sys_futex ++239 common sched_setaffinity sys_sched_setaffinity compat_sys_sched_setaffinity ++240 common sched_getaffinity sys_sched_getaffinity compat_sys_sched_getaffinity ++241 common tgkill sys_tgkill sys_tgkill ++243 common io_setup sys_io_setup compat_sys_io_setup ++244 common io_destroy sys_io_destroy compat_sys_io_destroy ++245 common io_getevents sys_io_getevents compat_sys_io_getevents ++246 common io_submit sys_io_submit compat_sys_io_submit ++247 common io_cancel sys_io_cancel compat_sys_io_cancel ++248 common exit_group sys_exit_group sys_exit_group ++249 common epoll_create sys_epoll_create sys_epoll_create ++250 common epoll_ctl sys_epoll_ctl compat_sys_epoll_ctl ++251 common epoll_wait sys_epoll_wait compat_sys_epoll_wait ++252 common set_tid_address sys_set_tid_address compat_sys_set_tid_address ++253 common fadvise64 sys_fadvise64_64 compat_sys_s390_fadvise64 ++254 common timer_create sys_timer_create compat_sys_timer_create ++255 common timer_settime sys_timer_settime compat_sys_timer_settime ++256 common timer_gettime sys_timer_gettime compat_sys_timer_gettime ++257 common timer_getoverrun sys_timer_getoverrun sys_timer_getoverrun ++258 common timer_delete sys_timer_delete sys_timer_delete ++259 common clock_settime sys_clock_settime compat_sys_clock_settime ++260 common clock_gettime sys_clock_gettime compat_sys_clock_gettime ++261 common clock_getres sys_clock_getres compat_sys_clock_getres ++262 common clock_nanosleep sys_clock_nanosleep compat_sys_clock_nanosleep ++264 32 fadvise64_64 - compat_sys_s390_fadvise64_64 ++265 common statfs64 sys_statfs64 compat_sys_statfs64 ++266 common fstatfs64 sys_fstatfs64 compat_sys_fstatfs64 ++267 common remap_file_pages sys_remap_file_pages compat_sys_remap_file_pages ++268 common mbind sys_mbind compat_sys_mbind ++269 common get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy ++270 common set_mempolicy sys_set_mempolicy compat_sys_set_mempolicy ++271 common mq_open sys_mq_open compat_sys_mq_open ++272 common mq_unlink sys_mq_unlink compat_sys_mq_unlink ++273 common mq_timedsend sys_mq_timedsend compat_sys_mq_timedsend ++274 common mq_timedreceive sys_mq_timedreceive compat_sys_mq_timedreceive ++275 common mq_notify sys_mq_notify compat_sys_mq_notify ++276 common mq_getsetattr sys_mq_getsetattr compat_sys_mq_getsetattr ++277 common kexec_load sys_kexec_load compat_sys_kexec_load ++278 common add_key sys_add_key compat_sys_add_key ++279 common request_key sys_request_key compat_sys_request_key ++280 common keyctl sys_keyctl compat_sys_keyctl ++281 common waitid sys_waitid compat_sys_waitid ++282 common ioprio_set sys_ioprio_set sys_ioprio_set ++283 common ioprio_get sys_ioprio_get sys_ioprio_get ++284 common inotify_init sys_inotify_init sys_inotify_init ++285 common inotify_add_watch sys_inotify_add_watch compat_sys_inotify_add_watch ++286 common inotify_rm_watch sys_inotify_rm_watch sys_inotify_rm_watch ++287 common migrate_pages sys_migrate_pages compat_sys_migrate_pages ++288 common openat sys_openat compat_sys_openat ++289 common mkdirat sys_mkdirat compat_sys_mkdirat ++290 common mknodat sys_mknodat compat_sys_mknodat ++291 common fchownat sys_fchownat compat_sys_fchownat ++292 common futimesat sys_futimesat compat_sys_futimesat ++293 32 fstatat64 - compat_sys_s390_fstatat64 ++293 64 newfstatat sys_newfstatat - ++294 common unlinkat sys_unlinkat compat_sys_unlinkat ++295 common renameat sys_renameat compat_sys_renameat ++296 common linkat sys_linkat compat_sys_linkat ++297 common symlinkat sys_symlinkat compat_sys_symlinkat ++298 common readlinkat sys_readlinkat compat_sys_readlinkat ++299 common fchmodat sys_fchmodat compat_sys_fchmodat ++300 common faccessat sys_faccessat compat_sys_faccessat ++301 common pselect6 sys_pselect6 compat_sys_pselect6 ++302 common ppoll sys_ppoll compat_sys_ppoll ++303 common unshare sys_unshare compat_sys_unshare ++304 common set_robust_list sys_set_robust_list compat_sys_set_robust_list ++305 common get_robust_list sys_get_robust_list compat_sys_get_robust_list ++306 common splice sys_splice compat_sys_splice ++307 common sync_file_range sys_sync_file_range compat_sys_s390_sync_file_range ++308 common tee sys_tee compat_sys_tee ++309 common vmsplice sys_vmsplice compat_sys_vmsplice ++310 common move_pages sys_move_pages compat_sys_move_pages ++311 common getcpu sys_getcpu compat_sys_getcpu ++312 common epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait ++313 common utimes sys_utimes compat_sys_utimes ++314 common fallocate sys_fallocate compat_sys_s390_fallocate ++315 common utimensat sys_utimensat compat_sys_utimensat ++316 common signalfd sys_signalfd compat_sys_signalfd ++317 common timerfd - - ++318 common eventfd sys_eventfd sys_eventfd ++319 common timerfd_create sys_timerfd_create sys_timerfd_create ++320 common timerfd_settime sys_timerfd_settime compat_sys_timerfd_settime ++321 common timerfd_gettime sys_timerfd_gettime compat_sys_timerfd_gettime ++322 common signalfd4 sys_signalfd4 compat_sys_signalfd4 ++323 common eventfd2 sys_eventfd2 sys_eventfd2 ++324 common inotify_init1 sys_inotify_init1 sys_inotify_init1 ++325 common pipe2 sys_pipe2 compat_sys_pipe2 ++326 common dup3 sys_dup3 sys_dup3 ++327 common epoll_create1 sys_epoll_create1 sys_epoll_create1 ++328 common preadv sys_preadv compat_sys_preadv ++329 common pwritev sys_pwritev compat_sys_pwritev ++330 common rt_tgsigqueueinfo sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo ++331 common perf_event_open sys_perf_event_open compat_sys_perf_event_open ++332 common fanotify_init sys_fanotify_init sys_fanotify_init ++333 common fanotify_mark sys_fanotify_mark compat_sys_fanotify_mark ++334 common prlimit64 sys_prlimit64 compat_sys_prlimit64 ++335 common name_to_handle_at sys_name_to_handle_at compat_sys_name_to_handle_at ++336 common open_by_handle_at sys_open_by_handle_at compat_sys_open_by_handle_at ++337 common clock_adjtime sys_clock_adjtime compat_sys_clock_adjtime ++338 common syncfs sys_syncfs sys_syncfs ++339 common setns sys_setns sys_setns ++340 common process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv ++341 common process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev ++342 common s390_runtime_instr sys_s390_runtime_instr sys_s390_runtime_instr ++343 common kcmp sys_kcmp compat_sys_kcmp ++344 common finit_module sys_finit_module compat_sys_finit_module ++345 common sched_setattr sys_sched_setattr compat_sys_sched_setattr ++346 common sched_getattr sys_sched_getattr compat_sys_sched_getattr ++347 common renameat2 sys_renameat2 compat_sys_renameat2 ++348 common seccomp sys_seccomp compat_sys_seccomp ++349 common getrandom sys_getrandom compat_sys_getrandom ++350 common memfd_create sys_memfd_create compat_sys_memfd_create ++351 common bpf sys_bpf compat_sys_bpf ++352 common s390_pci_mmio_write sys_s390_pci_mmio_write compat_sys_s390_pci_mmio_write ++353 common s390_pci_mmio_read sys_s390_pci_mmio_read compat_sys_s390_pci_mmio_read ++354 common execveat sys_execveat compat_sys_execveat ++355 common userfaultfd sys_userfaultfd sys_userfaultfd ++356 common membarrier sys_membarrier sys_membarrier ++357 common recvmmsg sys_recvmmsg compat_sys_recvmmsg ++358 common sendmmsg sys_sendmmsg compat_sys_sendmmsg ++359 common socket sys_socket sys_socket ++360 common socketpair sys_socketpair compat_sys_socketpair ++361 common bind sys_bind compat_sys_bind ++362 common connect sys_connect compat_sys_connect ++363 common listen sys_listen sys_listen ++364 common accept4 sys_accept4 compat_sys_accept4 ++365 common getsockopt sys_getsockopt compat_sys_getsockopt ++366 common setsockopt sys_setsockopt compat_sys_setsockopt ++367 common getsockname sys_getsockname compat_sys_getsockname ++368 common getpeername sys_getpeername compat_sys_getpeername ++369 common sendto sys_sendto compat_sys_sendto ++370 common sendmsg sys_sendmsg compat_sys_sendmsg ++371 common recvfrom sys_recvfrom compat_sys_recvfrom ++372 common recvmsg sys_recvmsg compat_sys_recvmsg ++373 common shutdown sys_shutdown sys_shutdown ++374 common mlock2 sys_mlock2 compat_sys_mlock2 ++375 common copy_file_range sys_copy_file_range compat_sys_copy_file_range ++376 common preadv2 sys_preadv2 compat_sys_preadv2 ++377 common pwritev2 sys_pwritev2 compat_sys_pwritev2 ++378 common s390_guarded_storage sys_s390_guarded_storage compat_sys_s390_guarded_storage ++379 common statx sys_statx compat_sys_statx ++380 common s390_sthyi sys_s390_sthyi compat_sys_s390_sthyi +diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c +index c0815a3..539c3d4 100644 +--- a/tools/perf/builtin-c2c.c ++++ b/tools/perf/builtin-c2c.c +@@ -2245,7 +2245,7 @@ static int perf_c2c__browse_cacheline(struct hist_entry *he) + c2c_browser__update_nr_entries(browser); + + while (1) { +- key = hist_browser__run(browser, "? - help"); ++ key = hist_browser__run(browser, "? - help", true); + + switch (key) { + case 's': +@@ -2314,7 +2314,7 @@ static int perf_c2c__hists_browse(struct hists *hists) + c2c_browser__update_nr_entries(browser); + + while (1) { +- key = hist_browser__run(browser, "? - help"); ++ key = hist_browser__run(browser, "? - help", true); + + switch (key) { + case 'q': +diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c +index bf4ca74..a217623 100644 +--- a/tools/perf/builtin-record.c ++++ b/tools/perf/builtin-record.c +@@ -881,6 +881,15 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) + } + } + ++ /* ++ * If we have just single event and are sending data ++ * through pipe, we need to force the ids allocation, ++ * because we synthesize event name through the pipe ++ * and need the id for that. ++ */ ++ if (data->is_pipe && rec->evlist->nr_entries == 1) ++ rec->opts.sample_id = true; ++ + if (record__open(rec) != 0) { + err = -1; + goto out_child; +diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c +index 42a52dc..4ad5dc6 100644 +--- a/tools/perf/builtin-report.c ++++ b/tools/perf/builtin-report.c +@@ -530,7 +530,8 @@ static int report__browse_hists(struct report *rep) + case 1: + ret = perf_evlist__tui_browse_hists(evlist, help, NULL, + rep->min_percent, +- &session->header.env); ++ &session->header.env, ++ true); + /* + * Usually "ret" is the last pressed key, and we only + * care if the key notifies us to switch data file. +diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c +index 98bf9d3..54a4c15 100644 +--- a/tools/perf/builtin-stat.c ++++ b/tools/perf/builtin-stat.c +@@ -917,7 +917,7 @@ static void print_metric_csv(void *ctx, + char buf[64], *vals, *ends; + + if (unit == NULL || fmt == NULL) { +- fprintf(out, "%s%s%s%s", csv_sep, csv_sep, csv_sep, csv_sep); ++ fprintf(out, "%s%s", csv_sep, csv_sep); + return; + } + snprintf(buf, sizeof(buf), fmt, val); +diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c +index c6ccda5..35ac016 100644 +--- a/tools/perf/builtin-top.c ++++ b/tools/perf/builtin-top.c +@@ -283,8 +283,9 @@ static void perf_top__print_sym_table(struct perf_top *top) + + printf("%-*.*s\n", win_width, win_width, graph_dotted_line); + +- if (hists->stats.nr_lost_warned != +- hists->stats.nr_events[PERF_RECORD_LOST]) { ++ if (!top->record_opts.overwrite && ++ (hists->stats.nr_lost_warned != ++ hists->stats.nr_events[PERF_RECORD_LOST])) { + hists->stats.nr_lost_warned = + hists->stats.nr_events[PERF_RECORD_LOST]; + color_fprintf(stdout, PERF_COLOR_RED, +@@ -611,7 +612,8 @@ static void *display_thread_tui(void *arg) + + perf_evlist__tui_browse_hists(top->evlist, help, &hbt, + top->min_percent, +- &top->session->header.env); ++ &top->session->header.env, ++ !top->record_opts.overwrite); + + done = 1; + return NULL; +@@ -807,15 +809,23 @@ static void perf_event__process_sample(struct perf_tool *tool, + + static void perf_top__mmap_read_idx(struct perf_top *top, int idx) + { ++ struct record_opts *opts = &top->record_opts; ++ struct perf_evlist *evlist = top->evlist; + struct perf_sample sample; + struct perf_evsel *evsel; ++ struct perf_mmap *md; + struct perf_session *session = top->session; + union perf_event *event; + struct machine *machine; ++ u64 end, start; + int ret; + +- while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) { +- ret = perf_evlist__parse_sample(top->evlist, event, &sample); ++ md = opts->overwrite ? &evlist->overwrite_mmap[idx] : &evlist->mmap[idx]; ++ if (perf_mmap__read_init(md, opts->overwrite, &start, &end) < 0) ++ return; ++ ++ while ((event = perf_mmap__read_event(md, opts->overwrite, &start, end)) != NULL) { ++ ret = perf_evlist__parse_sample(evlist, event, &sample); + if (ret) { + pr_err("Can't parse sample, err = %d\n", ret); + goto next_event; +@@ -869,16 +879,120 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) + } else + ++session->evlist->stats.nr_unknown_events; + next_event: +- perf_evlist__mmap_consume(top->evlist, idx); ++ perf_mmap__consume(md, opts->overwrite); + } ++ ++ perf_mmap__read_done(md); + } + + static void perf_top__mmap_read(struct perf_top *top) + { ++ bool overwrite = top->record_opts.overwrite; ++ struct perf_evlist *evlist = top->evlist; ++ unsigned long long start, end; + int i; + ++ start = rdclock(); ++ if (overwrite) ++ perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_DATA_PENDING); ++ + for (i = 0; i < top->evlist->nr_mmaps; i++) + perf_top__mmap_read_idx(top, i); ++ ++ if (overwrite) { ++ perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_EMPTY); ++ perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_RUNNING); ++ } ++ end = rdclock(); ++ ++ if ((end - start) > (unsigned long long)top->delay_secs * NSEC_PER_SEC) ++ ui__warning("Too slow to read ring buffer.\n" ++ "Please try increasing the period (-c) or\n" ++ "decreasing the freq (-F) or\n" ++ "limiting the number of CPUs (-C)\n"); ++} ++ ++/* ++ * Check per-event overwrite term. ++ * perf top should support consistent term for all events. ++ * - All events don't have per-event term ++ * E.g. "cpu/cpu-cycles/,cpu/instructions/" ++ * Nothing change, return 0. ++ * - All events have same per-event term ++ * E.g. "cpu/cpu-cycles,no-overwrite/,cpu/instructions,no-overwrite/ ++ * Using the per-event setting to replace the opts->overwrite if ++ * they are different, then return 0. ++ * - Events have different per-event term ++ * E.g. "cpu/cpu-cycles,overwrite/,cpu/instructions,no-overwrite/" ++ * Return -1 ++ * - Some of the event set per-event term, but some not. ++ * E.g. "cpu/cpu-cycles/,cpu/instructions,no-overwrite/" ++ * Return -1 ++ */ ++static int perf_top__overwrite_check(struct perf_top *top) ++{ ++ struct record_opts *opts = &top->record_opts; ++ struct perf_evlist *evlist = top->evlist; ++ struct perf_evsel_config_term *term; ++ struct list_head *config_terms; ++ struct perf_evsel *evsel; ++ int set, overwrite = -1; ++ ++ evlist__for_each_entry(evlist, evsel) { ++ set = -1; ++ config_terms = &evsel->config_terms; ++ list_for_each_entry(term, config_terms, list) { ++ if (term->type == PERF_EVSEL__CONFIG_TERM_OVERWRITE) ++ set = term->val.overwrite ? 1 : 0; ++ } ++ ++ /* no term for current and previous event (likely) */ ++ if ((overwrite < 0) && (set < 0)) ++ continue; ++ ++ /* has term for both current and previous event, compare */ ++ if ((overwrite >= 0) && (set >= 0) && (overwrite != set)) ++ return -1; ++ ++ /* no term for current event but has term for previous one */ ++ if ((overwrite >= 0) && (set < 0)) ++ return -1; ++ ++ /* has term for current event */ ++ if ((overwrite < 0) && (set >= 0)) { ++ /* if it's first event, set overwrite */ ++ if (evsel == perf_evlist__first(evlist)) ++ overwrite = set; ++ else ++ return -1; ++ } ++ } ++ ++ if ((overwrite >= 0) && (opts->overwrite != overwrite)) ++ opts->overwrite = overwrite; ++ ++ return 0; ++} ++ ++static int perf_top_overwrite_fallback(struct perf_top *top, ++ struct perf_evsel *evsel) ++{ ++ struct record_opts *opts = &top->record_opts; ++ struct perf_evlist *evlist = top->evlist; ++ struct perf_evsel *counter; ++ ++ if (!opts->overwrite) ++ return 0; ++ ++ /* only fall back when first event fails */ ++ if (evsel != perf_evlist__first(evlist)) ++ return 0; ++ ++ evlist__for_each_entry(evlist, counter) ++ counter->attr.write_backward = false; ++ opts->overwrite = false; ++ pr_debug2("fall back to non-overwrite mode\n"); ++ return 1; + } + + static int perf_top__start_counters(struct perf_top *top) +@@ -888,12 +1002,33 @@ static int perf_top__start_counters(struct perf_top *top) + struct perf_evlist *evlist = top->evlist; + struct record_opts *opts = &top->record_opts; + ++ if (perf_top__overwrite_check(top)) { ++ ui__error("perf top only support consistent per-event " ++ "overwrite setting for all events\n"); ++ goto out_err; ++ } ++ + perf_evlist__config(evlist, opts, &callchain_param); + + evlist__for_each_entry(evlist, counter) { + try_again: + if (perf_evsel__open(counter, top->evlist->cpus, + top->evlist->threads) < 0) { ++ ++ /* ++ * Specially handle overwrite fall back. ++ * Because perf top is the only tool which has ++ * overwrite mode by default, support ++ * both overwrite and non-overwrite mode, and ++ * require consistent mode for all events. ++ * ++ * May move it to generic code with more tools ++ * have similar attribute. ++ */ ++ if (perf_missing_features.write_backward && ++ perf_top_overwrite_fallback(top, counter)) ++ goto try_again; ++ + if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) { + if (verbose > 0) + ui__warning("%s\n", msg); +@@ -1033,7 +1168,7 @@ static int __cmd_top(struct perf_top *top) + + perf_top__mmap_read(top); + +- if (hits == top->samples) ++ if (opts->overwrite || (hits == top->samples)) + ret = perf_evlist__poll(top->evlist, 100); + + if (resize) { +@@ -1127,6 +1262,7 @@ int cmd_top(int argc, const char **argv) + .uses_mmap = true, + }, + .proc_map_timeout = 500, ++ .overwrite = 1, + }, + .max_stack = sysctl_perf_event_max_stack, + .sym_pcnt_filter = 5, +diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh +index 51abdb0..790ec25 100755 +--- a/tools/perf/check-headers.sh ++++ b/tools/perf/check-headers.sh +@@ -33,7 +33,6 @@ arch/s390/include/uapi/asm/kvm.h + arch/s390/include/uapi/asm/kvm_perf.h + arch/s390/include/uapi/asm/ptrace.h + arch/s390/include/uapi/asm/sie.h +-arch/s390/include/uapi/asm/unistd.h + arch/arm/include/uapi/asm/kvm.h + arch/arm64/include/uapi/asm/kvm.h + arch/alpha/include/uapi/asm/errno.h +diff --git a/tools/perf/perf.h b/tools/perf/perf.h +index cfe4623..57b9b34 100644 +--- a/tools/perf/perf.h ++++ b/tools/perf/perf.h +@@ -61,6 +61,7 @@ struct record_opts { + bool tail_synthesize; + bool overwrite; + bool ignore_missing_thread; ++ bool sample_id; + unsigned int freq; + unsigned int mmap_pages; + unsigned int auxtrace_mmap_pages; +diff --git a/tools/perf/pmu-events/arch/arm64/cortex-a53/branch.json b/tools/perf/pmu-events/arch/arm64/cortex-a53/branch.json +new file mode 100644 +index 0000000..3b62087 +--- /dev/null ++++ b/tools/perf/pmu-events/arch/arm64/cortex-a53/branch.json +@@ -0,0 +1,27 @@ ++[ ++ {, ++ "EventCode": "0x7A", ++ "EventName": "BR_INDIRECT_SPEC", ++ "BriefDescription": "Branch speculatively executed - Indirect branch" ++ }, ++ {, ++ "EventCode": "0xC9", ++ "EventName": "BR_COND", ++ "BriefDescription": "Conditional branch executed" ++ }, ++ {, ++ "EventCode": "0xCA", ++ "EventName": "BR_INDIRECT_MISPRED", ++ "BriefDescription": "Indirect branch mispredicted" ++ }, ++ {, ++ "EventCode": "0xCB", ++ "EventName": "BR_INDIRECT_MISPRED_ADDR", ++ "BriefDescription": "Indirect branch mispredicted because of address miscompare" ++ }, ++ {, ++ "EventCode": "0xCC", ++ "EventName": "BR_COND_MISPRED", ++ "BriefDescription": "Conditional branch mispredicted" ++ } ++] +diff --git a/tools/perf/pmu-events/arch/arm64/cortex-a53/bus.json b/tools/perf/pmu-events/arch/arm64/cortex-a53/bus.json +new file mode 100644 +index 0000000..480d9f7 +--- /dev/null ++++ b/tools/perf/pmu-events/arch/arm64/cortex-a53/bus.json +@@ -0,0 +1,22 @@ ++[ ++ {, ++ "EventCode": "0x60", ++ "EventName": "BUS_ACCESS_LD", ++ "BriefDescription": "Bus access - Read" ++ }, ++ {, ++ "EventCode": "0x61", ++ "EventName": "BUS_ACCESS_ST", ++ "BriefDescription": "Bus access - Write" ++ }, ++ {, ++ "EventCode": "0xC0", ++ "EventName": "EXT_MEM_REQ", ++ "BriefDescription": "External memory request" ++ }, ++ {, ++ "EventCode": "0xC1", ++ "EventName": "EXT_MEM_REQ_NC", ++ "BriefDescription": "Non-cacheable external memory request" ++ } ++] +diff --git a/tools/perf/pmu-events/arch/arm64/cortex-a53/cache.json b/tools/perf/pmu-events/arch/arm64/cortex-a53/cache.json +new file mode 100644 +index 0000000..11baad6 +--- /dev/null ++++ b/tools/perf/pmu-events/arch/arm64/cortex-a53/cache.json +@@ -0,0 +1,27 @@ ++[ ++ {, ++ "EventCode": "0xC2", ++ "EventName": "PREFETCH_LINEFILL", ++ "BriefDescription": "Linefill because of prefetch" ++ }, ++ {, ++ "EventCode": "0xC3", ++ "EventName": "PREFETCH_LINEFILL_DROP", ++ "BriefDescription": "Instruction Cache Throttle occurred" ++ }, ++ {, ++ "EventCode": "0xC4", ++ "EventName": "READ_ALLOC_ENTER", ++ "BriefDescription": "Entering read allocate mode" ++ }, ++ {, ++ "EventCode": "0xC5", ++ "EventName": "READ_ALLOC", ++ "BriefDescription": "Read allocate mode" ++ }, ++ {, ++ "EventCode": "0xC8", ++ "EventName": "EXT_SNOOP", ++ "BriefDescription": "SCU Snooped data from another CPU for this CPU" ++ } ++] +diff --git a/tools/perf/pmu-events/arch/arm64/cortex-a53/memory.json b/tools/perf/pmu-events/arch/arm64/cortex-a53/memory.json +new file mode 100644 +index 0000000..480d9f7 +--- /dev/null ++++ b/tools/perf/pmu-events/arch/arm64/cortex-a53/memory.json +@@ -0,0 +1,22 @@ ++[ ++ {, ++ "EventCode": "0x60", ++ "EventName": "BUS_ACCESS_LD", ++ "BriefDescription": "Bus access - Read" ++ }, ++ {, ++ "EventCode": "0x61", ++ "EventName": "BUS_ACCESS_ST", ++ "BriefDescription": "Bus access - Write" ++ }, ++ {, ++ "EventCode": "0xC0", ++ "EventName": "EXT_MEM_REQ", ++ "BriefDescription": "External memory request" ++ }, ++ {, ++ "EventCode": "0xC1", ++ "EventName": "EXT_MEM_REQ_NC", ++ "BriefDescription": "Non-cacheable external memory request" ++ } ++] +diff --git a/tools/perf/pmu-events/arch/arm64/cortex-a53/other.json b/tools/perf/pmu-events/arch/arm64/cortex-a53/other.json +new file mode 100644 +index 0000000..73a2240 +--- /dev/null ++++ b/tools/perf/pmu-events/arch/arm64/cortex-a53/other.json +@@ -0,0 +1,32 @@ ++[ ++ {, ++ "EventCode": "0x86", ++ "EventName": "EXC_IRQ", ++ "BriefDescription": "Exception taken, IRQ" ++ }, ++ {, ++ "EventCode": "0x87", ++ "EventName": "EXC_FIQ", ++ "BriefDescription": "Exception taken, FIQ" ++ }, ++ {, ++ "EventCode": "0xC6", ++ "EventName": "PRE_DECODE_ERR", ++ "BriefDescription": "Pre-decode error" ++ }, ++ {, ++ "EventCode": "0xD0", ++ "EventName": "L1I_CACHE_ERR", ++ "BriefDescription": "L1 Instruction Cache (data or tag) memory error" ++ }, ++ {, ++ "EventCode": "0xD1", ++ "EventName": "L1D_CACHE_ERR", ++ "BriefDescription": "L1 Data Cache (data, tag or dirty) memory error, correctable or non-correctable" ++ }, ++ {, ++ "EventCode": "0xD2", ++ "EventName": "TLB_ERR", ++ "BriefDescription": "TLB memory error" ++ } ++] +diff --git a/tools/perf/pmu-events/arch/arm64/cortex-a53/pipeline.json b/tools/perf/pmu-events/arch/arm64/cortex-a53/pipeline.json +new file mode 100644 +index 0000000..3149fb9 +--- /dev/null ++++ b/tools/perf/pmu-events/arch/arm64/cortex-a53/pipeline.json +@@ -0,0 +1,52 @@ ++[ ++ {, ++ "EventCode": "0xC7", ++ "EventName": "STALL_SB_FULL", ++ "BriefDescription": "Data Write operation that stalls the pipeline because the store buffer is full" ++ }, ++ {, ++ "EventCode": "0xE0", ++ "EventName": "OTHER_IQ_DEP_STALL", ++ "BriefDescription": "Cycles that the DPU IQ is empty and that is not because of a recent micro-TLB miss, instruction cache miss or pre-decode error" ++ }, ++ {, ++ "EventCode": "0xE1", ++ "EventName": "IC_DEP_STALL", ++ "BriefDescription": "Cycles the DPU IQ is empty and there is an instruction cache miss being processed" ++ }, ++ {, ++ "EventCode": "0xE2", ++ "EventName": "IUTLB_DEP_STALL", ++ "BriefDescription": "Cycles the DPU IQ is empty and there is an instruction micro-TLB miss being processed" ++ }, ++ {, ++ "EventCode": "0xE3", ++ "EventName": "DECODE_DEP_STALL", ++ "BriefDescription": "Cycles the DPU IQ is empty and there is a pre-decode error being processed" ++ }, ++ {, ++ "EventCode": "0xE4", ++ "EventName": "OTHER_INTERLOCK_STALL", ++ "BriefDescription": "Cycles there is an interlock other than Advanced SIMD/Floating-point instructions or load/store instruction" ++ }, ++ {, ++ "EventCode": "0xE5", ++ "EventName": "AGU_DEP_STALL", ++ "BriefDescription": "Cycles there is an interlock for a load/store instruction waiting for data to calculate the address in the AGU" ++ }, ++ {, ++ "EventCode": "0xE6", ++ "EventName": "SIMD_DEP_STALL", ++ "BriefDescription": "Cycles there is an interlock for an Advanced SIMD/Floating-point operation." ++ }, ++ {, ++ "EventCode": "0xE7", ++ "EventName": "LD_DEP_STALL", ++ "BriefDescription": "Cycles there is a stall in the Wr stage because of a load miss" ++ }, ++ {, ++ "EventCode": "0xE8", ++ "EventName": "ST_DEP_STALL", ++ "BriefDescription": "Cycles there is a stall in the Wr stage because of a store" ++ } ++] +diff --git a/tools/perf/pmu-events/arch/arm64/mapfile.csv b/tools/perf/pmu-events/arch/arm64/mapfile.csv +index 219d675..e61c9ca 100644 +--- a/tools/perf/pmu-events/arch/arm64/mapfile.csv ++++ b/tools/perf/pmu-events/arch/arm64/mapfile.csv +@@ -13,3 +13,4 @@ + # + #Family-model,Version,Filename,EventType + 0x00000000420f5160,v1,cavium,core ++0x00000000410fd03[[:xdigit:]],v1,cortex-a53,core +diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c +index 4035d43..e0b1b41 100644 +--- a/tools/perf/tests/backward-ring-buffer.c ++++ b/tools/perf/tests/backward-ring-buffer.c +@@ -31,10 +31,12 @@ static int count_samples(struct perf_evlist *evlist, int *sample_count, + int i; + + for (i = 0; i < evlist->nr_mmaps; i++) { ++ struct perf_mmap *map = &evlist->overwrite_mmap[i]; + union perf_event *event; ++ u64 start, end; + +- perf_mmap__read_catchup(&evlist->overwrite_mmap[i]); +- while ((event = perf_mmap__read_backward(&evlist->overwrite_mmap[i])) != NULL) { ++ perf_mmap__read_init(map, true, &start, &end); ++ while ((event = perf_mmap__read_event(map, true, &start, end)) != NULL) { + const u32 type = event->header.type; + + switch (type) { +@@ -49,6 +51,7 @@ static int count_samples(struct perf_evlist *evlist, int *sample_count, + return TEST_FAIL; + } + } ++ perf_mmap__read_done(map); + } + return TEST_OK; + } +diff --git a/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh b/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh +index 8b3da21..c446c89 100755 +--- a/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh ++++ b/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh +@@ -22,10 +22,23 @@ trace_libc_inet_pton_backtrace() { + expected[4]="rtt min.*" + expected[5]="[0-9]+\.[0-9]+[[:space:]]+probe_libc:inet_pton:\([[:xdigit:]]+\)" + expected[6]=".*inet_pton[[:space:]]\($libc\)$" +- expected[7]="getaddrinfo[[:space:]]\($libc\)$" +- expected[8]=".*\(.*/bin/ping.*\)$" +- +- perf trace --no-syscalls -e probe_libc:inet_pton/max-stack=3/ ping -6 -c 1 ::1 2>&1 | grep -v ^$ | while read line ; do ++ case "$(uname -m)" in ++ s390x) ++ eventattr='call-graph=dwarf' ++ expected[7]="gaih_inet[[:space:]]\(inlined\)$" ++ expected[8]="__GI_getaddrinfo[[:space:]]\(inlined\)$" ++ expected[9]="main[[:space:]]\(.*/bin/ping.*\)$" ++ expected[10]="__libc_start_main[[:space:]]\($libc\)$" ++ expected[11]="_start[[:space:]]\(.*/bin/ping.*\)$" ++ ;; ++ *) ++ eventattr='max-stack=3' ++ expected[7]="getaddrinfo[[:space:]]\($libc\)$" ++ expected[8]=".*\(.*/bin/ping.*\)$" ++ ;; ++ esac ++ ++ perf trace --no-syscalls -e probe_libc:inet_pton/$eventattr/ ping -6 -c 1 ::1 2>&1 | grep -v ^$ | while read line ; do + echo $line + echo "$line" | egrep -q "${expected[$idx]}" + if [ $? -ne 0 ] ; then +@@ -33,7 +46,7 @@ trace_libc_inet_pton_backtrace() { + exit 1 + fi + let idx+=1 +- [ $idx -eq 9 ] && break ++ [ -z "${expected[$idx]}" ] && break + done + } + +diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c +index 2864279..fbf927c 100644 +--- a/tools/perf/ui/browsers/annotate.c ++++ b/tools/perf/ui/browsers/annotate.c +@@ -327,7 +327,32 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) + if (!disasm_line__is_valid_jump(cursor, sym)) + return; + ++ /* ++ * This first was seen with a gcc function, _cpp_lex_token, that ++ * has the usual jumps: ++ * ++ * │1159e6c: ↓ jne 115aa32 <_cpp_lex_token@@Base+0xf92> ++ * ++ * I.e. jumps to a label inside that function (_cpp_lex_token), and ++ * those works, but also this kind: ++ * ++ * │1159e8b: ↓ jne c469be ++ * ++ * I.e. jumps to another function, outside _cpp_lex_token, which ++ * are not being correctly handled generating as a side effect references ++ * to ab->offset[] entries that are set to NULL, so to make this code ++ * more robust, check that here. ++ * ++ * A proper fix for will be put in place, looking at the function ++ * name right after the '<' token and probably treating this like a ++ * 'call' instruction. ++ */ + target = ab->offsets[cursor->ops.target.offset]; ++ if (target == NULL) { ++ ui_helpline__printf("WARN: jump target inconsistency, press 'o', ab->offsets[%#x] = NULL\n", ++ cursor->ops.target.offset); ++ return; ++ } + + bcursor = browser_line(&cursor->al); + btarget = browser_line(target); +diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c +index 68146f4..6495ee5 100644 +--- a/tools/perf/ui/browsers/hists.c ++++ b/tools/perf/ui/browsers/hists.c +@@ -608,7 +608,8 @@ static int hist_browser__title(struct hist_browser *browser, char *bf, size_t si + return browser->title ? browser->title(browser, bf, size) : 0; + } + +-int hist_browser__run(struct hist_browser *browser, const char *help) ++int hist_browser__run(struct hist_browser *browser, const char *help, ++ bool warn_lost_event) + { + int key; + char title[160]; +@@ -638,8 +639,9 @@ int hist_browser__run(struct hist_browser *browser, const char *help) + nr_entries = hist_browser__nr_entries(browser); + ui_browser__update_nr_entries(&browser->b, nr_entries); + +- if (browser->hists->stats.nr_lost_warned != +- browser->hists->stats.nr_events[PERF_RECORD_LOST]) { ++ if (warn_lost_event && ++ (browser->hists->stats.nr_lost_warned != ++ browser->hists->stats.nr_events[PERF_RECORD_LOST])) { + browser->hists->stats.nr_lost_warned = + browser->hists->stats.nr_events[PERF_RECORD_LOST]; + ui_browser__warn_lost_events(&browser->b); +@@ -2763,7 +2765,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, + bool left_exits, + struct hist_browser_timer *hbt, + float min_pcnt, +- struct perf_env *env) ++ struct perf_env *env, ++ bool warn_lost_event) + { + struct hists *hists = evsel__hists(evsel); + struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env); +@@ -2844,7 +2847,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, + + nr_options = 0; + +- key = hist_browser__run(browser, helpline); ++ key = hist_browser__run(browser, helpline, ++ warn_lost_event); + + if (browser->he_selection != NULL) { + thread = hist_browser__selected_thread(browser); +@@ -3184,7 +3188,8 @@ static void perf_evsel_menu__write(struct ui_browser *browser, + + static int perf_evsel_menu__run(struct perf_evsel_menu *menu, + int nr_events, const char *help, +- struct hist_browser_timer *hbt) ++ struct hist_browser_timer *hbt, ++ bool warn_lost_event) + { + struct perf_evlist *evlist = menu->b.priv; + struct perf_evsel *pos; +@@ -3203,7 +3208,9 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, + case K_TIMER: + hbt->timer(hbt->arg); + +- if (!menu->lost_events_warned && menu->lost_events) { ++ if (!menu->lost_events_warned && ++ menu->lost_events && ++ warn_lost_event) { + ui_browser__warn_lost_events(&menu->b); + menu->lost_events_warned = true; + } +@@ -3224,7 +3231,8 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, + key = perf_evsel__hists_browse(pos, nr_events, help, + true, hbt, + menu->min_pcnt, +- menu->env); ++ menu->env, ++ warn_lost_event); + ui_browser__show_title(&menu->b, title); + switch (key) { + case K_TAB: +@@ -3282,7 +3290,8 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, + int nr_entries, const char *help, + struct hist_browser_timer *hbt, + float min_pcnt, +- struct perf_env *env) ++ struct perf_env *env, ++ bool warn_lost_event) + { + struct perf_evsel *pos; + struct perf_evsel_menu menu = { +@@ -3309,13 +3318,15 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, + menu.b.width = line_len; + } + +- return perf_evsel_menu__run(&menu, nr_entries, help, hbt); ++ return perf_evsel_menu__run(&menu, nr_entries, help, ++ hbt, warn_lost_event); + } + + int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, + struct hist_browser_timer *hbt, + float min_pcnt, +- struct perf_env *env) ++ struct perf_env *env, ++ bool warn_lost_event) + { + int nr_entries = evlist->nr_entries; + +@@ -3325,7 +3336,7 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, + + return perf_evsel__hists_browse(first, nr_entries, help, + false, hbt, min_pcnt, +- env); ++ env, warn_lost_event); + } + + if (symbol_conf.event_group) { +@@ -3342,5 +3353,6 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, + } + + return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, +- hbt, min_pcnt, env); ++ hbt, min_pcnt, env, ++ warn_lost_event); + } +diff --git a/tools/perf/ui/browsers/hists.h b/tools/perf/ui/browsers/hists.h +index ba43177..9428bee 100644 +--- a/tools/perf/ui/browsers/hists.h ++++ b/tools/perf/ui/browsers/hists.h +@@ -28,7 +28,8 @@ struct hist_browser { + + struct hist_browser *hist_browser__new(struct hists *hists); + void hist_browser__delete(struct hist_browser *browser); +-int hist_browser__run(struct hist_browser *browser, const char *help); ++int hist_browser__run(struct hist_browser *browser, const char *help, ++ bool warn_lost_event); + void hist_browser__init(struct hist_browser *browser, + struct hists *hists); + #endif /* _PERF_UI_BROWSER_HISTS_H_ */ +diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c +index 9faf3b5..6470ea2 100644 +--- a/tools/perf/util/auxtrace.c ++++ b/tools/perf/util/auxtrace.c +@@ -60,6 +60,12 @@ + #include "sane_ctype.h" + #include "symbol/kallsyms.h" + ++static bool auxtrace__dont_decode(struct perf_session *session) ++{ ++ return !session->itrace_synth_opts || ++ session->itrace_synth_opts->dont_decode; ++} ++ + int auxtrace_mmap__mmap(struct auxtrace_mmap *mm, + struct auxtrace_mmap_params *mp, + void *userpg, int fd) +@@ -762,6 +768,9 @@ int auxtrace_queues__process_index(struct auxtrace_queues *queues, + size_t i; + int err; + ++ if (auxtrace__dont_decode(session)) ++ return 0; ++ + list_for_each_entry(auxtrace_index, &session->auxtrace_index, list) { + for (i = 0; i < auxtrace_index->nr; i++) { + ent = &auxtrace_index->entries[i]; +@@ -892,12 +901,6 @@ int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr, + return err; + } + +-static bool auxtrace__dont_decode(struct perf_session *session) +-{ +- return !session->itrace_synth_opts || +- session->itrace_synth_opts->dont_decode; +-} +- + int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_session *session) +diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c +index ac35cd2..e5fc14e 100644 +--- a/tools/perf/util/evlist.c ++++ b/tools/perf/util/evlist.c +@@ -715,28 +715,11 @@ union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, int + return perf_mmap__read_forward(md); + } + +-union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx) +-{ +- struct perf_mmap *md = &evlist->mmap[idx]; +- +- /* +- * No need to check messup for backward ring buffer: +- * We can always read arbitrary long data from a backward +- * ring buffer unless we forget to pause it before reading. +- */ +- return perf_mmap__read_backward(md); +-} +- + union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) + { + return perf_evlist__mmap_read_forward(evlist, idx); + } + +-void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx) +-{ +- perf_mmap__read_catchup(&evlist->mmap[idx]); +-} +- + void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx) + { + perf_mmap__consume(&evlist->mmap[idx], false); +diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h +index 75f8e0a..336b838 100644 +--- a/tools/perf/util/evlist.h ++++ b/tools/perf/util/evlist.h +@@ -133,10 +133,6 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx); + + union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, + int idx); +-union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist, +- int idx); +-void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx); +- + void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); + + int perf_evlist__open(struct perf_evlist *evlist); +diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c +index ff359c9..ef35168 100644 +--- a/tools/perf/util/evsel.c ++++ b/tools/perf/util/evsel.c +@@ -41,17 +41,7 @@ + + #include "sane_ctype.h" + +-static struct { +- bool sample_id_all; +- bool exclude_guest; +- bool mmap2; +- bool cloexec; +- bool clockid; +- bool clockid_wrong; +- bool lbr_flags; +- bool write_backward; +- bool group_read; +-} perf_missing_features; ++struct perf_missing_features perf_missing_features; + + static clockid_t clockid; + +diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h +index 846e416..a7487c6 100644 +--- a/tools/perf/util/evsel.h ++++ b/tools/perf/util/evsel.h +@@ -149,6 +149,20 @@ union u64_swap { + u32 val32[2]; + }; + ++struct perf_missing_features { ++ bool sample_id_all; ++ bool exclude_guest; ++ bool mmap2; ++ bool cloexec; ++ bool clockid; ++ bool clockid_wrong; ++ bool lbr_flags; ++ bool write_backward; ++ bool group_read; ++}; ++ ++extern struct perf_missing_features perf_missing_features; ++ + struct cpu_map; + struct target; + struct thread_map; +diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h +index f6630cb..02721b57 100644 +--- a/tools/perf/util/hist.h ++++ b/tools/perf/util/hist.h +@@ -430,7 +430,8 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, + int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, + struct hist_browser_timer *hbt, + float min_pcnt, +- struct perf_env *env); ++ struct perf_env *env, ++ bool warn_lost_event); + int script_browse(const char *script_opt); + #else + static inline +@@ -438,7 +439,8 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, + const char *help __maybe_unused, + struct hist_browser_timer *hbt __maybe_unused, + float min_pcnt __maybe_unused, +- struct perf_env *env __maybe_unused) ++ struct perf_env *env __maybe_unused, ++ bool warn_lost_event __maybe_unused) + { + return 0; + } +diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c +index 05076e6..91531a7 100644 +--- a/tools/perf/util/mmap.c ++++ b/tools/perf/util/mmap.c +@@ -22,29 +22,27 @@ size_t perf_mmap__mmap_len(struct perf_mmap *map) + + /* When check_messup is true, 'end' must points to a good entry */ + static union perf_event *perf_mmap__read(struct perf_mmap *map, +- u64 start, u64 end, u64 *prev) ++ u64 *startp, u64 end) + { + unsigned char *data = map->base + page_size; + union perf_event *event = NULL; +- int diff = end - start; ++ int diff = end - *startp; + + if (diff >= (int)sizeof(event->header)) { + size_t size; + +- event = (union perf_event *)&data[start & map->mask]; ++ event = (union perf_event *)&data[*startp & map->mask]; + size = event->header.size; + +- if (size < sizeof(event->header) || diff < (int)size) { +- event = NULL; +- goto broken_event; +- } ++ if (size < sizeof(event->header) || diff < (int)size) ++ return NULL; + + /* + * Event straddles the mmap boundary -- header should always + * be inside due to u64 alignment of output. + */ +- if ((start & map->mask) + size != ((start + size) & map->mask)) { +- unsigned int offset = start; ++ if ((*startp & map->mask) + size != ((*startp + size) & map->mask)) { ++ unsigned int offset = *startp; + unsigned int len = min(sizeof(*event), size), cpy; + void *dst = map->event_copy; + +@@ -59,20 +57,19 @@ static union perf_event *perf_mmap__read(struct perf_mmap *map, + event = (union perf_event *)map->event_copy; + } + +- start += size; ++ *startp += size; + } + +-broken_event: +- if (prev) +- *prev = start; +- + return event; + } + ++/* ++ * legacy interface for mmap read. ++ * Don't use it. Use perf_mmap__read_event(). ++ */ + union perf_event *perf_mmap__read_forward(struct perf_mmap *map) + { + u64 head; +- u64 old = map->prev; + + /* + * Check if event was unmapped due to a POLLHUP/POLLERR. +@@ -82,13 +79,26 @@ union perf_event *perf_mmap__read_forward(struct perf_mmap *map) + + head = perf_mmap__read_head(map); + +- return perf_mmap__read(map, old, head, &map->prev); ++ return perf_mmap__read(map, &map->prev, head); + } + +-union perf_event *perf_mmap__read_backward(struct perf_mmap *map) ++/* ++ * Read event from ring buffer one by one. ++ * Return one event for each call. ++ * ++ * Usage: ++ * perf_mmap__read_init() ++ * while(event = perf_mmap__read_event()) { ++ * //process the event ++ * perf_mmap__consume() ++ * } ++ * perf_mmap__read_done() ++ */ ++union perf_event *perf_mmap__read_event(struct perf_mmap *map, ++ bool overwrite, ++ u64 *startp, u64 end) + { +- u64 head, end; +- u64 start = map->prev; ++ union perf_event *event; + + /* + * Check if event was unmapped due to a POLLHUP/POLLERR. +@@ -96,40 +106,19 @@ union perf_event *perf_mmap__read_backward(struct perf_mmap *map) + if (!refcount_read(&map->refcnt)) + return NULL; + +- head = perf_mmap__read_head(map); +- if (!head) ++ if (startp == NULL) + return NULL; + +- /* +- * 'head' pointer starts from 0. Kernel minus sizeof(record) form +- * it each time when kernel writes to it, so in fact 'head' is +- * negative. 'end' pointer is made manually by adding the size of +- * the ring buffer to 'head' pointer, means the validate data can +- * read is the whole ring buffer. If 'end' is positive, the ring +- * buffer has not fully filled, so we must adjust 'end' to 0. +- * +- * However, since both 'head' and 'end' is unsigned, we can't +- * simply compare 'end' against 0. Here we compare '-head' and +- * the size of the ring buffer, where -head is the number of bytes +- * kernel write to the ring buffer. +- */ +- if (-head < (u64)(map->mask + 1)) +- end = 0; +- else +- end = head + map->mask + 1; +- +- return perf_mmap__read(map, start, end, &map->prev); +-} ++ /* non-overwirte doesn't pause the ringbuffer */ ++ if (!overwrite) ++ end = perf_mmap__read_head(map); + +-void perf_mmap__read_catchup(struct perf_mmap *map) +-{ +- u64 head; ++ event = perf_mmap__read(map, startp, end); + +- if (!refcount_read(&map->refcnt)) +- return; ++ if (!overwrite) ++ map->prev = *startp; + +- head = perf_mmap__read_head(map); +- map->prev = head; ++ return event; + } + + static bool perf_mmap__empty(struct perf_mmap *map) +@@ -267,41 +256,60 @@ static int overwrite_rb_find_range(void *buf, int mask, u64 head, u64 *start, u6 + return -1; + } + +-int perf_mmap__push(struct perf_mmap *md, bool overwrite, +- void *to, int push(void *to, void *buf, size_t size)) ++/* ++ * Report the start and end of the available data in ringbuffer ++ */ ++int perf_mmap__read_init(struct perf_mmap *md, bool overwrite, ++ u64 *startp, u64 *endp) + { + u64 head = perf_mmap__read_head(md); + u64 old = md->prev; +- u64 end = head, start = old; + unsigned char *data = md->base + page_size; + unsigned long size; +- void *buf; +- int rc = 0; + +- start = overwrite ? head : old; +- end = overwrite ? old : head; ++ *startp = overwrite ? head : old; ++ *endp = overwrite ? old : head; + +- if (start == end) +- return 0; ++ if (*startp == *endp) ++ return -EAGAIN; + +- size = end - start; ++ size = *endp - *startp; + if (size > (unsigned long)(md->mask) + 1) { + if (!overwrite) { + WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n"); + + md->prev = head; + perf_mmap__consume(md, overwrite); +- return 0; ++ return -EAGAIN; + } + + /* + * Backward ring buffer is full. We still have a chance to read + * most of data from it. + */ +- if (overwrite_rb_find_range(data, md->mask, head, &start, &end)) +- return -1; ++ if (overwrite_rb_find_range(data, md->mask, head, startp, endp)) ++ return -EINVAL; + } + ++ return 0; ++} ++ ++int perf_mmap__push(struct perf_mmap *md, bool overwrite, ++ void *to, int push(void *to, void *buf, size_t size)) ++{ ++ u64 head = perf_mmap__read_head(md); ++ u64 end, start; ++ unsigned char *data = md->base + page_size; ++ unsigned long size; ++ void *buf; ++ int rc = 0; ++ ++ rc = perf_mmap__read_init(md, overwrite, &start, &end); ++ if (rc < 0) ++ return (rc == -EAGAIN) ? 0 : -1; ++ ++ size = end - start; ++ + if ((start & md->mask) + size != (end & md->mask)) { + buf = &data[start & md->mask]; + size = md->mask + 1 - (start & md->mask); +@@ -327,3 +335,14 @@ int perf_mmap__push(struct perf_mmap *md, bool overwrite, + out: + return rc; + } ++ ++/* ++ * Mandatory for overwrite mode ++ * The direction of overwrite mode is backward. ++ * The last perf_mmap__read() will set tail to map->prev. ++ * Need to correct the map->prev to head which is the end of next read. ++ */ ++void perf_mmap__read_done(struct perf_mmap *map) ++{ ++ map->prev = perf_mmap__read_head(map); ++} +diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h +index e43d7b5..ec7d3a24 100644 +--- a/tools/perf/util/mmap.h ++++ b/tools/perf/util/mmap.h +@@ -65,8 +65,6 @@ void perf_mmap__put(struct perf_mmap *map); + + void perf_mmap__consume(struct perf_mmap *map, bool overwrite); + +-void perf_mmap__read_catchup(struct perf_mmap *md); +- + static inline u64 perf_mmap__read_head(struct perf_mmap *mm) + { + struct perf_event_mmap_page *pc = mm->base; +@@ -87,11 +85,17 @@ static inline void perf_mmap__write_tail(struct perf_mmap *md, u64 tail) + } + + union perf_event *perf_mmap__read_forward(struct perf_mmap *map); +-union perf_event *perf_mmap__read_backward(struct perf_mmap *map); ++ ++union perf_event *perf_mmap__read_event(struct perf_mmap *map, ++ bool overwrite, ++ u64 *startp, u64 end); + + int perf_mmap__push(struct perf_mmap *md, bool backward, + void *to, int push(void *to, void *buf, size_t size)); + + size_t perf_mmap__mmap_len(struct perf_mmap *map); + ++int perf_mmap__read_init(struct perf_mmap *md, bool overwrite, ++ u64 *startp, u64 *endp); ++void perf_mmap__read_done(struct perf_mmap *map); + #endif /*__PERF_MMAP_H */ +diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c +index 1e97937..6f09e49 100644 +--- a/tools/perf/util/record.c ++++ b/tools/perf/util/record.c +@@ -137,6 +137,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, + struct perf_evsel *evsel; + bool use_sample_identifier = false; + bool use_comm_exec; ++ bool sample_id = opts->sample_id; + + /* + * Set the evsel leader links before we configure attributes, +@@ -163,8 +164,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, + * match the id. + */ + use_sample_identifier = perf_can_sample_identifier(); +- evlist__for_each_entry(evlist, evsel) +- perf_evsel__set_sample_id(evsel, use_sample_identifier); ++ sample_id = true; + } else if (evlist->nr_entries > 1) { + struct perf_evsel *first = perf_evlist__first(evlist); + +@@ -174,6 +174,10 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, + use_sample_identifier = perf_can_sample_identifier(); + break; + } ++ sample_id = true; ++ } ++ ++ if (sample_id) { + evlist__for_each_entry(evlist, evsel) + perf_evsel__set_sample_id(evsel, use_sample_identifier); + } +diff --git a/tools/perf/util/trigger.h b/tools/perf/util/trigger.h +index 370138e..88223bc 100644 +--- a/tools/perf/util/trigger.h ++++ b/tools/perf/util/trigger.h +@@ -12,7 +12,7 @@ + * States and transits: + * + * +- * OFF--(on)--> READY --(hit)--> HIT ++ * OFF--> ON --> READY --(hit)--> HIT + * ^ | + * | (ready) + * | | +@@ -27,8 +27,9 @@ struct trigger { + volatile enum { + TRIGGER_ERROR = -2, + TRIGGER_OFF = -1, +- TRIGGER_READY = 0, +- TRIGGER_HIT = 1, ++ TRIGGER_ON = 0, ++ TRIGGER_READY = 1, ++ TRIGGER_HIT = 2, + } state; + const char *name; + }; +@@ -50,7 +51,7 @@ static inline bool trigger_is_error(struct trigger *t) + static inline void trigger_on(struct trigger *t) + { + TRIGGER_WARN_ONCE(t, TRIGGER_OFF); +- t->state = TRIGGER_READY; ++ t->state = TRIGGER_ON; + } + + static inline void trigger_ready(struct trigger *t) +diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c +index 443892d..1019bbc 100644 +--- a/tools/perf/util/util.c ++++ b/tools/perf/util/util.c +@@ -340,35 +340,15 @@ size_t hex_width(u64 v) + return n; + } + +-static int hex(char ch) +-{ +- if ((ch >= '0') && (ch <= '9')) +- return ch - '0'; +- if ((ch >= 'a') && (ch <= 'f')) +- return ch - 'a' + 10; +- if ((ch >= 'A') && (ch <= 'F')) +- return ch - 'A' + 10; +- return -1; +-} +- + /* + * While we find nice hex chars, build a long_val. + * Return number of chars processed. + */ + int hex2u64(const char *ptr, u64 *long_val) + { +- const char *p = ptr; +- *long_val = 0; +- +- while (*p) { +- const int hex_val = hex(*p); ++ char *p; + +- if (hex_val < 0) +- break; +- +- *long_val = (*long_val << 4) | hex_val; +- p++; +- } ++ *long_val = strtoull(ptr, &p, 16); + + return p - ptr; + } +diff --git a/tools/power/acpi/Makefile.config b/tools/power/acpi/Makefile.config +index a1883bb..2cccbba 100644 +--- a/tools/power/acpi/Makefile.config ++++ b/tools/power/acpi/Makefile.config +@@ -56,9 +56,6 @@ INSTALL_SCRIPT = ${INSTALL_PROGRAM} + # to compile vs uClibc, that can be done here as well. + CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc- + CROSS_COMPILE ?= $(CROSS) +-CC = $(CROSS_COMPILE)gcc +-LD = $(CROSS_COMPILE)gcc +-STRIP = $(CROSS_COMPILE)strip + HOSTCC = gcc + + # check if compiler option is supported +diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include +index fcb3ed0..dd61446 100644 +--- a/tools/scripts/Makefile.include ++++ b/tools/scripts/Makefile.include +@@ -42,6 +42,24 @@ EXTRA_WARNINGS += -Wformat + + CC_NO_CLANG := $(shell $(CC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?) + ++# Makefiles suck: This macro sets a default value of $(2) for the ++# variable named by $(1), unless the variable has been set by ++# environment or command line. This is necessary for CC and AR ++# because make sets default values, so the simpler ?= approach ++# won't work as expected. ++define allow-override ++ $(if $(or $(findstring environment,$(origin $(1))),\ ++ $(findstring command line,$(origin $(1)))),,\ ++ $(eval $(1) = $(2))) ++endef ++ ++# Allow setting various cross-compile vars or setting CROSS_COMPILE as a prefix. ++$(call allow-override,CC,$(CROSS_COMPILE)gcc) ++$(call allow-override,AR,$(CROSS_COMPILE)ar) ++$(call allow-override,LD,$(CROSS_COMPILE)ld) ++$(call allow-override,CXX,$(CROSS_COMPILE)g++) ++$(call allow-override,STRIP,$(CROSS_COMPILE)strip) ++ + ifeq ($(CC_NO_CLANG), 1) + EXTRA_WARNINGS += -Wstrict-aliasing=3 + endif +diff --git a/tools/spi/Makefile b/tools/spi/Makefile +index 90615e1..815d155 100644 +--- a/tools/spi/Makefile ++++ b/tools/spi/Makefile +@@ -11,8 +11,6 @@ endif + # (this improves performance and avoids hard-to-debug behaviour); + MAKEFLAGS += -r + +-CC = $(CROSS_COMPILE)gcc +-LD = $(CROSS_COMPILE)ld + CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include + + ALL_TARGETS := spidev_test spidev_fdx +diff --git a/tools/testing/radix-tree/idr-test.c b/tools/testing/radix-tree/idr-test.c +index 44ef9eb..6c645eb 100644 +--- a/tools/testing/radix-tree/idr-test.c ++++ b/tools/testing/radix-tree/idr-test.c +@@ -178,6 +178,55 @@ void idr_get_next_test(int base) + idr_destroy(&idr); + } + ++int idr_u32_cb(int id, void *ptr, void *data) ++{ ++ BUG_ON(id < 0); ++ BUG_ON(ptr != DUMMY_PTR); ++ return 0; ++} ++ ++void idr_u32_test1(struct idr *idr, u32 handle) ++{ ++ static bool warned = false; ++ u32 id = handle; ++ int sid = 0; ++ void *ptr; ++ ++ BUG_ON(idr_alloc_u32(idr, DUMMY_PTR, &id, id, GFP_KERNEL)); ++ BUG_ON(id != handle); ++ BUG_ON(idr_alloc_u32(idr, DUMMY_PTR, &id, id, GFP_KERNEL) != -ENOSPC); ++ BUG_ON(id != handle); ++ if (!warned && id > INT_MAX) ++ printk("vvv Ignore these warnings\n"); ++ ptr = idr_get_next(idr, &sid); ++ if (id > INT_MAX) { ++ BUG_ON(ptr != NULL); ++ BUG_ON(sid != 0); ++ } else { ++ BUG_ON(ptr != DUMMY_PTR); ++ BUG_ON(sid != id); ++ } ++ idr_for_each(idr, idr_u32_cb, NULL); ++ if (!warned && id > INT_MAX) { ++ printk("^^^ Warnings over\n"); ++ warned = true; ++ } ++ BUG_ON(idr_remove(idr, id) != DUMMY_PTR); ++ BUG_ON(!idr_is_empty(idr)); ++} ++ ++void idr_u32_test(int base) ++{ ++ DEFINE_IDR(idr); ++ idr_init_base(&idr, base); ++ idr_u32_test1(&idr, 10); ++ idr_u32_test1(&idr, 0x7fffffff); ++ idr_u32_test1(&idr, 0x80000000); ++ idr_u32_test1(&idr, 0x80000001); ++ idr_u32_test1(&idr, 0xffe00000); ++ idr_u32_test1(&idr, 0xffffffff); ++} ++ + void idr_checks(void) + { + unsigned long i; +@@ -248,6 +297,9 @@ void idr_checks(void) + idr_get_next_test(0); + idr_get_next_test(1); + idr_get_next_test(4); ++ idr_u32_test(4); ++ idr_u32_test(1); ++ idr_u32_test(0); + } + + /* +diff --git a/tools/testing/radix-tree/linux.c b/tools/testing/radix-tree/linux.c +index 6903ccf..44a0d1a 100644 +--- a/tools/testing/radix-tree/linux.c ++++ b/tools/testing/radix-tree/linux.c +@@ -29,7 +29,7 @@ void *kmem_cache_alloc(struct kmem_cache *cachep, int flags) + { + struct radix_tree_node *node; + +- if (flags & __GFP_NOWARN) ++ if (!(flags & __GFP_DIRECT_RECLAIM)) + return NULL; + + pthread_mutex_lock(&cachep->lock); +@@ -73,10 +73,17 @@ void kmem_cache_free(struct kmem_cache *cachep, void *objp) + + void *kmalloc(size_t size, gfp_t gfp) + { +- void *ret = malloc(size); ++ void *ret; ++ ++ if (!(gfp & __GFP_DIRECT_RECLAIM)) ++ return NULL; ++ ++ ret = malloc(size); + uatomic_inc(&nr_allocated); + if (kmalloc_verbose) + printf("Allocating %p from malloc\n", ret); ++ if (gfp & __GFP_ZERO) ++ memset(ret, 0, size); + return ret; + } + +diff --git a/tools/testing/radix-tree/linux/compiler_types.h b/tools/testing/radix-tree/linux/compiler_types.h +new file mode 100644 +index 0000000..e69de29 +diff --git a/tools/testing/radix-tree/linux/gfp.h b/tools/testing/radix-tree/linux/gfp.h +index e9fff59..e3201cc 100644 +--- a/tools/testing/radix-tree/linux/gfp.h ++++ b/tools/testing/radix-tree/linux/gfp.h +@@ -11,6 +11,7 @@ + #define __GFP_IO 0x40u + #define __GFP_FS 0x80u + #define __GFP_NOWARN 0x200u ++#define __GFP_ZERO 0x8000u + #define __GFP_ATOMIC 0x80000u + #define __GFP_ACCOUNT 0x100000u + #define __GFP_DIRECT_RECLAIM 0x400000u +diff --git a/tools/testing/radix-tree/linux/slab.h b/tools/testing/radix-tree/linux/slab.h +index 979baee..a037def 100644 +--- a/tools/testing/radix-tree/linux/slab.h ++++ b/tools/testing/radix-tree/linux/slab.h +@@ -3,6 +3,7 @@ + #define SLAB_H + + #include ++#include + + #define SLAB_HWCACHE_ALIGN 1 + #define SLAB_PANIC 2 +@@ -11,6 +12,11 @@ + void *kmalloc(size_t size, gfp_t); + void kfree(void *); + ++static inline void *kzalloc(size_t size, gfp_t gfp) ++{ ++ return kmalloc(size, gfp | __GFP_ZERO); ++} ++ + void *kmem_cache_alloc(struct kmem_cache *cachep, int flags); + void kmem_cache_free(struct kmem_cache *cachep, void *objp); + +diff --git a/tools/testing/selftests/android/Makefile b/tools/testing/selftests/android/Makefile +index 1a74922..f6304d2 100644 +--- a/tools/testing/selftests/android/Makefile ++++ b/tools/testing/selftests/android/Makefile +@@ -11,11 +11,11 @@ all: + BUILD_TARGET=$(OUTPUT)/$$DIR; \ + mkdir $$BUILD_TARGET -p; \ + make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ +- #SUBDIR test prog name should be in the form: SUBDIR_test.sh ++ #SUBDIR test prog name should be in the form: SUBDIR_test.sh \ + TEST=$$DIR"_test.sh"; \ +- if [ -e $$DIR/$$TEST ]; then +- rsync -a $$DIR/$$TEST $$BUILD_TARGET/; +- fi ++ if [ -e $$DIR/$$TEST ]; then \ ++ rsync -a $$DIR/$$TEST $$BUILD_TARGET/; \ ++ fi \ + done + + override define RUN_TESTS +diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore +index cc15af2..9cf83f8 100644 +--- a/tools/testing/selftests/bpf/.gitignore ++++ b/tools/testing/selftests/bpf/.gitignore +@@ -11,3 +11,4 @@ test_progs + test_tcpbpf_user + test_verifier_log + feature ++test_libbpf_open +diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c +index 436c4c7..9e03a4c 100644 +--- a/tools/testing/selftests/bpf/test_maps.c ++++ b/tools/testing/selftests/bpf/test_maps.c +@@ -126,6 +126,8 @@ static void test_hashmap_sizes(int task, void *data) + fd = bpf_create_map(BPF_MAP_TYPE_HASH, i, j, + 2, map_flags); + if (fd < 0) { ++ if (errno == ENOMEM) ++ return; + printf("Failed to create hashmap key=%d value=%d '%s'\n", + i, j, strerror(errno)); + exit(1); +diff --git a/tools/testing/selftests/bpf/test_tcpbpf_kern.c b/tools/testing/selftests/bpf/test_tcpbpf_kern.c +index 57119ad..3e645ee 100644 +--- a/tools/testing/selftests/bpf/test_tcpbpf_kern.c ++++ b/tools/testing/selftests/bpf/test_tcpbpf_kern.c +@@ -5,7 +5,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c +index c0f16e9..437c0b1 100644 +--- a/tools/testing/selftests/bpf/test_verifier.c ++++ b/tools/testing/selftests/bpf/test_verifier.c +@@ -2587,6 +2587,32 @@ static struct bpf_test tests[] = { + .result = ACCEPT, + }, + { ++ "runtime/jit: pass negative index to tail_call", ++ .insns = { ++ BPF_MOV64_IMM(BPF_REG_3, -1), ++ BPF_LD_MAP_FD(BPF_REG_2, 0), ++ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, ++ BPF_FUNC_tail_call), ++ BPF_MOV64_IMM(BPF_REG_0, 0), ++ BPF_EXIT_INSN(), ++ }, ++ .fixup_prog = { 1 }, ++ .result = ACCEPT, ++ }, ++ { ++ "runtime/jit: pass > 32bit index to tail_call", ++ .insns = { ++ BPF_LD_IMM64(BPF_REG_3, 0x100000000ULL), ++ BPF_LD_MAP_FD(BPF_REG_2, 0), ++ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, ++ BPF_FUNC_tail_call), ++ BPF_MOV64_IMM(BPF_REG_0, 0), ++ BPF_EXIT_INSN(), ++ }, ++ .fixup_prog = { 2 }, ++ .result = ACCEPT, ++ }, ++ { + "stack pointer arithmetic", + .insns = { + BPF_MOV64_IMM(BPF_REG_1, 4), +@@ -11137,6 +11163,64 @@ static struct bpf_test tests[] = { + .result = REJECT, + .prog_type = BPF_PROG_TYPE_TRACEPOINT, + }, ++ { ++ "xadd/w check unaligned stack", ++ .insns = { ++ BPF_MOV64_IMM(BPF_REG_0, 1), ++ BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8), ++ BPF_STX_XADD(BPF_W, BPF_REG_10, BPF_REG_0, -7), ++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8), ++ BPF_EXIT_INSN(), ++ }, ++ .result = REJECT, ++ .errstr = "misaligned stack access off", ++ .prog_type = BPF_PROG_TYPE_SCHED_CLS, ++ }, ++ { ++ "xadd/w check unaligned map", ++ .insns = { ++ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), ++ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), ++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), ++ BPF_LD_MAP_FD(BPF_REG_1, 0), ++ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, ++ BPF_FUNC_map_lookup_elem), ++ BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), ++ BPF_EXIT_INSN(), ++ BPF_MOV64_IMM(BPF_REG_1, 1), ++ BPF_STX_XADD(BPF_W, BPF_REG_0, BPF_REG_1, 3), ++ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 3), ++ BPF_EXIT_INSN(), ++ }, ++ .fixup_map1 = { 3 }, ++ .result = REJECT, ++ .errstr = "misaligned value access off", ++ .prog_type = BPF_PROG_TYPE_SCHED_CLS, ++ }, ++ { ++ "xadd/w check unaligned pkt", ++ .insns = { ++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, ++ offsetof(struct xdp_md, data)), ++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, ++ offsetof(struct xdp_md, data_end)), ++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), ++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), ++ BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 2), ++ BPF_MOV64_IMM(BPF_REG_0, 99), ++ BPF_JMP_IMM(BPF_JA, 0, 0, 6), ++ BPF_MOV64_IMM(BPF_REG_0, 1), ++ BPF_ST_MEM(BPF_W, BPF_REG_2, 0, 0), ++ BPF_ST_MEM(BPF_W, BPF_REG_2, 3, 0), ++ BPF_STX_XADD(BPF_W, BPF_REG_2, BPF_REG_0, 1), ++ BPF_STX_XADD(BPF_W, BPF_REG_2, BPF_REG_0, 2), ++ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 1), ++ BPF_EXIT_INSN(), ++ }, ++ .result = REJECT, ++ .errstr = "BPF_XADD stores into R2 packet", ++ .prog_type = BPF_PROG_TYPE_XDP, ++ }, + }; + + static int probe_filter_length(const struct bpf_insn *fp) +diff --git a/tools/testing/selftests/futex/Makefile b/tools/testing/selftests/futex/Makefile +index cea4adc..a63e845 100644 +--- a/tools/testing/selftests/futex/Makefile ++++ b/tools/testing/selftests/futex/Makefile +@@ -12,9 +12,9 @@ all: + BUILD_TARGET=$(OUTPUT)/$$DIR; \ + mkdir $$BUILD_TARGET -p; \ + make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ +- if [ -e $$DIR/$(TEST_PROGS) ]; then +- rsync -a $$DIR/$(TEST_PROGS) $$BUILD_TARGET/; +- fi ++ if [ -e $$DIR/$(TEST_PROGS) ]; then \ ++ rsync -a $$DIR/$(TEST_PROGS) $$BUILD_TARGET/; \ ++ fi \ + done + + override define RUN_TESTS +diff --git a/tools/testing/selftests/memfd/Makefile b/tools/testing/selftests/memfd/Makefile +index a5276a9..0862e6f 100644 +--- a/tools/testing/selftests/memfd/Makefile ++++ b/tools/testing/selftests/memfd/Makefile +@@ -5,6 +5,7 @@ CFLAGS += -I../../../../include/ + CFLAGS += -I../../../../usr/include/ + + TEST_PROGS := run_tests.sh ++TEST_FILES := run_fuse_test.sh + TEST_GEN_FILES := memfd_test fuse_mnt fuse_test + + fuse_mnt.o: CFLAGS += $(shell pkg-config fuse --cflags) +diff --git a/tools/testing/selftests/memfd/config b/tools/testing/selftests/memfd/config +new file mode 100644 +index 0000000..835c7f4 +--- /dev/null ++++ b/tools/testing/selftests/memfd/config +@@ -0,0 +1 @@ ++CONFIG_FUSE_FS=m +diff --git a/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile +index 86636d2..686da51 100644 +--- a/tools/testing/selftests/memory-hotplug/Makefile ++++ b/tools/testing/selftests/memory-hotplug/Makefile +@@ -4,8 +4,9 @@ all: + include ../lib.mk + + TEST_PROGS := mem-on-off-test.sh +-override RUN_TESTS := ./mem-on-off-test.sh -r 2 && echo "selftests: memory-hotplug [PASS]" || echo "selftests: memory-hotplug [FAIL]" +-override EMIT_TESTS := echo "$(RUN_TESTS)" ++override RUN_TESTS := @./mem-on-off-test.sh -r 2 && echo "selftests: memory-hotplug [PASS]" || echo "selftests: memory-hotplug [FAIL]" ++ ++override EMIT_TESTS := echo "$(subst @,,$(RUN_TESTS))" + + run_full_test: + @/bin/bash ./mem-on-off-test.sh && echo "memory-hotplug selftests: [PASS]" || echo "memory-hotplug selftests: [FAIL]" +diff --git a/tools/testing/selftests/powerpc/alignment/alignment_handler.c b/tools/testing/selftests/powerpc/alignment/alignment_handler.c +index 39fd362..0f2698f 100644 +--- a/tools/testing/selftests/powerpc/alignment/alignment_handler.c ++++ b/tools/testing/selftests/powerpc/alignment/alignment_handler.c +@@ -57,7 +57,7 @@ volatile int gotsig; + + void sighandler(int sig, siginfo_t *info, void *ctx) + { +- struct ucontext *ucp = ctx; ++ ucontext_t *ucp = ctx; + + if (!testing) { + signal(sig, SIG_DFL); +diff --git a/tools/testing/selftests/powerpc/mm/subpage_prot.c b/tools/testing/selftests/powerpc/mm/subpage_prot.c +index 35ade74..3ae77ba 100644 +--- a/tools/testing/selftests/powerpc/mm/subpage_prot.c ++++ b/tools/testing/selftests/powerpc/mm/subpage_prot.c +@@ -135,6 +135,16 @@ static int run_test(void *addr, unsigned long size) + return 0; + } + ++static int syscall_available(void) ++{ ++ int rc; ++ ++ errno = 0; ++ rc = syscall(__NR_subpage_prot, 0, 0, 0); ++ ++ return rc == 0 || (errno != ENOENT && errno != ENOSYS); ++} ++ + int test_anon(void) + { + unsigned long align; +@@ -145,6 +155,8 @@ int test_anon(void) + void *mallocblock; + unsigned long mallocsize; + ++ SKIP_IF(!syscall_available()); ++ + if (getpagesize() != 0x10000) { + fprintf(stderr, "Kernel page size must be 64K!\n"); + return 1; +@@ -180,6 +192,8 @@ int test_file(void) + off_t filesize; + int fd; + ++ SKIP_IF(!syscall_available()); ++ + fd = open(file_name, O_RDWR); + if (fd == -1) { + perror("failed to open file"); +diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile +index a234539..5c72ff9 100644 +--- a/tools/testing/selftests/powerpc/tm/Makefile ++++ b/tools/testing/selftests/powerpc/tm/Makefile +@@ -16,7 +16,7 @@ $(OUTPUT)/tm-syscall: tm-syscall-asm.S + $(OUTPUT)/tm-syscall: CFLAGS += -I../../../../../usr/include + $(OUTPUT)/tm-tmspr: CFLAGS += -pthread + $(OUTPUT)/tm-vmx-unavail: CFLAGS += -pthread -m64 +-$(OUTPUT)/tm-resched-dscr: ../pmu/lib.o ++$(OUTPUT)/tm-resched-dscr: ../pmu/lib.c + $(OUTPUT)/tm-unavailable: CFLAGS += -O0 -pthread -m64 -Wno-error=uninitialized -mvsx + $(OUTPUT)/tm-trap: CFLAGS += -O0 -pthread -m64 + +diff --git a/tools/testing/selftests/powerpc/tm/tm-trap.c b/tools/testing/selftests/powerpc/tm/tm-trap.c +index 5d92c23..179d592 100644 +--- a/tools/testing/selftests/powerpc/tm/tm-trap.c ++++ b/tools/testing/selftests/powerpc/tm/tm-trap.c +@@ -255,6 +255,8 @@ int tm_trap_test(void) + + struct sigaction trap_sa; + ++ SKIP_IF(!have_htm()); ++ + trap_sa.sa_flags = SA_SIGINFO; + trap_sa.sa_sigaction = trap_signal_handler; + sigaction(SIGTRAP, &trap_sa, NULL); +diff --git a/tools/testing/selftests/pstore/config b/tools/testing/selftests/pstore/config +index 6a8e5a9..d148f9f 100644 +--- a/tools/testing/selftests/pstore/config ++++ b/tools/testing/selftests/pstore/config +@@ -2,3 +2,4 @@ CONFIG_MISC_FILESYSTEMS=y + CONFIG_PSTORE=y + CONFIG_PSTORE_PMSG=y + CONFIG_PSTORE_CONSOLE=y ++CONFIG_PSTORE_RAM=m +diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c +index 0b457e8..5df6099 100644 +--- a/tools/testing/selftests/seccomp/seccomp_bpf.c ++++ b/tools/testing/selftests/seccomp/seccomp_bpf.c +@@ -141,6 +141,15 @@ struct seccomp_data { + #define SECCOMP_FILTER_FLAG_LOG 2 + #endif + ++#ifndef PTRACE_SECCOMP_GET_METADATA ++#define PTRACE_SECCOMP_GET_METADATA 0x420d ++ ++struct seccomp_metadata { ++ __u64 filter_off; /* Input: which filter */ ++ __u64 flags; /* Output: filter's flags */ ++}; ++#endif ++ + #ifndef seccomp + int seccomp(unsigned int op, unsigned int flags, void *args) + { +@@ -2845,6 +2854,58 @@ TEST(get_action_avail) + EXPECT_EQ(errno, EOPNOTSUPP); + } + ++TEST(get_metadata) ++{ ++ pid_t pid; ++ int pipefd[2]; ++ char buf; ++ struct seccomp_metadata md; ++ ++ ASSERT_EQ(0, pipe(pipefd)); ++ ++ pid = fork(); ++ ASSERT_GE(pid, 0); ++ if (pid == 0) { ++ struct sock_filter filter[] = { ++ BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), ++ }; ++ struct sock_fprog prog = { ++ .len = (unsigned short)ARRAY_SIZE(filter), ++ .filter = filter, ++ }; ++ ++ /* one with log, one without */ ++ ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, ++ SECCOMP_FILTER_FLAG_LOG, &prog)); ++ ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog)); ++ ++ ASSERT_EQ(0, close(pipefd[0])); ++ ASSERT_EQ(1, write(pipefd[1], "1", 1)); ++ ASSERT_EQ(0, close(pipefd[1])); ++ ++ while (1) ++ sleep(100); ++ } ++ ++ ASSERT_EQ(0, close(pipefd[1])); ++ ASSERT_EQ(1, read(pipefd[0], &buf, 1)); ++ ++ ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid)); ++ ASSERT_EQ(pid, waitpid(pid, NULL, 0)); ++ ++ md.filter_off = 0; ++ ASSERT_EQ(sizeof(md), ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md)); ++ EXPECT_EQ(md.flags, SECCOMP_FILTER_FLAG_LOG); ++ EXPECT_EQ(md.filter_off, 0); ++ ++ md.filter_off = 1; ++ ASSERT_EQ(sizeof(md), ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md)); ++ EXPECT_EQ(md.flags, 0); ++ EXPECT_EQ(md.filter_off, 1); ++ ++ ASSERT_EQ(0, kill(pid, SIGKILL)); ++} ++ + /* + * TODO: + * - add microbenchmarks +diff --git a/tools/testing/selftests/sync/Makefile b/tools/testing/selftests/sync/Makefile +index b3c8ba3..d0121a8 100644 +--- a/tools/testing/selftests/sync/Makefile ++++ b/tools/testing/selftests/sync/Makefile +@@ -30,7 +30,7 @@ $(TEST_CUSTOM_PROGS): $(TESTS) $(OBJS) + $(CC) -o $(TEST_CUSTOM_PROGS) $(OBJS) $(TESTS) $(CFLAGS) $(LDFLAGS) + + $(OBJS): $(OUTPUT)/%.o: %.c +- $(CC) -c $^ -o $@ ++ $(CC) -c $^ -o $@ $(CFLAGS) + + $(TESTS): $(OUTPUT)/%.o: %.c + $(CC) -c $^ -o $@ +diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json b/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json +index e3407505..90bba48 100644 +--- a/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json ++++ b/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json +@@ -315,7 +315,7 @@ + "cmdUnderTest": "$TC actions ls action skbmod", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbmod index 4", +- "matchPattern": "action order [0-9]*: skbmod pipe set etype 0x0031", ++ "matchPattern": "action order [0-9]*: skbmod pipe set etype 0x31", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbmod" +diff --git a/tools/testing/selftests/vDSO/Makefile b/tools/testing/selftests/vDSO/Makefile +index 3d5a62ff..f5d7a78 100644 +--- a/tools/testing/selftests/vDSO/Makefile ++++ b/tools/testing/selftests/vDSO/Makefile +@@ -1,4 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 ++include ../lib.mk ++ + ifndef CROSS_COMPILE + CFLAGS := -std=gnu99 + CFLAGS_vdso_standalone_test_x86 := -nostdlib -fno-asynchronous-unwind-tables -fno-stack-protector +@@ -6,16 +8,14 @@ ifeq ($(CONFIG_X86_32),y) + LDLIBS += -lgcc_s + endif + +-TEST_PROGS := vdso_test vdso_standalone_test_x86 ++TEST_PROGS := $(OUTPUT)/vdso_test $(OUTPUT)/vdso_standalone_test_x86 + + all: $(TEST_PROGS) +-vdso_test: parse_vdso.c vdso_test.c +-vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c ++$(OUTPUT)/vdso_test: parse_vdso.c vdso_test.c ++$(OUTPUT)/vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c + $(CC) $(CFLAGS) $(CFLAGS_vdso_standalone_test_x86) \ + vdso_standalone_test_x86.c parse_vdso.c \ +- -o vdso_standalone_test_x86 ++ -o $@ + +-include ../lib.mk +-clean: +- rm -fr $(TEST_PROGS) ++EXTRA_CLEAN := $(TEST_PROGS) + endif +diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore +index 63c94d7..342c7bc 100644 +--- a/tools/testing/selftests/vm/.gitignore ++++ b/tools/testing/selftests/vm/.gitignore +@@ -11,3 +11,4 @@ mlock-intersect-test + mlock-random-test + virtual_address_range + gup_benchmark ++va_128TBswitch +diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests +index d256189..22d5646 100755 +--- a/tools/testing/selftests/vm/run_vmtests ++++ b/tools/testing/selftests/vm/run_vmtests +@@ -2,25 +2,33 @@ + # SPDX-License-Identifier: GPL-2.0 + #please run as root + +-#we need 256M, below is the size in kB +-needmem=262144 + mnt=./huge + exitcode=0 + +-#get pagesize and freepages from /proc/meminfo ++#get huge pagesize and freepages from /proc/meminfo + while read name size unit; do + if [ "$name" = "HugePages_Free:" ]; then + freepgs=$size + fi + if [ "$name" = "Hugepagesize:" ]; then +- pgsize=$size ++ hpgsize_KB=$size + fi + done < /proc/meminfo + ++# Simple hugetlbfs tests have a hardcoded minimum requirement of ++# huge pages totaling 256MB (262144KB) in size. The userfaultfd ++# hugetlb test requires a minimum of 2 * nr_cpus huge pages. Take ++# both of these requirements into account and attempt to increase ++# number of huge pages available. ++nr_cpus=$(nproc) ++hpgsize_MB=$((hpgsize_KB / 1024)) ++half_ufd_size_MB=$((((nr_cpus * hpgsize_MB + 127) / 128) * 128)) ++needmem_KB=$((half_ufd_size_MB * 2 * 1024)) ++ + #set proper nr_hugepages +-if [ -n "$freepgs" ] && [ -n "$pgsize" ]; then ++if [ -n "$freepgs" ] && [ -n "$hpgsize_KB" ]; then + nr_hugepgs=`cat /proc/sys/vm/nr_hugepages` +- needpgs=`expr $needmem / $pgsize` ++ needpgs=$((needmem_KB / hpgsize_KB)) + tries=2 + while [ $tries -gt 0 ] && [ $freepgs -lt $needpgs ]; do + lackpgs=$(( $needpgs - $freepgs )) +@@ -107,8 +115,9 @@ fi + echo "---------------------------" + echo "running userfaultfd_hugetlb" + echo "---------------------------" +-# 256MB total huge pages == 128MB src and 128MB dst +-./userfaultfd hugetlb 128 32 $mnt/ufd_test_file ++# Test requires source and destination huge pages. Size of source ++# (half_ufd_size_MB) is passed as argument to test. ++./userfaultfd hugetlb $half_ufd_size_MB 32 $mnt/ufd_test_file + if [ $? -ne 0 ]; then + echo "[FAIL]" + exitcode=1 +diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile +index 10ca46d..d744991 100644 +--- a/tools/testing/selftests/x86/Makefile ++++ b/tools/testing/selftests/x86/Makefile +@@ -5,16 +5,26 @@ include ../lib.mk + + .PHONY: all all_32 all_64 warn_32bit_failure clean + +-TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \ +- check_initial_reg_state sigreturn ldt_gdt iopl mpx-mini-test ioperm \ ++UNAME_M := $(shell uname -m) ++CAN_BUILD_I386 := $(shell ./check_cc.sh $(CC) trivial_32bit_program.c -m32) ++CAN_BUILD_X86_64 := $(shell ./check_cc.sh $(CC) trivial_64bit_program.c) ++ ++TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \ ++ check_initial_reg_state sigreturn iopl mpx-mini-test ioperm \ + protection_keys test_vdso test_vsyscall + TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ + test_FCMOV test_FCOMI test_FISTTP \ + vdso_restorer +-TARGETS_C_64BIT_ONLY := fsgsbase sysret_rip 5lvl ++TARGETS_C_64BIT_ONLY := fsgsbase sysret_rip ++# Some selftests require 32bit support enabled also on 64bit systems ++TARGETS_C_32BIT_NEEDED := ldt_gdt ptrace_syscall + +-TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) ++TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) $(TARGETS_C_32BIT_NEEDED) + TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY) ++ifeq ($(CAN_BUILD_I386)$(CAN_BUILD_X86_64),11) ++TARGETS_C_64BIT_ALL += $(TARGETS_C_32BIT_NEEDED) ++endif ++ + BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32) + BINARIES_64 := $(TARGETS_C_64BIT_ALL:%=%_64) + +@@ -23,10 +33,6 @@ BINARIES_64 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_64)) + + CFLAGS := -O2 -g -std=gnu99 -pthread -Wall -no-pie + +-UNAME_M := $(shell uname -m) +-CAN_BUILD_I386 := $(shell ./check_cc.sh $(CC) trivial_32bit_program.c -m32) +-CAN_BUILD_X86_64 := $(shell ./check_cc.sh $(CC) trivial_64bit_program.c) +- + define gen-target-rule-32 + $(1) $(1)_32: $(OUTPUT)/$(1)_32 + .PHONY: $(1) $(1)_32 +@@ -40,12 +46,14 @@ endef + ifeq ($(CAN_BUILD_I386),1) + all: all_32 + TEST_PROGS += $(BINARIES_32) ++EXTRA_CFLAGS += -DCAN_BUILD_32 + $(foreach t,$(TARGETS_C_32BIT_ALL),$(eval $(call gen-target-rule-32,$(t)))) + endif + + ifeq ($(CAN_BUILD_X86_64),1) + all: all_64 + TEST_PROGS += $(BINARIES_64) ++EXTRA_CFLAGS += -DCAN_BUILD_64 + $(foreach t,$(TARGETS_C_64BIT_ALL),$(eval $(call gen-target-rule-64,$(t)))) + endif + +diff --git a/tools/testing/selftests/x86/mpx-mini-test.c b/tools/testing/selftests/x86/mpx-mini-test.c +index ec0f6b4..9c0325e 100644 +--- a/tools/testing/selftests/x86/mpx-mini-test.c ++++ b/tools/testing/selftests/x86/mpx-mini-test.c +@@ -315,11 +315,39 @@ static inline void *__si_bounds_upper(siginfo_t *si) + return si->si_upper; + } + #else ++ ++/* ++ * This deals with old version of _sigfault in some distros: ++ * ++ ++old _sigfault: ++ struct { ++ void *si_addr; ++ } _sigfault; ++ ++new _sigfault: ++ struct { ++ void __user *_addr; ++ int _trapno; ++ short _addr_lsb; ++ union { ++ struct { ++ void __user *_lower; ++ void __user *_upper; ++ } _addr_bnd; ++ __u32 _pkey; ++ }; ++ } _sigfault; ++ * ++ */ ++ + static inline void **__si_bounds_hack(siginfo_t *si) + { + void *sigfault = &si->_sifields._sigfault; + void *end_sigfault = sigfault + sizeof(si->_sifields._sigfault); +- void **__si_lower = end_sigfault; ++ int *trapno = (int*)end_sigfault; ++ /* skip _trapno and _addr_lsb */ ++ void **__si_lower = (void**)(trapno + 2); + + return __si_lower; + } +@@ -331,7 +359,7 @@ static inline void *__si_bounds_lower(siginfo_t *si) + + static inline void *__si_bounds_upper(siginfo_t *si) + { +- return (*__si_bounds_hack(si)) + sizeof(void *); ++ return *(__si_bounds_hack(si) + 1); + } + #endif + +diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c +index bc1b073..f15aa5a 100644 +--- a/tools/testing/selftests/x86/protection_keys.c ++++ b/tools/testing/selftests/x86/protection_keys.c +@@ -393,34 +393,6 @@ pid_t fork_lazy_child(void) + return forkret; + } + +-void davecmp(void *_a, void *_b, int len) +-{ +- int i; +- unsigned long *a = _a; +- unsigned long *b = _b; +- +- for (i = 0; i < len / sizeof(*a); i++) { +- if (a[i] == b[i]) +- continue; +- +- dprintf3("[%3d]: a: %016lx b: %016lx\n", i, a[i], b[i]); +- } +-} +- +-void dumpit(char *f) +-{ +- int fd = open(f, O_RDONLY); +- char buf[100]; +- int nr_read; +- +- dprintf2("maps fd: %d\n", fd); +- do { +- nr_read = read(fd, &buf[0], sizeof(buf)); +- write(1, buf, nr_read); +- } while (nr_read > 0); +- close(fd); +-} +- + #define PKEY_DISABLE_ACCESS 0x1 + #define PKEY_DISABLE_WRITE 0x2 + +diff --git a/tools/testing/selftests/x86/single_step_syscall.c b/tools/testing/selftests/x86/single_step_syscall.c +index a48da95..ddfdd63 100644 +--- a/tools/testing/selftests/x86/single_step_syscall.c ++++ b/tools/testing/selftests/x86/single_step_syscall.c +@@ -119,7 +119,9 @@ static void check_result(void) + + int main() + { ++#ifdef CAN_BUILD_32 + int tmp; ++#endif + + sethandler(SIGTRAP, sigtrap, 0); + +@@ -139,12 +141,13 @@ int main() + : : "c" (post_nop) : "r11"); + check_result(); + #endif +- ++#ifdef CAN_BUILD_32 + printf("[RUN]\tSet TF and check int80\n"); + set_eflags(get_eflags() | X86_EFLAGS_TF); + asm volatile ("int $0x80" : "=a" (tmp) : "a" (SYS_getpid) + : INT80_CLOBBERS); + check_result(); ++#endif + + /* + * This test is particularly interesting if fast syscalls use +diff --git a/tools/testing/selftests/x86/test_mremap_vdso.c b/tools/testing/selftests/x86/test_mremap_vdso.c +index bf0d687..64f11c8 100644 +--- a/tools/testing/selftests/x86/test_mremap_vdso.c ++++ b/tools/testing/selftests/x86/test_mremap_vdso.c +@@ -90,8 +90,12 @@ int main(int argc, char **argv, char **envp) + vdso_size += PAGE_SIZE; + } + ++#ifdef __i386__ + /* Glibc is likely to explode now - exit with raw syscall */ + asm volatile ("int $0x80" : : "a" (__NR_exit), "b" (!!ret)); ++#else /* __x86_64__ */ ++ syscall(SYS_exit, ret); ++#endif + } else { + int status; + +diff --git a/tools/testing/selftests/x86/test_vdso.c b/tools/testing/selftests/x86/test_vdso.c +index 29973cd..2352590 100644 +--- a/tools/testing/selftests/x86/test_vdso.c ++++ b/tools/testing/selftests/x86/test_vdso.c +@@ -26,20 +26,59 @@ + # endif + #endif + ++/* max length of lines in /proc/self/maps - anything longer is skipped here */ ++#define MAPS_LINE_LEN 128 ++ + int nerrs = 0; + ++typedef long (*getcpu_t)(unsigned *, unsigned *, void *); ++ ++getcpu_t vgetcpu; ++getcpu_t vdso_getcpu; ++ ++static void *vsyscall_getcpu(void) ++{ + #ifdef __x86_64__ +-# define VSYS(x) (x) ++ FILE *maps; ++ char line[MAPS_LINE_LEN]; ++ bool found = false; ++ ++ maps = fopen("/proc/self/maps", "r"); ++ if (!maps) /* might still be present, but ignore it here, as we test vDSO not vsyscall */ ++ return NULL; ++ ++ while (fgets(line, MAPS_LINE_LEN, maps)) { ++ char r, x; ++ void *start, *end; ++ char name[MAPS_LINE_LEN]; ++ ++ /* sscanf() is safe here as strlen(name) >= strlen(line) */ ++ if (sscanf(line, "%p-%p %c-%cp %*x %*x:%*x %*u %s", ++ &start, &end, &r, &x, name) != 5) ++ continue; ++ ++ if (strcmp(name, "[vsyscall]")) ++ continue; ++ ++ /* assume entries are OK, as we test vDSO here not vsyscall */ ++ found = true; ++ break; ++ } ++ ++ fclose(maps); ++ ++ if (!found) { ++ printf("Warning: failed to find vsyscall getcpu\n"); ++ return NULL; ++ } ++ return (void *) (0xffffffffff600800); + #else +-# define VSYS(x) 0 ++ return NULL; + #endif ++} + +-typedef long (*getcpu_t)(unsigned *, unsigned *, void *); +- +-const getcpu_t vgetcpu = (getcpu_t)VSYS(0xffffffffff600800); +-getcpu_t vdso_getcpu; + +-void fill_function_pointers() ++static void fill_function_pointers() + { + void *vdso = dlopen("linux-vdso.so.1", + RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); +@@ -54,6 +93,8 @@ void fill_function_pointers() + vdso_getcpu = (getcpu_t)dlsym(vdso, "__vdso_getcpu"); + if (!vdso_getcpu) + printf("Warning: failed to find getcpu in vDSO\n"); ++ ++ vgetcpu = (getcpu_t) vsyscall_getcpu(); + } + + static long sys_getcpu(unsigned * cpu, unsigned * node, +diff --git a/tools/testing/selftests/x86/test_vsyscall.c b/tools/testing/selftests/x86/test_vsyscall.c +index 7a744fa..0b4f1cc 100644 +--- a/tools/testing/selftests/x86/test_vsyscall.c ++++ b/tools/testing/selftests/x86/test_vsyscall.c +@@ -33,6 +33,9 @@ + # endif + #endif + ++/* max length of lines in /proc/self/maps - anything longer is skipped here */ ++#define MAPS_LINE_LEN 128 ++ + static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), + int flags) + { +@@ -98,7 +101,7 @@ static int init_vsys(void) + #ifdef __x86_64__ + int nerrs = 0; + FILE *maps; +- char line[128]; ++ char line[MAPS_LINE_LEN]; + bool found = false; + + maps = fopen("/proc/self/maps", "r"); +@@ -108,10 +111,12 @@ static int init_vsys(void) + return 0; + } + +- while (fgets(line, sizeof(line), maps)) { ++ while (fgets(line, MAPS_LINE_LEN, maps)) { + char r, x; + void *start, *end; +- char name[128]; ++ char name[MAPS_LINE_LEN]; ++ ++ /* sscanf() is safe here as strlen(name) >= strlen(line) */ + if (sscanf(line, "%p-%p %c-%cp %*x %*x:%*x %*u %s", + &start, &end, &r, &x, name) != 5) + continue; +@@ -445,7 +450,7 @@ static void sigtrap(int sig, siginfo_t *info, void *ctx_void) + num_vsyscall_traps++; + } + +-static int test_native_vsyscall(void) ++static int test_emulation(void) + { + time_t tmp; + bool is_native; +@@ -453,7 +458,7 @@ static int test_native_vsyscall(void) + if (!vtime) + return 0; + +- printf("[RUN]\tchecking for native vsyscall\n"); ++ printf("[RUN]\tchecking that vsyscalls are emulated\n"); + sethandler(SIGTRAP, sigtrap, 0); + set_eflags(get_eflags() | X86_EFLAGS_TF); + vtime(&tmp); +@@ -469,11 +474,12 @@ static int test_native_vsyscall(void) + */ + is_native = (num_vsyscall_traps > 1); + +- printf("\tvsyscalls are %s (%d instructions in vsyscall page)\n", ++ printf("[%s]\tvsyscalls are %s (%d instructions in vsyscall page)\n", ++ (is_native ? "FAIL" : "OK"), + (is_native ? "native" : "emulated"), + (int)num_vsyscall_traps); + +- return 0; ++ return is_native; + } + #endif + +@@ -493,7 +499,7 @@ int main(int argc, char **argv) + nerrs += test_vsys_r(); + + #ifdef __x86_64__ +- nerrs += test_native_vsyscall(); ++ nerrs += test_emulation(); + #endif + + return nerrs ? 1 : 0; +diff --git a/tools/usb/Makefile b/tools/usb/Makefile +index 4e65060..01d758d 100644 +--- a/tools/usb/Makefile ++++ b/tools/usb/Makefile +@@ -1,7 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 + # Makefile for USB tools + +-CC = $(CROSS_COMPILE)gcc + PTHREAD_LIBS = -lpthread + WARNINGS = -Wall -Wextra + CFLAGS = $(WARNINGS) -g -I../include +diff --git a/tools/vm/Makefile b/tools/vm/Makefile +index be320b9..20f6cf0 100644 +--- a/tools/vm/Makefile ++++ b/tools/vm/Makefile +@@ -6,7 +6,6 @@ TARGETS=page-types slabinfo page_owner_sort + LIB_DIR = ../lib/api + LIBS = $(LIB_DIR)/libapi.a + +-CC = $(CROSS_COMPILE)gcc + CFLAGS = -Wall -Wextra -I../lib/ + LDFLAGS = $(LIBS) + +diff --git a/tools/wmi/Makefile b/tools/wmi/Makefile +index e664f11..e0e8723 100644 +--- a/tools/wmi/Makefile ++++ b/tools/wmi/Makefile +@@ -2,7 +2,6 @@ PREFIX ?= /usr + SBINDIR ?= sbin + INSTALL ?= install + CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include +-CC = $(CROSS_COMPILE)gcc + + TARGET = dell-smbios-example + +diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c +index 70268c0..70f4c30 100644 +--- a/virt/kvm/arm/arch_timer.c ++++ b/virt/kvm/arm/arch_timer.c +@@ -36,6 +36,8 @@ static struct timecounter *timecounter; + static unsigned int host_vtimer_irq; + static u32 host_vtimer_irq_flags; + ++static DEFINE_STATIC_KEY_FALSE(has_gic_active_state); ++ + static const struct kvm_irq_level default_ptimer_irq = { + .irq = 30, + .level = 1, +@@ -56,6 +58,12 @@ u64 kvm_phys_timer_read(void) + return timecounter->cc->read(timecounter->cc); + } + ++static inline bool userspace_irqchip(struct kvm *kvm) ++{ ++ return static_branch_unlikely(&userspace_irqchip_in_use) && ++ unlikely(!irqchip_in_kernel(kvm)); ++} ++ + static void soft_timer_start(struct hrtimer *hrt, u64 ns) + { + hrtimer_start(hrt, ktime_add_ns(ktime_get(), ns), +@@ -69,25 +77,6 @@ static void soft_timer_cancel(struct hrtimer *hrt, struct work_struct *work) + cancel_work_sync(work); + } + +-static void kvm_vtimer_update_mask_user(struct kvm_vcpu *vcpu) +-{ +- struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); +- +- /* +- * When using a userspace irqchip with the architected timers, we must +- * prevent continuously exiting from the guest, and therefore mask the +- * physical interrupt by disabling it on the host interrupt controller +- * when the virtual level is high, such that the guest can make +- * forward progress. Once we detect the output level being +- * de-asserted, we unmask the interrupt again so that we exit from the +- * guest when the timer fires. +- */ +- if (vtimer->irq.level) +- disable_percpu_irq(host_vtimer_irq); +- else +- enable_percpu_irq(host_vtimer_irq, 0); +-} +- + static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id) + { + struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id; +@@ -106,9 +95,9 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id) + if (kvm_timer_should_fire(vtimer)) + kvm_timer_update_irq(vcpu, true, vtimer); + +- if (static_branch_unlikely(&userspace_irqchip_in_use) && +- unlikely(!irqchip_in_kernel(vcpu->kvm))) +- kvm_vtimer_update_mask_user(vcpu); ++ if (userspace_irqchip(vcpu->kvm) && ++ !static_branch_unlikely(&has_gic_active_state)) ++ disable_percpu_irq(host_vtimer_irq); + + return IRQ_HANDLED; + } +@@ -290,8 +279,7 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level, + trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_ctx->irq.irq, + timer_ctx->irq.level); + +- if (!static_branch_unlikely(&userspace_irqchip_in_use) || +- likely(irqchip_in_kernel(vcpu->kvm))) { ++ if (!userspace_irqchip(vcpu->kvm)) { + ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, + timer_ctx->irq.irq, + timer_ctx->irq.level, +@@ -350,12 +338,6 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu) + phys_timer_emulate(vcpu); + } + +-static void __timer_snapshot_state(struct arch_timer_context *timer) +-{ +- timer->cnt_ctl = read_sysreg_el0(cntv_ctl); +- timer->cnt_cval = read_sysreg_el0(cntv_cval); +-} +- + static void vtimer_save_state(struct kvm_vcpu *vcpu) + { + struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; +@@ -367,8 +349,10 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu) + if (!vtimer->loaded) + goto out; + +- if (timer->enabled) +- __timer_snapshot_state(vtimer); ++ if (timer->enabled) { ++ vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl); ++ vtimer->cnt_cval = read_sysreg_el0(cntv_cval); ++ } + + /* Disable the virtual timer */ + write_sysreg_el0(0, cntv_ctl); +@@ -460,23 +444,43 @@ static void set_cntvoff(u64 cntvoff) + kvm_call_hyp(__kvm_timer_set_cntvoff, low, high); + } + +-static void kvm_timer_vcpu_load_vgic(struct kvm_vcpu *vcpu) ++static inline void set_vtimer_irq_phys_active(struct kvm_vcpu *vcpu, bool active) ++{ ++ int r; ++ r = irq_set_irqchip_state(host_vtimer_irq, IRQCHIP_STATE_ACTIVE, active); ++ WARN_ON(r); ++} ++ ++static void kvm_timer_vcpu_load_gic(struct kvm_vcpu *vcpu) + { + struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); + bool phys_active; +- int ret; + +- phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq); +- +- ret = irq_set_irqchip_state(host_vtimer_irq, +- IRQCHIP_STATE_ACTIVE, +- phys_active); +- WARN_ON(ret); ++ if (irqchip_in_kernel(vcpu->kvm)) ++ phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq); ++ else ++ phys_active = vtimer->irq.level; ++ set_vtimer_irq_phys_active(vcpu, phys_active); + } + +-static void kvm_timer_vcpu_load_user(struct kvm_vcpu *vcpu) ++static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu) + { +- kvm_vtimer_update_mask_user(vcpu); ++ struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); ++ ++ /* ++ * When using a userspace irqchip with the architected timers and a ++ * host interrupt controller that doesn't support an active state, we ++ * must still prevent continuously exiting from the guest, and ++ * therefore mask the physical interrupt by disabling it on the host ++ * interrupt controller when the virtual level is high, such that the ++ * guest can make forward progress. Once we detect the output level ++ * being de-asserted, we unmask the interrupt again so that we exit ++ * from the guest when the timer fires. ++ */ ++ if (vtimer->irq.level) ++ disable_percpu_irq(host_vtimer_irq); ++ else ++ enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags); + } + + void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu) +@@ -487,10 +491,10 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu) + if (unlikely(!timer->enabled)) + return; + +- if (unlikely(!irqchip_in_kernel(vcpu->kvm))) +- kvm_timer_vcpu_load_user(vcpu); ++ if (static_branch_likely(&has_gic_active_state)) ++ kvm_timer_vcpu_load_gic(vcpu); + else +- kvm_timer_vcpu_load_vgic(vcpu); ++ kvm_timer_vcpu_load_nogic(vcpu); + + set_cntvoff(vtimer->cntvoff); + +@@ -555,18 +559,24 @@ static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu) + { + struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); + +- if (unlikely(!irqchip_in_kernel(vcpu->kvm))) { +- __timer_snapshot_state(vtimer); +- if (!kvm_timer_should_fire(vtimer)) { +- kvm_timer_update_irq(vcpu, false, vtimer); +- kvm_vtimer_update_mask_user(vcpu); +- } ++ if (!kvm_timer_should_fire(vtimer)) { ++ kvm_timer_update_irq(vcpu, false, vtimer); ++ if (static_branch_likely(&has_gic_active_state)) ++ set_vtimer_irq_phys_active(vcpu, false); ++ else ++ enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags); + } + } + + void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu) + { +- unmask_vtimer_irq_user(vcpu); ++ struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; ++ ++ if (unlikely(!timer->enabled)) ++ return; ++ ++ if (unlikely(!irqchip_in_kernel(vcpu->kvm))) ++ unmask_vtimer_irq_user(vcpu); + } + + int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu) +@@ -753,6 +763,8 @@ int kvm_timer_hyp_init(bool has_gic) + kvm_err("kvm_arch_timer: error setting vcpu affinity\n"); + goto out_free_irq; + } ++ ++ static_branch_enable(&has_gic_active_state); + } + + kvm_info("virtual timer IRQ%d\n", host_vtimer_irq); +diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c +index 4501e65..65dea3f 100644 +--- a/virt/kvm/kvm_main.c ++++ b/virt/kvm/kvm_main.c +@@ -969,8 +969,7 @@ int __kvm_set_memory_region(struct kvm *kvm, + /* Check for overlaps */ + r = -EEXIST; + kvm_for_each_memslot(slot, __kvm_memslots(kvm, as_id)) { +- if ((slot->id >= KVM_USER_MEM_SLOTS) || +- (slot->id == id)) ++ if (slot->id == id) + continue; + if (!((base_gfn + npages <= slot->base_gfn) || + (base_gfn >= slot->base_gfn + slot->npages))) diff --git a/diffs/diff2.diff b/diffs/diff2.diff new file mode 100644 index 0000000..ca5b5b8 --- /dev/null +++ b/diffs/diff2.diff @@ -0,0 +1,8510 @@ +diff --git a/Documentation/devicetree/bindings/dma/mv-xor-v2.txt b/Documentation/devicetree/bindings/dma/mv-xor-v2.txt +index 217a90e..9c38bbe 100644 +--- a/Documentation/devicetree/bindings/dma/mv-xor-v2.txt ++++ b/Documentation/devicetree/bindings/dma/mv-xor-v2.txt +@@ -11,7 +11,11 @@ Required properties: + interrupts. + + Optional properties: +-- clocks: Optional reference to the clock used by the XOR engine. ++- clocks: Optional reference to the clocks used by the XOR engine. ++- clock-names: mandatory if there is a second clock, in this case the ++ name must be "core" for the first clock and "reg" for the second ++ one ++ + + Example: + +diff --git a/Documentation/sphinx/kerneldoc.py b/Documentation/sphinx/kerneldoc.py +index 39aa9e8..fbedcc3 100644 +--- a/Documentation/sphinx/kerneldoc.py ++++ b/Documentation/sphinx/kerneldoc.py +@@ -36,8 +36,7 @@ import glob + + from docutils import nodes, statemachine + from docutils.statemachine import ViewList +-from docutils.parsers.rst import directives +-from sphinx.util.compat import Directive ++from docutils.parsers.rst import directives, Directive + from sphinx.ext.autodoc import AutodocReporter + + __version__ = '1.0' +diff --git a/Makefile b/Makefile +index c4322de..e02d092 100644 +--- a/Makefile ++++ b/Makefile +@@ -2,7 +2,7 @@ + VERSION = 4 + PATCHLEVEL = 16 + SUBLEVEL = 0 +-EXTRAVERSION = -rc4 ++EXTRAVERSION = -rc5 + NAME = Fearless Coyote + + # *DOCUMENTATION* +diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c +index 52f15cd..b5a2833 100644 +--- a/arch/arm64/kernel/cpu_errata.c ++++ b/arch/arm64/kernel/cpu_errata.c +@@ -178,7 +178,7 @@ static int enable_smccc_arch_workaround_1(void *data) + case PSCI_CONDUIT_HVC: + arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_ARCH_WORKAROUND_1, &res); +- if (res.a0) ++ if ((int)res.a0 < 0) + return 0; + cb = call_hvc_arch_workaround_1; + smccc_start = __smccc_workaround_1_hvc_start; +@@ -188,7 +188,7 @@ static int enable_smccc_arch_workaround_1(void *data) + case PSCI_CONDUIT_SMC: + arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_ARCH_WORKAROUND_1, &res); +- if (res.a0) ++ if ((int)res.a0 < 0) + return 0; + cb = call_smc_arch_workaround_1; + smccc_start = __smccc_workaround_1_smc_start; +diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c +index 84a019f..8c704f1 100644 +--- a/arch/arm64/mm/mmu.c ++++ b/arch/arm64/mm/mmu.c +@@ -108,7 +108,7 @@ static bool pgattr_change_is_safe(u64 old, u64 new) + * The following mapping attributes may be updated in live + * kernel mappings without the need for break-before-make. + */ +- static const pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE; ++ static const pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE | PTE_NG; + + /* creating or taking down mappings is always safe */ + if (old == 0 || new == 0) +@@ -118,9 +118,9 @@ static bool pgattr_change_is_safe(u64 old, u64 new) + if ((old | new) & PTE_CONT) + return false; + +- /* Transitioning from Global to Non-Global is safe */ +- if (((old ^ new) == PTE_NG) && (new & PTE_NG)) +- return true; ++ /* Transitioning from Non-Global to Global is unsafe */ ++ if (old & ~new & PTE_NG) ++ return false; + + return ((old ^ new) & ~mask) == 0; + } +diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c +index 0c85481..5cb4e46 100644 +--- a/arch/powerpc/kvm/book3s_64_mmu_radix.c ++++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c +@@ -195,6 +195,12 @@ static void kvmppc_pte_free(pte_t *ptep) + kmem_cache_free(kvm_pte_cache, ptep); + } + ++/* Like pmd_huge() and pmd_large(), but works regardless of config options */ ++static inline int pmd_is_leaf(pmd_t pmd) ++{ ++ return !!(pmd_val(pmd) & _PAGE_PTE); ++} ++ + static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa, + unsigned int level, unsigned long mmu_seq) + { +@@ -219,7 +225,7 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa, + else + new_pmd = pmd_alloc_one(kvm->mm, gpa); + +- if (level == 0 && !(pmd && pmd_present(*pmd))) ++ if (level == 0 && !(pmd && pmd_present(*pmd) && !pmd_is_leaf(*pmd))) + new_ptep = kvmppc_pte_alloc(); + + /* Check if we might have been invalidated; let the guest retry if so */ +@@ -244,12 +250,30 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa, + new_pmd = NULL; + } + pmd = pmd_offset(pud, gpa); +- if (pmd_large(*pmd)) { +- /* Someone else has instantiated a large page here; retry */ +- ret = -EAGAIN; +- goto out_unlock; +- } +- if (level == 1 && !pmd_none(*pmd)) { ++ if (pmd_is_leaf(*pmd)) { ++ unsigned long lgpa = gpa & PMD_MASK; ++ ++ /* ++ * If we raced with another CPU which has just put ++ * a 2MB pte in after we saw a pte page, try again. ++ */ ++ if (level == 0 && !new_ptep) { ++ ret = -EAGAIN; ++ goto out_unlock; ++ } ++ /* Valid 2MB page here already, remove it */ ++ old = kvmppc_radix_update_pte(kvm, pmdp_ptep(pmd), ++ ~0UL, 0, lgpa, PMD_SHIFT); ++ kvmppc_radix_tlbie_page(kvm, lgpa, PMD_SHIFT); ++ if (old & _PAGE_DIRTY) { ++ unsigned long gfn = lgpa >> PAGE_SHIFT; ++ struct kvm_memory_slot *memslot; ++ memslot = gfn_to_memslot(kvm, gfn); ++ if (memslot && memslot->dirty_bitmap) ++ kvmppc_update_dirty_map(memslot, ++ gfn, PMD_SIZE); ++ } ++ } else if (level == 1 && !pmd_none(*pmd)) { + /* + * There's a page table page here, but we wanted + * to install a large page. Tell the caller and let +@@ -412,28 +436,24 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, + } else { + page = pages[0]; + pfn = page_to_pfn(page); +- if (PageHuge(page)) { +- page = compound_head(page); +- pte_size <<= compound_order(page); ++ if (PageCompound(page)) { ++ pte_size <<= compound_order(compound_head(page)); + /* See if we can insert a 2MB large-page PTE here */ + if (pte_size >= PMD_SIZE && +- (gpa & PMD_MASK & PAGE_MASK) == +- (hva & PMD_MASK & PAGE_MASK)) { ++ (gpa & (PMD_SIZE - PAGE_SIZE)) == ++ (hva & (PMD_SIZE - PAGE_SIZE))) { + level = 1; + pfn &= ~((PMD_SIZE >> PAGE_SHIFT) - 1); + } + } + /* See if we can provide write access */ + if (writing) { +- /* +- * We assume gup_fast has set dirty on the host PTE. +- */ + pgflags |= _PAGE_WRITE; + } else { + local_irq_save(flags); + ptep = find_current_mm_pte(current->mm->pgd, + hva, NULL, NULL); +- if (ptep && pte_write(*ptep) && pte_dirty(*ptep)) ++ if (ptep && pte_write(*ptep)) + pgflags |= _PAGE_WRITE; + local_irq_restore(flags); + } +@@ -459,18 +479,15 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, + pte = pfn_pte(pfn, __pgprot(pgflags)); + ret = kvmppc_create_pte(kvm, pte, gpa, level, mmu_seq); + } +- if (ret == 0 || ret == -EAGAIN) +- ret = RESUME_GUEST; + + if (page) { +- /* +- * We drop pages[0] here, not page because page might +- * have been set to the head page of a compound, but +- * we have to drop the reference on the correct tail +- * page to match the get inside gup() +- */ +- put_page(pages[0]); ++ if (!ret && (pgflags & _PAGE_WRITE)) ++ set_page_dirty_lock(page); ++ put_page(page); + } ++ ++ if (ret == 0 || ret == -EAGAIN) ++ ret = RESUME_GUEST; + return ret; + } + +@@ -644,7 +661,7 @@ void kvmppc_free_radix(struct kvm *kvm) + continue; + pmd = pmd_offset(pud, 0); + for (im = 0; im < PTRS_PER_PMD; ++im, ++pmd) { +- if (pmd_huge(*pmd)) { ++ if (pmd_is_leaf(*pmd)) { + pmd_clear(pmd); + continue; + } +diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c +index 8970735..9cb9448 100644 +--- a/arch/powerpc/kvm/book3s_hv.c ++++ b/arch/powerpc/kvm/book3s_hv.c +@@ -2885,7 +2885,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) + */ + trace_hardirqs_on(); + +- guest_enter(); ++ guest_enter_irqoff(); + + srcu_idx = srcu_read_lock(&vc->kvm->srcu); + +@@ -2893,8 +2893,6 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) + + srcu_read_unlock(&vc->kvm->srcu, srcu_idx); + +- guest_exit(); +- + trace_hardirqs_off(); + set_irq_happened(trap); + +@@ -2937,6 +2935,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) + kvmppc_set_host_core(pcpu); + + local_irq_enable(); ++ guest_exit(); + + /* Let secondaries go back to the offline loop */ + for (i = 0; i < controlled_threads; ++i) { +@@ -3656,15 +3655,17 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu) + goto up_out; + + psize = vma_kernel_pagesize(vma); +- porder = __ilog2(psize); + + up_read(¤t->mm->mmap_sem); + + /* We can handle 4k, 64k or 16M pages in the VRMA */ +- err = -EINVAL; +- if (!(psize == 0x1000 || psize == 0x10000 || +- psize == 0x1000000)) +- goto out_srcu; ++ if (psize >= 0x1000000) ++ psize = 0x1000000; ++ else if (psize >= 0x10000) ++ psize = 0x10000; ++ else ++ psize = 0x1000; ++ porder = __ilog2(psize); + + senc = slb_pgsize_encoding(psize); + kvm->arch.vrma_slb_v = senc | SLB_VSID_B_1T | +diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c +index 403e642..52c2053 100644 +--- a/arch/powerpc/kvm/powerpc.c ++++ b/arch/powerpc/kvm/powerpc.c +@@ -1345,7 +1345,7 @@ static int kvmppc_emulate_mmio_vsx_loadstore(struct kvm_vcpu *vcpu, + int kvmppc_handle_load128_by2x64(struct kvm_run *run, struct kvm_vcpu *vcpu, + unsigned int rt, int is_default_endian) + { +- enum emulation_result emulated; ++ enum emulation_result emulated = EMULATE_DONE; + + while (vcpu->arch.mmio_vmx_copy_nums) { + emulated = __kvmppc_handle_load(run, vcpu, rt, 8, +@@ -1608,7 +1608,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) + + kvm_sigset_deactivate(vcpu); + ++#ifdef CONFIG_ALTIVEC + out: ++#endif + vcpu_put(vcpu); + return r; + } +diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c +index 77d7818..339ac09 100644 +--- a/arch/s390/kvm/kvm-s390.c ++++ b/arch/s390/kvm/kvm-s390.c +@@ -86,6 +86,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { + { "deliver_prefix_signal", VCPU_STAT(deliver_prefix_signal) }, + { "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) }, + { "deliver_program_interruption", VCPU_STAT(deliver_program_int) }, ++ { "deliver_io_interrupt", VCPU_STAT(deliver_io_int) }, + { "exit_wait_state", VCPU_STAT(exit_wait_state) }, + { "instruction_epsw", VCPU_STAT(instruction_epsw) }, + { "instruction_gs", VCPU_STAT(instruction_gs) }, +@@ -2146,6 +2147,7 @@ static void sca_add_vcpu(struct kvm_vcpu *vcpu) + /* we still need the basic sca for the ipte control */ + vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32); + vcpu->arch.sie_block->scaol = (__u32)(__u64)sca; ++ return; + } + read_lock(&vcpu->kvm->arch.sca_lock); + if (vcpu->kvm->arch.use_esca) { +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index eb7f43f..0fa71a7 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -2307,7 +2307,7 @@ choice + it can be used to assist security vulnerability exploitation. + + This setting can be changed at boot time via the kernel command +- line parameter vsyscall=[native|emulate|none]. ++ line parameter vsyscall=[emulate|none]. + + On a system with recent enough glibc (2.14 or newer) and no + static binaries, you can say None without a performance penalty +@@ -2315,15 +2315,6 @@ choice + + If unsure, select "Emulate". + +- config LEGACY_VSYSCALL_NATIVE +- bool "Native" +- help +- Actual executable code is located in the fixed vsyscall +- address mapping, implementing time() efficiently. Since +- this makes the mapping executable, it can be used during +- security vulnerability exploitation (traditionally as +- ROP gadgets). This configuration is not recommended. +- + config LEGACY_VSYSCALL_EMULATE + bool "Emulate" + help +diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S +index e811dd9..08425c4 100644 +--- a/arch/x86/entry/entry_64_compat.S ++++ b/arch/x86/entry/entry_64_compat.S +@@ -363,9 +363,7 @@ ENTRY(entry_INT80_compat) + pushq 2*8(%rdi) /* regs->ip */ + pushq 1*8(%rdi) /* regs->orig_ax */ + +- movq (%rdi), %rdi /* restore %rdi */ +- +- pushq %rdi /* pt_regs->di */ ++ pushq (%rdi) /* pt_regs->di */ + pushq %rsi /* pt_regs->si */ + pushq %rdx /* pt_regs->dx */ + pushq %rcx /* pt_regs->cx */ +@@ -406,15 +404,3 @@ ENTRY(entry_INT80_compat) + TRACE_IRQS_ON + jmp swapgs_restore_regs_and_return_to_usermode + END(entry_INT80_compat) +- +-ENTRY(stub32_clone) +- /* +- * The 32-bit clone ABI is: clone(..., int tls_val, int *child_tidptr). +- * The 64-bit clone ABI is: clone(..., int *child_tidptr, int tls_val). +- * +- * The native 64-bit kernel's sys_clone() implements the latter, +- * so we need to swap arguments here before calling it: +- */ +- xchg %r8, %rcx +- jmp sys_clone +-ENDPROC(stub32_clone) +diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl +index 448ac21..2a5e99c 100644 +--- a/arch/x86/entry/syscalls/syscall_32.tbl ++++ b/arch/x86/entry/syscalls/syscall_32.tbl +@@ -8,12 +8,12 @@ + # + 0 i386 restart_syscall sys_restart_syscall + 1 i386 exit sys_exit +-2 i386 fork sys_fork sys_fork ++2 i386 fork sys_fork + 3 i386 read sys_read + 4 i386 write sys_write + 5 i386 open sys_open compat_sys_open + 6 i386 close sys_close +-7 i386 waitpid sys_waitpid sys32_waitpid ++7 i386 waitpid sys_waitpid compat_sys_x86_waitpid + 8 i386 creat sys_creat + 9 i386 link sys_link + 10 i386 unlink sys_unlink +@@ -78,7 +78,7 @@ + 69 i386 ssetmask sys_ssetmask + 70 i386 setreuid sys_setreuid16 + 71 i386 setregid sys_setregid16 +-72 i386 sigsuspend sys_sigsuspend sys_sigsuspend ++72 i386 sigsuspend sys_sigsuspend + 73 i386 sigpending sys_sigpending compat_sys_sigpending + 74 i386 sethostname sys_sethostname + 75 i386 setrlimit sys_setrlimit compat_sys_setrlimit +@@ -96,7 +96,7 @@ + 87 i386 swapon sys_swapon + 88 i386 reboot sys_reboot + 89 i386 readdir sys_old_readdir compat_sys_old_readdir +-90 i386 mmap sys_old_mmap sys32_mmap ++90 i386 mmap sys_old_mmap compat_sys_x86_mmap + 91 i386 munmap sys_munmap + 92 i386 truncate sys_truncate compat_sys_truncate + 93 i386 ftruncate sys_ftruncate compat_sys_ftruncate +@@ -126,7 +126,7 @@ + 117 i386 ipc sys_ipc compat_sys_ipc + 118 i386 fsync sys_fsync + 119 i386 sigreturn sys_sigreturn sys32_sigreturn +-120 i386 clone sys_clone stub32_clone ++120 i386 clone sys_clone compat_sys_x86_clone + 121 i386 setdomainname sys_setdomainname + 122 i386 uname sys_newuname + 123 i386 modify_ldt sys_modify_ldt +@@ -186,8 +186,8 @@ + 177 i386 rt_sigtimedwait sys_rt_sigtimedwait compat_sys_rt_sigtimedwait + 178 i386 rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo + 179 i386 rt_sigsuspend sys_rt_sigsuspend +-180 i386 pread64 sys_pread64 sys32_pread +-181 i386 pwrite64 sys_pwrite64 sys32_pwrite ++180 i386 pread64 sys_pread64 compat_sys_x86_pread ++181 i386 pwrite64 sys_pwrite64 compat_sys_x86_pwrite + 182 i386 chown sys_chown16 + 183 i386 getcwd sys_getcwd + 184 i386 capget sys_capget +@@ -196,14 +196,14 @@ + 187 i386 sendfile sys_sendfile compat_sys_sendfile + 188 i386 getpmsg + 189 i386 putpmsg +-190 i386 vfork sys_vfork sys_vfork ++190 i386 vfork sys_vfork + 191 i386 ugetrlimit sys_getrlimit compat_sys_getrlimit + 192 i386 mmap2 sys_mmap_pgoff +-193 i386 truncate64 sys_truncate64 sys32_truncate64 +-194 i386 ftruncate64 sys_ftruncate64 sys32_ftruncate64 +-195 i386 stat64 sys_stat64 sys32_stat64 +-196 i386 lstat64 sys_lstat64 sys32_lstat64 +-197 i386 fstat64 sys_fstat64 sys32_fstat64 ++193 i386 truncate64 sys_truncate64 compat_sys_x86_truncate64 ++194 i386 ftruncate64 sys_ftruncate64 compat_sys_x86_ftruncate64 ++195 i386 stat64 sys_stat64 compat_sys_x86_stat64 ++196 i386 lstat64 sys_lstat64 compat_sys_x86_lstat64 ++197 i386 fstat64 sys_fstat64 compat_sys_x86_fstat64 + 198 i386 lchown32 sys_lchown + 199 i386 getuid32 sys_getuid + 200 i386 getgid32 sys_getgid +@@ -231,7 +231,7 @@ + # 222 is unused + # 223 is unused + 224 i386 gettid sys_gettid +-225 i386 readahead sys_readahead sys32_readahead ++225 i386 readahead sys_readahead compat_sys_x86_readahead + 226 i386 setxattr sys_setxattr + 227 i386 lsetxattr sys_lsetxattr + 228 i386 fsetxattr sys_fsetxattr +@@ -256,7 +256,7 @@ + 247 i386 io_getevents sys_io_getevents compat_sys_io_getevents + 248 i386 io_submit sys_io_submit compat_sys_io_submit + 249 i386 io_cancel sys_io_cancel +-250 i386 fadvise64 sys_fadvise64 sys32_fadvise64 ++250 i386 fadvise64 sys_fadvise64 compat_sys_x86_fadvise64 + # 251 is available for reuse (was briefly sys_set_zone_reclaim) + 252 i386 exit_group sys_exit_group + 253 i386 lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie +@@ -278,7 +278,7 @@ + 269 i386 fstatfs64 sys_fstatfs64 compat_sys_fstatfs64 + 270 i386 tgkill sys_tgkill + 271 i386 utimes sys_utimes compat_sys_utimes +-272 i386 fadvise64_64 sys_fadvise64_64 sys32_fadvise64_64 ++272 i386 fadvise64_64 sys_fadvise64_64 compat_sys_x86_fadvise64_64 + 273 i386 vserver + 274 i386 mbind sys_mbind + 275 i386 get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy +@@ -306,7 +306,7 @@ + 297 i386 mknodat sys_mknodat + 298 i386 fchownat sys_fchownat + 299 i386 futimesat sys_futimesat compat_sys_futimesat +-300 i386 fstatat64 sys_fstatat64 sys32_fstatat ++300 i386 fstatat64 sys_fstatat64 compat_sys_x86_fstatat + 301 i386 unlinkat sys_unlinkat + 302 i386 renameat sys_renameat + 303 i386 linkat sys_linkat +@@ -320,7 +320,7 @@ + 311 i386 set_robust_list sys_set_robust_list compat_sys_set_robust_list + 312 i386 get_robust_list sys_get_robust_list compat_sys_get_robust_list + 313 i386 splice sys_splice +-314 i386 sync_file_range sys_sync_file_range sys32_sync_file_range ++314 i386 sync_file_range sys_sync_file_range compat_sys_x86_sync_file_range + 315 i386 tee sys_tee + 316 i386 vmsplice sys_vmsplice compat_sys_vmsplice + 317 i386 move_pages sys_move_pages compat_sys_move_pages +@@ -330,7 +330,7 @@ + 321 i386 signalfd sys_signalfd compat_sys_signalfd + 322 i386 timerfd_create sys_timerfd_create + 323 i386 eventfd sys_eventfd +-324 i386 fallocate sys_fallocate sys32_fallocate ++324 i386 fallocate sys_fallocate compat_sys_x86_fallocate + 325 i386 timerfd_settime sys_timerfd_settime compat_sys_timerfd_settime + 326 i386 timerfd_gettime sys_timerfd_gettime compat_sys_timerfd_gettime + 327 i386 signalfd4 sys_signalfd4 compat_sys_signalfd4 +diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c +index 577fa8a..8560ef6 100644 +--- a/arch/x86/entry/vsyscall/vsyscall_64.c ++++ b/arch/x86/entry/vsyscall/vsyscall_64.c +@@ -42,10 +42,8 @@ + #define CREATE_TRACE_POINTS + #include "vsyscall_trace.h" + +-static enum { EMULATE, NATIVE, NONE } vsyscall_mode = +-#if defined(CONFIG_LEGACY_VSYSCALL_NATIVE) +- NATIVE; +-#elif defined(CONFIG_LEGACY_VSYSCALL_NONE) ++static enum { EMULATE, NONE } vsyscall_mode = ++#ifdef CONFIG_LEGACY_VSYSCALL_NONE + NONE; + #else + EMULATE; +@@ -56,8 +54,6 @@ static int __init vsyscall_setup(char *str) + if (str) { + if (!strcmp("emulate", str)) + vsyscall_mode = EMULATE; +- else if (!strcmp("native", str)) +- vsyscall_mode = NATIVE; + else if (!strcmp("none", str)) + vsyscall_mode = NONE; + else +@@ -139,10 +135,6 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) + + WARN_ON_ONCE(address != regs->ip); + +- /* This should be unreachable in NATIVE mode. */ +- if (WARN_ON(vsyscall_mode == NATIVE)) +- return false; +- + if (vsyscall_mode == NONE) { + warn_bad_vsyscall(KERN_INFO, regs, + "vsyscall attempted with vsyscall=none"); +@@ -370,9 +362,7 @@ void __init map_vsyscall(void) + + if (vsyscall_mode != NONE) { + __set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall, +- vsyscall_mode == NATIVE +- ? PAGE_KERNEL_VSYSCALL +- : PAGE_KERNEL_VVAR); ++ PAGE_KERNEL_VVAR); + set_vsyscall_pgtable_user_bits(swapper_pg_dir); + } + +diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c +index 6d8044a..22ec65b 100644 +--- a/arch/x86/events/intel/uncore_snbep.c ++++ b/arch/x86/events/intel/uncore_snbep.c +@@ -3606,7 +3606,7 @@ static struct intel_uncore_type skx_uncore_imc = { + }; + + static struct attribute *skx_upi_uncore_formats_attr[] = { +- &format_attr_event_ext.attr, ++ &format_attr_event.attr, + &format_attr_umask_ext.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, +diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c +index 96cd33b..6512498 100644 +--- a/arch/x86/ia32/sys_ia32.c ++++ b/arch/x86/ia32/sys_ia32.c +@@ -51,15 +51,14 @@ + #define AA(__x) ((unsigned long)(__x)) + + +-asmlinkage long sys32_truncate64(const char __user *filename, +- unsigned long offset_low, +- unsigned long offset_high) ++COMPAT_SYSCALL_DEFINE3(x86_truncate64, const char __user *, filename, ++ unsigned long, offset_low, unsigned long, offset_high) + { + return sys_truncate(filename, ((loff_t) offset_high << 32) | offset_low); + } + +-asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long offset_low, +- unsigned long offset_high) ++COMPAT_SYSCALL_DEFINE3(x86_ftruncate64, unsigned int, fd, ++ unsigned long, offset_low, unsigned long, offset_high) + { + return sys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low); + } +@@ -96,8 +95,8 @@ static int cp_stat64(struct stat64 __user *ubuf, struct kstat *stat) + return 0; + } + +-asmlinkage long sys32_stat64(const char __user *filename, +- struct stat64 __user *statbuf) ++COMPAT_SYSCALL_DEFINE2(x86_stat64, const char __user *, filename, ++ struct stat64 __user *, statbuf) + { + struct kstat stat; + int ret = vfs_stat(filename, &stat); +@@ -107,8 +106,8 @@ asmlinkage long sys32_stat64(const char __user *filename, + return ret; + } + +-asmlinkage long sys32_lstat64(const char __user *filename, +- struct stat64 __user *statbuf) ++COMPAT_SYSCALL_DEFINE2(x86_lstat64, const char __user *, filename, ++ struct stat64 __user *, statbuf) + { + struct kstat stat; + int ret = vfs_lstat(filename, &stat); +@@ -117,7 +116,8 @@ asmlinkage long sys32_lstat64(const char __user *filename, + return ret; + } + +-asmlinkage long sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf) ++COMPAT_SYSCALL_DEFINE2(x86_fstat64, unsigned int, fd, ++ struct stat64 __user *, statbuf) + { + struct kstat stat; + int ret = vfs_fstat(fd, &stat); +@@ -126,8 +126,9 @@ asmlinkage long sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf) + return ret; + } + +-asmlinkage long sys32_fstatat(unsigned int dfd, const char __user *filename, +- struct stat64 __user *statbuf, int flag) ++COMPAT_SYSCALL_DEFINE4(x86_fstatat, unsigned int, dfd, ++ const char __user *, filename, ++ struct stat64 __user *, statbuf, int, flag) + { + struct kstat stat; + int error; +@@ -153,7 +154,7 @@ struct mmap_arg_struct32 { + unsigned int offset; + }; + +-asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *arg) ++COMPAT_SYSCALL_DEFINE1(x86_mmap, struct mmap_arg_struct32 __user *, arg) + { + struct mmap_arg_struct32 a; + +@@ -167,22 +168,22 @@ asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *arg) + a.offset>>PAGE_SHIFT); + } + +-asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int __user *stat_addr, +- int options) ++COMPAT_SYSCALL_DEFINE3(x86_waitpid, compat_pid_t, pid, unsigned int __user *, ++ stat_addr, int, options) + { + return compat_sys_wait4(pid, stat_addr, options, NULL); + } + + /* warning: next two assume little endian */ +-asmlinkage long sys32_pread(unsigned int fd, char __user *ubuf, u32 count, +- u32 poslo, u32 poshi) ++COMPAT_SYSCALL_DEFINE5(x86_pread, unsigned int, fd, char __user *, ubuf, ++ u32, count, u32, poslo, u32, poshi) + { + return sys_pread64(fd, ubuf, count, + ((loff_t)AA(poshi) << 32) | AA(poslo)); + } + +-asmlinkage long sys32_pwrite(unsigned int fd, const char __user *ubuf, +- u32 count, u32 poslo, u32 poshi) ++COMPAT_SYSCALL_DEFINE5(x86_pwrite, unsigned int, fd, const char __user *, ubuf, ++ u32, count, u32, poslo, u32, poshi) + { + return sys_pwrite64(fd, ubuf, count, + ((loff_t)AA(poshi) << 32) | AA(poslo)); +@@ -193,8 +194,9 @@ asmlinkage long sys32_pwrite(unsigned int fd, const char __user *ubuf, + * Some system calls that need sign extended arguments. This could be + * done by a generic wrapper. + */ +-long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, +- __u32 len_low, __u32 len_high, int advice) ++COMPAT_SYSCALL_DEFINE6(x86_fadvise64_64, int, fd, __u32, offset_low, ++ __u32, offset_high, __u32, len_low, __u32, len_high, ++ int, advice) + { + return sys_fadvise64_64(fd, + (((u64)offset_high)<<32) | offset_low, +@@ -202,31 +204,43 @@ long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, + advice); + } + +-asmlinkage ssize_t sys32_readahead(int fd, unsigned off_lo, unsigned off_hi, +- size_t count) ++COMPAT_SYSCALL_DEFINE4(x86_readahead, int, fd, unsigned int, off_lo, ++ unsigned int, off_hi, size_t, count) + { + return sys_readahead(fd, ((u64)off_hi << 32) | off_lo, count); + } + +-asmlinkage long sys32_sync_file_range(int fd, unsigned off_low, unsigned off_hi, +- unsigned n_low, unsigned n_hi, int flags) ++COMPAT_SYSCALL_DEFINE6(x86_sync_file_range, int, fd, unsigned int, off_low, ++ unsigned int, off_hi, unsigned int, n_low, ++ unsigned int, n_hi, int, flags) + { + return sys_sync_file_range(fd, + ((u64)off_hi << 32) | off_low, + ((u64)n_hi << 32) | n_low, flags); + } + +-asmlinkage long sys32_fadvise64(int fd, unsigned offset_lo, unsigned offset_hi, +- size_t len, int advice) ++COMPAT_SYSCALL_DEFINE5(x86_fadvise64, int, fd, unsigned int, offset_lo, ++ unsigned int, offset_hi, size_t, len, int, advice) + { + return sys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo, + len, advice); + } + +-asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo, +- unsigned offset_hi, unsigned len_lo, +- unsigned len_hi) ++COMPAT_SYSCALL_DEFINE6(x86_fallocate, int, fd, int, mode, ++ unsigned int, offset_lo, unsigned int, offset_hi, ++ unsigned int, len_lo, unsigned int, len_hi) + { + return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo, + ((u64)len_hi << 32) | len_lo); + } ++ ++/* ++ * The 32-bit clone ABI is CONFIG_CLONE_BACKWARDS ++ */ ++COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags, ++ unsigned long, newsp, int __user *, parent_tidptr, ++ unsigned long, tls_val, int __user *, child_tidptr) ++{ ++ return sys_clone(clone_flags, newsp, parent_tidptr, child_tidptr, ++ tls_val); ++} +diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h +index 246f15b..acfe755 100644 +--- a/arch/x86/include/asm/pgtable_types.h ++++ b/arch/x86/include/asm/pgtable_types.h +@@ -174,7 +174,6 @@ enum page_cache_mode { + #define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) + #define __PAGE_KERNEL_RX (__PAGE_KERNEL_EXEC & ~_PAGE_RW) + #define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_NOCACHE) +-#define __PAGE_KERNEL_VSYSCALL (__PAGE_KERNEL_RX | _PAGE_USER) + #define __PAGE_KERNEL_VVAR (__PAGE_KERNEL_RO | _PAGE_USER) + #define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) + #define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) +@@ -206,7 +205,6 @@ enum page_cache_mode { + #define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE | _PAGE_ENC) + #define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE | _PAGE_ENC) + #define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC | _PAGE_ENC) +-#define PAGE_KERNEL_VSYSCALL __pgprot(__PAGE_KERNEL_VSYSCALL | _PAGE_ENC) + #define PAGE_KERNEL_VVAR __pgprot(__PAGE_KERNEL_VVAR | _PAGE_ENC) + + #define PAGE_KERNEL_IO __pgprot(__PAGE_KERNEL_IO) +diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h +index d6baf23..5c019d2 100644 +--- a/arch/x86/include/asm/sections.h ++++ b/arch/x86/include/asm/sections.h +@@ -10,6 +10,7 @@ extern struct exception_table_entry __stop___ex_table[]; + + #if defined(CONFIG_X86_64) + extern char __end_rodata_hpage_align[]; ++extern char __entry_trampoline_start[], __entry_trampoline_end[]; + #endif + + #endif /* _ASM_X86_SECTIONS_H */ +diff --git a/arch/x86/include/asm/sys_ia32.h b/arch/x86/include/asm/sys_ia32.h +index 82c34ee..906794a 100644 +--- a/arch/x86/include/asm/sys_ia32.h ++++ b/arch/x86/include/asm/sys_ia32.h +@@ -20,31 +20,43 @@ + #include + + /* ia32/sys_ia32.c */ +-asmlinkage long sys32_truncate64(const char __user *, unsigned long, unsigned long); +-asmlinkage long sys32_ftruncate64(unsigned int, unsigned long, unsigned long); ++asmlinkage long compat_sys_x86_truncate64(const char __user *, unsigned long, ++ unsigned long); ++asmlinkage long compat_sys_x86_ftruncate64(unsigned int, unsigned long, ++ unsigned long); + +-asmlinkage long sys32_stat64(const char __user *, struct stat64 __user *); +-asmlinkage long sys32_lstat64(const char __user *, struct stat64 __user *); +-asmlinkage long sys32_fstat64(unsigned int, struct stat64 __user *); +-asmlinkage long sys32_fstatat(unsigned int, const char __user *, ++asmlinkage long compat_sys_x86_stat64(const char __user *, ++ struct stat64 __user *); ++asmlinkage long compat_sys_x86_lstat64(const char __user *, ++ struct stat64 __user *); ++asmlinkage long compat_sys_x86_fstat64(unsigned int, struct stat64 __user *); ++asmlinkage long compat_sys_x86_fstatat(unsigned int, const char __user *, + struct stat64 __user *, int); + struct mmap_arg_struct32; +-asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *); ++asmlinkage long compat_sys_x86_mmap(struct mmap_arg_struct32 __user *); + +-asmlinkage long sys32_waitpid(compat_pid_t, unsigned int __user *, int); ++asmlinkage long compat_sys_x86_waitpid(compat_pid_t, unsigned int __user *, ++ int); + +-asmlinkage long sys32_pread(unsigned int, char __user *, u32, u32, u32); +-asmlinkage long sys32_pwrite(unsigned int, const char __user *, u32, u32, u32); ++asmlinkage long compat_sys_x86_pread(unsigned int, char __user *, u32, u32, ++ u32); ++asmlinkage long compat_sys_x86_pwrite(unsigned int, const char __user *, u32, ++ u32, u32); + +-long sys32_fadvise64_64(int, __u32, __u32, __u32, __u32, int); +-long sys32_vm86_warning(void); ++asmlinkage long compat_sys_x86_fadvise64_64(int, __u32, __u32, __u32, __u32, ++ int); + +-asmlinkage ssize_t sys32_readahead(int, unsigned, unsigned, size_t); +-asmlinkage long sys32_sync_file_range(int, unsigned, unsigned, +- unsigned, unsigned, int); +-asmlinkage long sys32_fadvise64(int, unsigned, unsigned, size_t, int); +-asmlinkage long sys32_fallocate(int, int, unsigned, +- unsigned, unsigned, unsigned); ++asmlinkage ssize_t compat_sys_x86_readahead(int, unsigned int, unsigned int, ++ size_t); ++asmlinkage long compat_sys_x86_sync_file_range(int, unsigned int, unsigned int, ++ unsigned int, unsigned int, ++ int); ++asmlinkage long compat_sys_x86_fadvise64(int, unsigned int, unsigned int, ++ size_t, int); ++asmlinkage long compat_sys_x86_fallocate(int, int, unsigned int, unsigned int, ++ unsigned int, unsigned int); ++asmlinkage long compat_sys_x86_clone(unsigned long, unsigned long, int __user *, ++ unsigned long, int __user *); + + /* ia32/ia32_signal.c */ + asmlinkage long sys32_sigreturn(void); +diff --git a/arch/x86/include/uapi/asm/mce.h b/arch/x86/include/uapi/asm/mce.h +index 91723461..435db58 100644 +--- a/arch/x86/include/uapi/asm/mce.h ++++ b/arch/x86/include/uapi/asm/mce.h +@@ -30,6 +30,7 @@ struct mce { + __u64 synd; /* MCA_SYND MSR: only valid on SMCA systems */ + __u64 ipid; /* MCA_IPID MSR: only valid on SMCA systems */ + __u64 ppin; /* Protected Processor Inventory Number */ ++ __u32 microcode;/* Microcode revision */ + }; + + #define MCE_GET_RECORD_LEN _IOR('M', 1, int) +diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c +index d19e903..4aa9fd3 100644 +--- a/arch/x86/kernel/cpu/intel.c ++++ b/arch/x86/kernel/cpu/intel.c +@@ -144,6 +144,13 @@ static bool bad_spectre_microcode(struct cpuinfo_x86 *c) + { + int i; + ++ /* ++ * We know that the hypervisor lie to us on the microcode version so ++ * we may as well hope that it is running the correct version. ++ */ ++ if (cpu_has(c, X86_FEATURE_HYPERVISOR)) ++ return false; ++ + for (i = 0; i < ARRAY_SIZE(spectre_bad_microcodes); i++) { + if (c->x86_model == spectre_bad_microcodes[i].model && + c->x86_stepping == spectre_bad_microcodes[i].stepping) +diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c +index 8ff94d1..466f473 100644 +--- a/arch/x86/kernel/cpu/mcheck/mce.c ++++ b/arch/x86/kernel/cpu/mcheck/mce.c +@@ -56,6 +56,9 @@ + + static DEFINE_MUTEX(mce_log_mutex); + ++/* sysfs synchronization */ ++static DEFINE_MUTEX(mce_sysfs_mutex); ++ + #define CREATE_TRACE_POINTS + #include + +@@ -130,6 +133,8 @@ void mce_setup(struct mce *m) + + if (this_cpu_has(X86_FEATURE_INTEL_PPIN)) + rdmsrl(MSR_PPIN, m->ppin); ++ ++ m->microcode = boot_cpu_data.microcode; + } + + DEFINE_PER_CPU(struct mce, injectm); +@@ -262,7 +267,7 @@ static void __print_mce(struct mce *m) + */ + pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x microcode %x\n", + m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid, +- cpu_data(m->extcpu).microcode); ++ m->microcode); + } + + static void print_mce(struct mce *m) +@@ -2086,6 +2091,7 @@ static ssize_t set_ignore_ce(struct device *s, + if (kstrtou64(buf, 0, &new) < 0) + return -EINVAL; + ++ mutex_lock(&mce_sysfs_mutex); + if (mca_cfg.ignore_ce ^ !!new) { + if (new) { + /* disable ce features */ +@@ -2098,6 +2104,8 @@ static ssize_t set_ignore_ce(struct device *s, + on_each_cpu(mce_enable_ce, (void *)1, 1); + } + } ++ mutex_unlock(&mce_sysfs_mutex); ++ + return size; + } + +@@ -2110,6 +2118,7 @@ static ssize_t set_cmci_disabled(struct device *s, + if (kstrtou64(buf, 0, &new) < 0) + return -EINVAL; + ++ mutex_lock(&mce_sysfs_mutex); + if (mca_cfg.cmci_disabled ^ !!new) { + if (new) { + /* disable cmci */ +@@ -2121,6 +2130,8 @@ static ssize_t set_cmci_disabled(struct device *s, + on_each_cpu(mce_enable_ce, NULL, 1); + } + } ++ mutex_unlock(&mce_sysfs_mutex); ++ + return size; + } + +@@ -2128,8 +2139,19 @@ static ssize_t store_int_with_restart(struct device *s, + struct device_attribute *attr, + const char *buf, size_t size) + { +- ssize_t ret = device_store_int(s, attr, buf, size); ++ unsigned long old_check_interval = check_interval; ++ ssize_t ret = device_store_ulong(s, attr, buf, size); ++ ++ if (check_interval == old_check_interval) ++ return ret; ++ ++ if (check_interval < 1) ++ check_interval = 1; ++ ++ mutex_lock(&mce_sysfs_mutex); + mce_restart(); ++ mutex_unlock(&mce_sysfs_mutex); ++ + return ret; + } + +diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c +index aa1b9a4..70ecbc8 100644 +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -22,13 +22,16 @@ + #define pr_fmt(fmt) "microcode: " fmt + + #include ++#include + #include + #include + #include + #include + #include ++#include + #include + #include ++#include + #include + #include + +@@ -64,6 +67,11 @@ LIST_HEAD(microcode_cache); + */ + static DEFINE_MUTEX(microcode_mutex); + ++/* ++ * Serialize late loading so that CPUs get updated one-by-one. ++ */ ++static DEFINE_SPINLOCK(update_lock); ++ + struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; + + struct cpu_info_ctx { +@@ -373,26 +381,23 @@ static int collect_cpu_info(int cpu) + return ret; + } + +-struct apply_microcode_ctx { +- enum ucode_state err; +-}; +- + static void apply_microcode_local(void *arg) + { +- struct apply_microcode_ctx *ctx = arg; ++ enum ucode_state *err = arg; + +- ctx->err = microcode_ops->apply_microcode(smp_processor_id()); ++ *err = microcode_ops->apply_microcode(smp_processor_id()); + } + + static int apply_microcode_on_target(int cpu) + { +- struct apply_microcode_ctx ctx = { .err = 0 }; ++ enum ucode_state err; + int ret; + +- ret = smp_call_function_single(cpu, apply_microcode_local, &ctx, 1); +- if (!ret) +- ret = ctx.err; +- ++ ret = smp_call_function_single(cpu, apply_microcode_local, &err, 1); ++ if (!ret) { ++ if (err == UCODE_ERROR) ++ ret = 1; ++ } + return ret; + } + +@@ -489,19 +494,100 @@ static void __exit microcode_dev_exit(void) + /* fake device for request_firmware */ + static struct platform_device *microcode_pdev; + +-static enum ucode_state reload_for_cpu(int cpu) ++/* ++ * Late loading dance. Why the heavy-handed stomp_machine effort? ++ * ++ * - HT siblings must be idle and not execute other code while the other sibling ++ * is loading microcode in order to avoid any negative interactions caused by ++ * the loading. ++ * ++ * - In addition, microcode update on the cores must be serialized until this ++ * requirement can be relaxed in the future. Right now, this is conservative ++ * and good. ++ */ ++#define SPINUNIT 100 /* 100 nsec */ ++ ++static int check_online_cpus(void) + { +- struct ucode_cpu_info *uci = ucode_cpu_info + cpu; +- enum ucode_state ustate; ++ if (num_online_cpus() == num_present_cpus()) ++ return 0; + +- if (!uci->valid) +- return UCODE_OK; ++ pr_err("Not all CPUs online, aborting microcode update.\n"); ++ ++ return -EINVAL; ++} ++ ++static atomic_t late_cpus; ++ ++/* ++ * Returns: ++ * < 0 - on error ++ * 0 - no update done ++ * 1 - microcode was updated ++ */ ++static int __reload_late(void *info) ++{ ++ unsigned int timeout = NSEC_PER_SEC; ++ int all_cpus = num_online_cpus(); ++ int cpu = smp_processor_id(); ++ enum ucode_state err; ++ int ret = 0; ++ ++ atomic_dec(&late_cpus); ++ ++ /* ++ * Wait for all CPUs to arrive. A load will not be attempted unless all ++ * CPUs show up. ++ * */ ++ while (atomic_read(&late_cpus)) { ++ if (timeout < SPINUNIT) { ++ pr_err("Timeout while waiting for CPUs rendezvous, remaining: %d\n", ++ atomic_read(&late_cpus)); ++ return -1; ++ } + +- ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, true); +- if (ustate != UCODE_OK) +- return ustate; ++ ndelay(SPINUNIT); ++ timeout -= SPINUNIT; + +- return apply_microcode_on_target(cpu); ++ touch_nmi_watchdog(); ++ } ++ ++ spin_lock(&update_lock); ++ apply_microcode_local(&err); ++ spin_unlock(&update_lock); ++ ++ if (err > UCODE_NFOUND) { ++ pr_warn("Error reloading microcode on CPU %d\n", cpu); ++ ret = -1; ++ } else if (err == UCODE_UPDATED) { ++ ret = 1; ++ } ++ ++ atomic_inc(&late_cpus); ++ ++ while (atomic_read(&late_cpus) != all_cpus) ++ cpu_relax(); ++ ++ return ret; ++} ++ ++/* ++ * Reload microcode late on all CPUs. Wait for a sec until they ++ * all gather together. ++ */ ++static int microcode_reload_late(void) ++{ ++ int ret; ++ ++ atomic_set(&late_cpus, num_online_cpus()); ++ ++ ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask); ++ if (ret < 0) ++ return ret; ++ else if (ret > 0) ++ microcode_check(); ++ ++ return ret; + } + + static ssize_t reload_store(struct device *dev, +@@ -509,10 +595,9 @@ static ssize_t reload_store(struct device *dev, + const char *buf, size_t size) + { + enum ucode_state tmp_ret = UCODE_OK; +- bool do_callback = false; ++ int bsp = boot_cpu_data.cpu_index; + unsigned long val; + ssize_t ret = 0; +- int cpu; + + ret = kstrtoul(buf, 0, &val); + if (ret) +@@ -521,29 +606,24 @@ static ssize_t reload_store(struct device *dev, + if (val != 1) + return size; + +- get_online_cpus(); +- mutex_lock(µcode_mutex); +- for_each_online_cpu(cpu) { +- tmp_ret = reload_for_cpu(cpu); +- if (tmp_ret > UCODE_NFOUND) { +- pr_warn("Error reloading microcode on CPU %d\n", cpu); +- +- /* set retval for the first encountered reload error */ +- if (!ret) +- ret = -EINVAL; +- } ++ tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev, true); ++ if (tmp_ret != UCODE_OK) ++ return size; + +- if (tmp_ret == UCODE_UPDATED) +- do_callback = true; +- } ++ get_online_cpus(); + +- if (!ret && do_callback) +- microcode_check(); ++ ret = check_online_cpus(); ++ if (ret) ++ goto put; + ++ mutex_lock(µcode_mutex); ++ ret = microcode_reload_late(); + mutex_unlock(µcode_mutex); ++ ++put: + put_online_cpus(); + +- if (!ret) ++ if (ret >= 0) + ret = size; + + return ret; +diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c +index 923054a..2aded9d 100644 +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -589,6 +589,23 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early) + if (!mc) + return 0; + ++ /* ++ * Save us the MSR write below - which is a particular expensive ++ * operation - when the other hyperthread has updated the microcode ++ * already. ++ */ ++ rev = intel_get_microcode_revision(); ++ if (rev >= mc->hdr.rev) { ++ uci->cpu_sig.rev = rev; ++ return UCODE_OK; ++ } ++ ++ /* ++ * Writeback and invalidate caches before updating microcode to avoid ++ * internal issues depending on what the microcode is updating. ++ */ ++ native_wbinvd(); ++ + /* write microcode via MSR 0x79 */ + native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); + +@@ -774,9 +791,9 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) + + static enum ucode_state apply_microcode_intel(int cpu) + { ++ struct ucode_cpu_info *uci = ucode_cpu_info + cpu; ++ struct cpuinfo_x86 *c = &cpu_data(cpu); + struct microcode_intel *mc; +- struct ucode_cpu_info *uci; +- struct cpuinfo_x86 *c; + static int prev_rev; + u32 rev; + +@@ -784,15 +801,32 @@ static enum ucode_state apply_microcode_intel(int cpu) + if (WARN_ON(raw_smp_processor_id() != cpu)) + return UCODE_ERROR; + +- uci = ucode_cpu_info + cpu; +- mc = uci->mc; ++ /* Look for a newer patch in our cache: */ ++ mc = find_patch(uci); + if (!mc) { +- /* Look for a newer patch in our cache: */ +- mc = find_patch(uci); ++ mc = uci->mc; + if (!mc) + return UCODE_NFOUND; + } + ++ /* ++ * Save us the MSR write below - which is a particular expensive ++ * operation - when the other hyperthread has updated the microcode ++ * already. ++ */ ++ rev = intel_get_microcode_revision(); ++ if (rev >= mc->hdr.rev) { ++ uci->cpu_sig.rev = rev; ++ c->microcode = rev; ++ return UCODE_OK; ++ } ++ ++ /* ++ * Writeback and invalidate caches before updating microcode to avoid ++ * internal issues depending on what the microcode is updating. ++ */ ++ native_wbinvd(); ++ + /* write microcode via MSR 0x79 */ + wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); + +@@ -813,8 +847,6 @@ static enum ucode_state apply_microcode_intel(int cpu) + prev_rev = rev; + } + +- c = &cpu_data(cpu); +- + uci->cpu_sig.rev = rev; + c->microcode = rev; + +diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c +index 2f72330..38deafe 100644 +--- a/arch/x86/kernel/ioport.c ++++ b/arch/x86/kernel/ioport.c +@@ -23,7 +23,7 @@ + /* + * this changes the io permissions bitmap in the current task. + */ +-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) ++SYSCALL_DEFINE3(ioperm, unsigned long, from, unsigned long, num, int, turn_on) + { + struct thread_struct *t = ¤t->thread; + struct tss_struct *tss; +diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c +index bd36f3c..0715f82 100644 +--- a/arch/x86/kernel/kprobes/core.c ++++ b/arch/x86/kernel/kprobes/core.c +@@ -1168,10 +1168,18 @@ NOKPROBE_SYMBOL(longjmp_break_handler); + + bool arch_within_kprobe_blacklist(unsigned long addr) + { ++ bool is_in_entry_trampoline_section = false; ++ ++#ifdef CONFIG_X86_64 ++ is_in_entry_trampoline_section = ++ (addr >= (unsigned long)__entry_trampoline_start && ++ addr < (unsigned long)__entry_trampoline_end); ++#endif + return (addr >= (unsigned long)__kprobes_text_start && + addr < (unsigned long)__kprobes_text_end) || + (addr >= (unsigned long)__entry_text_start && +- addr < (unsigned long)__entry_text_end); ++ addr < (unsigned long)__entry_text_end) || ++ is_in_entry_trampoline_section; + } + + int __init arch_init_kprobes(void) +diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S +index 9b138a0..b854ebf 100644 +--- a/arch/x86/kernel/vmlinux.lds.S ++++ b/arch/x86/kernel/vmlinux.lds.S +@@ -118,9 +118,11 @@ SECTIONS + + #ifdef CONFIG_X86_64 + . = ALIGN(PAGE_SIZE); ++ VMLINUX_SYMBOL(__entry_trampoline_start) = .; + _entry_trampoline = .; + *(.entry_trampoline) + . = ALIGN(PAGE_SIZE); ++ VMLINUX_SYMBOL(__entry_trampoline_end) = .; + ASSERT(. - _entry_trampoline == PAGE_SIZE, "entry trampoline is too big"); + #endif + +diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c +index ce38f16..631507f 100644 +--- a/arch/x86/mm/pti.c ++++ b/arch/x86/mm/pti.c +@@ -332,7 +332,7 @@ static void __init pti_clone_user_shared(void) + } + + /* +- * Clone the ESPFIX P4D into the user space visinble page table ++ * Clone the ESPFIX P4D into the user space visible page table + */ + static void __init pti_setup_espfix64(void) + { +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index 87855b5..ee62d2d 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -266,7 +266,7 @@ static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos) + struct iov_iter i; + ssize_t bw; + +- iov_iter_bvec(&i, ITER_BVEC, bvec, 1, bvec->bv_len); ++ iov_iter_bvec(&i, ITER_BVEC | WRITE, bvec, 1, bvec->bv_len); + + file_start_write(file); + bw = vfs_iter_write(file, &i, ppos, 0); +diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c +index e126e4c..92ec1bb 100644 +--- a/drivers/block/xen-blkfront.c ++++ b/drivers/block/xen-blkfront.c +@@ -262,6 +262,7 @@ static DEFINE_SPINLOCK(minor_lock); + + static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo); + static void blkfront_gather_backend_features(struct blkfront_info *info); ++static int negotiate_mq(struct blkfront_info *info); + + static int get_id_from_freelist(struct blkfront_ring_info *rinfo) + { +@@ -1774,11 +1775,18 @@ static int talk_to_blkback(struct xenbus_device *dev, + unsigned int i, max_page_order; + unsigned int ring_page_order; + ++ if (!info) ++ return -ENODEV; ++ + max_page_order = xenbus_read_unsigned(info->xbdev->otherend, + "max-ring-page-order", 0); + ring_page_order = min(xen_blkif_max_ring_order, max_page_order); + info->nr_ring_pages = 1 << ring_page_order; + ++ err = negotiate_mq(info); ++ if (err) ++ goto destroy_blkring; ++ + for (i = 0; i < info->nr_rings; i++) { + struct blkfront_ring_info *rinfo = &info->rinfo[i]; + +@@ -1978,11 +1986,6 @@ static int blkfront_probe(struct xenbus_device *dev, + } + + info->xbdev = dev; +- err = negotiate_mq(info); +- if (err) { +- kfree(info); +- return err; +- } + + mutex_init(&info->mutex); + info->vdevice = vdevice; +@@ -2099,10 +2102,6 @@ static int blkfront_resume(struct xenbus_device *dev) + + blkif_free(info, info->connected == BLKIF_STATE_CONNECTED); + +- err = negotiate_mq(info); +- if (err) +- return err; +- + err = talk_to_blkback(dev, info); + if (!err) + blk_mq_update_nr_hw_queues(&info->tag_set, info->nr_rings); +diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig +index b3b4ed9..d2e5382 100644 +--- a/drivers/clocksource/Kconfig ++++ b/drivers/clocksource/Kconfig +@@ -386,6 +386,7 @@ config ATMEL_PIT + + config ATMEL_ST + bool "Atmel ST timer support" if COMPILE_TEST ++ depends on HAS_IOMEM + select TIMER_OF + select MFD_SYSCON + help +diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c +index f652a0e..3548caa 100644 +--- a/drivers/dma/mv_xor_v2.c ++++ b/drivers/dma/mv_xor_v2.c +@@ -163,6 +163,7 @@ struct mv_xor_v2_device { + void __iomem *dma_base; + void __iomem *glob_base; + struct clk *clk; ++ struct clk *reg_clk; + struct tasklet_struct irq_tasklet; + struct list_head free_sw_desc; + struct dma_device dmadev; +@@ -749,13 +750,26 @@ static int mv_xor_v2_probe(struct platform_device *pdev) + if (ret) + return ret; + ++ xor_dev->reg_clk = devm_clk_get(&pdev->dev, "reg"); ++ if (PTR_ERR(xor_dev->reg_clk) != -ENOENT) { ++ if (!IS_ERR(xor_dev->reg_clk)) { ++ ret = clk_prepare_enable(xor_dev->reg_clk); ++ if (ret) ++ return ret; ++ } else { ++ return PTR_ERR(xor_dev->reg_clk); ++ } ++ } ++ + xor_dev->clk = devm_clk_get(&pdev->dev, NULL); +- if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER) +- return -EPROBE_DEFER; ++ if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER) { ++ ret = EPROBE_DEFER; ++ goto disable_reg_clk; ++ } + if (!IS_ERR(xor_dev->clk)) { + ret = clk_prepare_enable(xor_dev->clk); + if (ret) +- return ret; ++ goto disable_reg_clk; + } + + ret = platform_msi_domain_alloc_irqs(&pdev->dev, 1, +@@ -866,8 +880,9 @@ static int mv_xor_v2_probe(struct platform_device *pdev) + free_msi_irqs: + platform_msi_domain_free_irqs(&pdev->dev); + disable_clk: +- if (!IS_ERR(xor_dev->clk)) +- clk_disable_unprepare(xor_dev->clk); ++ clk_disable_unprepare(xor_dev->clk); ++disable_reg_clk: ++ clk_disable_unprepare(xor_dev->reg_clk); + return ret; + } + +diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c +index e3ff162..d0cacdb 100644 +--- a/drivers/dma/sh/rcar-dmac.c ++++ b/drivers/dma/sh/rcar-dmac.c +@@ -917,7 +917,7 @@ rcar_dmac_chan_prep_sg(struct rcar_dmac_chan *chan, struct scatterlist *sgl, + + rcar_dmac_chan_configure_desc(chan, desc); + +- max_chunk_size = (RCAR_DMATCR_MASK + 1) << desc->xfer_shift; ++ max_chunk_size = RCAR_DMATCR_MASK << desc->xfer_shift; + + /* + * Allocate and fill the transfer chunk descriptors. We own the only +diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c +index e76de57..ebaea8b 100644 +--- a/drivers/gpio/gpio-rcar.c ++++ b/drivers/gpio/gpio-rcar.c +@@ -14,7 +14,6 @@ + * GNU General Public License for more details. + */ + +-#include + #include + #include + #include +@@ -37,10 +36,9 @@ struct gpio_rcar_priv { + struct platform_device *pdev; + struct gpio_chip gpio_chip; + struct irq_chip irq_chip; +- struct clk *clk; + unsigned int irq_parent; ++ atomic_t wakeup_path; + bool has_both_edge_trigger; +- bool needs_clk; + }; + + #define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */ +@@ -186,13 +184,10 @@ static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on) + } + } + +- if (!p->clk) +- return 0; +- + if (on) +- clk_enable(p->clk); ++ atomic_inc(&p->wakeup_path); + else +- clk_disable(p->clk); ++ atomic_dec(&p->wakeup_path); + + return 0; + } +@@ -330,17 +325,14 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset, + + struct gpio_rcar_info { + bool has_both_edge_trigger; +- bool needs_clk; + }; + + static const struct gpio_rcar_info gpio_rcar_info_gen1 = { + .has_both_edge_trigger = false, +- .needs_clk = false, + }; + + static const struct gpio_rcar_info gpio_rcar_info_gen2 = { + .has_both_edge_trigger = true, +- .needs_clk = true, + }; + + static const struct of_device_id gpio_rcar_of_table[] = { +@@ -403,7 +395,6 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins) + ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args); + *npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK; + p->has_both_edge_trigger = info->has_both_edge_trigger; +- p->needs_clk = info->needs_clk; + + if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) { + dev_warn(&p->pdev->dev, +@@ -440,16 +431,6 @@ static int gpio_rcar_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, p); + +- p->clk = devm_clk_get(dev, NULL); +- if (IS_ERR(p->clk)) { +- if (p->needs_clk) { +- dev_err(dev, "unable to get clock\n"); +- ret = PTR_ERR(p->clk); +- goto err0; +- } +- p->clk = NULL; +- } +- + pm_runtime_enable(dev); + + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); +@@ -531,11 +512,24 @@ static int gpio_rcar_remove(struct platform_device *pdev) + return 0; + } + ++static int __maybe_unused gpio_rcar_suspend(struct device *dev) ++{ ++ struct gpio_rcar_priv *p = dev_get_drvdata(dev); ++ ++ if (atomic_read(&p->wakeup_path)) ++ device_set_wakeup_path(dev); ++ ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, NULL); ++ + static struct platform_driver gpio_rcar_device_driver = { + .probe = gpio_rcar_probe, + .remove = gpio_rcar_remove, + .driver = { + .name = "gpio_rcar", ++ .pm = &gpio_rcar_pm_ops, + .of_match_table = of_match_ptr(gpio_rcar_of_table), + } + }; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +index 57afad7..8fa850a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +@@ -540,6 +540,9 @@ int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev, + size_t size; + u32 retry = 3; + ++ if (amdgpu_acpi_pcie_notify_device_ready(adev)) ++ return -EINVAL; ++ + /* Get the device handle */ + handle = ACPI_HANDLE(&adev->pdev->dev); + if (!handle) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +index 13044e6..561d331 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +@@ -481,7 +481,7 @@ static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf, + result = 0; + + if (*pos < 12) { +- early[0] = amdgpu_ring_get_rptr(ring); ++ early[0] = amdgpu_ring_get_rptr(ring) & ring->buf_mask; + early[1] = amdgpu_ring_get_wptr(ring) & ring->buf_mask; + early[2] = ring->wptr & ring->buf_mask; + for (i = *pos / 4; i < 3 && size; i++) { +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +index b2eae86..5c26a8e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +@@ -299,12 +299,15 @@ int amdgpu_uvd_suspend(struct amdgpu_device *adev) + + cancel_delayed_work_sync(&adev->uvd.idle_work); + +- for (i = 0; i < adev->uvd.max_handles; ++i) +- if (atomic_read(&adev->uvd.handles[i])) +- break; ++ /* only valid for physical mode */ ++ if (adev->asic_type < CHIP_POLARIS10) { ++ for (i = 0; i < adev->uvd.max_handles; ++i) ++ if (atomic_read(&adev->uvd.handles[i])) ++ break; + +- if (i == AMDGPU_MAX_UVD_HANDLES) +- return 0; ++ if (i == adev->uvd.max_handles) ++ return 0; ++ } + + size = amdgpu_bo_size(adev->uvd.vcpu_bo); + ptr = adev->uvd.cpu_addr; +diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +index bd2c4f7..a712f4b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +@@ -3093,7 +3093,7 @@ static int dce_v6_0_hpd_irq(struct amdgpu_device *adev, + tmp |= DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK; + WREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd], tmp); + schedule_work(&adev->hotplug_work); +- DRM_INFO("IH: HPD%d\n", hpd + 1); ++ DRM_DEBUG("IH: HPD%d\n", hpd + 1); + } + + return 0; +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +index a066c5e..a430969 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +@@ -4384,34 +4384,8 @@ static void gfx_v7_0_gpu_early_init(struct amdgpu_device *adev) + case CHIP_KAVERI: + adev->gfx.config.max_shader_engines = 1; + adev->gfx.config.max_tile_pipes = 4; +- if ((adev->pdev->device == 0x1304) || +- (adev->pdev->device == 0x1305) || +- (adev->pdev->device == 0x130C) || +- (adev->pdev->device == 0x130F) || +- (adev->pdev->device == 0x1310) || +- (adev->pdev->device == 0x1311) || +- (adev->pdev->device == 0x131C)) { +- adev->gfx.config.max_cu_per_sh = 8; +- adev->gfx.config.max_backends_per_se = 2; +- } else if ((adev->pdev->device == 0x1309) || +- (adev->pdev->device == 0x130A) || +- (adev->pdev->device == 0x130D) || +- (adev->pdev->device == 0x1313) || +- (adev->pdev->device == 0x131D)) { +- adev->gfx.config.max_cu_per_sh = 6; +- adev->gfx.config.max_backends_per_se = 2; +- } else if ((adev->pdev->device == 0x1306) || +- (adev->pdev->device == 0x1307) || +- (adev->pdev->device == 0x130B) || +- (adev->pdev->device == 0x130E) || +- (adev->pdev->device == 0x1315) || +- (adev->pdev->device == 0x131B)) { +- adev->gfx.config.max_cu_per_sh = 4; +- adev->gfx.config.max_backends_per_se = 1; +- } else { +- adev->gfx.config.max_cu_per_sh = 3; +- adev->gfx.config.max_backends_per_se = 1; +- } ++ adev->gfx.config.max_cu_per_sh = 8; ++ adev->gfx.config.max_backends_per_se = 2; + adev->gfx.config.max_sh_per_se = 1; + adev->gfx.config.max_texture_channel_caches = 4; + adev->gfx.config.max_gprs = 256; +diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c +index 543101d..2095173 100644 +--- a/drivers/gpu/drm/amd/amdgpu/si.c ++++ b/drivers/gpu/drm/amd/amdgpu/si.c +@@ -31,6 +31,7 @@ + #include "amdgpu_uvd.h" + #include "amdgpu_vce.h" + #include "atom.h" ++#include "amd_pcie.h" + #include "amdgpu_powerplay.h" + #include "sid.h" + #include "si_ih.h" +@@ -1461,8 +1462,8 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) + { + struct pci_dev *root = adev->pdev->bus->self; + int bridge_pos, gpu_pos; +- u32 speed_cntl, mask, current_data_rate; +- int ret, i; ++ u32 speed_cntl, current_data_rate; ++ int i; + u16 tmp16; + + if (pci_is_root_bus(adev->pdev->bus)) +@@ -1474,23 +1475,20 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) + if (adev->flags & AMD_IS_APU) + return; + +- ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask); +- if (ret != 0) +- return; +- +- if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80))) ++ if (!(adev->pm.pcie_gen_mask & (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 | ++ CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3))) + return; + + speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); + current_data_rate = (speed_cntl & LC_CURRENT_DATA_RATE_MASK) >> + LC_CURRENT_DATA_RATE_SHIFT; +- if (mask & DRM_PCIE_SPEED_80) { ++ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) { + if (current_data_rate == 2) { + DRM_INFO("PCIE gen 3 link speeds already enabled\n"); + return; + } + DRM_INFO("enabling PCIE gen 3 link speeds, disable with amdgpu.pcie_gen2=0\n"); +- } else if (mask & DRM_PCIE_SPEED_50) { ++ } else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) { + if (current_data_rate == 1) { + DRM_INFO("PCIE gen 2 link speeds already enabled\n"); + return; +@@ -1506,7 +1504,7 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) + if (!gpu_pos) + return; + +- if (mask & DRM_PCIE_SPEED_80) { ++ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) { + if (current_data_rate != 2) { + u16 bridge_cfg, gpu_cfg; + u16 bridge_cfg2, gpu_cfg2; +@@ -1589,9 +1587,9 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) + + pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16); + tmp16 &= ~0xf; +- if (mask & DRM_PCIE_SPEED_80) ++ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) + tmp16 |= 3; +- else if (mask & DRM_PCIE_SPEED_50) ++ else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) + tmp16 |= 2; + else + tmp16 |= 1; +diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c +index ce675a7..22f0b7f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c ++++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c +@@ -26,6 +26,7 @@ + #include "amdgpu_pm.h" + #include "amdgpu_dpm.h" + #include "amdgpu_atombios.h" ++#include "amd_pcie.h" + #include "sid.h" + #include "r600_dpm.h" + #include "si_dpm.h" +@@ -3331,29 +3332,6 @@ static void btc_apply_voltage_delta_rules(struct amdgpu_device *adev, + } + } + +-static enum amdgpu_pcie_gen r600_get_pcie_gen_support(struct amdgpu_device *adev, +- u32 sys_mask, +- enum amdgpu_pcie_gen asic_gen, +- enum amdgpu_pcie_gen default_gen) +-{ +- switch (asic_gen) { +- case AMDGPU_PCIE_GEN1: +- return AMDGPU_PCIE_GEN1; +- case AMDGPU_PCIE_GEN2: +- return AMDGPU_PCIE_GEN2; +- case AMDGPU_PCIE_GEN3: +- return AMDGPU_PCIE_GEN3; +- default: +- if ((sys_mask & DRM_PCIE_SPEED_80) && (default_gen == AMDGPU_PCIE_GEN3)) +- return AMDGPU_PCIE_GEN3; +- else if ((sys_mask & DRM_PCIE_SPEED_50) && (default_gen == AMDGPU_PCIE_GEN2)) +- return AMDGPU_PCIE_GEN2; +- else +- return AMDGPU_PCIE_GEN1; +- } +- return AMDGPU_PCIE_GEN1; +-} +- + static void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b, + u32 *p, u32 *u) + { +@@ -5028,10 +5006,11 @@ static int si_populate_smc_acpi_state(struct amdgpu_device *adev, + table->ACPIState.levels[0].vddc.index, + &table->ACPIState.levels[0].std_vddc); + } +- table->ACPIState.levels[0].gen2PCIE = (u8)r600_get_pcie_gen_support(adev, +- si_pi->sys_pcie_mask, +- si_pi->boot_pcie_gen, +- AMDGPU_PCIE_GEN1); ++ table->ACPIState.levels[0].gen2PCIE = ++ (u8)amdgpu_get_pcie_gen_support(adev, ++ si_pi->sys_pcie_mask, ++ si_pi->boot_pcie_gen, ++ AMDGPU_PCIE_GEN1); + + if (si_pi->vddc_phase_shed_control) + si_populate_phase_shedding_value(adev, +@@ -7168,10 +7147,10 @@ static void si_parse_pplib_clock_info(struct amdgpu_device *adev, + pl->vddc = le16_to_cpu(clock_info->si.usVDDC); + pl->vddci = le16_to_cpu(clock_info->si.usVDDCI); + pl->flags = le32_to_cpu(clock_info->si.ulFlags); +- pl->pcie_gen = r600_get_pcie_gen_support(adev, +- si_pi->sys_pcie_mask, +- si_pi->boot_pcie_gen, +- clock_info->si.ucPCIEGen); ++ pl->pcie_gen = amdgpu_get_pcie_gen_support(adev, ++ si_pi->sys_pcie_mask, ++ si_pi->boot_pcie_gen, ++ clock_info->si.ucPCIEGen); + + /* patch up vddc if necessary */ + ret = si_get_leakage_voltage_from_leakage_index(adev, pl->vddc, +@@ -7326,7 +7305,6 @@ static int si_dpm_init(struct amdgpu_device *adev) + struct si_power_info *si_pi; + struct atom_clock_dividers dividers; + int ret; +- u32 mask; + + si_pi = kzalloc(sizeof(struct si_power_info), GFP_KERNEL); + if (si_pi == NULL) +@@ -7336,11 +7314,9 @@ static int si_dpm_init(struct amdgpu_device *adev) + eg_pi = &ni_pi->eg; + pi = &eg_pi->rv7xx; + +- ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask); +- if (ret) +- si_pi->sys_pcie_mask = 0; +- else +- si_pi->sys_pcie_mask = mask; ++ si_pi->sys_pcie_mask = ++ (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK) >> ++ CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT; + si_pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID; + si_pi->boot_pcie_gen = si_get_current_pcie_speed(adev); + +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 862835d..c345e64 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -1037,6 +1037,10 @@ static void handle_hpd_rx_irq(void *param) + !is_mst_root_connector) { + /* Downstream Port status changed. */ + if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) { ++ ++ if (aconnector->fake_enable) ++ aconnector->fake_enable = false; ++ + amdgpu_dm_update_connector_after_detect(aconnector); + + +@@ -2012,30 +2016,32 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, + dst.width = stream->timing.h_addressable; + dst.height = stream->timing.v_addressable; + +- rmx_type = dm_state->scaling; +- if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) { +- if (src.width * dst.height < +- src.height * dst.width) { +- /* height needs less upscaling/more downscaling */ +- dst.width = src.width * +- dst.height / src.height; +- } else { +- /* width needs less upscaling/more downscaling */ +- dst.height = src.height * +- dst.width / src.width; ++ if (dm_state) { ++ rmx_type = dm_state->scaling; ++ if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) { ++ if (src.width * dst.height < ++ src.height * dst.width) { ++ /* height needs less upscaling/more downscaling */ ++ dst.width = src.width * ++ dst.height / src.height; ++ } else { ++ /* width needs less upscaling/more downscaling */ ++ dst.height = src.height * ++ dst.width / src.width; ++ } ++ } else if (rmx_type == RMX_CENTER) { ++ dst = src; + } +- } else if (rmx_type == RMX_CENTER) { +- dst = src; +- } + +- dst.x = (stream->timing.h_addressable - dst.width) / 2; +- dst.y = (stream->timing.v_addressable - dst.height) / 2; ++ dst.x = (stream->timing.h_addressable - dst.width) / 2; ++ dst.y = (stream->timing.v_addressable - dst.height) / 2; + +- if (dm_state->underscan_enable) { +- dst.x += dm_state->underscan_hborder / 2; +- dst.y += dm_state->underscan_vborder / 2; +- dst.width -= dm_state->underscan_hborder; +- dst.height -= dm_state->underscan_vborder; ++ if (dm_state->underscan_enable) { ++ dst.x += dm_state->underscan_hborder / 2; ++ dst.y += dm_state->underscan_vborder / 2; ++ dst.width -= dm_state->underscan_hborder; ++ dst.height -= dm_state->underscan_vborder; ++ } + } + + stream->src = src; +@@ -2360,12 +2366,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + + if (aconnector == NULL) { + DRM_ERROR("aconnector is NULL!\n"); +- goto drm_connector_null; +- } +- +- if (dm_state == NULL) { +- DRM_ERROR("dm_state is NULL!\n"); +- goto dm_state_null; ++ return stream; + } + + drm_connector = &aconnector->base; +@@ -2377,18 +2378,18 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + */ + if (aconnector->mst_port) { + dm_dp_mst_dc_sink_create(drm_connector); +- goto mst_dc_sink_create_done; ++ return stream; + } + + if (create_fake_sink(aconnector)) +- goto stream_create_fail; ++ return stream; + } + + stream = dc_create_stream_for_sink(aconnector->dc_sink); + + if (stream == NULL) { + DRM_ERROR("Failed to create stream for sink!\n"); +- goto stream_create_fail; ++ return stream; + } + + list_for_each_entry(preferred_mode, &aconnector->base.modes, head) { +@@ -2414,9 +2415,12 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + } else { + decide_crtc_timing_for_drm_display_mode( + &mode, preferred_mode, +- dm_state->scaling != RMX_OFF); ++ dm_state ? (dm_state->scaling != RMX_OFF) : false); + } + ++ if (!dm_state) ++ drm_mode_set_crtcinfo(&mode, 0); ++ + fill_stream_properties_from_drm_display_mode(stream, + &mode, &aconnector->base); + update_stream_scaling_settings(&mode, dm_state, stream); +@@ -2426,10 +2430,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + drm_connector, + aconnector->dc_sink); + +-stream_create_fail: +-dm_state_null: +-drm_connector_null: +-mst_dc_sink_create_done: ++ update_stream_signal(stream); ++ + return stream; + } + +@@ -2497,6 +2499,27 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc) + return &state->base; + } + ++ ++static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable) ++{ ++ enum dc_irq_source irq_source; ++ struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); ++ struct amdgpu_device *adev = crtc->dev->dev_private; ++ ++ irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst; ++ return dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY; ++} ++ ++static int dm_enable_vblank(struct drm_crtc *crtc) ++{ ++ return dm_set_vblank(crtc, true); ++} ++ ++static void dm_disable_vblank(struct drm_crtc *crtc) ++{ ++ dm_set_vblank(crtc, false); ++} ++ + /* Implemented only the options currently availible for the driver */ + static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { + .reset = dm_crtc_reset_state, +@@ -2506,6 +2529,8 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = dm_crtc_duplicate_state, + .atomic_destroy_state = dm_crtc_destroy_state, ++ .enable_vblank = dm_enable_vblank, ++ .disable_vblank = dm_disable_vblank, + }; + + static enum drm_connector_status +@@ -2800,7 +2825,7 @@ int amdgpu_dm_connector_mode_valid(struct drm_connector *connector, + goto fail; + } + +- stream = dc_create_stream_for_sink(dc_sink); ++ stream = create_stream_for_sink(aconnector, mode, NULL); + if (stream == NULL) { + DRM_ERROR("Failed to create stream for sink!\n"); + goto fail; +@@ -3060,6 +3085,9 @@ static int dm_plane_atomic_check(struct drm_plane *plane, + if (!dm_plane_state->dc_state) + return 0; + ++ if (!fill_rects_from_plane_state(state, dm_plane_state->dc_state)) ++ return -EINVAL; ++ + if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK) + return 0; + +@@ -4632,8 +4660,6 @@ static int dm_update_planes_state(struct dc *dc, + bool pflip_needed = !state->allow_modeset; + int ret = 0; + +- if (pflip_needed) +- return ret; + + /* Add new planes */ + for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { +@@ -4648,6 +4674,8 @@ static int dm_update_planes_state(struct dc *dc, + + /* Remove any changed/removed planes */ + if (!enable) { ++ if (pflip_needed) ++ continue; + + if (!old_plane_crtc) + continue; +@@ -4679,6 +4707,7 @@ static int dm_update_planes_state(struct dc *dc, + *lock_and_validation_needed = true; + + } else { /* Add new planes */ ++ struct dc_plane_state *dc_new_plane_state; + + if (drm_atomic_plane_disabling(plane->state, new_plane_state)) + continue; +@@ -4692,38 +4721,50 @@ static int dm_update_planes_state(struct dc *dc, + if (!dm_new_crtc_state->stream) + continue; + ++ if (pflip_needed) ++ continue; + + WARN_ON(dm_new_plane_state->dc_state); + +- dm_new_plane_state->dc_state = dc_create_plane_state(dc); +- +- DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n", +- plane->base.id, new_plane_crtc->base.id); +- +- if (!dm_new_plane_state->dc_state) { ++ dc_new_plane_state = dc_create_plane_state(dc); ++ if (!dc_new_plane_state) { + ret = -EINVAL; + return ret; + } + ++ DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n", ++ plane->base.id, new_plane_crtc->base.id); ++ + ret = fill_plane_attributes( + new_plane_crtc->dev->dev_private, +- dm_new_plane_state->dc_state, ++ dc_new_plane_state, + new_plane_state, + new_crtc_state); +- if (ret) ++ if (ret) { ++ dc_plane_state_release(dc_new_plane_state); + return ret; ++ } + +- ++ /* ++ * Any atomic check errors that occur after this will ++ * not need a release. The plane state will be attached ++ * to the stream, and therefore part of the atomic ++ * state. It'll be released when the atomic state is ++ * cleaned. ++ */ + if (!dc_add_plane_to_context( + dc, + dm_new_crtc_state->stream, +- dm_new_plane_state->dc_state, ++ dc_new_plane_state, + dm_state->context)) { + ++ dc_plane_state_release(dc_new_plane_state); + ret = -EINVAL; + return ret; + } + ++ dm_new_plane_state->dc_state = dc_new_plane_state; ++ + /* Tell DC to do a full surface update every time there + * is a plane change. Inefficient, but works for now. + */ +@@ -4737,6 +4778,30 @@ static int dm_update_planes_state(struct dc *dc, + return ret; + } + ++static int dm_atomic_check_plane_state_fb(struct drm_atomic_state *state, ++ struct drm_crtc *crtc) ++{ ++ struct drm_plane *plane; ++ struct drm_crtc_state *crtc_state; ++ ++ WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc)); ++ ++ drm_for_each_plane_mask(plane, state->dev, crtc->state->plane_mask) { ++ struct drm_plane_state *plane_state = ++ drm_atomic_get_plane_state(state, plane); ++ ++ if (IS_ERR(plane_state)) ++ return -EDEADLK; ++ ++ crtc_state = drm_atomic_get_crtc_state(plane_state->state, crtc); ++ if (crtc->primary == plane && crtc_state->active) { ++ if (!plane_state->fb) ++ return -EINVAL; ++ } ++ } ++ return 0; ++} ++ + static int amdgpu_dm_atomic_check(struct drm_device *dev, + struct drm_atomic_state *state) + { +@@ -4760,6 +4825,10 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, + goto fail; + + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { ++ ret = dm_atomic_check_plane_state_fb(state, crtc); ++ if (ret) ++ goto fail; ++ + if (!drm_atomic_crtc_needs_modeset(new_crtc_state) && + !new_crtc_state->color_mgmt_changed) + continue; +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +index 1874b6c..4220550 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +@@ -683,10 +683,8 @@ static const struct amdgpu_irq_src_funcs dm_hpd_irq_funcs = { + + void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev) + { +- if (adev->mode_info.num_crtc > 0) +- adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_VLINE1 + adev->mode_info.num_crtc; +- else +- adev->crtc_irq.num_types = 0; ++ ++ adev->crtc_irq.num_types = adev->mode_info.num_crtc; + adev->crtc_irq.funcs = &dm_crtc_irq_funcs; + + adev->pageflip_irq.num_types = adev->mode_info.num_crtc; +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 f3d87f4..93421da 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 +@@ -189,6 +189,12 @@ void dm_dp_mst_dc_sink_create(struct drm_connector *connector) + .link = aconnector->dc_link, + .sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST }; + ++ /* ++ * TODO: Need to further figure out why ddc.algo is NULL while MST port exists ++ */ ++ if (!aconnector->port || !aconnector->port->aux.ddc.algo) ++ return; ++ + edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port); + + if (!edid) { +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index 35e84ed..12868c7 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -1358,13 +1358,13 @@ enum dc_irq_source dc_interrupt_to_irq_source( + return dal_irq_service_to_irq_source(dc->res_pool->irqs, src_id, ext_id); + } + +-void dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable) ++bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable) + { + + if (dc == NULL) +- return; ++ return false; + +- dal_irq_service_set(dc->res_pool->irqs, src, enable); ++ return dal_irq_service_set(dc->res_pool->irqs, src, enable); + } + + void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src) +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c +index a374282..be55461 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c +@@ -1749,8 +1749,7 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) + link->link_enc, + pipe_ctx->clock_source->id, + display_color_depth, +- pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A, +- pipe_ctx->stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK, ++ pipe_ctx->stream->signal, + stream->phy_pix_clk); + + if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) +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 95b8dd0..4d07ffe 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -1360,9 +1360,6 @@ bool dc_is_stream_scaling_unchanged( + return true; + } + +-/* Maximum TMDS single link pixel clock 165MHz */ +-#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ 165000 +- + static void update_stream_engine_usage( + struct resource_context *res_ctx, + const struct resource_pool *pool, +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 539c3e0..cd58197 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +@@ -33,8 +33,7 @@ + /******************************************************************************* + * Private functions + ******************************************************************************/ +-#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST 297000 +-static void update_stream_signal(struct dc_stream_state *stream) ++void update_stream_signal(struct dc_stream_state *stream) + { + + struct dc_sink *dc_sink = stream->sink; +@@ -45,8 +44,9 @@ static void update_stream_signal(struct dc_stream_state *stream) + stream->signal = dc_sink->sink_signal; + + if (dc_is_dvi_signal(stream->signal)) { +- if (stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST && +- stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) ++ if (stream->ctx->dc->caps.dual_link_dvi && ++ stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK && ++ stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) + stream->signal = SIGNAL_TYPE_DVI_DUAL_LINK; + else + stream->signal = SIGNAL_TYPE_DVI_SINGLE_LINK; +@@ -193,6 +193,7 @@ bool dc_stream_set_cursor_attributes( + + core_dc = stream->ctx->dc; + res_ctx = &core_dc->current_state->res_ctx; ++ stream->cursor_attributes = *attributes; + + for (i = 0; i < MAX_PIPES; i++) { + struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; +@@ -204,34 +205,8 @@ bool dc_stream_set_cursor_attributes( + continue; + + +- if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes != NULL) +- pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes( +- pipe_ctx->plane_res.ipp, attributes); +- +- if (pipe_ctx->plane_res.hubp != NULL && +- pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes != NULL) +- pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( +- pipe_ctx->plane_res.hubp, attributes); +- +- if (pipe_ctx->plane_res.mi != NULL && +- pipe_ctx->plane_res.mi->funcs->set_cursor_attributes != NULL) +- pipe_ctx->plane_res.mi->funcs->set_cursor_attributes( +- pipe_ctx->plane_res.mi, attributes); +- +- +- if (pipe_ctx->plane_res.xfm != NULL && +- pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes != NULL) +- pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes( +- pipe_ctx->plane_res.xfm, attributes); +- +- if (pipe_ctx->plane_res.dpp != NULL && +- pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes != NULL) +- pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( +- pipe_ctx->plane_res.dpp, attributes->color_format); ++ core_dc->hwss.set_cursor_attribute(pipe_ctx); + } +- +- stream->cursor_attributes = *attributes; +- + return true; + } + +@@ -255,21 +230,10 @@ bool dc_stream_set_cursor_position( + + core_dc = stream->ctx->dc; + res_ctx = &core_dc->current_state->res_ctx; ++ stream->cursor_position = *position; + + for (i = 0; i < MAX_PIPES; i++) { + struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; +- struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; +- struct mem_input *mi = pipe_ctx->plane_res.mi; +- struct hubp *hubp = pipe_ctx->plane_res.hubp; +- struct dpp *dpp = pipe_ctx->plane_res.dpp; +- struct dc_cursor_position pos_cpy = *position; +- struct dc_cursor_mi_param param = { +- .pixel_clk_khz = stream->timing.pix_clk_khz, +- .ref_clk_khz = core_dc->res_pool->ref_clock_inKhz, +- .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, +- .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, +- .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz +- }; + + if (pipe_ctx->stream != stream || + (!pipe_ctx->plane_res.mi && !pipe_ctx->plane_res.hubp) || +@@ -278,33 +242,9 @@ bool dc_stream_set_cursor_position( + !pipe_ctx->plane_res.ipp) + continue; + +- if (pipe_ctx->plane_state->address.type +- == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) +- pos_cpy.enable = false; +- +- if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) +- pos_cpy.enable = false; +- +- +- if (ipp != NULL && ipp->funcs->ipp_cursor_set_position != NULL) +- ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, ¶m); +- +- if (mi != NULL && mi->funcs->set_cursor_position != NULL) +- mi->funcs->set_cursor_position(mi, &pos_cpy, ¶m); +- +- if (!hubp) +- continue; +- +- if (hubp->funcs->set_cursor_position != NULL) +- hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); +- +- if (dpp != NULL && dpp->funcs->set_cursor_position != NULL) +- dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width); +- ++ core_dc->hwss.set_cursor_position(pipe_ctx); + } + +- stream->cursor_position = *position; +- + return true; + } + +diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h +index e2e3c9d..d6d5661 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc.h ++++ b/drivers/gpu/drm/amd/display/dc/dc.h +@@ -62,6 +62,7 @@ struct dc_caps { + bool dcc_const_color; + bool dynamic_audio; + bool is_apu; ++ bool dual_link_dvi; + }; + + struct dc_dcc_surface_param { +@@ -672,7 +673,7 @@ enum dc_irq_source dc_interrupt_to_irq_source( + struct dc *dc, + uint32_t src_id, + uint32_t ext_id); +-void dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable); ++bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable); + void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src); + enum dc_irq_source dc_get_hpd_irq_source_at_index( + struct dc *dc, uint32_t link_index); +diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h +index 01c60f1..456e4d2 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h +@@ -237,6 +237,8 @@ enum surface_update_type dc_check_update_surfaces_for_stream( + */ + struct dc_stream_state *dc_create_stream_for_sink(struct dc_sink *dc_sink); + ++void update_stream_signal(struct dc_stream_state *stream); ++ + void dc_stream_retain(struct dc_stream_state *dc_stream); + void dc_stream_release(struct dc_stream_state *dc_stream); + +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +index b73db9e..a993279 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +@@ -236,6 +236,7 @@ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ ++ SR(VGA_TEST_CONTROL), \ + SR(DC_IP_REQUEST_CNTL), \ + BL_REG_LIST() + +@@ -337,6 +338,7 @@ struct dce_hwseq_registers { + uint32_t D2VGA_CONTROL; + uint32_t D3VGA_CONTROL; + uint32_t D4VGA_CONTROL; ++ uint32_t VGA_TEST_CONTROL; + /* MMHUB registers. read only. temporary hack */ + uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32; + uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32; +@@ -493,6 +495,9 @@ struct dce_hwseq_registers { + HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ ++ HWS_SF(, D1VGA_CONTROL, D1VGA_MODE_ENABLE, mask_sh),\ ++ HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_ENABLE, mask_sh),\ ++ HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_RENDER_START, mask_sh),\ + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \ + HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) + +@@ -583,7 +588,10 @@ struct dce_hwseq_registers { + type DCFCLK_GATE_DIS; \ + type DCHUBBUB_GLOBAL_TIMER_REFDIV; \ + type DENTIST_DPPCLK_WDIVIDER; \ +- type DENTIST_DISPCLK_WDIVIDER; ++ type DENTIST_DISPCLK_WDIVIDER; \ ++ type VGA_TEST_ENABLE; \ ++ type VGA_TEST_RENDER_START; \ ++ type D1VGA_MODE_ENABLE; + + struct dce_hwseq_shift { + HWSEQ_REG_FIELD_LIST(uint8_t) +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +index a266e3f..e4741f1 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +@@ -82,13 +82,6 @@ + #define DCE110_DIG_FE_SOURCE_SELECT_DIGF 0x20 + #define DCE110_DIG_FE_SOURCE_SELECT_DIGG 0x40 + +-/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */ +-#define TMDS_MIN_PIXEL_CLOCK 25000 +-/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */ +-#define TMDS_MAX_PIXEL_CLOCK 165000 +-/* For current ASICs pixel clock - 600MHz */ +-#define MAX_ENCODER_CLOCK 600000 +- + enum { + DP_MST_UPDATE_MAX_RETRY = 50 + }; +@@ -683,6 +676,7 @@ void dce110_link_encoder_construct( + { + struct bp_encoder_cap_info bp_cap_info = {0}; + const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs; ++ enum bp_result result = BP_RESULT_OK; + + enc110->base.funcs = &dce110_lnk_enc_funcs; + enc110->base.ctx = init_data->ctx; +@@ -757,15 +751,24 @@ void dce110_link_encoder_construct( + enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; + } + ++ /* default to one to mirror Windows behavior */ ++ enc110->base.features.flags.bits.HDMI_6GB_EN = 1; ++ ++ result = bp_funcs->get_encoder_cap_info(enc110->base.ctx->dc_bios, ++ enc110->base.id, &bp_cap_info); ++ + /* Override features with DCE-specific values */ +- if (BP_RESULT_OK == bp_funcs->get_encoder_cap_info( +- enc110->base.ctx->dc_bios, enc110->base.id, +- &bp_cap_info)) { ++ if (BP_RESULT_OK == result) { + enc110->base.features.flags.bits.IS_HBR2_CAPABLE = + bp_cap_info.DP_HBR2_EN; + enc110->base.features.flags.bits.IS_HBR3_CAPABLE = + bp_cap_info.DP_HBR3_EN; + enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN; ++ } else { ++ dm_logger_write(enc110->base.ctx->logger, LOG_WARNING, ++ "%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", ++ __func__, ++ result); + } + } + +@@ -904,8 +907,7 @@ void dce110_link_encoder_enable_tmds_output( + struct link_encoder *enc, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, +- bool hdmi, +- bool dual_link, ++ enum signal_type signal, + uint32_t pixel_clock) + { + struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); +@@ -919,16 +921,12 @@ void dce110_link_encoder_enable_tmds_output( + cntl.engine_id = enc->preferred_engine; + cntl.transmitter = enc110->base.transmitter; + cntl.pll_id = clock_source; +- if (hdmi) { +- cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A; +- cntl.lanes_number = 4; +- } else if (dual_link) { +- cntl.signal = SIGNAL_TYPE_DVI_DUAL_LINK; ++ cntl.signal = signal; ++ if (cntl.signal == SIGNAL_TYPE_DVI_DUAL_LINK) + cntl.lanes_number = 8; +- } else { +- cntl.signal = SIGNAL_TYPE_DVI_SINGLE_LINK; ++ else + cntl.lanes_number = 4; +- } ++ + cntl.hpd_sel = enc110->base.hpd_source; + + cntl.pixel_clock = pixel_clock; +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h +index 8ca9afe..0ec3433 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h +@@ -210,8 +210,7 @@ void dce110_link_encoder_enable_tmds_output( + struct link_encoder *enc, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, +- bool hdmi, +- bool dual_link, ++ enum signal_type signal, + uint32_t pixel_clock); + + /* enables DP PHY output */ +diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +index 3ea43e2..442dd2d 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +@@ -852,6 +852,7 @@ static bool construct( + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 40; + dc->caps.max_cursor_size = 128; ++ dc->caps.dual_link_dvi = true; + + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.timing_generators[i] = +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 86cdd7b4..6f382a3 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 +@@ -688,15 +688,22 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) + struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; + struct dc_link *link = pipe_ctx->stream->sink->link; + +- /* 1. update AVI info frame (HDMI, DP) +- * we always need to update info frame +- */ ++ + uint32_t active_total_with_borders; + uint32_t early_control = 0; + struct timing_generator *tg = pipe_ctx->stream_res.tg; + +- /* TODOFPGA may change to hwss.update_info_frame */ ++ /* For MST, there are multiply stream go to only one link. ++ * connect DIG back_end to front_end while enable_stream and ++ * disconnect them during disable_stream ++ * BY this, it is logic clean to separate stream and link */ ++ link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, ++ pipe_ctx->stream_res.stream_enc->id, true); ++ ++ /* update AVI info frame (HDMI, DP)*/ ++ /* TODO: FPGA may change to hwss.update_info_frame */ + dce110_update_info_frame(pipe_ctx); ++ + /* enable early control to avoid corruption on DP monitor*/ + active_total_with_borders = + timing->h_addressable +@@ -717,12 +724,8 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) + pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc); + } + +- /* For MST, there are multiply stream go to only one link. +- * connect DIG back_end to front_end while enable_stream and +- * disconnect them during disable_stream +- * BY this, it is logic clean to separate stream and link */ +- link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, +- pipe_ctx->stream_res.stream_enc->id, true); ++ ++ + + } + +@@ -1690,9 +1693,13 @@ static void apply_min_clocks( + * Check if FBC can be enabled + */ + static bool should_enable_fbc(struct dc *dc, +- struct dc_state *context) ++ struct dc_state *context, ++ uint32_t *pipe_idx) + { +- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[0]; ++ uint32_t i; ++ struct pipe_ctx *pipe_ctx = NULL; ++ struct resource_context *res_ctx = &context->res_ctx; ++ + + ASSERT(dc->fbc_compressor); + +@@ -1704,6 +1711,14 @@ static bool should_enable_fbc(struct dc *dc, + if (context->stream_count != 1) + return false; + ++ for (i = 0; i < dc->res_pool->pipe_count; i++) { ++ if (res_ctx->pipe_ctx[i].stream) { ++ pipe_ctx = &res_ctx->pipe_ctx[i]; ++ *pipe_idx = i; ++ break; ++ } ++ } ++ + /* Only supports eDP */ + if (pipe_ctx->stream->sink->link->connector_signal != SIGNAL_TYPE_EDP) + return false; +@@ -1729,11 +1744,14 @@ static bool should_enable_fbc(struct dc *dc, + static void enable_fbc(struct dc *dc, + struct dc_state *context) + { +- if (should_enable_fbc(dc, context)) { ++ uint32_t pipe_idx = 0; ++ ++ if (should_enable_fbc(dc, context, &pipe_idx)) { + /* Program GRPH COMPRESSED ADDRESS and PITCH */ + struct compr_addr_and_pitch_params params = {0, 0, 0}; + struct compressor *compr = dc->fbc_compressor; +- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[0]; ++ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx]; ++ + + params.source_view_width = pipe_ctx->stream->timing.h_addressable; + params.source_view_height = pipe_ctx->stream->timing.v_addressable; +@@ -2915,6 +2933,49 @@ static void program_csc_matrix(struct pipe_ctx *pipe_ctx, + } + } + ++void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx) ++{ ++ struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; ++ struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; ++ struct mem_input *mi = pipe_ctx->plane_res.mi; ++ struct dc_cursor_mi_param param = { ++ .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, ++ .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, ++ .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, ++ .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, ++ .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz ++ }; ++ ++ if (pipe_ctx->plane_state->address.type ++ == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) ++ pos_cpy.enable = false; ++ ++ if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) ++ pos_cpy.enable = false; ++ ++ if (ipp->funcs->ipp_cursor_set_position) ++ ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, ¶m); ++ if (mi->funcs->set_cursor_position) ++ mi->funcs->set_cursor_position(mi, &pos_cpy, ¶m); ++} ++ ++void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx) ++{ ++ struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; ++ ++ if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes) ++ pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes( ++ pipe_ctx->plane_res.ipp, attributes); ++ ++ if (pipe_ctx->plane_res.mi->funcs->set_cursor_attributes) ++ pipe_ctx->plane_res.mi->funcs->set_cursor_attributes( ++ pipe_ctx->plane_res.mi, attributes); ++ ++ if (pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes) ++ pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes( ++ pipe_ctx->plane_res.xfm, attributes); ++} ++ + static void ready_shared_resources(struct dc *dc, struct dc_state *context) {} + + static void optimize_shared_resources(struct dc *dc) {} +@@ -2957,6 +3018,8 @@ static const struct hw_sequencer_funcs dce110_funcs = { + .edp_backlight_control = hwss_edp_backlight_control, + .edp_power_control = hwss_edp_power_control, + .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, ++ .set_cursor_position = dce110_set_cursor_position, ++ .set_cursor_attribute = dce110_set_cursor_attribute + }; + + void dce110_hw_sequencer_construct(struct dc *dc) +diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +index 7c47795..00f18c4 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +@@ -846,6 +846,16 @@ static bool dce110_validate_bandwidth( + return result; + } + ++enum dc_status dce110_validate_plane(const struct dc_plane_state *plane_state, ++ struct dc_caps *caps) ++{ ++ if (((plane_state->dst_rect.width * 2) < plane_state->src_rect.width) || ++ ((plane_state->dst_rect.height * 2) < plane_state->src_rect.height)) ++ return DC_FAIL_SURFACE_VALIDATE; ++ ++ return DC_OK; ++} ++ + static bool dce110_validate_surface_sets( + struct dc_state *context) + { +@@ -869,6 +879,13 @@ static bool dce110_validate_surface_sets( + plane->src_rect.height > 1080)) + return false; + ++ /* we don't have the logic to support underlay ++ * only yet so block the use case where we get ++ * NV12 plane as top layer ++ */ ++ if (j == 0) ++ return false; ++ + /* irrespective of plane format, + * stream should be RGB encoded + */ +@@ -1021,6 +1038,7 @@ static const struct resource_funcs dce110_res_pool_funcs = { + .link_enc_create = dce110_link_encoder_create, + .validate_guaranteed = dce110_validate_guaranteed, + .validate_bandwidth = dce110_validate_bandwidth, ++ .validate_plane = dce110_validate_plane, + .acquire_idle_pipe_for_layer = dce110_acquire_underlay, + .add_stream_to_ctx = dce110_add_stream_to_ctx, + .validate_global = dce110_validate_global +diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +index 663e0a0..98d9cd0 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +@@ -1103,6 +1103,8 @@ static bool construct( + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.max_cursor_size = 128; ++ dc->caps.dual_link_dvi = true; ++ + + /************************************************* + * Create resources * +diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +index 57cd673..5aab01d 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +@@ -835,6 +835,8 @@ static bool construct( + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.max_cursor_size = 128; ++ dc->caps.dual_link_dvi = true; ++ + dc->debug = debug_defaults; + + /************************************************* +diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +index 8f2bd56..25d7eb1 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +@@ -793,6 +793,7 @@ static bool dce80_construct( + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 40; + dc->caps.max_cursor_size = 128; ++ dc->caps.dual_link_dvi = true; + + /************************************************* + * Create resources * +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 8257286..072e448 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 +@@ -238,10 +238,24 @@ static void enable_power_gating_plane( + static void disable_vga( + struct dce_hwseq *hws) + { ++ unsigned int in_vga_mode = 0; ++ ++ REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga_mode); ++ ++ if (in_vga_mode == 0) ++ return; ++ + REG_WRITE(D1VGA_CONTROL, 0); +- REG_WRITE(D2VGA_CONTROL, 0); +- REG_WRITE(D3VGA_CONTROL, 0); +- REG_WRITE(D4VGA_CONTROL, 0); ++ ++ /* HW Engineer's Notes: ++ * During switch from vga->extended, if we set the VGA_TEST_ENABLE and ++ * then hit the VGA_TEST_RENDER_START, then the DCHUBP timing gets updated correctly. ++ * ++ * Then vBIOS will have it poll for the VGA_TEST_RENDER_DONE and unset ++ * VGA_TEST_ENABLE, to leave it in the same state as before. ++ */ ++ REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_ENABLE, 1); ++ REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1); + } + + static void dpp_pg_control( +@@ -1761,6 +1775,11 @@ static void update_dchubp_dpp( + &pipe_ctx->plane_res.scl_data.viewport_c); + } + ++ if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { ++ dc->hwss.set_cursor_position(pipe_ctx); ++ dc->hwss.set_cursor_attribute(pipe_ctx); ++ } ++ + if (plane_state->update_flags.bits.full_update) { + /*gamut remap*/ + program_gamut_remap(pipe_ctx); +@@ -2296,7 +2315,7 @@ static bool dcn10_dummy_display_power_gating( + return true; + } + +-void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) ++static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) + { + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + struct timing_generator *tg = pipe_ctx->stream_res.tg; +@@ -2316,12 +2335,46 @@ void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) + } + } + +-void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) ++static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) + { + if (hws->ctx->dc->res_pool->hubbub != NULL) + hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data); + } + ++static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) ++{ ++ struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; ++ struct hubp *hubp = pipe_ctx->plane_res.hubp; ++ struct dpp *dpp = pipe_ctx->plane_res.dpp; ++ struct dc_cursor_mi_param param = { ++ .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, ++ .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, ++ .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, ++ .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, ++ .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz ++ }; ++ ++ if (pipe_ctx->plane_state->address.type ++ == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) ++ pos_cpy.enable = false; ++ ++ if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) ++ pos_cpy.enable = false; ++ ++ hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); ++ dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width); ++} ++ ++static void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) ++{ ++ struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; ++ ++ pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( ++ pipe_ctx->plane_res.hubp, attributes); ++ pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( ++ pipe_ctx->plane_res.dpp, attributes->color_format); ++} ++ + static const struct hw_sequencer_funcs dcn10_funcs = { + .program_gamut_remap = program_gamut_remap, + .program_csc_matrix = program_csc_matrix, +@@ -2362,6 +2415,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = { + .edp_backlight_control = hwss_edp_backlight_control, + .edp_power_control = hwss_edp_power_control, + .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, ++ .set_cursor_position = dcn10_set_cursor_position, ++ .set_cursor_attribute = dcn10_set_cursor_attribute + }; + + +diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +index 0fd329d..54d8a13 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +@@ -123,8 +123,7 @@ struct link_encoder_funcs { + void (*enable_tmds_output)(struct link_encoder *enc, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, +- bool hdmi, +- bool dual_link, ++ enum signal_type signal, + uint32_t pixel_clock); + void (*enable_dp_output)(struct link_encoder *enc, + const struct dc_link_settings *link_settings, +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 4c0aa56..379c6ec 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +@@ -198,6 +198,9 @@ struct hw_sequencer_funcs { + bool enable); + void (*edp_wait_for_hpd_ready)(struct dc_link *link, bool power_up); + ++ void (*set_cursor_position)(struct pipe_ctx *pipe); ++ void (*set_cursor_attribute)(struct pipe_ctx *pipe); ++ + }; + + void color_space_to_black_color( +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 f7e40b2..d3e1923 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 +@@ -217,7 +217,7 @@ bool dce110_vblank_set( + core_dc->current_state->res_ctx.pipe_ctx[pipe_offset].stream_res.tg; + + if (enable) { +- if (!tg->funcs->arm_vert_intr(tg, 2)) { ++ if (!tg || !tg->funcs->arm_vert_intr(tg, 2)) { + DC_ERROR("Failed to get VBLANK!\n"); + return false; + } +diff --git a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c +index 57a54a7..1c079ba 100644 +--- a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c +@@ -42,8 +42,7 @@ static void virtual_link_encoder_enable_tmds_output( + struct link_encoder *enc, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, +- bool hdmi, +- bool dual_link, ++ enum signal_type signal, + uint32_t pixel_clock) {} + + static void virtual_link_encoder_enable_dp_output( +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 7a9b43f..36bbad5 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 +@@ -419,11 +419,6 @@ struct bios_event_info { + bool backlight_changed; + }; + +-enum { +- HDMI_PIXEL_CLOCK_IN_KHZ_297 = 297000, +- TMDS_PIXEL_CLOCK_IN_KHZ_165 = 165000 +-}; +- + /* + * DFS-bypass flag + */ +diff --git a/drivers/gpu/drm/amd/display/include/signal_types.h b/drivers/gpu/drm/amd/display/include/signal_types.h +index b5ebde6..199c5db 100644 +--- a/drivers/gpu/drm/amd/display/include/signal_types.h ++++ b/drivers/gpu/drm/amd/display/include/signal_types.h +@@ -26,6 +26,11 @@ + #ifndef __DC_SIGNAL_TYPES_H__ + #define __DC_SIGNAL_TYPES_H__ + ++/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */ ++#define TMDS_MIN_PIXEL_CLOCK 25000 ++/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */ ++#define TMDS_MAX_PIXEL_CLOCK 165000 ++ + enum signal_type { + SIGNAL_TYPE_NONE = 0L, /* no signal */ + SIGNAL_TYPE_DVI_SINGLE_LINK = (1 << 0), +diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c +index dd89abd..66ee9d8 100644 +--- a/drivers/gpu/drm/i915/i915_gem.c ++++ b/drivers/gpu/drm/i915/i915_gem.c +@@ -3205,8 +3205,10 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) + * rolling the global seqno forward (since this would complete requests + * for which we haven't set the fence error to EIO yet). + */ +- for_each_engine(engine, i915, id) ++ for_each_engine(engine, i915, id) { ++ i915_gem_reset_prepare_engine(engine); + engine->submit_request = nop_submit_request; ++ } + + /* + * Make sure no one is running the old callback before we proceed with +@@ -3244,6 +3246,8 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) + intel_engine_init_global_seqno(engine, + intel_engine_last_submit(engine)); + spin_unlock_irqrestore(&engine->timeline->lock, flags); ++ ++ i915_gem_reset_finish_engine(engine); + } + + set_bit(I915_WEDGED, &i915->gpu_error.flags); +diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c +index 0be50e4..f8fe5ff 100644 +--- a/drivers/gpu/drm/i915/i915_perf.c ++++ b/drivers/gpu/drm/i915/i915_perf.c +@@ -1303,9 +1303,8 @@ static void i915_oa_stream_destroy(struct i915_perf_stream *stream) + */ + mutex_lock(&dev_priv->drm.struct_mutex); + dev_priv->perf.oa.exclusive_stream = NULL; +- mutex_unlock(&dev_priv->drm.struct_mutex); +- + dev_priv->perf.oa.ops.disable_metric_set(dev_priv); ++ mutex_unlock(&dev_priv->drm.struct_mutex); + + free_oa_buffer(dev_priv); + +@@ -1756,22 +1755,13 @@ static int gen8_switch_to_updated_kernel_context(struct drm_i915_private *dev_pr + * Note: it's only the RCS/Render context that has any OA state. + */ + static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv, +- const struct i915_oa_config *oa_config, +- bool interruptible) ++ const struct i915_oa_config *oa_config) + { + struct i915_gem_context *ctx; + int ret; + unsigned int wait_flags = I915_WAIT_LOCKED; + +- if (interruptible) { +- ret = i915_mutex_lock_interruptible(&dev_priv->drm); +- if (ret) +- return ret; +- +- wait_flags |= I915_WAIT_INTERRUPTIBLE; +- } else { +- mutex_lock(&dev_priv->drm.struct_mutex); +- } ++ lockdep_assert_held(&dev_priv->drm.struct_mutex); + + /* Switch away from any user context. */ + ret = gen8_switch_to_updated_kernel_context(dev_priv, oa_config); +@@ -1819,8 +1809,6 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv, + } + + out: +- mutex_unlock(&dev_priv->drm.struct_mutex); +- + return ret; + } + +@@ -1863,7 +1851,7 @@ static int gen8_enable_metric_set(struct drm_i915_private *dev_priv, + * to make sure all slices/subslices are ON before writing to NOA + * registers. + */ +- ret = gen8_configure_all_contexts(dev_priv, oa_config, true); ++ ret = gen8_configure_all_contexts(dev_priv, oa_config); + if (ret) + return ret; + +@@ -1878,7 +1866,7 @@ static int gen8_enable_metric_set(struct drm_i915_private *dev_priv, + static void gen8_disable_metric_set(struct drm_i915_private *dev_priv) + { + /* Reset all contexts' slices/subslices configurations. */ +- gen8_configure_all_contexts(dev_priv, NULL, false); ++ gen8_configure_all_contexts(dev_priv, NULL); + + I915_WRITE(GDT_CHICKEN_BITS, (I915_READ(GDT_CHICKEN_BITS) & + ~GT_NOA_ENABLE)); +@@ -1888,7 +1876,7 @@ static void gen8_disable_metric_set(struct drm_i915_private *dev_priv) + static void gen10_disable_metric_set(struct drm_i915_private *dev_priv) + { + /* Reset all contexts' slices/subslices configurations. */ +- gen8_configure_all_contexts(dev_priv, NULL, false); ++ gen8_configure_all_contexts(dev_priv, NULL); + + /* Make sure we disable noa to save power. */ + I915_WRITE(RPM_CONFIG1, +@@ -2138,6 +2126,10 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, + if (ret) + goto err_oa_buf_alloc; + ++ ret = i915_mutex_lock_interruptible(&dev_priv->drm); ++ if (ret) ++ goto err_lock; ++ + ret = dev_priv->perf.oa.ops.enable_metric_set(dev_priv, + stream->oa_config); + if (ret) +@@ -2145,23 +2137,17 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, + + stream->ops = &i915_oa_stream_ops; + +- /* Lock device for exclusive_stream access late because +- * enable_metric_set() might lock as well on gen8+. +- */ +- ret = i915_mutex_lock_interruptible(&dev_priv->drm); +- if (ret) +- goto err_lock; +- + dev_priv->perf.oa.exclusive_stream = stream; + + mutex_unlock(&dev_priv->drm.struct_mutex); + + return 0; + +-err_lock: ++err_enable: + dev_priv->perf.oa.ops.disable_metric_set(dev_priv); ++ mutex_unlock(&dev_priv->drm.struct_mutex); + +-err_enable: ++err_lock: + free_oa_buffer(dev_priv); + + err_oa_buf_alloc: +diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c +index 7ece2f0..e0fca03 100644 +--- a/drivers/gpu/drm/i915/intel_lrc.c ++++ b/drivers/gpu/drm/i915/intel_lrc.c +@@ -719,6 +719,8 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) + struct rb_node *rb; + unsigned long flags; + ++ GEM_TRACE("%s\n", engine->name); ++ + spin_lock_irqsave(&engine->timeline->lock, flags); + + /* Cancel the requests on the HW and clear the ELSP tracker. */ +@@ -765,6 +767,9 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) + */ + clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); + ++ /* Mark all CS interrupts as complete */ ++ execlists->active = 0; ++ + spin_unlock_irqrestore(&engine->timeline->lock, flags); + } + +diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c +index d3045a3..7c73bc7 100644 +--- a/drivers/gpu/drm/radeon/cik.c ++++ b/drivers/gpu/drm/radeon/cik.c +@@ -3221,35 +3221,8 @@ static void cik_gpu_init(struct radeon_device *rdev) + case CHIP_KAVERI: + rdev->config.cik.max_shader_engines = 1; + rdev->config.cik.max_tile_pipes = 4; +- if ((rdev->pdev->device == 0x1304) || +- (rdev->pdev->device == 0x1305) || +- (rdev->pdev->device == 0x130C) || +- (rdev->pdev->device == 0x130F) || +- (rdev->pdev->device == 0x1310) || +- (rdev->pdev->device == 0x1311) || +- (rdev->pdev->device == 0x131C)) { +- rdev->config.cik.max_cu_per_sh = 8; +- rdev->config.cik.max_backends_per_se = 2; +- } else if ((rdev->pdev->device == 0x1309) || +- (rdev->pdev->device == 0x130A) || +- (rdev->pdev->device == 0x130D) || +- (rdev->pdev->device == 0x1313) || +- (rdev->pdev->device == 0x131D)) { +- rdev->config.cik.max_cu_per_sh = 6; +- rdev->config.cik.max_backends_per_se = 2; +- } else if ((rdev->pdev->device == 0x1306) || +- (rdev->pdev->device == 0x1307) || +- (rdev->pdev->device == 0x130B) || +- (rdev->pdev->device == 0x130E) || +- (rdev->pdev->device == 0x1315) || +- (rdev->pdev->device == 0x1318) || +- (rdev->pdev->device == 0x131B)) { +- rdev->config.cik.max_cu_per_sh = 4; +- rdev->config.cik.max_backends_per_se = 1; +- } else { +- rdev->config.cik.max_cu_per_sh = 3; +- rdev->config.cik.max_backends_per_se = 1; +- } ++ rdev->config.cik.max_cu_per_sh = 8; ++ rdev->config.cik.max_backends_per_se = 2; + rdev->config.cik.max_sh_per_se = 1; + rdev->config.cik.max_texture_channel_caches = 4; + rdev->config.cik.max_gprs = 256; +diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c +index 5decae0..78cbc31 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c ++++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c +@@ -93,6 +93,8 @@ static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc, + + DRM_DEBUG_DRIVER("Disabling the CRTC\n"); + ++ drm_crtc_vblank_off(crtc); ++ + sun4i_tcon_set_status(scrtc->tcon, encoder, false); + + if (crtc->state->event && !crtc->state->active) { +@@ -113,6 +115,8 @@ static void sun4i_crtc_atomic_enable(struct drm_crtc *crtc, + DRM_DEBUG_DRIVER("Enabling the CRTC\n"); + + sun4i_tcon_set_status(scrtc->tcon, encoder, true); ++ ++ drm_crtc_vblank_on(crtc); + } + + static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc) +diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c +index 023f39b..e36004f 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c ++++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c +@@ -132,10 +132,13 @@ static int sun4i_dclk_get_phase(struct clk_hw *hw) + static int sun4i_dclk_set_phase(struct clk_hw *hw, int degrees) + { + struct sun4i_dclk *dclk = hw_to_dclk(hw); ++ u32 val = degrees / 120; ++ ++ val <<= 28; + + regmap_update_bits(dclk->regmap, SUN4I_TCON0_IO_POL_REG, + GENMASK(29, 28), +- degrees / 120); ++ val); + + return 0; + } +diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c +index 832f8f9..b8da5a5 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c ++++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c +@@ -92,6 +92,8 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector, + + DRM_DEBUG_DRIVER("Vertical parameters OK\n"); + ++ tcon->dclk_min_div = 6; ++ tcon->dclk_max_div = 127; + rounded_rate = clk_round_rate(tcon->dclk, rate); + if (rounded_rate < rate) + return MODE_CLOCK_LOW; +diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c +index b396011..2de586b 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c ++++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c +@@ -101,10 +101,12 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel, + return; + } + +- if (enabled) ++ if (enabled) { + clk_prepare_enable(clk); +- else ++ } else { ++ clk_rate_exclusive_put(clk); + clk_disable_unprepare(clk); ++ } + } + + static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon, +@@ -873,52 +875,56 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, + return ret; + } + +- /* +- * This can only be made optional since we've had DT nodes +- * without the LVDS reset properties. +- * +- * If the property is missing, just disable LVDS, and print a +- * warning. +- */ +- tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds"); +- if (IS_ERR(tcon->lvds_rst)) { +- dev_err(dev, "Couldn't get our reset line\n"); +- return PTR_ERR(tcon->lvds_rst); +- } else if (tcon->lvds_rst) { +- has_lvds_rst = true; +- reset_control_reset(tcon->lvds_rst); +- } else { +- has_lvds_rst = false; +- } ++ if (tcon->quirks->supports_lvds) { ++ /* ++ * This can only be made optional since we've had DT ++ * nodes without the LVDS reset properties. ++ * ++ * If the property is missing, just disable LVDS, and ++ * print a warning. ++ */ ++ tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds"); ++ if (IS_ERR(tcon->lvds_rst)) { ++ dev_err(dev, "Couldn't get our reset line\n"); ++ return PTR_ERR(tcon->lvds_rst); ++ } else if (tcon->lvds_rst) { ++ has_lvds_rst = true; ++ reset_control_reset(tcon->lvds_rst); ++ } else { ++ has_lvds_rst = false; ++ } + +- /* +- * This can only be made optional since we've had DT nodes +- * without the LVDS reset properties. +- * +- * If the property is missing, just disable LVDS, and print a +- * warning. +- */ +- if (tcon->quirks->has_lvds_alt) { +- tcon->lvds_pll = devm_clk_get(dev, "lvds-alt"); +- if (IS_ERR(tcon->lvds_pll)) { +- if (PTR_ERR(tcon->lvds_pll) == -ENOENT) { +- has_lvds_alt = false; ++ /* ++ * This can only be made optional since we've had DT ++ * nodes without the LVDS reset properties. ++ * ++ * If the property is missing, just disable LVDS, and ++ * print a warning. ++ */ ++ if (tcon->quirks->has_lvds_alt) { ++ tcon->lvds_pll = devm_clk_get(dev, "lvds-alt"); ++ if (IS_ERR(tcon->lvds_pll)) { ++ if (PTR_ERR(tcon->lvds_pll) == -ENOENT) { ++ has_lvds_alt = false; ++ } else { ++ dev_err(dev, "Couldn't get the LVDS PLL\n"); ++ return PTR_ERR(tcon->lvds_pll); ++ } + } else { +- dev_err(dev, "Couldn't get the LVDS PLL\n"); +- return PTR_ERR(tcon->lvds_pll); ++ has_lvds_alt = true; + } +- } else { +- has_lvds_alt = true; + } +- } + +- if (!has_lvds_rst || (tcon->quirks->has_lvds_alt && !has_lvds_alt)) { +- dev_warn(dev, +- "Missing LVDS properties, Please upgrade your DT\n"); +- dev_warn(dev, "LVDS output disabled\n"); +- can_lvds = false; ++ if (!has_lvds_rst || ++ (tcon->quirks->has_lvds_alt && !has_lvds_alt)) { ++ dev_warn(dev, "Missing LVDS properties, Please upgrade your DT\n"); ++ dev_warn(dev, "LVDS output disabled\n"); ++ can_lvds = false; ++ } else { ++ can_lvds = true; ++ } + } else { +- can_lvds = true; ++ can_lvds = false; + } + + ret = sun4i_tcon_init_clocks(dev, tcon); +@@ -1137,7 +1143,7 @@ static const struct sun4i_tcon_quirks sun8i_a33_quirks = { + }; + + static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = { +- /* nothing is supported */ ++ .supports_lvds = true, + }; + + static const struct sun4i_tcon_quirks sun8i_v3s_quirks = { +diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h +index b761c7b..278700c 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h ++++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h +@@ -175,6 +175,7 @@ struct sun4i_tcon_quirks { + bool has_channel_1; /* a33 does not have channel 1 */ + bool has_lvds_alt; /* Does the LVDS clock have a parent other than the TCON clock? */ + bool needs_de_be_mux; /* sun6i needs mux to select backend */ ++ bool supports_lvds; /* Does the TCON support an LVDS output? */ + + /* callback to handle tcon muxing options */ + int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *); +diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c +index a5b4cf0..9183d148d 100644 +--- a/drivers/infiniband/core/addr.c ++++ b/drivers/infiniband/core/addr.c +@@ -550,18 +550,13 @@ static int addr_resolve(struct sockaddr *src_in, + dst_release(dst); + } + +- if (ndev->flags & IFF_LOOPBACK) { +- ret = rdma_translate_ip(dst_in, addr); +- /* +- * Put the loopback device and get the translated +- * device instead. +- */ ++ if (ndev) { ++ if (ndev->flags & IFF_LOOPBACK) ++ ret = rdma_translate_ip(dst_in, addr); ++ else ++ addr->bound_dev_if = ndev->ifindex; + dev_put(ndev); +- ndev = dev_get_by_index(addr->net, addr->bound_dev_if); +- } else { +- addr->bound_dev_if = ndev->ifindex; + } +- dev_put(ndev); + + return ret; + } +diff --git a/drivers/infiniband/core/cq.c b/drivers/infiniband/core/cq.c +index bc79ca8..af5ad6a 100644 +--- a/drivers/infiniband/core/cq.c ++++ b/drivers/infiniband/core/cq.c +@@ -17,6 +17,7 @@ + + /* # of WCs to poll for with a single call to ib_poll_cq */ + #define IB_POLL_BATCH 16 ++#define IB_POLL_BATCH_DIRECT 8 + + /* # of WCs to iterate over before yielding */ + #define IB_POLL_BUDGET_IRQ 256 +@@ -25,18 +26,18 @@ + #define IB_POLL_FLAGS \ + (IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS) + +-static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) ++static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *wcs, ++ int batch) + { + int i, n, completed = 0; +- struct ib_wc *wcs = poll_wc ? : cq->wc; + + /* + * budget might be (-1) if the caller does not + * want to bound this call, thus we need unsigned + * minimum here. + */ +- while ((n = ib_poll_cq(cq, min_t(u32, IB_POLL_BATCH, +- budget - completed), wcs)) > 0) { ++ while ((n = ib_poll_cq(cq, min_t(u32, batch, ++ budget - completed), wcs)) > 0) { + for (i = 0; i < n; i++) { + struct ib_wc *wc = &wcs[i]; + +@@ -48,8 +49,7 @@ static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) + + completed += n; + +- if (n != IB_POLL_BATCH || +- (budget != -1 && completed >= budget)) ++ if (n != batch || (budget != -1 && completed >= budget)) + break; + } + +@@ -72,9 +72,9 @@ static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) + */ + int ib_process_cq_direct(struct ib_cq *cq, int budget) + { +- struct ib_wc wcs[IB_POLL_BATCH]; ++ struct ib_wc wcs[IB_POLL_BATCH_DIRECT]; + +- return __ib_process_cq(cq, budget, wcs); ++ return __ib_process_cq(cq, budget, wcs, IB_POLL_BATCH_DIRECT); + } + EXPORT_SYMBOL(ib_process_cq_direct); + +@@ -88,7 +88,7 @@ static int ib_poll_handler(struct irq_poll *iop, int budget) + struct ib_cq *cq = container_of(iop, struct ib_cq, iop); + int completed; + +- completed = __ib_process_cq(cq, budget, NULL); ++ completed = __ib_process_cq(cq, budget, cq->wc, IB_POLL_BATCH); + if (completed < budget) { + irq_poll_complete(&cq->iop); + if (ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0) +@@ -108,7 +108,8 @@ static void ib_cq_poll_work(struct work_struct *work) + struct ib_cq *cq = container_of(work, struct ib_cq, work); + int completed; + +- completed = __ib_process_cq(cq, IB_POLL_BUDGET_WORKQUEUE, NULL); ++ completed = __ib_process_cq(cq, IB_POLL_BUDGET_WORKQUEUE, cq->wc, ++ IB_POLL_BATCH); + if (completed >= IB_POLL_BUDGET_WORKQUEUE || + ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0) + queue_work(ib_comp_wq, &cq->work); +diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c +index e8010e7..bb065c9 100644 +--- a/drivers/infiniband/core/device.c ++++ b/drivers/infiniband/core/device.c +@@ -536,14 +536,14 @@ int ib_register_device(struct ib_device *device, + ret = device->query_device(device, &device->attrs, &uhw); + if (ret) { + pr_warn("Couldn't query the device attributes\n"); +- goto cache_cleanup; ++ goto cg_cleanup; + } + + ret = ib_device_register_sysfs(device, port_callback); + if (ret) { + pr_warn("Couldn't register device %s with driver model\n", + device->name); +- goto cache_cleanup; ++ goto cg_cleanup; + } + + device->reg_state = IB_DEV_REGISTERED; +@@ -559,6 +559,8 @@ int ib_register_device(struct ib_device *device, + mutex_unlock(&device_mutex); + return 0; + ++cg_cleanup: ++ ib_device_unregister_rdmacg(device); + cache_cleanup: + ib_cache_cleanup_one(device); + ib_cache_release_one(device); +diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c +index 8cf15d4..9f029a1 100644 +--- a/drivers/infiniband/core/sa_query.c ++++ b/drivers/infiniband/core/sa_query.c +@@ -1291,10 +1291,9 @@ int ib_init_ah_attr_from_path(struct ib_device *device, u8 port_num, + + resolved_dev = dev_get_by_index(dev_addr.net, + dev_addr.bound_dev_if); +- if (resolved_dev->flags & IFF_LOOPBACK) { +- dev_put(resolved_dev); +- resolved_dev = idev; +- dev_hold(resolved_dev); ++ if (!resolved_dev) { ++ dev_put(idev); ++ return -ENODEV; + } + ndev = ib_get_ndev_from_path(rec); + rcu_read_lock(); +diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c +index f015f1b..3a9d0f5 100644 +--- a/drivers/infiniband/core/ucma.c ++++ b/drivers/infiniband/core/ucma.c +@@ -1149,6 +1149,9 @@ static ssize_t ucma_init_qp_attr(struct ucma_file *file, + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + ++ if (cmd.qp_state > IB_QPS_ERR) ++ return -EINVAL; ++ + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); +@@ -1294,6 +1297,9 @@ static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf, + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + ++ if (unlikely(cmd.optval > KMALLOC_MAX_SIZE)) ++ return -EINVAL; ++ + optval = memdup_user((void __user *) (unsigned long) cmd.optval, + cmd.optlen); + if (IS_ERR(optval)) { +diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +index 643174d..0dd75f4 100644 +--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c ++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +@@ -785,7 +785,7 @@ int bnxt_re_query_ah(struct ib_ah *ib_ah, struct rdma_ah_attr *ah_attr) + return 0; + } + +-static unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp) ++unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp) + __acquires(&qp->scq->cq_lock) __acquires(&qp->rcq->cq_lock) + { + unsigned long flags; +@@ -799,8 +799,8 @@ static unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp) + return flags; + } + +-static void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp, +- unsigned long flags) ++void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp, ++ unsigned long flags) + __releases(&qp->scq->cq_lock) __releases(&qp->rcq->cq_lock) + { + if (qp->rcq != qp->scq) +@@ -1606,6 +1606,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, + int status; + union ib_gid sgid; + struct ib_gid_attr sgid_attr; ++ unsigned int flags; + u8 nw_type; + + qp->qplib_qp.modify_flags = 0; +@@ -1634,14 +1635,18 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, + dev_dbg(rdev_to_dev(rdev), + "Move QP = %p to flush list\n", + qp); ++ flags = bnxt_re_lock_cqs(qp); + bnxt_qplib_add_flush_qp(&qp->qplib_qp); ++ bnxt_re_unlock_cqs(qp, flags); + } + if (!qp->sumem && + qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_RESET) { + dev_dbg(rdev_to_dev(rdev), + "Move QP = %p out of flush list\n", + qp); ++ flags = bnxt_re_lock_cqs(qp); + bnxt_qplib_clean_qp(&qp->qplib_qp); ++ bnxt_re_unlock_cqs(qp, flags); + } + } + if (qp_attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) { +@@ -2227,10 +2232,13 @@ static int bnxt_re_build_inv_wqe(struct ib_send_wr *wr, + wqe->type = BNXT_QPLIB_SWQE_TYPE_LOCAL_INV; + wqe->local_inv.inv_l_key = wr->ex.invalidate_rkey; + ++ /* Need unconditional fence for local invalidate ++ * opcode to work as expected. ++ */ ++ wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; ++ + if (wr->send_flags & IB_SEND_SIGNALED) + wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP; +- if (wr->send_flags & IB_SEND_FENCE) +- wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; + if (wr->send_flags & IB_SEND_SOLICITED) + wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SOLICIT_EVENT; + +@@ -2251,8 +2259,12 @@ static int bnxt_re_build_reg_wqe(struct ib_reg_wr *wr, + wqe->frmr.levels = qplib_frpl->hwq.level + 1; + wqe->type = BNXT_QPLIB_SWQE_TYPE_REG_MR; + +- if (wr->wr.send_flags & IB_SEND_FENCE) +- wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; ++ /* Need unconditional fence for reg_mr ++ * opcode to function as expected. ++ */ ++ ++ wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; ++ + if (wr->wr.send_flags & IB_SEND_SIGNALED) + wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP; + +diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h +index b88a48d..e62b7c2 100644 +--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h ++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h +@@ -222,4 +222,7 @@ struct ib_ucontext *bnxt_re_alloc_ucontext(struct ib_device *ibdev, + struct ib_udata *udata); + int bnxt_re_dealloc_ucontext(struct ib_ucontext *context); + int bnxt_re_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); ++ ++unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp); ++void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp, unsigned long flags); + #endif /* __BNXT_RE_IB_VERBS_H__ */ +diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c +index 33a4480..f6e3617 100644 +--- a/drivers/infiniband/hw/bnxt_re/main.c ++++ b/drivers/infiniband/hw/bnxt_re/main.c +@@ -730,6 +730,13 @@ static int bnxt_re_handle_qp_async_event(struct creq_qp_event *qp_event, + struct bnxt_re_qp *qp) + { + struct ib_event event; ++ unsigned int flags; ++ ++ if (qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR) { ++ flags = bnxt_re_lock_cqs(qp); ++ bnxt_qplib_add_flush_qp(&qp->qplib_qp); ++ bnxt_re_unlock_cqs(qp, flags); ++ } + + memset(&event, 0, sizeof(event)); + if (qp->qplib_qp.srq) { +@@ -1416,9 +1423,12 @@ static void bnxt_re_task(struct work_struct *work) + switch (re_work->event) { + case NETDEV_REGISTER: + rc = bnxt_re_ib_reg(rdev); +- if (rc) ++ if (rc) { + dev_err(rdev_to_dev(rdev), + "Failed to register with IB: %#x", rc); ++ bnxt_re_remove_one(rdev); ++ bnxt_re_dev_unreg(rdev); ++ } + break; + case NETDEV_UP: + bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1, +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c +index 3ea5b96..06b42c8 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c +@@ -88,75 +88,35 @@ static void __bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp) + } + } + +-void bnxt_qplib_acquire_cq_locks(struct bnxt_qplib_qp *qp, +- unsigned long *flags) +- __acquires(&qp->scq->hwq.lock) __acquires(&qp->rcq->hwq.lock) ++static void bnxt_qplib_acquire_cq_flush_locks(struct bnxt_qplib_qp *qp, ++ unsigned long *flags) ++ __acquires(&qp->scq->flush_lock) __acquires(&qp->rcq->flush_lock) + { +- spin_lock_irqsave(&qp->scq->hwq.lock, *flags); ++ spin_lock_irqsave(&qp->scq->flush_lock, *flags); + if (qp->scq == qp->rcq) +- __acquire(&qp->rcq->hwq.lock); ++ __acquire(&qp->rcq->flush_lock); + else +- spin_lock(&qp->rcq->hwq.lock); ++ spin_lock(&qp->rcq->flush_lock); + } + +-void bnxt_qplib_release_cq_locks(struct bnxt_qplib_qp *qp, +- unsigned long *flags) +- __releases(&qp->scq->hwq.lock) __releases(&qp->rcq->hwq.lock) ++static void bnxt_qplib_release_cq_flush_locks(struct bnxt_qplib_qp *qp, ++ unsigned long *flags) ++ __releases(&qp->scq->flush_lock) __releases(&qp->rcq->flush_lock) + { + if (qp->scq == qp->rcq) +- __release(&qp->rcq->hwq.lock); ++ __release(&qp->rcq->flush_lock); + else +- spin_unlock(&qp->rcq->hwq.lock); +- spin_unlock_irqrestore(&qp->scq->hwq.lock, *flags); +-} +- +-static struct bnxt_qplib_cq *bnxt_qplib_find_buddy_cq(struct bnxt_qplib_qp *qp, +- struct bnxt_qplib_cq *cq) +-{ +- struct bnxt_qplib_cq *buddy_cq = NULL; +- +- if (qp->scq == qp->rcq) +- buddy_cq = NULL; +- else if (qp->scq == cq) +- buddy_cq = qp->rcq; +- else +- buddy_cq = qp->scq; +- return buddy_cq; +-} +- +-static void bnxt_qplib_lock_buddy_cq(struct bnxt_qplib_qp *qp, +- struct bnxt_qplib_cq *cq) +- __acquires(&buddy_cq->hwq.lock) +-{ +- struct bnxt_qplib_cq *buddy_cq = NULL; +- +- buddy_cq = bnxt_qplib_find_buddy_cq(qp, cq); +- if (!buddy_cq) +- __acquire(&cq->hwq.lock); +- else +- spin_lock(&buddy_cq->hwq.lock); +-} +- +-static void bnxt_qplib_unlock_buddy_cq(struct bnxt_qplib_qp *qp, +- struct bnxt_qplib_cq *cq) +- __releases(&buddy_cq->hwq.lock) +-{ +- struct bnxt_qplib_cq *buddy_cq = NULL; +- +- buddy_cq = bnxt_qplib_find_buddy_cq(qp, cq); +- if (!buddy_cq) +- __release(&cq->hwq.lock); +- else +- spin_unlock(&buddy_cq->hwq.lock); ++ spin_unlock(&qp->rcq->flush_lock); ++ spin_unlock_irqrestore(&qp->scq->flush_lock, *flags); + } + + void bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp) + { + unsigned long flags; + +- bnxt_qplib_acquire_cq_locks(qp, &flags); ++ bnxt_qplib_acquire_cq_flush_locks(qp, &flags); + __bnxt_qplib_add_flush_qp(qp); +- bnxt_qplib_release_cq_locks(qp, &flags); ++ bnxt_qplib_release_cq_flush_locks(qp, &flags); + } + + static void __bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp) +@@ -177,7 +137,7 @@ void bnxt_qplib_clean_qp(struct bnxt_qplib_qp *qp) + { + unsigned long flags; + +- bnxt_qplib_acquire_cq_locks(qp, &flags); ++ bnxt_qplib_acquire_cq_flush_locks(qp, &flags); + __clean_cq(qp->scq, (u64)(unsigned long)qp); + qp->sq.hwq.prod = 0; + qp->sq.hwq.cons = 0; +@@ -186,7 +146,7 @@ void bnxt_qplib_clean_qp(struct bnxt_qplib_qp *qp) + qp->rq.hwq.cons = 0; + + __bnxt_qplib_del_flush_qp(qp); +- bnxt_qplib_release_cq_locks(qp, &flags); ++ bnxt_qplib_release_cq_flush_locks(qp, &flags); + } + + static void bnxt_qpn_cqn_sched_task(struct work_struct *work) +@@ -2107,9 +2067,6 @@ void bnxt_qplib_mark_qp_error(void *qp_handle) + /* Must block new posting of SQ and RQ */ + qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; + bnxt_qplib_cancel_phantom_processing(qp); +- +- /* Add qp to flush list of the CQ */ +- __bnxt_qplib_add_flush_qp(qp); + } + + /* Note: SQE is valid from sw_sq_cons up to cqe_sq_cons (exclusive) +@@ -2285,9 +2242,9 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq, + sw_sq_cons, cqe->wr_id, cqe->status); + cqe++; + (*budget)--; +- bnxt_qplib_lock_buddy_cq(qp, cq); + bnxt_qplib_mark_qp_error(qp); +- bnxt_qplib_unlock_buddy_cq(qp, cq); ++ /* Add qp to flush list of the CQ */ ++ bnxt_qplib_add_flush_qp(qp); + } else { + if (swq->flags & SQ_SEND_FLAGS_SIGNAL_COMP) { + /* Before we complete, do WA 9060 */ +@@ -2403,9 +2360,7 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq, + if (hwcqe->status != CQ_RES_RC_STATUS_OK) { + qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; + /* Add qp to flush list of the CQ */ +- bnxt_qplib_lock_buddy_cq(qp, cq); +- __bnxt_qplib_add_flush_qp(qp); +- bnxt_qplib_unlock_buddy_cq(qp, cq); ++ bnxt_qplib_add_flush_qp(qp); + } + } + +@@ -2489,9 +2444,7 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq, + if (hwcqe->status != CQ_RES_RC_STATUS_OK) { + qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; + /* Add qp to flush list of the CQ */ +- bnxt_qplib_lock_buddy_cq(qp, cq); +- __bnxt_qplib_add_flush_qp(qp); +- bnxt_qplib_unlock_buddy_cq(qp, cq); ++ bnxt_qplib_add_flush_qp(qp); + } + } + done: +@@ -2501,11 +2454,9 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq, + bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq) + { + struct cq_base *hw_cqe, **hw_cqe_ptr; +- unsigned long flags; + u32 sw_cons, raw_cons; + bool rc = true; + +- spin_lock_irqsave(&cq->hwq.lock, flags); + raw_cons = cq->hwq.cons; + sw_cons = HWQ_CMP(raw_cons, &cq->hwq); + hw_cqe_ptr = (struct cq_base **)cq->hwq.pbl_ptr; +@@ -2513,7 +2464,6 @@ bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq) + + /* Check for Valid bit. If the CQE is valid, return false */ + rc = !CQE_CMP_VALID(hw_cqe, raw_cons, cq->hwq.max_elements); +- spin_unlock_irqrestore(&cq->hwq.lock, flags); + return rc; + } + +@@ -2602,9 +2552,7 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq, + if (hwcqe->status != CQ_RES_RC_STATUS_OK) { + qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; + /* Add qp to flush list of the CQ */ +- bnxt_qplib_lock_buddy_cq(qp, cq); +- __bnxt_qplib_add_flush_qp(qp); +- bnxt_qplib_unlock_buddy_cq(qp, cq); ++ bnxt_qplib_add_flush_qp(qp); + } + } + +@@ -2719,9 +2667,7 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq, + */ + + /* Add qp to flush list of the CQ */ +- bnxt_qplib_lock_buddy_cq(qp, cq); +- __bnxt_qplib_add_flush_qp(qp); +- bnxt_qplib_unlock_buddy_cq(qp, cq); ++ bnxt_qplib_add_flush_qp(qp); + done: + return rc; + } +@@ -2750,7 +2696,7 @@ int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq, + u32 budget = num_cqes; + unsigned long flags; + +- spin_lock_irqsave(&cq->hwq.lock, flags); ++ spin_lock_irqsave(&cq->flush_lock, flags); + list_for_each_entry(qp, &cq->sqf_head, sq_flush) { + dev_dbg(&cq->hwq.pdev->dev, + "QPLIB: FP: Flushing SQ QP= %p", +@@ -2764,7 +2710,7 @@ int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq, + qp); + __flush_rq(&qp->rq, qp, &cqe, &budget); + } +- spin_unlock_irqrestore(&cq->hwq.lock, flags); ++ spin_unlock_irqrestore(&cq->flush_lock, flags); + + return num_cqes - budget; + } +@@ -2773,11 +2719,9 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, + int num_cqes, struct bnxt_qplib_qp **lib_qp) + { + struct cq_base *hw_cqe, **hw_cqe_ptr; +- unsigned long flags; + u32 sw_cons, raw_cons; + int budget, rc = 0; + +- spin_lock_irqsave(&cq->hwq.lock, flags); + raw_cons = cq->hwq.cons; + budget = num_cqes; + +@@ -2853,20 +2797,15 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, + bnxt_qplib_arm_cq(cq, DBR_DBR_TYPE_CQ); + } + exit: +- spin_unlock_irqrestore(&cq->hwq.lock, flags); + return num_cqes - budget; + } + + void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type) + { +- unsigned long flags; +- +- spin_lock_irqsave(&cq->hwq.lock, flags); + if (arm_type) + bnxt_qplib_arm_cq(cq, arm_type); + /* Using cq->arm_state variable to track whether to issue cq handler */ + atomic_set(&cq->arm_state, 1); +- spin_unlock_irqrestore(&cq->hwq.lock, flags); + } + + void bnxt_qplib_flush_cqn_wq(struct bnxt_qplib_qp *qp) +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h +index ca0a2ff..ade9f13 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h ++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h +@@ -389,6 +389,18 @@ struct bnxt_qplib_cq { + struct list_head sqf_head, rqf_head; + atomic_t arm_state; + spinlock_t compl_lock; /* synch CQ handlers */ ++/* Locking Notes: ++ * QP can move to error state from modify_qp, async error event or error ++ * CQE as part of poll_cq. When QP is moved to error state, it gets added ++ * to two flush lists, one each for SQ and RQ. ++ * Each flush list is protected by qplib_cq->flush_lock. Both scq and rcq ++ * flush_locks should be acquired when QP is moved to error. The control path ++ * operations(modify_qp and async error events) are synchronized with poll_cq ++ * using upper level CQ locks (bnxt_re_cq->cq_lock) of both SCQ and RCQ. ++ * The qplib_cq->flush_lock is required to synchronize two instances of poll_cq ++ * of the same QP while manipulating the flush list. ++ */ ++ spinlock_t flush_lock; /* QP flush management */ + }; + + #define BNXT_QPLIB_MAX_IRRQE_ENTRY_SIZE sizeof(struct xrrq_irrq) +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +index 8329ec6..80027a4 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +@@ -305,9 +305,8 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw, + err_event->res_err_state_reason); + if (!qp) + break; +- bnxt_qplib_acquire_cq_locks(qp, &flags); + bnxt_qplib_mark_qp_error(qp); +- bnxt_qplib_release_cq_locks(qp, &flags); ++ rcfw->aeq_handler(rcfw, qp_event, qp); + break; + default: + /* Command Response */ +@@ -460,7 +459,11 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, + int rc; + + RCFW_CMD_PREP(req, INITIALIZE_FW, cmd_flags); +- ++ /* Supply (log-base-2-of-host-page-size - base-page-shift) ++ * to bono to adjust the doorbell page sizes. ++ */ ++ req.log2_dbr_pg_size = cpu_to_le16(PAGE_SHIFT - ++ RCFW_DBR_BASE_PAGE_SHIFT); + /* + * VFs need not setup the HW context area, PF + * shall setup this area for VF. Skipping the +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +index 6bee6e3..c7cce2e 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h ++++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +@@ -49,6 +49,7 @@ + #define RCFW_COMM_SIZE 0x104 + + #define RCFW_DBR_PCI_BAR_REGION 2 ++#define RCFW_DBR_BASE_PAGE_SHIFT 12 + + #define RCFW_CMD_PREP(req, CMD, cmd_flags) \ + do { \ +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c +index 0305798..ee98e5e 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c +@@ -139,7 +139,8 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, + attr->max_pkey = le32_to_cpu(sb->max_pkeys); + + attr->max_inline_data = le32_to_cpu(sb->max_inline_data); +- attr->l2_db_size = (sb->l2_db_space_size + 1) * PAGE_SIZE; ++ attr->l2_db_size = (sb->l2_db_space_size + 1) * ++ (0x01 << RCFW_DBR_BASE_PAGE_SHIFT); + attr->max_sgid = le32_to_cpu(sb->max_gid); + + bnxt_qplib_query_version(rcfw, attr->fw_ver); +diff --git a/drivers/infiniband/hw/bnxt_re/roce_hsi.h b/drivers/infiniband/hw/bnxt_re/roce_hsi.h +index 2d7ea09..3e5a4f7 100644 +--- a/drivers/infiniband/hw/bnxt_re/roce_hsi.h ++++ b/drivers/infiniband/hw/bnxt_re/roce_hsi.h +@@ -1761,7 +1761,30 @@ struct cmdq_initialize_fw { + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_2M (0x3UL << 4) + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_8M (0x4UL << 4) + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_1G (0x5UL << 4) +- __le16 reserved16; ++ /* This value is (log-base-2-of-DBR-page-size - 12). ++ * 0 for 4KB. HW supported values are enumerated below. ++ */ ++ __le16 log2_dbr_pg_size; ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_MASK 0xfUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_SFT 0 ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4K 0x0UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8K 0x1UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16K 0x2UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32K 0x3UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64K 0x4UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128K 0x5UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_256K 0x6UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_512K 0x7UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_1M 0x8UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_2M 0x9UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4M 0xaUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8M 0xbUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16M 0xcUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32M 0xdUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64M 0xeUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M 0xfUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_LAST \ ++ CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M + __le64 qpc_page_dir; + __le64 mrw_page_dir; + __le64 srq_page_dir; +diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c +index 9a566ee..82adc0d 100644 +--- a/drivers/infiniband/hw/mlx4/cq.c ++++ b/drivers/infiniband/hw/mlx4/cq.c +@@ -601,6 +601,7 @@ static void use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct + wc->dlid_path_bits = 0; + + if (is_eth) { ++ wc->slid = 0; + wc->vlan_id = be16_to_cpu(hdr->tun.sl_vid); + memcpy(&(wc->smac[0]), (char *)&hdr->tun.mac_31_0, 4); + memcpy(&(wc->smac[4]), (char *)&hdr->tun.slid_mac_47_32, 2); +@@ -851,7 +852,6 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, + } + } + +- wc->slid = be16_to_cpu(cqe->rlid); + g_mlpath_rqpn = be32_to_cpu(cqe->g_mlpath_rqpn); + wc->src_qp = g_mlpath_rqpn & 0xffffff; + wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f; +@@ -860,6 +860,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, + wc->wc_flags |= mlx4_ib_ipoib_csum_ok(cqe->status, + cqe->checksum) ? IB_WC_IP_CSUM_OK : 0; + if (is_eth) { ++ wc->slid = 0; + wc->sl = be16_to_cpu(cqe->sl_vid) >> 13; + if (be32_to_cpu(cqe->vlan_my_qpn) & + MLX4_CQE_CVLAN_PRESENT_MASK) { +@@ -871,6 +872,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, + memcpy(wc->smac, cqe->smac, ETH_ALEN); + wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC); + } else { ++ wc->slid = be16_to_cpu(cqe->rlid); + wc->sl = be16_to_cpu(cqe->sl_vid) >> 12; + wc->vlan_id = 0xffff; + } +diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c +index 8d2ee93..5a0e4fc 100644 +--- a/drivers/infiniband/hw/mlx4/main.c ++++ b/drivers/infiniband/hw/mlx4/main.c +@@ -219,8 +219,6 @@ static int mlx4_ib_update_gids_v1_v2(struct gid_entry *gids, + gid_tbl[i].version = 2; + if (!ipv6_addr_v4mapped((struct in6_addr *)&gids[i].gid)) + gid_tbl[i].type = 1; +- else +- memset(&gid_tbl[i].gid, 0, 12); + } + } + +@@ -366,8 +364,13 @@ static int mlx4_ib_del_gid(struct ib_device *device, + if (!gids) { + ret = -ENOMEM; + } else { +- for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) +- memcpy(&gids[i].gid, &port_gid_table->gids[i].gid, sizeof(union ib_gid)); ++ for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) { ++ memcpy(&gids[i].gid, ++ &port_gid_table->gids[i].gid, ++ sizeof(union ib_gid)); ++ gids[i].gid_type = ++ port_gid_table->gids[i].gid_type; ++ } + } + } + spin_unlock_bh(&iboe->lock); +diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c +index 5b974fb..15457c9 100644 +--- a/drivers/infiniband/hw/mlx5/cq.c ++++ b/drivers/infiniband/hw/mlx5/cq.c +@@ -226,7 +226,6 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, + wc->ex.invalidate_rkey = be32_to_cpu(cqe->imm_inval_pkey); + break; + } +- wc->slid = be16_to_cpu(cqe->slid); + wc->src_qp = be32_to_cpu(cqe->flags_rqpn) & 0xffffff; + wc->dlid_path_bits = cqe->ml_path; + g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3; +@@ -241,10 +240,12 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, + } + + if (ll != IB_LINK_LAYER_ETHERNET) { ++ wc->slid = be16_to_cpu(cqe->slid); + wc->sl = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0xf; + return; + } + ++ wc->slid = 0; + vlan_present = cqe->l4_l3_hdr_type & 0x1; + roce_packet_type = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0x3; + if (vlan_present) { +@@ -1177,7 +1178,12 @@ static int resize_user(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, + if (ucmd.reserved0 || ucmd.reserved1) + return -EINVAL; + +- umem = ib_umem_get(context, ucmd.buf_addr, entries * ucmd.cqe_size, ++ /* check multiplication overflow */ ++ if (ucmd.cqe_size && SIZE_MAX / ucmd.cqe_size <= entries - 1) ++ return -EINVAL; ++ ++ umem = ib_umem_get(context, ucmd.buf_addr, ++ (size_t)ucmd.cqe_size * entries, + IB_ACCESS_LOCAL_WRITE, 1); + if (IS_ERR(umem)) { + err = PTR_ERR(umem); +diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c +index 4236c80..033b6af 100644 +--- a/drivers/infiniband/hw/mlx5/main.c ++++ b/drivers/infiniband/hw/mlx5/main.c +@@ -245,12 +245,16 @@ struct mlx5_core_dev *mlx5_ib_get_native_port_mdev(struct mlx5_ib_dev *ibdev, + struct mlx5_ib_multiport_info *mpi; + struct mlx5_ib_port *port; + ++ if (!mlx5_core_mp_enabled(ibdev->mdev) || ++ ll != IB_LINK_LAYER_ETHERNET) { ++ if (native_port_num) ++ *native_port_num = ib_port_num; ++ return ibdev->mdev; ++ } ++ + if (native_port_num) + *native_port_num = 1; + +- if (!mlx5_core_mp_enabled(ibdev->mdev) || ll != IB_LINK_LAYER_ETHERNET) +- return ibdev->mdev; +- + port = &ibdev->port[ib_port_num - 1]; + if (!port) + return NULL; +@@ -3263,7 +3267,7 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + struct mlx5_ib_dev *ibdev; + struct ib_event ibev; + bool fatal = false; +- u8 port = 0; ++ u8 port = (u8)work->param; + + if (mlx5_core_is_mp_slave(work->dev)) { + ibdev = mlx5_ib_get_ibdev_from_mpi(work->context); +@@ -3283,8 +3287,6 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + case MLX5_DEV_EVENT_PORT_UP: + case MLX5_DEV_EVENT_PORT_DOWN: + case MLX5_DEV_EVENT_PORT_INITIALIZED: +- port = (u8)work->param; +- + /* In RoCE, port up/down events are handled in + * mlx5_netdev_event(). + */ +@@ -3298,24 +3300,19 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + + case MLX5_DEV_EVENT_LID_CHANGE: + ibev.event = IB_EVENT_LID_CHANGE; +- port = (u8)work->param; + break; + + case MLX5_DEV_EVENT_PKEY_CHANGE: + ibev.event = IB_EVENT_PKEY_CHANGE; +- port = (u8)work->param; +- + schedule_work(&ibdev->devr.ports[port - 1].pkey_change_work); + break; + + case MLX5_DEV_EVENT_GUID_CHANGE: + ibev.event = IB_EVENT_GID_CHANGE; +- port = (u8)work->param; + break; + + case MLX5_DEV_EVENT_CLIENT_REREG: + ibev.event = IB_EVENT_CLIENT_REREGISTER; +- port = (u8)work->param; + break; + case MLX5_DEV_EVENT_DELAY_DROP_TIMEOUT: + schedule_work(&ibdev->delay_drop.delay_drop_work); +@@ -3327,7 +3324,7 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + ibev.device = &ibdev->ib_dev; + ibev.element.port_num = port; + +- if (port < 1 || port > ibdev->num_ports) { ++ if (!rdma_is_port_valid(&ibdev->ib_dev, port)) { + mlx5_ib_warn(ibdev, "warning: event on port %d\n", port); + goto out; + } +diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c +index 556e015..1961c6a 100644 +--- a/drivers/infiniband/hw/mlx5/mr.c ++++ b/drivers/infiniband/hw/mlx5/mr.c +@@ -1816,7 +1816,6 @@ mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr, + + mr->ibmr.iova = sg_dma_address(sg) + sg_offset; + mr->ibmr.length = 0; +- mr->ndescs = sg_nents; + + for_each_sg(sgl, sg, sg_nents, i) { + if (unlikely(i >= mr->max_descs)) +@@ -1828,6 +1827,7 @@ mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr, + + sg_offset = 0; + } ++ mr->ndescs = i; + + if (sg_offset_p) + *sg_offset_p = sg_offset; +diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c +index 39d24bf..36197fb 100644 +--- a/drivers/infiniband/hw/mlx5/qp.c ++++ b/drivers/infiniband/hw/mlx5/qp.c +@@ -1584,6 +1584,7 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, + u32 uidx = MLX5_IB_DEFAULT_UIDX; + struct mlx5_ib_create_qp ucmd; + struct mlx5_ib_qp_base *base; ++ int mlx5_st; + void *qpc; + u32 *in; + int err; +@@ -1592,6 +1593,10 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, + spin_lock_init(&qp->sq.lock); + spin_lock_init(&qp->rq.lock); + ++ mlx5_st = to_mlx5_st(init_attr->qp_type); ++ if (mlx5_st < 0) ++ return -EINVAL; ++ + if (init_attr->rwq_ind_tbl) { + if (!udata) + return -ENOSYS; +@@ -1753,7 +1758,7 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, + + qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); + +- MLX5_SET(qpc, qpc, st, to_mlx5_st(init_attr->qp_type)); ++ MLX5_SET(qpc, qpc, st, mlx5_st); + MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); + + if (init_attr->qp_type != MLX5_IB_QPT_REG_UMR) +@@ -3095,8 +3100,10 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, + goto out; + + if (mlx5_cur >= MLX5_QP_NUM_STATE || mlx5_new >= MLX5_QP_NUM_STATE || +- !optab[mlx5_cur][mlx5_new]) ++ !optab[mlx5_cur][mlx5_new]) { ++ err = -EINVAL; + goto out; ++ } + + op = optab[mlx5_cur][mlx5_new]; + optpar = ib_mask_to_mlx5_opt(attr_mask); +diff --git a/drivers/infiniband/hw/qedr/qedr_iw_cm.c b/drivers/infiniband/hw/qedr/qedr_iw_cm.c +index 478b731..26dc374 100644 +--- a/drivers/infiniband/hw/qedr/qedr_iw_cm.c ++++ b/drivers/infiniband/hw/qedr/qedr_iw_cm.c +@@ -458,8 +458,7 @@ qedr_addr6_resolve(struct qedr_dev *dev, + } + return -EINVAL; + } +- neigh = dst_neigh_lookup(dst, &dst_in); +- ++ neigh = dst_neigh_lookup(dst, &fl6.daddr); + if (neigh) { + rcu_read_lock(); + if (neigh->nud_state & NUD_VALID) { +@@ -494,10 +493,14 @@ int qedr_iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) + + qp = idr_find(&dev->qpidr, conn_param->qpn); + +- laddr = (struct sockaddr_in *)&cm_id->local_addr; +- raddr = (struct sockaddr_in *)&cm_id->remote_addr; +- laddr6 = (struct sockaddr_in6 *)&cm_id->local_addr; +- raddr6 = (struct sockaddr_in6 *)&cm_id->remote_addr; ++ laddr = (struct sockaddr_in *)&cm_id->m_local_addr; ++ raddr = (struct sockaddr_in *)&cm_id->m_remote_addr; ++ laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr; ++ raddr6 = (struct sockaddr_in6 *)&cm_id->m_remote_addr; ++ ++ DP_DEBUG(dev, QEDR_MSG_IWARP, "MAPPED %d %d\n", ++ ntohs(((struct sockaddr_in *)&cm_id->remote_addr)->sin_port), ++ ntohs(raddr->sin_port)); + + DP_DEBUG(dev, QEDR_MSG_IWARP, + "Connect source address: %pISpc, remote address: %pISpc\n", +@@ -599,8 +602,8 @@ int qedr_iw_create_listen(struct iw_cm_id *cm_id, int backlog) + int rc; + int i; + +- laddr = (struct sockaddr_in *)&cm_id->local_addr; +- laddr6 = (struct sockaddr_in6 *)&cm_id->local_addr; ++ laddr = (struct sockaddr_in *)&cm_id->m_local_addr; ++ laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr; + + DP_DEBUG(dev, QEDR_MSG_IWARP, + "Create Listener address: %pISpc\n", &cm_id->local_addr); +diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c +index 53f00db..875b172 100644 +--- a/drivers/infiniband/hw/qedr/verbs.c ++++ b/drivers/infiniband/hw/qedr/verbs.c +@@ -3034,6 +3034,11 @@ static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + + switch (wr->opcode) { + case IB_WR_SEND_WITH_IMM: ++ if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) { ++ rc = -EINVAL; ++ *bad_wr = wr; ++ break; ++ } + wqe->req_type = RDMA_SQ_REQ_TYPE_SEND_WITH_IMM; + swqe = (struct rdma_sq_send_wqe_1st *)wqe; + swqe->wqe_size = 2; +@@ -3075,6 +3080,11 @@ static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + break; + + case IB_WR_RDMA_WRITE_WITH_IMM: ++ if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) { ++ rc = -EINVAL; ++ *bad_wr = wr; ++ break; ++ } + wqe->req_type = RDMA_SQ_REQ_TYPE_RDMA_WR_WITH_IMM; + rwqe = (struct rdma_sq_rdma_wqe_1st *)wqe; + +@@ -3724,7 +3734,7 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) + { + struct qedr_dev *dev = get_qedr_dev(ibcq->device); + struct qedr_cq *cq = get_qedr_cq(ibcq); +- union rdma_cqe *cqe = cq->latest_cqe; ++ union rdma_cqe *cqe; + u32 old_cons, new_cons; + unsigned long flags; + int update = 0; +@@ -3741,6 +3751,7 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) + return qedr_gsi_poll_cq(ibcq, num_entries, wc); + + spin_lock_irqsave(&cq->cq_lock, flags); ++ cqe = cq->latest_cqe; + old_cons = qed_chain_get_cons_idx_u32(&cq->pbl); + while (num_entries && is_valid_cqe(cq, cqe)) { + struct qedr_qp *qp; +diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c +index 4d1d8df..f227314 100644 +--- a/drivers/md/bcache/super.c ++++ b/drivers/md/bcache/super.c +@@ -963,6 +963,7 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, + uint32_t rtime = cpu_to_le32(get_seconds()); + struct uuid_entry *u; + char buf[BDEVNAME_SIZE]; ++ struct cached_dev *exist_dc, *t; + + bdevname(dc->bdev, buf); + +@@ -987,6 +988,16 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, + return -EINVAL; + } + ++ /* Check whether already attached */ ++ list_for_each_entry_safe(exist_dc, t, &c->cached_devs, list) { ++ if (!memcmp(dc->sb.uuid, exist_dc->sb.uuid, 16)) { ++ pr_err("Tried to attach %s but duplicate UUID already attached", ++ buf); ++ ++ return -EINVAL; ++ } ++ } ++ + u = uuid_find(c, dc->sb.uuid); + + if (u && +@@ -1204,7 +1215,7 @@ static void register_bdev(struct cache_sb *sb, struct page *sb_page, + + return; + err: +- pr_notice("error opening %s: %s", bdevname(bdev, name), err); ++ pr_notice("error %s: %s", bdevname(bdev, name), err); + bcache_device_stop(&dc->disk); + } + +@@ -1883,6 +1894,8 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page, + const char *err = NULL; /* must be set for any error case */ + int ret = 0; + ++ bdevname(bdev, name); ++ + memcpy(&ca->sb, sb, sizeof(struct cache_sb)); + ca->bdev = bdev; + ca->bdev->bd_holder = ca; +@@ -1891,11 +1904,12 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page, + bio_first_bvec_all(&ca->sb_bio)->bv_page = sb_page; + get_page(sb_page); + +- if (blk_queue_discard(bdev_get_queue(ca->bdev))) ++ if (blk_queue_discard(bdev_get_queue(bdev))) + ca->discard = CACHE_DISCARD(&ca->sb); + + ret = cache_alloc(ca); + if (ret != 0) { ++ blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); + if (ret == -ENOMEM) + err = "cache_alloc(): -ENOMEM"; + else +@@ -1918,14 +1932,14 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page, + goto out; + } + +- pr_info("registered cache device %s", bdevname(bdev, name)); ++ pr_info("registered cache device %s", name); + + out: + kobject_put(&ca->kobj); + + err: + if (err) +- pr_notice("error opening %s: %s", bdevname(bdev, name), err); ++ pr_notice("error %s: %s", name, err); + + return ret; + } +@@ -2014,6 +2028,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, + if (err) + goto err_close; + ++ err = "failed to register device"; + if (SB_IS_BDEV(sb)) { + struct cached_dev *dc = kzalloc(sizeof(*dc), GFP_KERNEL); + if (!dc) +@@ -2028,7 +2043,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, + goto err_close; + + if (register_cache(sb, sb_page, bdev, ca) != 0) +- goto err_close; ++ goto err; + } + out: + if (sb_page) +@@ -2041,7 +2056,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, + err_close: + blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); + err: +- pr_info("error opening %s: %s", path, err); ++ pr_info("error %s: %s", path, err); + ret = -EINVAL; + goto out; + } +diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c +index 414c9af..aa2032f 100644 +--- a/drivers/md/dm-bufio.c ++++ b/drivers/md/dm-bufio.c +@@ -386,9 +386,6 @@ static void __cache_size_refresh(void) + static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, + enum data_mode *data_mode) + { +- unsigned noio_flag; +- void *ptr; +- + if (c->block_size <= DM_BUFIO_BLOCK_SIZE_SLAB_LIMIT) { + *data_mode = DATA_MODE_SLAB; + return kmem_cache_alloc(DM_BUFIO_CACHE(c), gfp_mask); +@@ -412,16 +409,15 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, + * all allocations done by this process (including pagetables) are done + * as if GFP_NOIO was specified. + */ ++ if (gfp_mask & __GFP_NORETRY) { ++ unsigned noio_flag = memalloc_noio_save(); ++ void *ptr = __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL); + +- if (gfp_mask & __GFP_NORETRY) +- noio_flag = memalloc_noio_save(); +- +- ptr = __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL); +- +- if (gfp_mask & __GFP_NORETRY) + memalloc_noio_restore(noio_flag); ++ return ptr; ++ } + +- return ptr; ++ return __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL); + } + + /* +diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c +index 7d3e572..3fde9e9 100644 +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -211,25 +212,13 @@ static int alloc_multipath_stage2(struct dm_target *ti, struct multipath *m) + else + m->queue_mode = DM_TYPE_REQUEST_BASED; + +- } else if (m->queue_mode == DM_TYPE_BIO_BASED || +- m->queue_mode == DM_TYPE_NVME_BIO_BASED) { ++ } else if (m->queue_mode == DM_TYPE_BIO_BASED) { + INIT_WORK(&m->process_queued_bios, process_queued_bios); +- +- if (m->queue_mode == DM_TYPE_BIO_BASED) { +- /* +- * bio-based doesn't support any direct scsi_dh management; +- * it just discovers if a scsi_dh is attached. +- */ +- set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags); +- } +- } +- +- if (m->queue_mode != DM_TYPE_NVME_BIO_BASED) { +- set_bit(MPATHF_QUEUE_IO, &m->flags); +- atomic_set(&m->pg_init_in_progress, 0); +- atomic_set(&m->pg_init_count, 0); +- m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT; +- init_waitqueue_head(&m->pg_init_wait); ++ /* ++ * bio-based doesn't support any direct scsi_dh management; ++ * it just discovers if a scsi_dh is attached. ++ */ ++ set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags); + } + + dm_table_set_type(ti->table, m->queue_mode); +@@ -337,14 +326,12 @@ static void __switch_pg(struct multipath *m, struct priority_group *pg) + { + m->current_pg = pg; + +- if (m->queue_mode == DM_TYPE_NVME_BIO_BASED) +- return; +- + /* Must we initialise the PG first, and queue I/O till it's ready? */ + if (m->hw_handler_name) { + set_bit(MPATHF_PG_INIT_REQUIRED, &m->flags); + set_bit(MPATHF_QUEUE_IO, &m->flags); + } else { ++ /* FIXME: not needed if no scsi_dh is attached */ + clear_bit(MPATHF_PG_INIT_REQUIRED, &m->flags); + clear_bit(MPATHF_QUEUE_IO, &m->flags); + } +@@ -385,8 +372,7 @@ static struct pgpath *choose_pgpath(struct multipath *m, size_t nr_bytes) + unsigned bypassed = 1; + + if (!atomic_read(&m->nr_valid_paths)) { +- if (m->queue_mode != DM_TYPE_NVME_BIO_BASED) +- clear_bit(MPATHF_QUEUE_IO, &m->flags); ++ clear_bit(MPATHF_QUEUE_IO, &m->flags); + goto failed; + } + +@@ -599,7 +585,7 @@ static struct pgpath *__map_bio(struct multipath *m, struct bio *bio) + return pgpath; + } + +-static struct pgpath *__map_bio_nvme(struct multipath *m, struct bio *bio) ++static struct pgpath *__map_bio_fast(struct multipath *m, struct bio *bio) + { + struct pgpath *pgpath; + unsigned long flags; +@@ -634,8 +620,8 @@ static int __multipath_map_bio(struct multipath *m, struct bio *bio, + { + struct pgpath *pgpath; + +- if (m->queue_mode == DM_TYPE_NVME_BIO_BASED) +- pgpath = __map_bio_nvme(m, bio); ++ if (!m->hw_handler_name) ++ pgpath = __map_bio_fast(m, bio); + else + pgpath = __map_bio(m, bio); + +@@ -675,8 +661,7 @@ static void process_queued_io_list(struct multipath *m) + { + if (m->queue_mode == DM_TYPE_MQ_REQUEST_BASED) + dm_mq_kick_requeue_list(dm_table_get_md(m->ti->table)); +- else if (m->queue_mode == DM_TYPE_BIO_BASED || +- m->queue_mode == DM_TYPE_NVME_BIO_BASED) ++ else if (m->queue_mode == DM_TYPE_BIO_BASED) + queue_work(kmultipathd, &m->process_queued_bios); + } + +@@ -838,6 +823,16 @@ static int setup_scsi_dh(struct block_device *bdev, struct multipath *m, char ** + */ + kfree(m->hw_handler_name); + m->hw_handler_name = attached_handler_name; ++ ++ /* ++ * Init fields that are only used when a scsi_dh is attached ++ */ ++ if (!test_and_set_bit(MPATHF_QUEUE_IO, &m->flags)) { ++ atomic_set(&m->pg_init_in_progress, 0); ++ atomic_set(&m->pg_init_count, 0); ++ m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT; ++ init_waitqueue_head(&m->pg_init_wait); ++ } + } + } + +@@ -873,6 +868,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps + int r; + struct pgpath *p; + struct multipath *m = ti->private; ++ struct scsi_device *sdev; + + /* we need at least a path arg */ + if (as->argc < 1) { +@@ -891,7 +887,9 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps + goto bad; + } + +- if (m->queue_mode != DM_TYPE_NVME_BIO_BASED) { ++ sdev = scsi_device_from_queue(bdev_get_queue(p->path.dev->bdev)); ++ if (sdev) { ++ put_device(&sdev->sdev_gendev); + INIT_DELAYED_WORK(&p->activate_path, activate_path_work); + r = setup_scsi_dh(p->path.dev->bdev, m, &ti->error); + if (r) { +@@ -1001,8 +999,7 @@ static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m) + if (!hw_argc) + return 0; + +- if (m->queue_mode == DM_TYPE_BIO_BASED || +- m->queue_mode == DM_TYPE_NVME_BIO_BASED) { ++ if (m->queue_mode == DM_TYPE_BIO_BASED) { + dm_consume_args(as, hw_argc); + DMERR("bio-based multipath doesn't allow hardware handler args"); + return 0; +@@ -1091,8 +1088,6 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) + + if (!strcasecmp(queue_mode_name, "bio")) + m->queue_mode = DM_TYPE_BIO_BASED; +- else if (!strcasecmp(queue_mode_name, "nvme")) +- m->queue_mode = DM_TYPE_NVME_BIO_BASED; + else if (!strcasecmp(queue_mode_name, "rq")) + m->queue_mode = DM_TYPE_REQUEST_BASED; + else if (!strcasecmp(queue_mode_name, "mq")) +@@ -1193,7 +1188,7 @@ static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv) + ti->num_discard_bios = 1; + ti->num_write_same_bios = 1; + ti->num_write_zeroes_bios = 1; +- if (m->queue_mode == DM_TYPE_BIO_BASED || m->queue_mode == DM_TYPE_NVME_BIO_BASED) ++ if (m->queue_mode == DM_TYPE_BIO_BASED) + ti->per_io_data_size = multipath_per_bio_data_size(); + else + ti->per_io_data_size = sizeof(struct dm_mpath_io); +@@ -1730,9 +1725,6 @@ static void multipath_status(struct dm_target *ti, status_type_t type, + case DM_TYPE_BIO_BASED: + DMEMIT("queue_mode bio "); + break; +- case DM_TYPE_NVME_BIO_BASED: +- DMEMIT("queue_mode nvme "); +- break; + case DM_TYPE_MQ_REQUEST_BASED: + DMEMIT("queue_mode mq "); + break; +diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c +index 7ef469e..c1d1034 100644 +--- a/drivers/md/dm-raid.c ++++ b/drivers/md/dm-raid.c +@@ -3408,9 +3408,10 @@ static sector_t rs_get_progress(struct raid_set *rs, unsigned long recovery, + set_bit(RT_FLAG_RS_IN_SYNC, &rs->runtime_flags); + + } else { +- if (test_bit(MD_RECOVERY_NEEDED, &recovery) || +- test_bit(MD_RECOVERY_RESHAPE, &recovery) || +- test_bit(MD_RECOVERY_RUNNING, &recovery)) ++ if (!test_bit(MD_RECOVERY_INTR, &recovery) && ++ (test_bit(MD_RECOVERY_NEEDED, &recovery) || ++ test_bit(MD_RECOVERY_RESHAPE, &recovery) || ++ test_bit(MD_RECOVERY_RUNNING, &recovery))) + r = mddev->curr_resync_completed; + else + r = mddev->recovery_cp; +diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c +index 5fe7ec3..7eb3e2a 100644 +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -942,17 +942,12 @@ static int dm_table_determine_type(struct dm_table *t) + + if (t->type != DM_TYPE_NONE) { + /* target already set the table's type */ +- if (t->type == DM_TYPE_BIO_BASED) +- return 0; +- else if (t->type == DM_TYPE_NVME_BIO_BASED) { +- if (!dm_table_does_not_support_partial_completion(t)) { +- DMERR("nvme bio-based is only possible with devices" +- " that don't support partial completion"); +- return -EINVAL; +- } +- /* Fallthru, also verify all devices are blk-mq */ ++ if (t->type == DM_TYPE_BIO_BASED) { ++ /* possibly upgrade to a variant of bio-based */ ++ goto verify_bio_based; + } + BUG_ON(t->type == DM_TYPE_DAX_BIO_BASED); ++ BUG_ON(t->type == DM_TYPE_NVME_BIO_BASED); + goto verify_rq_based; + } + +@@ -985,6 +980,7 @@ static int dm_table_determine_type(struct dm_table *t) + } + + if (bio_based) { ++verify_bio_based: + /* We must use this table as bio-based */ + t->type = DM_TYPE_BIO_BASED; + if (dm_table_supports_dax(t) || +@@ -1755,7 +1751,7 @@ static int device_no_partial_completion(struct dm_target *ti, struct dm_dev *dev + char b[BDEVNAME_SIZE]; + + /* For now, NVMe devices are the only devices of this class */ +- return (strncmp(bdevname(dev->bdev, b), "nvme", 3) == 0); ++ return (strncmp(bdevname(dev->bdev, b), "nvme", 4) == 0); + } + + static bool dm_table_does_not_support_partial_completion(struct dm_table *t) +diff --git a/drivers/md/dm.c b/drivers/md/dm.c +index 6813680..45328d8 100644 +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -458,9 +458,11 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) + return dm_get_geometry(md, geo); + } + +-static int dm_grab_bdev_for_ioctl(struct mapped_device *md, +- struct block_device **bdev, +- fmode_t *mode) ++static char *_dm_claim_ptr = "I belong to device-mapper"; ++ ++static int dm_get_bdev_for_ioctl(struct mapped_device *md, ++ struct block_device **bdev, ++ fmode_t *mode) + { + struct dm_target *tgt; + struct dm_table *map; +@@ -490,6 +492,10 @@ static int dm_grab_bdev_for_ioctl(struct mapped_device *md, + goto out; + + bdgrab(*bdev); ++ r = blkdev_get(*bdev, *mode, _dm_claim_ptr); ++ if (r < 0) ++ goto out; ++ + dm_put_live_table(md, srcu_idx); + return r; + +@@ -508,7 +514,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, + struct mapped_device *md = bdev->bd_disk->private_data; + int r; + +- r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); ++ r = dm_get_bdev_for_ioctl(md, &bdev, &mode); + if (r < 0) + return r; + +@@ -528,7 +534,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, + + r = __blkdev_driver_ioctl(bdev, mode, cmd, arg); + out: +- bdput(bdev); ++ blkdev_put(bdev, mode); + return r; + } + +@@ -708,14 +714,13 @@ static void dm_put_live_table_fast(struct mapped_device *md) __releases(RCU) + static int open_table_device(struct table_device *td, dev_t dev, + struct mapped_device *md) + { +- static char *_claim_ptr = "I belong to device-mapper"; + struct block_device *bdev; + + int r; + + BUG_ON(td->dm_dev.bdev); + +- bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _claim_ptr); ++ bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _dm_claim_ptr); + if (IS_ERR(bdev)) + return PTR_ERR(bdev); + +@@ -3011,7 +3016,7 @@ static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type, + fmode_t mode; + int r; + +- r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); ++ r = dm_get_bdev_for_ioctl(md, &bdev, &mode); + if (r < 0) + return r; + +@@ -3021,7 +3026,7 @@ static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type, + else + r = -EOPNOTSUPP; + +- bdput(bdev); ++ blkdev_put(bdev, mode); + return r; + } + +@@ -3032,7 +3037,7 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type) + fmode_t mode; + int r; + +- r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); ++ r = dm_get_bdev_for_ioctl(md, &bdev, &mode); + if (r < 0) + return r; + +@@ -3042,7 +3047,7 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type) + else + r = -EOPNOTSUPP; + +- bdput(bdev); ++ blkdev_put(bdev, mode); + return r; + } + +@@ -3054,7 +3059,7 @@ static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key, + fmode_t mode; + int r; + +- r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); ++ r = dm_get_bdev_for_ioctl(md, &bdev, &mode); + if (r < 0) + return r; + +@@ -3064,7 +3069,7 @@ static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key, + else + r = -EOPNOTSUPP; + +- bdput(bdev); ++ blkdev_put(bdev, mode); + return r; + } + +@@ -3075,7 +3080,7 @@ static int dm_pr_clear(struct block_device *bdev, u64 key) + fmode_t mode; + int r; + +- r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); ++ r = dm_get_bdev_for_ioctl(md, &bdev, &mode); + if (r < 0) + return r; + +@@ -3085,7 +3090,7 @@ static int dm_pr_clear(struct block_device *bdev, u64 key) + else + r = -EOPNOTSUPP; + +- bdput(bdev); ++ blkdev_put(bdev, mode); + return r; + } + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c +index 21d29f7..d39b0b7 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c +@@ -124,7 +124,7 @@ void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force) + trigger_cmd_completions(dev); + } + +- mlx5_core_event(dev, MLX5_DEV_EVENT_SYS_ERROR, 0); ++ mlx5_core_event(dev, MLX5_DEV_EVENT_SYS_ERROR, 1); + mlx5_core_err(dev, "end\n"); + + unlock: +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 817e5e2..7aeca5d 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -3033,7 +3033,6 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) + ns->disk->disk_name); + + nvme_mpath_add_disk(ns->head); +- nvme_mpath_add_disk_links(ns); + return; + out_unlink_ns: + mutex_lock(&ctrl->subsys->lock); +@@ -3053,7 +3052,6 @@ static void nvme_ns_remove(struct nvme_ns *ns) + return; + + if (ns->disk && ns->disk->flags & GENHD_FL_UP) { +- nvme_mpath_remove_disk_links(ns); + sysfs_remove_group(&disk_to_dev(ns->disk)->kobj, + &nvme_ns_id_attr_group); + if (ns->ndev) +diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c +index a1c58e3..8f0f34d 100644 +--- a/drivers/nvme/host/fabrics.c ++++ b/drivers/nvme/host/fabrics.c +@@ -650,6 +650,11 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, + ret = -EINVAL; + goto out; + } ++ if (opts->discovery_nqn) { ++ pr_debug("Ignoring nr_io_queues value for discovery controller\n"); ++ break; ++ } ++ + opts->nr_io_queues = min_t(unsigned int, + num_online_cpus(), token); + break; +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index 7f51f84..1dc1387 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -1206,7 +1206,7 @@ nvme_fc_connect_admin_queue(struct nvme_fc_ctrl *ctrl, + sizeof(struct fcnvme_lsdesc_cr_assoc_cmd)); + + assoc_rqst->assoc_cmd.ersp_ratio = cpu_to_be16(ersp_ratio); +- assoc_rqst->assoc_cmd.sqsize = cpu_to_be16(qsize); ++ assoc_rqst->assoc_cmd.sqsize = cpu_to_be16(qsize - 1); + /* Linux supports only Dynamic controllers */ + assoc_rqst->assoc_cmd.cntlid = cpu_to_be16(0xffff); + uuid_copy(&assoc_rqst->assoc_cmd.hostid, &ctrl->ctrl.opts->host->id); +@@ -1321,7 +1321,7 @@ nvme_fc_connect_queue(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue, + sizeof(struct fcnvme_lsdesc_cr_conn_cmd)); + conn_rqst->connect_cmd.ersp_ratio = cpu_to_be16(ersp_ratio); + conn_rqst->connect_cmd.qid = cpu_to_be16(queue->qnum); +- conn_rqst->connect_cmd.sqsize = cpu_to_be16(qsize); ++ conn_rqst->connect_cmd.sqsize = cpu_to_be16(qsize - 1); + + lsop->queue = queue; + lsreq->rqstaddr = conn_rqst; +@@ -2481,11 +2481,11 @@ nvme_fc_create_io_queues(struct nvme_fc_ctrl *ctrl) + goto out_free_tag_set; + } + +- ret = nvme_fc_create_hw_io_queues(ctrl, ctrl->ctrl.opts->queue_size); ++ ret = nvme_fc_create_hw_io_queues(ctrl, ctrl->ctrl.sqsize + 1); + if (ret) + goto out_cleanup_blk_queue; + +- ret = nvme_fc_connect_io_queues(ctrl, ctrl->ctrl.opts->queue_size); ++ ret = nvme_fc_connect_io_queues(ctrl, ctrl->ctrl.sqsize + 1); + if (ret) + goto out_delete_hw_queues; + +@@ -2532,11 +2532,11 @@ nvme_fc_reinit_io_queues(struct nvme_fc_ctrl *ctrl) + if (ret) + goto out_free_io_queues; + +- ret = nvme_fc_create_hw_io_queues(ctrl, ctrl->ctrl.opts->queue_size); ++ ret = nvme_fc_create_hw_io_queues(ctrl, ctrl->ctrl.sqsize + 1); + if (ret) + goto out_free_io_queues; + +- ret = nvme_fc_connect_io_queues(ctrl, ctrl->ctrl.opts->queue_size); ++ ret = nvme_fc_connect_io_queues(ctrl, ctrl->ctrl.sqsize + 1); + if (ret) + goto out_delete_hw_queues; + +@@ -2632,13 +2632,12 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) + nvme_fc_init_queue(ctrl, 0); + + ret = __nvme_fc_create_hw_queue(ctrl, &ctrl->queues[0], 0, +- NVME_AQ_BLK_MQ_DEPTH); ++ NVME_AQ_DEPTH); + if (ret) + goto out_free_queue; + + ret = nvme_fc_connect_admin_queue(ctrl, &ctrl->queues[0], +- NVME_AQ_BLK_MQ_DEPTH, +- (NVME_AQ_BLK_MQ_DEPTH / 4)); ++ NVME_AQ_DEPTH, (NVME_AQ_DEPTH / 4)); + if (ret) + goto out_delete_hw_queue; + +@@ -2666,7 +2665,7 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) + } + + ctrl->ctrl.sqsize = +- min_t(int, NVME_CAP_MQES(ctrl->ctrl.cap) + 1, ctrl->ctrl.sqsize); ++ min_t(int, NVME_CAP_MQES(ctrl->ctrl.cap), ctrl->ctrl.sqsize); + + ret = nvme_enable_ctrl(&ctrl->ctrl, ctrl->ctrl.cap); + if (ret) +@@ -2699,6 +2698,14 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) + opts->queue_size = ctrl->ctrl.maxcmd; + } + ++ if (opts->queue_size > ctrl->ctrl.sqsize + 1) { ++ /* warn if sqsize is lower than queue_size */ ++ dev_warn(ctrl->ctrl.device, ++ "queue_size %zu > ctrl sqsize %u, clamping down\n", ++ opts->queue_size, ctrl->ctrl.sqsize + 1); ++ opts->queue_size = ctrl->ctrl.sqsize + 1; ++ } ++ + ret = nvme_fc_init_aen_ops(ctrl); + if (ret) + goto out_term_aen_ops; +diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c +index b7e5c6d..060f69e 100644 +--- a/drivers/nvme/host/multipath.c ++++ b/drivers/nvme/host/multipath.c +@@ -210,25 +210,6 @@ void nvme_mpath_add_disk(struct nvme_ns_head *head) + mutex_unlock(&head->subsys->lock); + } + +-void nvme_mpath_add_disk_links(struct nvme_ns *ns) +-{ +- struct kobject *slave_disk_kobj, *holder_disk_kobj; +- +- if (!ns->head->disk) +- return; +- +- slave_disk_kobj = &disk_to_dev(ns->disk)->kobj; +- if (sysfs_create_link(ns->head->disk->slave_dir, slave_disk_kobj, +- kobject_name(slave_disk_kobj))) +- return; +- +- holder_disk_kobj = &disk_to_dev(ns->head->disk)->kobj; +- if (sysfs_create_link(ns->disk->part0.holder_dir, holder_disk_kobj, +- kobject_name(holder_disk_kobj))) +- sysfs_remove_link(ns->head->disk->slave_dir, +- kobject_name(slave_disk_kobj)); +-} +- + void nvme_mpath_remove_disk(struct nvme_ns_head *head) + { + if (!head->disk) +@@ -243,14 +224,3 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head) + blk_cleanup_queue(head->disk->queue); + put_disk(head->disk); + } +- +-void nvme_mpath_remove_disk_links(struct nvme_ns *ns) +-{ +- if (!ns->head->disk) +- return; +- +- sysfs_remove_link(ns->disk->part0.holder_dir, +- kobject_name(&disk_to_dev(ns->head->disk)->kobj)); +- sysfs_remove_link(ns->head->disk->slave_dir, +- kobject_name(&disk_to_dev(ns->disk)->kobj)); +-} +diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h +index 0521e47..d733b14 100644 +--- a/drivers/nvme/host/nvme.h ++++ b/drivers/nvme/host/nvme.h +@@ -410,9 +410,7 @@ bool nvme_req_needs_failover(struct request *req, blk_status_t error); + void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl); + int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl,struct nvme_ns_head *head); + void nvme_mpath_add_disk(struct nvme_ns_head *head); +-void nvme_mpath_add_disk_links(struct nvme_ns *ns); + void nvme_mpath_remove_disk(struct nvme_ns_head *head); +-void nvme_mpath_remove_disk_links(struct nvme_ns *ns); + + static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns) + { +@@ -454,12 +452,6 @@ static inline void nvme_mpath_add_disk(struct nvme_ns_head *head) + static inline void nvme_mpath_remove_disk(struct nvme_ns_head *head) + { + } +-static inline void nvme_mpath_add_disk_links(struct nvme_ns *ns) +-{ +-} +-static inline void nvme_mpath_remove_disk_links(struct nvme_ns *ns) +-{ +-} + static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns) + { + } +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 5933a5c..b6f43b7 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -1153,12 +1153,6 @@ static bool nvme_should_reset(struct nvme_dev *dev, u32 csts) + if (!(csts & NVME_CSTS_CFS) && !nssro) + return false; + +- /* If PCI error recovery process is happening, we cannot reset or +- * the recovery mechanism will surely fail. +- */ +- if (pci_channel_offline(to_pci_dev(dev->dev))) +- return false; +- + return true; + } + +@@ -1189,6 +1183,13 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved) + struct nvme_command cmd; + u32 csts = readl(dev->bar + NVME_REG_CSTS); + ++ /* If PCI error recovery process is happening, we cannot reset or ++ * the recovery mechanism will surely fail. ++ */ ++ mb(); ++ if (pci_channel_offline(to_pci_dev(dev->dev))) ++ return BLK_EH_RESET_TIMER; ++ + /* + * Reset immediately if the controller is failed + */ +@@ -1913,7 +1914,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) + int result, nr_io_queues; + unsigned long size; + +- nr_io_queues = num_present_cpus(); ++ nr_io_queues = num_possible_cpus(); + result = nvme_set_queue_count(&dev->ctrl, &nr_io_queues); + if (result < 0) + return result; +diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c +index 8de2d5c..dc9303a 100644 +--- a/drivers/pci/dwc/pcie-designware-host.c ++++ b/drivers/pci/dwc/pcie-designware-host.c +@@ -613,7 +613,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp) + /* setup bus numbers */ + val = dw_pcie_readl_dbi(pci, PCI_PRIMARY_BUS); + val &= 0xff000000; +- val |= 0x00010100; ++ val |= 0x00ff0100; + dw_pcie_writel_dbi(pci, PCI_PRIMARY_BUS, val); + + /* setup command register */ +diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c +index 0c2ed11..f63db34 100644 +--- a/drivers/perf/arm_pmu.c ++++ b/drivers/perf/arm_pmu.c +@@ -638,7 +638,7 @@ static int arm_perf_teardown_cpu(unsigned int cpu, struct hlist_node *node) + if (irq_is_percpu_devid(irq)) + disable_percpu_irq(irq); + else +- disable_irq(irq); ++ disable_irq_nosync(irq); + } + + per_cpu(cpu_armpmu, cpu) = NULL; +diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig +index 9a8f964..d10ffe5 100644 +--- a/drivers/platform/x86/Kconfig ++++ b/drivers/platform/x86/Kconfig +@@ -105,31 +105,44 @@ config ASUS_LAPTOP + + If you have an ACPI-compatible ASUS laptop, say Y or M here. + ++# ++# If the DELL_SMBIOS_SMM feature is enabled, the DELL_SMBIOS driver ++# becomes dependent on the DCDBAS driver. The "depends" line prevents a ++# configuration where DELL_SMBIOS=y while DCDBAS=m. ++# + config DELL_SMBIOS +- tristate ++ tristate "Dell SMBIOS driver" ++ depends on DCDBAS || DCDBAS=n ++ ---help--- ++ This provides support for the Dell SMBIOS calling interface. ++ If you have a Dell computer you should enable this option. ++ ++ Be sure to select at least one backend for it to work properly. + + config DELL_SMBIOS_WMI +- tristate "Dell SMBIOS calling interface (WMI implementation)" ++ bool "Dell SMBIOS driver WMI backend" ++ default y + depends on ACPI_WMI + select DELL_WMI_DESCRIPTOR +- select DELL_SMBIOS ++ depends on DELL_SMBIOS + ---help--- + This provides an implementation for the Dell SMBIOS calling interface + communicated over ACPI-WMI. + +- If you have a Dell computer from >2007 you should say Y or M here. ++ If you have a Dell computer from >2007 you should say Y here. + If you aren't sure and this module doesn't work for your computer + it just won't load. + + config DELL_SMBIOS_SMM +- tristate "Dell SMBIOS calling interface (SMM implementation)" ++ bool "Dell SMBIOS driver SMM backend" ++ default y + depends on DCDBAS +- select DELL_SMBIOS ++ depends on DELL_SMBIOS + ---help--- + This provides an implementation for the Dell SMBIOS calling interface + communicated over SMI/SMM. + +- If you have a Dell computer from <=2017 you should say Y or M here. ++ If you have a Dell computer from <=2017 you should say Y here. + If you aren't sure and this module doesn't work for your computer + it just won't load. + +diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile +index c388608..2ba6cb7 100644 +--- a/drivers/platform/x86/Makefile ++++ b/drivers/platform/x86/Makefile +@@ -13,8 +13,9 @@ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o + obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o + obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o + obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o +-obj-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o +-obj-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o ++dell-smbios-objs := dell-smbios-base.o ++dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o ++dell-smbios-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o + obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o + obj-$(CONFIG_DELL_WMI) += dell-wmi.o + obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o +diff --git a/drivers/platform/x86/dell-smbios-base.c b/drivers/platform/x86/dell-smbios-base.c +new file mode 100644 +index 0000000..5bcf8a1 +--- /dev/null ++++ b/drivers/platform/x86/dell-smbios-base.c +@@ -0,0 +1,648 @@ ++/* ++ * Common functions for kernel modules using Dell SMBIOS ++ * ++ * Copyright (c) Red Hat ++ * Copyright (c) 2014 Gabriele Mazzotta ++ * Copyright (c) 2014 Pali Rohár ++ * ++ * Based on documentation in the libsmbios package: ++ * Copyright (C) 2005-2014 Dell Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "dell-smbios.h" ++ ++static u32 da_supported_commands; ++static int da_num_tokens; ++static struct platform_device *platform_device; ++static struct calling_interface_token *da_tokens; ++static struct device_attribute *token_location_attrs; ++static struct device_attribute *token_value_attrs; ++static struct attribute **token_attrs; ++static DEFINE_MUTEX(smbios_mutex); ++ ++struct smbios_device { ++ struct list_head list; ++ struct device *device; ++ int (*call_fn)(struct calling_interface_buffer *arg); ++}; ++ ++struct smbios_call { ++ u32 need_capability; ++ int cmd_class; ++ int cmd_select; ++}; ++ ++/* calls that are whitelisted for given capabilities */ ++static struct smbios_call call_whitelist[] = { ++ /* generally tokens are allowed, but may be further filtered or ++ * restricted by token blacklist or whitelist ++ */ ++ {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_STD}, ++ {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_AC}, ++ {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_BAT}, ++ {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD}, ++ {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_AC}, ++ {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT}, ++ /* used by userspace: fwupdate */ ++ {CAP_SYS_ADMIN, CLASS_ADMIN_PROP, SELECT_ADMIN_PROP}, ++ /* used by userspace: fwupd */ ++ {CAP_SYS_ADMIN, CLASS_INFO, SELECT_DOCK}, ++ {CAP_SYS_ADMIN, CLASS_FLASH_INTERFACE, SELECT_FLASH_INTERFACE}, ++}; ++ ++/* calls that are explicitly blacklisted */ ++static struct smbios_call call_blacklist[] = { ++ {0x0000, 1, 7}, /* manufacturing use */ ++ {0x0000, 6, 5}, /* manufacturing use */ ++ {0x0000, 11, 3}, /* write once */ ++ {0x0000, 11, 7}, /* write once */ ++ {0x0000, 11, 11}, /* write once */ ++ {0x0000, 19, -1}, /* diagnostics */ ++ /* handled by kernel: dell-laptop */ ++ {0x0000, CLASS_INFO, SELECT_RFKILL}, ++ {0x0000, CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT}, ++}; ++ ++struct token_range { ++ u32 need_capability; ++ u16 min; ++ u16 max; ++}; ++ ++/* tokens that are whitelisted for given capabilities */ ++static struct token_range token_whitelist[] = { ++ /* used by userspace: fwupdate */ ++ {CAP_SYS_ADMIN, CAPSULE_EN_TOKEN, CAPSULE_DIS_TOKEN}, ++ /* can indicate to userspace that WMI is needed */ ++ {0x0000, WSMT_EN_TOKEN, WSMT_DIS_TOKEN} ++}; ++ ++/* tokens that are explicitly blacklisted */ ++static struct token_range token_blacklist[] = { ++ {0x0000, 0x0058, 0x0059}, /* ME use */ ++ {0x0000, 0x00CD, 0x00D0}, /* raid shadow copy */ ++ {0x0000, 0x013A, 0x01FF}, /* sata shadow copy */ ++ {0x0000, 0x0175, 0x0176}, /* write once */ ++ {0x0000, 0x0195, 0x0197}, /* diagnostics */ ++ {0x0000, 0x01DC, 0x01DD}, /* manufacturing use */ ++ {0x0000, 0x027D, 0x0284}, /* diagnostics */ ++ {0x0000, 0x02E3, 0x02E3}, /* manufacturing use */ ++ {0x0000, 0x02FF, 0x02FF}, /* manufacturing use */ ++ {0x0000, 0x0300, 0x0302}, /* manufacturing use */ ++ {0x0000, 0x0325, 0x0326}, /* manufacturing use */ ++ {0x0000, 0x0332, 0x0335}, /* fan control */ ++ {0x0000, 0x0350, 0x0350}, /* manufacturing use */ ++ {0x0000, 0x0363, 0x0363}, /* manufacturing use */ ++ {0x0000, 0x0368, 0x0368}, /* manufacturing use */ ++ {0x0000, 0x03F6, 0x03F7}, /* manufacturing use */ ++ {0x0000, 0x049E, 0x049F}, /* manufacturing use */ ++ {0x0000, 0x04A0, 0x04A3}, /* disagnostics */ ++ {0x0000, 0x04E6, 0x04E7}, /* manufacturing use */ ++ {0x0000, 0x4000, 0x7FFF}, /* internal BIOS use */ ++ {0x0000, 0x9000, 0x9001}, /* internal BIOS use */ ++ {0x0000, 0xA000, 0xBFFF}, /* write only */ ++ {0x0000, 0xEFF0, 0xEFFF}, /* internal BIOS use */ ++ /* handled by kernel: dell-laptop */ ++ {0x0000, BRIGHTNESS_TOKEN, BRIGHTNESS_TOKEN}, ++ {0x0000, KBD_LED_OFF_TOKEN, KBD_LED_AUTO_TOKEN}, ++ {0x0000, KBD_LED_AC_TOKEN, KBD_LED_AC_TOKEN}, ++ {0x0000, KBD_LED_AUTO_25_TOKEN, KBD_LED_AUTO_75_TOKEN}, ++ {0x0000, KBD_LED_AUTO_100_TOKEN, KBD_LED_AUTO_100_TOKEN}, ++ {0x0000, GLOBAL_MIC_MUTE_ENABLE, GLOBAL_MIC_MUTE_DISABLE}, ++}; ++ ++static LIST_HEAD(smbios_device_list); ++ ++int dell_smbios_error(int value) ++{ ++ switch (value) { ++ case 0: /* Completed successfully */ ++ return 0; ++ case -1: /* Completed with error */ ++ return -EIO; ++ case -2: /* Function not supported */ ++ return -ENXIO; ++ default: /* Unknown error */ ++ return -EINVAL; ++ } ++} ++EXPORT_SYMBOL_GPL(dell_smbios_error); ++ ++int dell_smbios_register_device(struct device *d, void *call_fn) ++{ ++ struct smbios_device *priv; ++ ++ priv = devm_kzalloc(d, sizeof(struct smbios_device), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ get_device(d); ++ priv->device = d; ++ priv->call_fn = call_fn; ++ mutex_lock(&smbios_mutex); ++ list_add_tail(&priv->list, &smbios_device_list); ++ mutex_unlock(&smbios_mutex); ++ dev_dbg(d, "Added device: %s\n", d->driver->name); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(dell_smbios_register_device); ++ ++void dell_smbios_unregister_device(struct device *d) ++{ ++ struct smbios_device *priv; ++ ++ mutex_lock(&smbios_mutex); ++ list_for_each_entry(priv, &smbios_device_list, list) { ++ if (priv->device == d) { ++ list_del(&priv->list); ++ put_device(d); ++ break; ++ } ++ } ++ mutex_unlock(&smbios_mutex); ++ dev_dbg(d, "Remove device: %s\n", d->driver->name); ++} ++EXPORT_SYMBOL_GPL(dell_smbios_unregister_device); ++ ++int dell_smbios_call_filter(struct device *d, ++ struct calling_interface_buffer *buffer) ++{ ++ u16 t = 0; ++ int i; ++ ++ /* can't make calls over 30 */ ++ if (buffer->cmd_class > 30) { ++ dev_dbg(d, "class too big: %u\n", buffer->cmd_class); ++ return -EINVAL; ++ } ++ ++ /* supported calls on the particular system */ ++ if (!(da_supported_commands & (1 << buffer->cmd_class))) { ++ dev_dbg(d, "invalid command, supported commands: 0x%8x\n", ++ da_supported_commands); ++ return -EINVAL; ++ } ++ ++ /* match against call blacklist */ ++ for (i = 0; i < ARRAY_SIZE(call_blacklist); i++) { ++ if (buffer->cmd_class != call_blacklist[i].cmd_class) ++ continue; ++ if (buffer->cmd_select != call_blacklist[i].cmd_select && ++ call_blacklist[i].cmd_select != -1) ++ continue; ++ dev_dbg(d, "blacklisted command: %u/%u\n", ++ buffer->cmd_class, buffer->cmd_select); ++ return -EINVAL; ++ } ++ ++ /* if a token call, find token ID */ ++ ++ if ((buffer->cmd_class == CLASS_TOKEN_READ || ++ buffer->cmd_class == CLASS_TOKEN_WRITE) && ++ buffer->cmd_select < 3) { ++ /* find the matching token ID */ ++ for (i = 0; i < da_num_tokens; i++) { ++ if (da_tokens[i].location != buffer->input[0]) ++ continue; ++ t = da_tokens[i].tokenID; ++ break; ++ } ++ ++ /* token call; but token didn't exist */ ++ if (!t) { ++ dev_dbg(d, "token at location %04x doesn't exist\n", ++ buffer->input[0]); ++ return -EINVAL; ++ } ++ ++ /* match against token blacklist */ ++ for (i = 0; i < ARRAY_SIZE(token_blacklist); i++) { ++ if (!token_blacklist[i].min || !token_blacklist[i].max) ++ continue; ++ if (t >= token_blacklist[i].min && ++ t <= token_blacklist[i].max) ++ return -EINVAL; ++ } ++ ++ /* match against token whitelist */ ++ for (i = 0; i < ARRAY_SIZE(token_whitelist); i++) { ++ if (!token_whitelist[i].min || !token_whitelist[i].max) ++ continue; ++ if (t < token_whitelist[i].min || ++ t > token_whitelist[i].max) ++ continue; ++ if (!token_whitelist[i].need_capability || ++ capable(token_whitelist[i].need_capability)) { ++ dev_dbg(d, "whitelisted token: %x\n", t); ++ return 0; ++ } ++ ++ } ++ } ++ /* match against call whitelist */ ++ for (i = 0; i < ARRAY_SIZE(call_whitelist); i++) { ++ if (buffer->cmd_class != call_whitelist[i].cmd_class) ++ continue; ++ if (buffer->cmd_select != call_whitelist[i].cmd_select) ++ continue; ++ if (!call_whitelist[i].need_capability || ++ capable(call_whitelist[i].need_capability)) { ++ dev_dbg(d, "whitelisted capable command: %u/%u\n", ++ buffer->cmd_class, buffer->cmd_select); ++ return 0; ++ } ++ dev_dbg(d, "missing capability %d for %u/%u\n", ++ call_whitelist[i].need_capability, ++ buffer->cmd_class, buffer->cmd_select); ++ ++ } ++ ++ /* not in a whitelist, only allow processes with capabilities */ ++ if (capable(CAP_SYS_RAWIO)) { ++ dev_dbg(d, "Allowing %u/%u due to CAP_SYS_RAWIO\n", ++ buffer->cmd_class, buffer->cmd_select); ++ return 0; ++ } ++ ++ return -EACCES; ++} ++EXPORT_SYMBOL_GPL(dell_smbios_call_filter); ++ ++int dell_smbios_call(struct calling_interface_buffer *buffer) ++{ ++ int (*call_fn)(struct calling_interface_buffer *) = NULL; ++ struct device *selected_dev = NULL; ++ struct smbios_device *priv; ++ int ret; ++ ++ mutex_lock(&smbios_mutex); ++ list_for_each_entry(priv, &smbios_device_list, list) { ++ if (!selected_dev || priv->device->id >= selected_dev->id) { ++ dev_dbg(priv->device, "Trying device ID: %d\n", ++ priv->device->id); ++ call_fn = priv->call_fn; ++ selected_dev = priv->device; ++ } ++ } ++ ++ if (!selected_dev) { ++ ret = -ENODEV; ++ pr_err("No dell-smbios drivers are loaded\n"); ++ goto out_smbios_call; ++ } ++ ++ ret = call_fn(buffer); ++ ++out_smbios_call: ++ mutex_unlock(&smbios_mutex); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(dell_smbios_call); ++ ++struct calling_interface_token *dell_smbios_find_token(int tokenid) ++{ ++ int i; ++ ++ for (i = 0; i < da_num_tokens; i++) { ++ if (da_tokens[i].tokenID == tokenid) ++ return &da_tokens[i]; ++ } ++ ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(dell_smbios_find_token); ++ ++static BLOCKING_NOTIFIER_HEAD(dell_laptop_chain_head); ++ ++int dell_laptop_register_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_register(&dell_laptop_chain_head, nb); ++} ++EXPORT_SYMBOL_GPL(dell_laptop_register_notifier); ++ ++int dell_laptop_unregister_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_unregister(&dell_laptop_chain_head, nb); ++} ++EXPORT_SYMBOL_GPL(dell_laptop_unregister_notifier); ++ ++void dell_laptop_call_notifier(unsigned long action, void *data) ++{ ++ blocking_notifier_call_chain(&dell_laptop_chain_head, action, data); ++} ++EXPORT_SYMBOL_GPL(dell_laptop_call_notifier); ++ ++static void __init parse_da_table(const struct dmi_header *dm) ++{ ++ /* Final token is a terminator, so we don't want to copy it */ ++ int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; ++ struct calling_interface_token *new_da_tokens; ++ struct calling_interface_structure *table = ++ container_of(dm, struct calling_interface_structure, header); ++ ++ /* ++ * 4 bytes of table header, plus 7 bytes of Dell header ++ * plus at least 6 bytes of entry ++ */ ++ ++ if (dm->length < 17) ++ return; ++ ++ da_supported_commands = table->supportedCmds; ++ ++ new_da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) * ++ sizeof(struct calling_interface_token), ++ GFP_KERNEL); ++ ++ if (!new_da_tokens) ++ return; ++ da_tokens = new_da_tokens; ++ ++ memcpy(da_tokens+da_num_tokens, table->tokens, ++ sizeof(struct calling_interface_token) * tokens); ++ ++ da_num_tokens += tokens; ++} ++ ++static void zero_duplicates(struct device *dev) ++{ ++ int i, j; ++ ++ for (i = 0; i < da_num_tokens; i++) { ++ if (da_tokens[i].tokenID == 0) ++ continue; ++ for (j = i+1; j < da_num_tokens; j++) { ++ if (da_tokens[j].tokenID == 0) ++ continue; ++ if (da_tokens[i].tokenID == da_tokens[j].tokenID) { ++ dev_dbg(dev, "Zeroing dup token ID %x(%x/%x)\n", ++ da_tokens[j].tokenID, ++ da_tokens[j].location, ++ da_tokens[j].value); ++ da_tokens[j].tokenID = 0; ++ } ++ } ++ } ++} ++ ++static void __init find_tokens(const struct dmi_header *dm, void *dummy) ++{ ++ switch (dm->type) { ++ case 0xd4: /* Indexed IO */ ++ case 0xd5: /* Protected Area Type 1 */ ++ case 0xd6: /* Protected Area Type 2 */ ++ break; ++ case 0xda: /* Calling interface */ ++ parse_da_table(dm); ++ break; ++ } ++} ++ ++static int match_attribute(struct device *dev, ++ struct device_attribute *attr) ++{ ++ int i; ++ ++ for (i = 0; i < da_num_tokens * 2; i++) { ++ if (!token_attrs[i]) ++ continue; ++ if (strcmp(token_attrs[i]->name, attr->attr.name) == 0) ++ return i/2; ++ } ++ dev_dbg(dev, "couldn't match: %s\n", attr->attr.name); ++ return -EINVAL; ++} ++ ++static ssize_t location_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int i; ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ ++ i = match_attribute(dev, attr); ++ if (i > 0) ++ return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].location); ++ return 0; ++} ++ ++static ssize_t value_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int i; ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ ++ i = match_attribute(dev, attr); ++ if (i > 0) ++ return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].value); ++ return 0; ++} ++ ++static struct attribute_group smbios_attribute_group = { ++ .name = "tokens" ++}; ++ ++static struct platform_driver platform_driver = { ++ .driver = { ++ .name = "dell-smbios", ++ }, ++}; ++ ++static int build_tokens_sysfs(struct platform_device *dev) ++{ ++ char *location_name; ++ char *value_name; ++ size_t size; ++ int ret; ++ int i, j; ++ ++ /* (number of tokens + 1 for null terminated */ ++ size = sizeof(struct device_attribute) * (da_num_tokens + 1); ++ token_location_attrs = kzalloc(size, GFP_KERNEL); ++ if (!token_location_attrs) ++ return -ENOMEM; ++ token_value_attrs = kzalloc(size, GFP_KERNEL); ++ if (!token_value_attrs) ++ goto out_allocate_value; ++ ++ /* need to store both location and value + terminator*/ ++ size = sizeof(struct attribute *) * ((2 * da_num_tokens) + 1); ++ token_attrs = kzalloc(size, GFP_KERNEL); ++ if (!token_attrs) ++ goto out_allocate_attrs; ++ ++ for (i = 0, j = 0; i < da_num_tokens; i++) { ++ /* skip empty */ ++ if (da_tokens[i].tokenID == 0) ++ continue; ++ /* add location */ ++ location_name = kasprintf(GFP_KERNEL, "%04x_location", ++ da_tokens[i].tokenID); ++ if (location_name == NULL) ++ goto out_unwind_strings; ++ sysfs_attr_init(&token_location_attrs[i].attr); ++ token_location_attrs[i].attr.name = location_name; ++ token_location_attrs[i].attr.mode = 0444; ++ token_location_attrs[i].show = location_show; ++ token_attrs[j++] = &token_location_attrs[i].attr; ++ ++ /* add value */ ++ value_name = kasprintf(GFP_KERNEL, "%04x_value", ++ da_tokens[i].tokenID); ++ if (value_name == NULL) ++ goto loop_fail_create_value; ++ sysfs_attr_init(&token_value_attrs[i].attr); ++ token_value_attrs[i].attr.name = value_name; ++ token_value_attrs[i].attr.mode = 0444; ++ token_value_attrs[i].show = value_show; ++ token_attrs[j++] = &token_value_attrs[i].attr; ++ continue; ++ ++loop_fail_create_value: ++ kfree(value_name); ++ goto out_unwind_strings; ++ } ++ smbios_attribute_group.attrs = token_attrs; ++ ++ ret = sysfs_create_group(&dev->dev.kobj, &smbios_attribute_group); ++ if (ret) ++ goto out_unwind_strings; ++ return 0; ++ ++out_unwind_strings: ++ for (i = i-1; i > 0; i--) { ++ kfree(token_location_attrs[i].attr.name); ++ kfree(token_value_attrs[i].attr.name); ++ } ++ kfree(token_attrs); ++out_allocate_attrs: ++ kfree(token_value_attrs); ++out_allocate_value: ++ kfree(token_location_attrs); ++ ++ return -ENOMEM; ++} ++ ++static void free_group(struct platform_device *pdev) ++{ ++ int i; ++ ++ sysfs_remove_group(&pdev->dev.kobj, ++ &smbios_attribute_group); ++ for (i = 0; i < da_num_tokens; i++) { ++ kfree(token_location_attrs[i].attr.name); ++ kfree(token_value_attrs[i].attr.name); ++ } ++ kfree(token_attrs); ++ kfree(token_value_attrs); ++ kfree(token_location_attrs); ++} ++ ++static int __init dell_smbios_init(void) ++{ ++ const struct dmi_device *valid; ++ int ret, wmi, smm; ++ ++ valid = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL); ++ if (!valid) { ++ pr_err("Unable to run on non-Dell system\n"); ++ return -ENODEV; ++ } ++ ++ dmi_walk(find_tokens, NULL); ++ ++ if (!da_tokens) { ++ pr_info("Unable to find dmi tokens\n"); ++ return -ENODEV; ++ } ++ ++ ret = platform_driver_register(&platform_driver); ++ if (ret) ++ goto fail_platform_driver; ++ ++ platform_device = platform_device_alloc("dell-smbios", 0); ++ if (!platform_device) { ++ ret = -ENOMEM; ++ goto fail_platform_device_alloc; ++ } ++ ret = platform_device_add(platform_device); ++ if (ret) ++ goto fail_platform_device_add; ++ ++ /* duplicate tokens will cause problems building sysfs files */ ++ zero_duplicates(&platform_device->dev); ++ ++ ret = build_tokens_sysfs(platform_device); ++ if (ret) ++ goto fail_create_group; ++ ++ /* register backends */ ++ wmi = init_dell_smbios_wmi(); ++ if (wmi) ++ pr_debug("Failed to initialize WMI backend: %d\n", wmi); ++ smm = init_dell_smbios_smm(); ++ if (smm) ++ pr_debug("Failed to initialize SMM backend: %d\n", smm); ++ if (wmi && smm) { ++ pr_err("No SMBIOS backends available (wmi: %d, smm: %d)\n", ++ wmi, smm); ++ goto fail_sysfs; ++ } ++ ++ return 0; ++ ++fail_sysfs: ++ free_group(platform_device); ++ ++fail_create_group: ++ platform_device_del(platform_device); ++ ++fail_platform_device_add: ++ platform_device_put(platform_device); ++ ++fail_platform_device_alloc: ++ platform_driver_unregister(&platform_driver); ++ ++fail_platform_driver: ++ kfree(da_tokens); ++ return ret; ++} ++ ++static void __exit dell_smbios_exit(void) ++{ ++ exit_dell_smbios_wmi(); ++ exit_dell_smbios_smm(); ++ mutex_lock(&smbios_mutex); ++ if (platform_device) { ++ free_group(platform_device); ++ platform_device_unregister(platform_device); ++ platform_driver_unregister(&platform_driver); ++ } ++ kfree(da_tokens); ++ mutex_unlock(&smbios_mutex); ++} ++ ++subsys_initcall(dell_smbios_init); ++module_exit(dell_smbios_exit); ++ ++MODULE_AUTHOR("Matthew Garrett "); ++MODULE_AUTHOR("Gabriele Mazzotta "); ++MODULE_AUTHOR("Pali Rohár "); ++MODULE_AUTHOR("Mario Limonciello "); ++MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/x86/dell-smbios-smm.c b/drivers/platform/x86/dell-smbios-smm.c +index 89f65c4..e9e9da5 100644 +--- a/drivers/platform/x86/dell-smbios-smm.c ++++ b/drivers/platform/x86/dell-smbios-smm.c +@@ -58,7 +58,7 @@ static const struct dmi_system_id dell_device_table[] __initconst = { + }; + MODULE_DEVICE_TABLE(dmi, dell_device_table); + +-static void __init parse_da_table(const struct dmi_header *dm) ++static void parse_da_table(const struct dmi_header *dm) + { + struct calling_interface_structure *table = + container_of(dm, struct calling_interface_structure, header); +@@ -73,7 +73,7 @@ static void __init parse_da_table(const struct dmi_header *dm) + da_command_code = table->cmdIOCode; + } + +-static void __init find_cmd_address(const struct dmi_header *dm, void *dummy) ++static void find_cmd_address(const struct dmi_header *dm, void *dummy) + { + switch (dm->type) { + case 0xda: /* Calling interface */ +@@ -128,7 +128,7 @@ static bool test_wsmt_enabled(void) + return false; + } + +-static int __init dell_smbios_smm_init(void) ++int init_dell_smbios_smm(void) + { + int ret; + /* +@@ -176,7 +176,7 @@ static int __init dell_smbios_smm_init(void) + return ret; + } + +-static void __exit dell_smbios_smm_exit(void) ++void exit_dell_smbios_smm(void) + { + if (platform_device) { + dell_smbios_unregister_device(&platform_device->dev); +@@ -184,13 +184,3 @@ static void __exit dell_smbios_smm_exit(void) + free_page((unsigned long)buffer); + } + } +- +-subsys_initcall(dell_smbios_smm_init); +-module_exit(dell_smbios_smm_exit); +- +-MODULE_AUTHOR("Matthew Garrett "); +-MODULE_AUTHOR("Gabriele Mazzotta "); +-MODULE_AUTHOR("Pali Rohár "); +-MODULE_AUTHOR("Mario Limonciello "); +-MODULE_DESCRIPTION("Dell SMBIOS communications over SMI"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c +index 609557a..fbefedb 100644 +--- a/drivers/platform/x86/dell-smbios-wmi.c ++++ b/drivers/platform/x86/dell-smbios-wmi.c +@@ -228,7 +228,7 @@ static const struct wmi_device_id dell_smbios_wmi_id_table[] = { + { }, + }; + +-static void __init parse_b1_table(const struct dmi_header *dm) ++static void parse_b1_table(const struct dmi_header *dm) + { + struct misc_bios_flags_structure *flags = + container_of(dm, struct misc_bios_flags_structure, header); +@@ -242,7 +242,7 @@ static void __init parse_b1_table(const struct dmi_header *dm) + wmi_supported = 1; + } + +-static void __init find_b1(const struct dmi_header *dm, void *dummy) ++static void find_b1(const struct dmi_header *dm, void *dummy) + { + switch (dm->type) { + case 0xb1: /* misc bios flags */ +@@ -261,7 +261,7 @@ static struct wmi_driver dell_smbios_wmi_driver = { + .filter_callback = dell_smbios_wmi_filter, + }; + +-static int __init init_dell_smbios_wmi(void) ++int init_dell_smbios_wmi(void) + { + dmi_walk(find_b1, NULL); + +@@ -271,15 +271,9 @@ static int __init init_dell_smbios_wmi(void) + return wmi_driver_register(&dell_smbios_wmi_driver); + } + +-static void __exit exit_dell_smbios_wmi(void) ++void exit_dell_smbios_wmi(void) + { + wmi_driver_unregister(&dell_smbios_wmi_driver); + } + +-module_init(init_dell_smbios_wmi); +-module_exit(exit_dell_smbios_wmi); +- + MODULE_ALIAS("wmi:" DELL_WMI_SMBIOS_GUID); +-MODULE_AUTHOR("Mario Limonciello "); +-MODULE_DESCRIPTION("Dell SMBIOS communications over WMI"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c +deleted file mode 100644 +index 8541cde..0000000 +--- a/drivers/platform/x86/dell-smbios.c ++++ /dev/null +@@ -1,627 +0,0 @@ +-/* +- * Common functions for kernel modules using Dell SMBIOS +- * +- * Copyright (c) Red Hat +- * Copyright (c) 2014 Gabriele Mazzotta +- * Copyright (c) 2014 Pali Rohár +- * +- * Based on documentation in the libsmbios package: +- * Copyright (C) 2005-2014 Dell Inc. +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include "dell-smbios.h" +- +-static u32 da_supported_commands; +-static int da_num_tokens; +-static struct platform_device *platform_device; +-static struct calling_interface_token *da_tokens; +-static struct device_attribute *token_location_attrs; +-static struct device_attribute *token_value_attrs; +-static struct attribute **token_attrs; +-static DEFINE_MUTEX(smbios_mutex); +- +-struct smbios_device { +- struct list_head list; +- struct device *device; +- int (*call_fn)(struct calling_interface_buffer *); +-}; +- +-struct smbios_call { +- u32 need_capability; +- int cmd_class; +- int cmd_select; +-}; +- +-/* calls that are whitelisted for given capabilities */ +-static struct smbios_call call_whitelist[] = { +- /* generally tokens are allowed, but may be further filtered or +- * restricted by token blacklist or whitelist +- */ +- {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_STD}, +- {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_AC}, +- {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_BAT}, +- {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD}, +- {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_AC}, +- {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT}, +- /* used by userspace: fwupdate */ +- {CAP_SYS_ADMIN, CLASS_ADMIN_PROP, SELECT_ADMIN_PROP}, +- /* used by userspace: fwupd */ +- {CAP_SYS_ADMIN, CLASS_INFO, SELECT_DOCK}, +- {CAP_SYS_ADMIN, CLASS_FLASH_INTERFACE, SELECT_FLASH_INTERFACE}, +-}; +- +-/* calls that are explicitly blacklisted */ +-static struct smbios_call call_blacklist[] = { +- {0x0000, 1, 7}, /* manufacturing use */ +- {0x0000, 6, 5}, /* manufacturing use */ +- {0x0000, 11, 3}, /* write once */ +- {0x0000, 11, 7}, /* write once */ +- {0x0000, 11, 11}, /* write once */ +- {0x0000, 19, -1}, /* diagnostics */ +- /* handled by kernel: dell-laptop */ +- {0x0000, CLASS_INFO, SELECT_RFKILL}, +- {0x0000, CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT}, +-}; +- +-struct token_range { +- u32 need_capability; +- u16 min; +- u16 max; +-}; +- +-/* tokens that are whitelisted for given capabilities */ +-static struct token_range token_whitelist[] = { +- /* used by userspace: fwupdate */ +- {CAP_SYS_ADMIN, CAPSULE_EN_TOKEN, CAPSULE_DIS_TOKEN}, +- /* can indicate to userspace that WMI is needed */ +- {0x0000, WSMT_EN_TOKEN, WSMT_DIS_TOKEN} +-}; +- +-/* tokens that are explicitly blacklisted */ +-static struct token_range token_blacklist[] = { +- {0x0000, 0x0058, 0x0059}, /* ME use */ +- {0x0000, 0x00CD, 0x00D0}, /* raid shadow copy */ +- {0x0000, 0x013A, 0x01FF}, /* sata shadow copy */ +- {0x0000, 0x0175, 0x0176}, /* write once */ +- {0x0000, 0x0195, 0x0197}, /* diagnostics */ +- {0x0000, 0x01DC, 0x01DD}, /* manufacturing use */ +- {0x0000, 0x027D, 0x0284}, /* diagnostics */ +- {0x0000, 0x02E3, 0x02E3}, /* manufacturing use */ +- {0x0000, 0x02FF, 0x02FF}, /* manufacturing use */ +- {0x0000, 0x0300, 0x0302}, /* manufacturing use */ +- {0x0000, 0x0325, 0x0326}, /* manufacturing use */ +- {0x0000, 0x0332, 0x0335}, /* fan control */ +- {0x0000, 0x0350, 0x0350}, /* manufacturing use */ +- {0x0000, 0x0363, 0x0363}, /* manufacturing use */ +- {0x0000, 0x0368, 0x0368}, /* manufacturing use */ +- {0x0000, 0x03F6, 0x03F7}, /* manufacturing use */ +- {0x0000, 0x049E, 0x049F}, /* manufacturing use */ +- {0x0000, 0x04A0, 0x04A3}, /* disagnostics */ +- {0x0000, 0x04E6, 0x04E7}, /* manufacturing use */ +- {0x0000, 0x4000, 0x7FFF}, /* internal BIOS use */ +- {0x0000, 0x9000, 0x9001}, /* internal BIOS use */ +- {0x0000, 0xA000, 0xBFFF}, /* write only */ +- {0x0000, 0xEFF0, 0xEFFF}, /* internal BIOS use */ +- /* handled by kernel: dell-laptop */ +- {0x0000, BRIGHTNESS_TOKEN, BRIGHTNESS_TOKEN}, +- {0x0000, KBD_LED_OFF_TOKEN, KBD_LED_AUTO_TOKEN}, +- {0x0000, KBD_LED_AC_TOKEN, KBD_LED_AC_TOKEN}, +- {0x0000, KBD_LED_AUTO_25_TOKEN, KBD_LED_AUTO_75_TOKEN}, +- {0x0000, KBD_LED_AUTO_100_TOKEN, KBD_LED_AUTO_100_TOKEN}, +- {0x0000, GLOBAL_MIC_MUTE_ENABLE, GLOBAL_MIC_MUTE_DISABLE}, +-}; +- +-static LIST_HEAD(smbios_device_list); +- +-int dell_smbios_error(int value) +-{ +- switch (value) { +- case 0: /* Completed successfully */ +- return 0; +- case -1: /* Completed with error */ +- return -EIO; +- case -2: /* Function not supported */ +- return -ENXIO; +- default: /* Unknown error */ +- return -EINVAL; +- } +-} +-EXPORT_SYMBOL_GPL(dell_smbios_error); +- +-int dell_smbios_register_device(struct device *d, void *call_fn) +-{ +- struct smbios_device *priv; +- +- priv = devm_kzalloc(d, sizeof(struct smbios_device), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- get_device(d); +- priv->device = d; +- priv->call_fn = call_fn; +- mutex_lock(&smbios_mutex); +- list_add_tail(&priv->list, &smbios_device_list); +- mutex_unlock(&smbios_mutex); +- dev_dbg(d, "Added device: %s\n", d->driver->name); +- return 0; +-} +-EXPORT_SYMBOL_GPL(dell_smbios_register_device); +- +-void dell_smbios_unregister_device(struct device *d) +-{ +- struct smbios_device *priv; +- +- mutex_lock(&smbios_mutex); +- list_for_each_entry(priv, &smbios_device_list, list) { +- if (priv->device == d) { +- list_del(&priv->list); +- put_device(d); +- break; +- } +- } +- mutex_unlock(&smbios_mutex); +- dev_dbg(d, "Remove device: %s\n", d->driver->name); +-} +-EXPORT_SYMBOL_GPL(dell_smbios_unregister_device); +- +-int dell_smbios_call_filter(struct device *d, +- struct calling_interface_buffer *buffer) +-{ +- u16 t = 0; +- int i; +- +- /* can't make calls over 30 */ +- if (buffer->cmd_class > 30) { +- dev_dbg(d, "class too big: %u\n", buffer->cmd_class); +- return -EINVAL; +- } +- +- /* supported calls on the particular system */ +- if (!(da_supported_commands & (1 << buffer->cmd_class))) { +- dev_dbg(d, "invalid command, supported commands: 0x%8x\n", +- da_supported_commands); +- return -EINVAL; +- } +- +- /* match against call blacklist */ +- for (i = 0; i < ARRAY_SIZE(call_blacklist); i++) { +- if (buffer->cmd_class != call_blacklist[i].cmd_class) +- continue; +- if (buffer->cmd_select != call_blacklist[i].cmd_select && +- call_blacklist[i].cmd_select != -1) +- continue; +- dev_dbg(d, "blacklisted command: %u/%u\n", +- buffer->cmd_class, buffer->cmd_select); +- return -EINVAL; +- } +- +- /* if a token call, find token ID */ +- +- if ((buffer->cmd_class == CLASS_TOKEN_READ || +- buffer->cmd_class == CLASS_TOKEN_WRITE) && +- buffer->cmd_select < 3) { +- /* find the matching token ID */ +- for (i = 0; i < da_num_tokens; i++) { +- if (da_tokens[i].location != buffer->input[0]) +- continue; +- t = da_tokens[i].tokenID; +- break; +- } +- +- /* token call; but token didn't exist */ +- if (!t) { +- dev_dbg(d, "token at location %04x doesn't exist\n", +- buffer->input[0]); +- return -EINVAL; +- } +- +- /* match against token blacklist */ +- for (i = 0; i < ARRAY_SIZE(token_blacklist); i++) { +- if (!token_blacklist[i].min || !token_blacklist[i].max) +- continue; +- if (t >= token_blacklist[i].min && +- t <= token_blacklist[i].max) +- return -EINVAL; +- } +- +- /* match against token whitelist */ +- for (i = 0; i < ARRAY_SIZE(token_whitelist); i++) { +- if (!token_whitelist[i].min || !token_whitelist[i].max) +- continue; +- if (t < token_whitelist[i].min || +- t > token_whitelist[i].max) +- continue; +- if (!token_whitelist[i].need_capability || +- capable(token_whitelist[i].need_capability)) { +- dev_dbg(d, "whitelisted token: %x\n", t); +- return 0; +- } +- +- } +- } +- /* match against call whitelist */ +- for (i = 0; i < ARRAY_SIZE(call_whitelist); i++) { +- if (buffer->cmd_class != call_whitelist[i].cmd_class) +- continue; +- if (buffer->cmd_select != call_whitelist[i].cmd_select) +- continue; +- if (!call_whitelist[i].need_capability || +- capable(call_whitelist[i].need_capability)) { +- dev_dbg(d, "whitelisted capable command: %u/%u\n", +- buffer->cmd_class, buffer->cmd_select); +- return 0; +- } +- dev_dbg(d, "missing capability %d for %u/%u\n", +- call_whitelist[i].need_capability, +- buffer->cmd_class, buffer->cmd_select); +- +- } +- +- /* not in a whitelist, only allow processes with capabilities */ +- if (capable(CAP_SYS_RAWIO)) { +- dev_dbg(d, "Allowing %u/%u due to CAP_SYS_RAWIO\n", +- buffer->cmd_class, buffer->cmd_select); +- return 0; +- } +- +- return -EACCES; +-} +-EXPORT_SYMBOL_GPL(dell_smbios_call_filter); +- +-int dell_smbios_call(struct calling_interface_buffer *buffer) +-{ +- int (*call_fn)(struct calling_interface_buffer *) = NULL; +- struct device *selected_dev = NULL; +- struct smbios_device *priv; +- int ret; +- +- mutex_lock(&smbios_mutex); +- list_for_each_entry(priv, &smbios_device_list, list) { +- if (!selected_dev || priv->device->id >= selected_dev->id) { +- dev_dbg(priv->device, "Trying device ID: %d\n", +- priv->device->id); +- call_fn = priv->call_fn; +- selected_dev = priv->device; +- } +- } +- +- if (!selected_dev) { +- ret = -ENODEV; +- pr_err("No dell-smbios drivers are loaded\n"); +- goto out_smbios_call; +- } +- +- ret = call_fn(buffer); +- +-out_smbios_call: +- mutex_unlock(&smbios_mutex); +- return ret; +-} +-EXPORT_SYMBOL_GPL(dell_smbios_call); +- +-struct calling_interface_token *dell_smbios_find_token(int tokenid) +-{ +- int i; +- +- for (i = 0; i < da_num_tokens; i++) { +- if (da_tokens[i].tokenID == tokenid) +- return &da_tokens[i]; +- } +- +- return NULL; +-} +-EXPORT_SYMBOL_GPL(dell_smbios_find_token); +- +-static BLOCKING_NOTIFIER_HEAD(dell_laptop_chain_head); +- +-int dell_laptop_register_notifier(struct notifier_block *nb) +-{ +- return blocking_notifier_chain_register(&dell_laptop_chain_head, nb); +-} +-EXPORT_SYMBOL_GPL(dell_laptop_register_notifier); +- +-int dell_laptop_unregister_notifier(struct notifier_block *nb) +-{ +- return blocking_notifier_chain_unregister(&dell_laptop_chain_head, nb); +-} +-EXPORT_SYMBOL_GPL(dell_laptop_unregister_notifier); +- +-void dell_laptop_call_notifier(unsigned long action, void *data) +-{ +- blocking_notifier_call_chain(&dell_laptop_chain_head, action, data); +-} +-EXPORT_SYMBOL_GPL(dell_laptop_call_notifier); +- +-static void __init parse_da_table(const struct dmi_header *dm) +-{ +- /* Final token is a terminator, so we don't want to copy it */ +- int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; +- struct calling_interface_token *new_da_tokens; +- struct calling_interface_structure *table = +- container_of(dm, struct calling_interface_structure, header); +- +- /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least +- 6 bytes of entry */ +- +- if (dm->length < 17) +- return; +- +- da_supported_commands = table->supportedCmds; +- +- new_da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) * +- sizeof(struct calling_interface_token), +- GFP_KERNEL); +- +- if (!new_da_tokens) +- return; +- da_tokens = new_da_tokens; +- +- memcpy(da_tokens+da_num_tokens, table->tokens, +- sizeof(struct calling_interface_token) * tokens); +- +- da_num_tokens += tokens; +-} +- +-static void zero_duplicates(struct device *dev) +-{ +- int i, j; +- +- for (i = 0; i < da_num_tokens; i++) { +- if (da_tokens[i].tokenID == 0) +- continue; +- for (j = i+1; j < da_num_tokens; j++) { +- if (da_tokens[j].tokenID == 0) +- continue; +- if (da_tokens[i].tokenID == da_tokens[j].tokenID) { +- dev_dbg(dev, "Zeroing dup token ID %x(%x/%x)\n", +- da_tokens[j].tokenID, +- da_tokens[j].location, +- da_tokens[j].value); +- da_tokens[j].tokenID = 0; +- } +- } +- } +-} +- +-static void __init find_tokens(const struct dmi_header *dm, void *dummy) +-{ +- switch (dm->type) { +- case 0xd4: /* Indexed IO */ +- case 0xd5: /* Protected Area Type 1 */ +- case 0xd6: /* Protected Area Type 2 */ +- break; +- case 0xda: /* Calling interface */ +- parse_da_table(dm); +- break; +- } +-} +- +-static int match_attribute(struct device *dev, +- struct device_attribute *attr) +-{ +- int i; +- +- for (i = 0; i < da_num_tokens * 2; i++) { +- if (!token_attrs[i]) +- continue; +- if (strcmp(token_attrs[i]->name, attr->attr.name) == 0) +- return i/2; +- } +- dev_dbg(dev, "couldn't match: %s\n", attr->attr.name); +- return -EINVAL; +-} +- +-static ssize_t location_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- int i; +- +- if (!capable(CAP_SYS_ADMIN)) +- return -EPERM; +- +- i = match_attribute(dev, attr); +- if (i > 0) +- return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].location); +- return 0; +-} +- +-static ssize_t value_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- int i; +- +- if (!capable(CAP_SYS_ADMIN)) +- return -EPERM; +- +- i = match_attribute(dev, attr); +- if (i > 0) +- return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].value); +- return 0; +-} +- +-static struct attribute_group smbios_attribute_group = { +- .name = "tokens" +-}; +- +-static struct platform_driver platform_driver = { +- .driver = { +- .name = "dell-smbios", +- }, +-}; +- +-static int build_tokens_sysfs(struct platform_device *dev) +-{ +- char *location_name; +- char *value_name; +- size_t size; +- int ret; +- int i, j; +- +- /* (number of tokens + 1 for null terminated */ +- size = sizeof(struct device_attribute) * (da_num_tokens + 1); +- token_location_attrs = kzalloc(size, GFP_KERNEL); +- if (!token_location_attrs) +- return -ENOMEM; +- token_value_attrs = kzalloc(size, GFP_KERNEL); +- if (!token_value_attrs) +- goto out_allocate_value; +- +- /* need to store both location and value + terminator*/ +- size = sizeof(struct attribute *) * ((2 * da_num_tokens) + 1); +- token_attrs = kzalloc(size, GFP_KERNEL); +- if (!token_attrs) +- goto out_allocate_attrs; +- +- for (i = 0, j = 0; i < da_num_tokens; i++) { +- /* skip empty */ +- if (da_tokens[i].tokenID == 0) +- continue; +- /* add location */ +- location_name = kasprintf(GFP_KERNEL, "%04x_location", +- da_tokens[i].tokenID); +- if (location_name == NULL) +- goto out_unwind_strings; +- sysfs_attr_init(&token_location_attrs[i].attr); +- token_location_attrs[i].attr.name = location_name; +- token_location_attrs[i].attr.mode = 0444; +- token_location_attrs[i].show = location_show; +- token_attrs[j++] = &token_location_attrs[i].attr; +- +- /* add value */ +- value_name = kasprintf(GFP_KERNEL, "%04x_value", +- da_tokens[i].tokenID); +- if (value_name == NULL) +- goto loop_fail_create_value; +- sysfs_attr_init(&token_value_attrs[i].attr); +- token_value_attrs[i].attr.name = value_name; +- token_value_attrs[i].attr.mode = 0444; +- token_value_attrs[i].show = value_show; +- token_attrs[j++] = &token_value_attrs[i].attr; +- continue; +- +-loop_fail_create_value: +- kfree(value_name); +- goto out_unwind_strings; +- } +- smbios_attribute_group.attrs = token_attrs; +- +- ret = sysfs_create_group(&dev->dev.kobj, &smbios_attribute_group); +- if (ret) +- goto out_unwind_strings; +- return 0; +- +-out_unwind_strings: +- for (i = i-1; i > 0; i--) { +- kfree(token_location_attrs[i].attr.name); +- kfree(token_value_attrs[i].attr.name); +- } +- kfree(token_attrs); +-out_allocate_attrs: +- kfree(token_value_attrs); +-out_allocate_value: +- kfree(token_location_attrs); +- +- return -ENOMEM; +-} +- +-static void free_group(struct platform_device *pdev) +-{ +- int i; +- +- sysfs_remove_group(&pdev->dev.kobj, +- &smbios_attribute_group); +- for (i = 0; i < da_num_tokens; i++) { +- kfree(token_location_attrs[i].attr.name); +- kfree(token_value_attrs[i].attr.name); +- } +- kfree(token_attrs); +- kfree(token_value_attrs); +- kfree(token_location_attrs); +-} +- +-static int __init dell_smbios_init(void) +-{ +- const struct dmi_device *valid; +- int ret; +- +- valid = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL); +- if (!valid) { +- pr_err("Unable to run on non-Dell system\n"); +- return -ENODEV; +- } +- +- dmi_walk(find_tokens, NULL); +- +- if (!da_tokens) { +- pr_info("Unable to find dmi tokens\n"); +- return -ENODEV; +- } +- +- ret = platform_driver_register(&platform_driver); +- if (ret) +- goto fail_platform_driver; +- +- platform_device = platform_device_alloc("dell-smbios", 0); +- if (!platform_device) { +- ret = -ENOMEM; +- goto fail_platform_device_alloc; +- } +- ret = platform_device_add(platform_device); +- if (ret) +- goto fail_platform_device_add; +- +- /* duplicate tokens will cause problems building sysfs files */ +- zero_duplicates(&platform_device->dev); +- +- ret = build_tokens_sysfs(platform_device); +- if (ret) +- goto fail_create_group; +- +- return 0; +- +-fail_create_group: +- platform_device_del(platform_device); +- +-fail_platform_device_add: +- platform_device_put(platform_device); +- +-fail_platform_device_alloc: +- platform_driver_unregister(&platform_driver); +- +-fail_platform_driver: +- kfree(da_tokens); +- return ret; +-} +- +-static void __exit dell_smbios_exit(void) +-{ +- mutex_lock(&smbios_mutex); +- if (platform_device) { +- free_group(platform_device); +- platform_device_unregister(platform_device); +- platform_driver_unregister(&platform_driver); +- } +- kfree(da_tokens); +- mutex_unlock(&smbios_mutex); +-} +- +-subsys_initcall(dell_smbios_init); +-module_exit(dell_smbios_exit); +- +-MODULE_AUTHOR("Matthew Garrett "); +-MODULE_AUTHOR("Gabriele Mazzotta "); +-MODULE_AUTHOR("Pali Rohár "); +-MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h +index 138d478..d8adaf9 100644 +--- a/drivers/platform/x86/dell-smbios.h ++++ b/drivers/platform/x86/dell-smbios.h +@@ -75,4 +75,29 @@ int dell_laptop_register_notifier(struct notifier_block *nb); + int dell_laptop_unregister_notifier(struct notifier_block *nb); + void dell_laptop_call_notifier(unsigned long action, void *data); + +-#endif ++/* for the supported backends */ ++#ifdef CONFIG_DELL_SMBIOS_WMI ++int init_dell_smbios_wmi(void); ++void exit_dell_smbios_wmi(void); ++#else /* CONFIG_DELL_SMBIOS_WMI */ ++static inline int init_dell_smbios_wmi(void) ++{ ++ return -ENODEV; ++} ++static inline void exit_dell_smbios_wmi(void) ++{} ++#endif /* CONFIG_DELL_SMBIOS_WMI */ ++ ++#ifdef CONFIG_DELL_SMBIOS_SMM ++int init_dell_smbios_smm(void); ++void exit_dell_smbios_smm(void); ++#else /* CONFIG_DELL_SMBIOS_SMM */ ++static inline int init_dell_smbios_smm(void) ++{ ++ return -ENODEV; ++} ++static inline void exit_dell_smbios_smm(void) ++{} ++#endif /* CONFIG_DELL_SMBIOS_SMM */ ++ ++#endif /* _DELL_SMBIOS_H_ */ +diff --git a/drivers/video/fbdev/sbuslib.c b/drivers/video/fbdev/sbuslib.c +index af6fc97..a436d44 100644 +--- a/drivers/video/fbdev/sbuslib.c ++++ b/drivers/video/fbdev/sbuslib.c +@@ -122,7 +122,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, + unsigned char __user *ured; + unsigned char __user *ugreen; + unsigned char __user *ublue; +- int index, count, i; ++ unsigned int index, count, i; + + if (get_user(index, &c->index) || + __get_user(count, &c->count) || +@@ -161,7 +161,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, + unsigned char __user *ugreen; + unsigned char __user *ublue; + struct fb_cmap *cmap = &info->cmap; +- int index, count, i; ++ unsigned int index, count, i; + u8 red, green, blue; + + if (get_user(index, &c->index) || +diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c +index e0678c1..3a33c53 100644 +--- a/drivers/watchdog/f71808e_wdt.c ++++ b/drivers/watchdog/f71808e_wdt.c +@@ -566,7 +566,8 @@ static ssize_t watchdog_write(struct file *file, const char __user *buf, + char c; + if (get_user(c, buf + i)) + return -EFAULT; +- expect_close = (c == 'V'); ++ if (c == 'V') ++ expect_close = true; + } + + /* Properly order writes across fork()ed processes */ +diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c +index f1f00df..b0a1580 100644 +--- a/drivers/watchdog/hpwdt.c ++++ b/drivers/watchdog/hpwdt.c +@@ -28,16 +28,7 @@ + #include + #include + #include +-#ifdef CONFIG_HPWDT_NMI_DECODING +-#include +-#include +-#include +-#include +-#include +-#include +-#endif /* CONFIG_HPWDT_NMI_DECODING */ + #include +-#include + + #define HPWDT_VERSION "1.4.0" + #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) +@@ -48,6 +39,9 @@ + static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */ + static unsigned int reload; /* the computed soft_margin */ + static bool nowayout = WATCHDOG_NOWAYOUT; ++#ifdef CONFIG_HPWDT_NMI_DECODING ++static unsigned int allow_kdump = 1; ++#endif + static char expect_release; + static unsigned long hpwdt_is_open; + +@@ -63,373 +57,6 @@ static const struct pci_device_id hpwdt_devices[] = { + }; + MODULE_DEVICE_TABLE(pci, hpwdt_devices); + +-#ifdef CONFIG_HPWDT_NMI_DECODING +-#define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */ +-#define CRU_BIOS_SIGNATURE_VALUE 0x55524324 +-#define PCI_BIOS32_PARAGRAPH_LEN 16 +-#define PCI_ROM_BASE1 0x000F0000 +-#define ROM_SIZE 0x10000 +- +-struct bios32_service_dir { +- u32 signature; +- u32 entry_point; +- u8 revision; +- u8 length; +- u8 checksum; +- u8 reserved[5]; +-}; +- +-/* type 212 */ +-struct smbios_cru64_info { +- u8 type; +- u8 byte_length; +- u16 handle; +- u32 signature; +- u64 physical_address; +- u32 double_length; +- u32 double_offset; +-}; +-#define SMBIOS_CRU64_INFORMATION 212 +- +-/* type 219 */ +-struct smbios_proliant_info { +- u8 type; +- u8 byte_length; +- u16 handle; +- u32 power_features; +- u32 omega_features; +- u32 reserved; +- u32 misc_features; +-}; +-#define SMBIOS_ICRU_INFORMATION 219 +- +- +-struct cmn_registers { +- union { +- struct { +- u8 ral; +- u8 rah; +- u16 rea2; +- }; +- u32 reax; +- } u1; +- union { +- struct { +- u8 rbl; +- u8 rbh; +- u8 reb2l; +- u8 reb2h; +- }; +- u32 rebx; +- } u2; +- union { +- struct { +- u8 rcl; +- u8 rch; +- u16 rec2; +- }; +- u32 recx; +- } u3; +- union { +- struct { +- u8 rdl; +- u8 rdh; +- u16 red2; +- }; +- u32 redx; +- } u4; +- +- u32 resi; +- u32 redi; +- u16 rds; +- u16 res; +- u32 reflags; +-} __attribute__((packed)); +- +-static unsigned int hpwdt_nmi_decoding; +-static unsigned int allow_kdump = 1; +-static unsigned int is_icru; +-static unsigned int is_uefi; +-static DEFINE_SPINLOCK(rom_lock); +-static void *cru_rom_addr; +-static struct cmn_registers cmn_regs; +- +-extern asmlinkage void asminline_call(struct cmn_registers *pi86Regs, +- unsigned long *pRomEntry); +- +-#ifdef CONFIG_X86_32 +-/* --32 Bit Bios------------------------------------------------------------ */ +- +-#define HPWDT_ARCH 32 +- +-asm(".text \n\t" +- ".align 4 \n\t" +- ".globl asminline_call \n" +- "asminline_call: \n\t" +- "pushl %ebp \n\t" +- "movl %esp, %ebp \n\t" +- "pusha \n\t" +- "pushf \n\t" +- "push %es \n\t" +- "push %ds \n\t" +- "pop %es \n\t" +- "movl 8(%ebp),%eax \n\t" +- "movl 4(%eax),%ebx \n\t" +- "movl 8(%eax),%ecx \n\t" +- "movl 12(%eax),%edx \n\t" +- "movl 16(%eax),%esi \n\t" +- "movl 20(%eax),%edi \n\t" +- "movl (%eax),%eax \n\t" +- "push %cs \n\t" +- "call *12(%ebp) \n\t" +- "pushf \n\t" +- "pushl %eax \n\t" +- "movl 8(%ebp),%eax \n\t" +- "movl %ebx,4(%eax) \n\t" +- "movl %ecx,8(%eax) \n\t" +- "movl %edx,12(%eax) \n\t" +- "movl %esi,16(%eax) \n\t" +- "movl %edi,20(%eax) \n\t" +- "movw %ds,24(%eax) \n\t" +- "movw %es,26(%eax) \n\t" +- "popl %ebx \n\t" +- "movl %ebx,(%eax) \n\t" +- "popl %ebx \n\t" +- "movl %ebx,28(%eax) \n\t" +- "pop %es \n\t" +- "popf \n\t" +- "popa \n\t" +- "leave \n\t" +- "ret \n\t" +- ".previous"); +- +- +-/* +- * cru_detect +- * +- * Routine Description: +- * This function uses the 32-bit BIOS Service Directory record to +- * search for a $CRU record. +- * +- * Return Value: +- * 0 : SUCCESS +- * <0 : FAILURE +- */ +-static int cru_detect(unsigned long map_entry, +- unsigned long map_offset) +-{ +- void *bios32_map; +- unsigned long *bios32_entrypoint; +- unsigned long cru_physical_address; +- unsigned long cru_length; +- unsigned long physical_bios_base = 0; +- unsigned long physical_bios_offset = 0; +- int retval = -ENODEV; +- +- bios32_map = ioremap(map_entry, (2 * PAGE_SIZE)); +- +- if (bios32_map == NULL) +- return -ENODEV; +- +- bios32_entrypoint = bios32_map + map_offset; +- +- cmn_regs.u1.reax = CRU_BIOS_SIGNATURE_VALUE; +- +- set_memory_x((unsigned long)bios32_map, 2); +- asminline_call(&cmn_regs, bios32_entrypoint); +- +- if (cmn_regs.u1.ral != 0) { +- pr_warn("Call succeeded but with an error: 0x%x\n", +- cmn_regs.u1.ral); +- } else { +- physical_bios_base = cmn_regs.u2.rebx; +- physical_bios_offset = cmn_regs.u4.redx; +- cru_length = cmn_regs.u3.recx; +- cru_physical_address = +- physical_bios_base + physical_bios_offset; +- +- /* If the values look OK, then map it in. */ +- if ((physical_bios_base + physical_bios_offset)) { +- cru_rom_addr = +- ioremap(cru_physical_address, cru_length); +- if (cru_rom_addr) { +- set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK, +- (cru_length + PAGE_SIZE - 1) >> PAGE_SHIFT); +- retval = 0; +- } +- } +- +- pr_debug("CRU Base Address: 0x%lx\n", physical_bios_base); +- pr_debug("CRU Offset Address: 0x%lx\n", physical_bios_offset); +- pr_debug("CRU Length: 0x%lx\n", cru_length); +- pr_debug("CRU Mapped Address: %p\n", &cru_rom_addr); +- } +- iounmap(bios32_map); +- return retval; +-} +- +-/* +- * bios_checksum +- */ +-static int bios_checksum(const char __iomem *ptr, int len) +-{ +- char sum = 0; +- int i; +- +- /* +- * calculate checksum of size bytes. This should add up +- * to zero if we have a valid header. +- */ +- for (i = 0; i < len; i++) +- sum += ptr[i]; +- +- return ((sum == 0) && (len > 0)); +-} +- +-/* +- * bios32_present +- * +- * Routine Description: +- * This function finds the 32-bit BIOS Service Directory +- * +- * Return Value: +- * 0 : SUCCESS +- * <0 : FAILURE +- */ +-static int bios32_present(const char __iomem *p) +-{ +- struct bios32_service_dir *bios_32_ptr; +- int length; +- unsigned long map_entry, map_offset; +- +- bios_32_ptr = (struct bios32_service_dir *) p; +- +- /* +- * Search for signature by checking equal to the swizzled value +- * instead of calling another routine to perform a strcmp. +- */ +- if (bios_32_ptr->signature == PCI_BIOS32_SD_VALUE) { +- length = bios_32_ptr->length * PCI_BIOS32_PARAGRAPH_LEN; +- if (bios_checksum(p, length)) { +- /* +- * According to the spec, we're looking for the +- * first 4KB-aligned address below the entrypoint +- * listed in the header. The Service Directory code +- * is guaranteed to occupy no more than 2 4KB pages. +- */ +- map_entry = bios_32_ptr->entry_point & ~(PAGE_SIZE - 1); +- map_offset = bios_32_ptr->entry_point - map_entry; +- +- return cru_detect(map_entry, map_offset); +- } +- } +- return -ENODEV; +-} +- +-static int detect_cru_service(void) +-{ +- char __iomem *p, *q; +- int rc = -1; +- +- /* +- * Search from 0x0f0000 through 0x0fffff, inclusive. +- */ +- p = ioremap(PCI_ROM_BASE1, ROM_SIZE); +- if (p == NULL) +- return -ENOMEM; +- +- for (q = p; q < p + ROM_SIZE; q += 16) { +- rc = bios32_present(q); +- if (!rc) +- break; +- } +- iounmap(p); +- return rc; +-} +-/* ------------------------------------------------------------------------- */ +-#endif /* CONFIG_X86_32 */ +-#ifdef CONFIG_X86_64 +-/* --64 Bit Bios------------------------------------------------------------ */ +- +-#define HPWDT_ARCH 64 +- +-asm(".text \n\t" +- ".align 4 \n\t" +- ".globl asminline_call \n\t" +- ".type asminline_call, @function \n\t" +- "asminline_call: \n\t" +- FRAME_BEGIN +- "pushq %rax \n\t" +- "pushq %rbx \n\t" +- "pushq %rdx \n\t" +- "pushq %r12 \n\t" +- "pushq %r9 \n\t" +- "movq %rsi, %r12 \n\t" +- "movq %rdi, %r9 \n\t" +- "movl 4(%r9),%ebx \n\t" +- "movl 8(%r9),%ecx \n\t" +- "movl 12(%r9),%edx \n\t" +- "movl 16(%r9),%esi \n\t" +- "movl 20(%r9),%edi \n\t" +- "movl (%r9),%eax \n\t" +- "call *%r12 \n\t" +- "pushfq \n\t" +- "popq %r12 \n\t" +- "movl %eax, (%r9) \n\t" +- "movl %ebx, 4(%r9) \n\t" +- "movl %ecx, 8(%r9) \n\t" +- "movl %edx, 12(%r9) \n\t" +- "movl %esi, 16(%r9) \n\t" +- "movl %edi, 20(%r9) \n\t" +- "movq %r12, %rax \n\t" +- "movl %eax, 28(%r9) \n\t" +- "popq %r9 \n\t" +- "popq %r12 \n\t" +- "popq %rdx \n\t" +- "popq %rbx \n\t" +- "popq %rax \n\t" +- FRAME_END +- "ret \n\t" +- ".previous"); +- +-/* +- * dmi_find_cru +- * +- * Routine Description: +- * This function checks whether or not a SMBIOS/DMI record is +- * the 64bit CRU info or not +- */ +-static void dmi_find_cru(const struct dmi_header *dm, void *dummy) +-{ +- struct smbios_cru64_info *smbios_cru64_ptr; +- unsigned long cru_physical_address; +- +- if (dm->type == SMBIOS_CRU64_INFORMATION) { +- smbios_cru64_ptr = (struct smbios_cru64_info *) dm; +- if (smbios_cru64_ptr->signature == CRU_BIOS_SIGNATURE_VALUE) { +- cru_physical_address = +- smbios_cru64_ptr->physical_address + +- smbios_cru64_ptr->double_offset; +- cru_rom_addr = ioremap(cru_physical_address, +- smbios_cru64_ptr->double_length); +- set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK, +- smbios_cru64_ptr->double_length >> PAGE_SHIFT); +- } +- } +-} +- +-static int detect_cru_service(void) +-{ +- cru_rom_addr = NULL; +- +- dmi_walk(dmi_find_cru, NULL); +- +- /* if cru_rom_addr has been set then we found a CRU service */ +- return ((cru_rom_addr != NULL) ? 0 : -ENODEV); +-} +-/* ------------------------------------------------------------------------- */ +-#endif /* CONFIG_X86_64 */ +-#endif /* CONFIG_HPWDT_NMI_DECODING */ + + /* + * Watchdog operations +@@ -486,30 +113,12 @@ static int hpwdt_my_nmi(void) + */ + static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) + { +- unsigned long rom_pl; +- static int die_nmi_called; +- +- if (!hpwdt_nmi_decoding) +- return NMI_DONE; +- + if ((ulReason == NMI_UNKNOWN) && !hpwdt_my_nmi()) + return NMI_DONE; + +- spin_lock_irqsave(&rom_lock, rom_pl); +- if (!die_nmi_called && !is_icru && !is_uefi) +- asminline_call(&cmn_regs, cru_rom_addr); +- die_nmi_called = 1; +- spin_unlock_irqrestore(&rom_lock, rom_pl); +- + if (allow_kdump) + hpwdt_stop(); + +- if (!is_icru && !is_uefi) { +- if (cmn_regs.u1.ral == 0) { +- nmi_panic(regs, "An NMI occurred, but unable to determine source.\n"); +- return NMI_HANDLED; +- } +- } + nmi_panic(regs, "An NMI occurred. Depending on your system the reason " + "for the NMI is logged in any one of the following " + "resources:\n" +@@ -675,84 +284,11 @@ static struct miscdevice hpwdt_miscdev = { + * Init & Exit + */ + +-#ifdef CONFIG_HPWDT_NMI_DECODING +-#ifdef CONFIG_X86_LOCAL_APIC +-static void hpwdt_check_nmi_decoding(struct pci_dev *dev) +-{ +- /* +- * If nmi_watchdog is turned off then we can turn on +- * our nmi decoding capability. +- */ +- hpwdt_nmi_decoding = 1; +-} +-#else +-static void hpwdt_check_nmi_decoding(struct pci_dev *dev) +-{ +- dev_warn(&dev->dev, "NMI decoding is disabled. " +- "Your kernel does not support a NMI Watchdog.\n"); +-} +-#endif /* CONFIG_X86_LOCAL_APIC */ +- +-/* +- * dmi_find_icru +- * +- * Routine Description: +- * This function checks whether or not we are on an iCRU-based server. +- * This check is independent of architecture and needs to be made for +- * any ProLiant system. +- */ +-static void dmi_find_icru(const struct dmi_header *dm, void *dummy) +-{ +- struct smbios_proliant_info *smbios_proliant_ptr; +- +- if (dm->type == SMBIOS_ICRU_INFORMATION) { +- smbios_proliant_ptr = (struct smbios_proliant_info *) dm; +- if (smbios_proliant_ptr->misc_features & 0x01) +- is_icru = 1; +- if (smbios_proliant_ptr->misc_features & 0x1400) +- is_uefi = 1; +- } +-} + + static int hpwdt_init_nmi_decoding(struct pci_dev *dev) + { ++#ifdef CONFIG_HPWDT_NMI_DECODING + int retval; +- +- /* +- * On typical CRU-based systems we need to map that service in +- * the BIOS. For 32 bit Operating Systems we need to go through +- * the 32 Bit BIOS Service Directory. For 64 bit Operating +- * Systems we get that service through SMBIOS. +- * +- * On systems that support the new iCRU service all we need to +- * do is call dmi_walk to get the supported flag value and skip +- * the old cru detect code. +- */ +- dmi_walk(dmi_find_icru, NULL); +- if (!is_icru && !is_uefi) { +- +- /* +- * We need to map the ROM to get the CRU service. +- * For 32 bit Operating Systems we need to go through the 32 Bit +- * BIOS Service Directory +- * For 64 bit Operating Systems we get that service through SMBIOS. +- */ +- retval = detect_cru_service(); +- if (retval < 0) { +- dev_warn(&dev->dev, +- "Unable to detect the %d Bit CRU Service.\n", +- HPWDT_ARCH); +- return retval; +- } +- +- /* +- * We know this is the only CRU call we need to make so lets keep as +- * few instructions as possible once the NMI comes in. +- */ +- cmn_regs.u1.rah = 0x0D; +- cmn_regs.u1.ral = 0x02; +- } +- + /* + * Only one function can register for NMI_UNKNOWN + */ +@@ -780,45 +316,26 @@ static int hpwdt_init_nmi_decoding(struct pci_dev *dev) + dev_warn(&dev->dev, + "Unable to register a die notifier (err=%d).\n", + retval); +- if (cru_rom_addr) +- iounmap(cru_rom_addr); + return retval; ++#endif /* CONFIG_HPWDT_NMI_DECODING */ ++ return 0; + } + + static void hpwdt_exit_nmi_decoding(void) + { ++#ifdef CONFIG_HPWDT_NMI_DECODING + unregister_nmi_handler(NMI_UNKNOWN, "hpwdt"); + unregister_nmi_handler(NMI_SERR, "hpwdt"); + unregister_nmi_handler(NMI_IO_CHECK, "hpwdt"); +- if (cru_rom_addr) +- iounmap(cru_rom_addr); +-} +-#else /* !CONFIG_HPWDT_NMI_DECODING */ +-static void hpwdt_check_nmi_decoding(struct pci_dev *dev) +-{ +-} +- +-static int hpwdt_init_nmi_decoding(struct pci_dev *dev) +-{ +- return 0; ++#endif + } + +-static void hpwdt_exit_nmi_decoding(void) +-{ +-} +-#endif /* CONFIG_HPWDT_NMI_DECODING */ +- + static int hpwdt_init_one(struct pci_dev *dev, + const struct pci_device_id *ent) + { + int retval; + + /* +- * Check if we can do NMI decoding or not +- */ +- hpwdt_check_nmi_decoding(dev); +- +- /* + * First let's find out if we are on an iLO2+ server. We will + * not run on a legacy ASM box. + * So we only support the G5 ProLiant servers and higher. +@@ -922,6 +439,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + #ifdef CONFIG_HPWDT_NMI_DECODING + module_param(allow_kdump, int, 0); + MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs"); +-#endif /* !CONFIG_HPWDT_NMI_DECODING */ ++#endif /* CONFIG_HPWDT_NMI_DECODING */ + + module_pci_driver(hpwdt_driver); +diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c +index 316c2eb..e8bd988 100644 +--- a/drivers/watchdog/sbsa_gwdt.c ++++ b/drivers/watchdog/sbsa_gwdt.c +@@ -50,6 +50,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -159,7 +160,7 @@ static unsigned int sbsa_gwdt_get_timeleft(struct watchdog_device *wdd) + !(readl(gwdt->control_base + SBSA_GWDT_WCS) & SBSA_GWDT_WCS_WS0)) + timeleft += readl(gwdt->control_base + SBSA_GWDT_WOR); + +- timeleft += readq(gwdt->control_base + SBSA_GWDT_WCV) - ++ timeleft += lo_hi_readq(gwdt->control_base + SBSA_GWDT_WCV) - + arch_counter_get_cntvct(); + + do_div(timeleft, gwdt->clk); +diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c +index 74888ca..ec9eb4f 100644 +--- a/drivers/xen/xenbus/xenbus_probe.c ++++ b/drivers/xen/xenbus/xenbus_probe.c +@@ -466,8 +466,11 @@ int xenbus_probe_node(struct xen_bus_type *bus, + + /* Register with generic device framework. */ + err = device_register(&xendev->dev); +- if (err) ++ if (err) { ++ put_device(&xendev->dev); ++ xendev = NULL; + goto fail; ++ } + + return 0; + fail: +diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c +index 8c10b05..621c517 100644 +--- a/fs/nfs/direct.c ++++ b/fs/nfs/direct.c +@@ -86,10 +86,10 @@ struct nfs_direct_req { + struct nfs_direct_mirror mirrors[NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX]; + int mirror_count; + ++ loff_t io_start; /* Start offset for I/O */ + ssize_t count, /* bytes actually processed */ + max_count, /* max expected count */ + bytes_left, /* bytes left to be sent */ +- io_start, /* start of IO */ + error; /* any reported error */ + struct completion completion; /* wait for i/o completion */ + +diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c +index c13e826..ee723aa 100644 +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -292,8 +292,11 @@ pnfs_detach_layout_hdr(struct pnfs_layout_hdr *lo) + void + pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo) + { +- struct inode *inode = lo->plh_inode; ++ struct inode *inode; + ++ if (!lo) ++ return; ++ inode = lo->plh_inode; + pnfs_layoutreturn_before_put_layout_hdr(lo); + + if (refcount_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) { +@@ -1241,10 +1244,12 @@ bool pnfs_roc(struct inode *ino, + spin_lock(&ino->i_lock); + lo = nfsi->layout; + if (!lo || !pnfs_layout_is_valid(lo) || +- test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) ++ test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) { ++ lo = NULL; + goto out_noroc; ++ } ++ pnfs_get_layout_hdr(lo); + if (test_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) { +- pnfs_get_layout_hdr(lo); + spin_unlock(&ino->i_lock); + wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN, + TASK_UNINTERRUPTIBLE); +@@ -1312,10 +1317,12 @@ bool pnfs_roc(struct inode *ino, + struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld; + if (ld->prepare_layoutreturn) + ld->prepare_layoutreturn(args); ++ pnfs_put_layout_hdr(lo); + return true; + } + if (layoutreturn) + pnfs_send_layoutreturn(lo, &stateid, iomode, true); ++ pnfs_put_layout_hdr(lo); + return false; + } + +diff --git a/fs/nfs/write.c b/fs/nfs/write.c +index 7428a66..e7d8cea 100644 +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -1876,40 +1876,43 @@ int nfs_generic_commit_list(struct inode *inode, struct list_head *head, + return status; + } + +-int nfs_commit_inode(struct inode *inode, int how) ++static int __nfs_commit_inode(struct inode *inode, int how, ++ struct writeback_control *wbc) + { + LIST_HEAD(head); + struct nfs_commit_info cinfo; + int may_wait = how & FLUSH_SYNC; +- int error = 0; +- int res; ++ int ret, nscan; + + nfs_init_cinfo_from_inode(&cinfo, inode); + nfs_commit_begin(cinfo.mds); +- res = nfs_scan_commit(inode, &head, &cinfo); +- if (res) +- error = nfs_generic_commit_list(inode, &head, how, &cinfo); ++ for (;;) { ++ ret = nscan = nfs_scan_commit(inode, &head, &cinfo); ++ if (ret <= 0) ++ break; ++ ret = nfs_generic_commit_list(inode, &head, how, &cinfo); ++ if (ret < 0) ++ break; ++ ret = 0; ++ if (wbc && wbc->sync_mode == WB_SYNC_NONE) { ++ if (nscan < wbc->nr_to_write) ++ wbc->nr_to_write -= nscan; ++ else ++ wbc->nr_to_write = 0; ++ } ++ if (nscan < INT_MAX) ++ break; ++ cond_resched(); ++ } + nfs_commit_end(cinfo.mds); +- if (res == 0) +- return res; +- if (error < 0) +- goto out_error; +- if (!may_wait) +- goto out_mark_dirty; +- error = wait_on_commit(cinfo.mds); +- if (error < 0) +- return error; +- return res; +-out_error: +- res = error; +- /* Note: If we exit without ensuring that the commit is complete, +- * we must mark the inode as dirty. Otherwise, future calls to +- * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure +- * that the data is on the disk. +- */ +-out_mark_dirty: +- __mark_inode_dirty(inode, I_DIRTY_DATASYNC); +- return res; ++ if (ret || !may_wait) ++ return ret; ++ return wait_on_commit(cinfo.mds); ++} ++ ++int nfs_commit_inode(struct inode *inode, int how) ++{ ++ return __nfs_commit_inode(inode, how, NULL); + } + EXPORT_SYMBOL_GPL(nfs_commit_inode); + +@@ -1919,11 +1922,11 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) + int flags = FLUSH_SYNC; + int ret = 0; + +- /* no commits means nothing needs to be done */ +- if (!atomic_long_read(&nfsi->commit_info.ncommit)) +- return ret; +- + if (wbc->sync_mode == WB_SYNC_NONE) { ++ /* no commits means nothing needs to be done */ ++ if (!atomic_long_read(&nfsi->commit_info.ncommit)) ++ goto check_requests_outstanding; ++ + /* Don't commit yet if this is a non-blocking flush and there + * are a lot of outstanding writes for this mapping. + */ +@@ -1934,16 +1937,16 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) + flags = 0; + } + +- ret = nfs_commit_inode(inode, flags); +- if (ret >= 0) { +- if (wbc->sync_mode == WB_SYNC_NONE) { +- if (ret < wbc->nr_to_write) +- wbc->nr_to_write -= ret; +- else +- wbc->nr_to_write = 0; +- } +- return 0; +- } ++ ret = __nfs_commit_inode(inode, flags, wbc); ++ if (!ret) { ++ if (flags & FLUSH_SYNC) ++ return 0; ++ } else if (atomic_long_read(&nfsi->commit_info.ncommit)) ++ goto out_mark_dirty; ++ ++check_requests_outstanding: ++ if (!atomic_read(&nfsi->commit_info.rpcs_out)) ++ return ret; + out_mark_dirty: + __mark_inode_dirty(inode, I_DIRTY_DATASYNC); + return ret; +diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h +index 88865e0..091033a 100644 +--- a/include/linux/of_pci.h ++++ b/include/linux/of_pci.h +@@ -13,7 +13,6 @@ struct device_node; + struct device_node *of_pci_find_child_device(struct device_node *parent, + unsigned int devfn); + int of_pci_get_devfn(struct device_node *np); +-int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin); + int of_pci_parse_bus_range(struct device_node *node, struct resource *res); + int of_get_pci_domain_nr(struct device_node *node); + int of_pci_get_max_link_speed(struct device_node *node); +@@ -34,12 +33,6 @@ static inline int of_pci_get_devfn(struct device_node *np) + } + + static inline int +-of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin) +-{ +- return 0; +-} +- +-static inline int + of_pci_parse_bus_range(struct device_node *node, struct resource *res) + { + return -EINVAL; +@@ -67,6 +60,16 @@ of_pci_get_max_link_speed(struct device_node *node) + static inline void of_pci_check_probe_only(void) { } + #endif + ++#if IS_ENABLED(CONFIG_OF_IRQ) ++int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin); ++#else ++static inline int ++of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ return 0; ++} ++#endif ++ + #if defined(CONFIG_OF_ADDRESS) + int of_pci_get_host_bridge_resources(struct device_node *dev, + unsigned char busno, unsigned char bus_max, +diff --git a/kernel/events/core.c b/kernel/events/core.c +index 96db9ae..4b83847 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -2246,7 +2246,7 @@ static void ctx_resched(struct perf_cpu_context *cpuctx, + struct perf_event_context *task_ctx, + enum event_type_t event_type) + { +- enum event_type_t ctx_event_type = event_type & EVENT_ALL; ++ enum event_type_t ctx_event_type; + bool cpu_event = !!(event_type & EVENT_CPU); + + /* +@@ -2256,6 +2256,8 @@ static void ctx_resched(struct perf_cpu_context *cpuctx, + if (event_type & EVENT_PINNED) + event_type |= EVENT_FLEXIBLE; + ++ ctx_event_type = event_type & EVENT_ALL; ++ + perf_pmu_disable(cpuctx->ctx.pmu); + if (task_ctx) + task_ctx_sched_out(cpuctx, task_ctx, event_type); +diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c +index 65cc0cb..940633c 100644 +--- a/kernel/locking/rtmutex.c ++++ b/kernel/locking/rtmutex.c +@@ -1616,11 +1616,12 @@ bool __sched __rt_mutex_futex_unlock(struct rt_mutex *lock, + void __sched rt_mutex_futex_unlock(struct rt_mutex *lock) + { + DEFINE_WAKE_Q(wake_q); ++ unsigned long flags; + bool postunlock; + +- raw_spin_lock_irq(&lock->wait_lock); ++ raw_spin_lock_irqsave(&lock->wait_lock, flags); + postunlock = __rt_mutex_futex_unlock(lock, &wake_q); +- raw_spin_unlock_irq(&lock->wait_lock); ++ raw_spin_unlock_irqrestore(&lock->wait_lock, flags); + + if (postunlock) + rt_mutex_postunlock(&wake_q); +diff --git a/kernel/panic.c b/kernel/panic.c +index 2cfef40..4b794f1 100644 +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -640,7 +640,7 @@ device_initcall(register_warn_debugfs); + */ + __visible void __stack_chk_fail(void) + { +- panic("stack-protector: Kernel stack is corrupted in: %p\n", ++ panic("stack-protector: Kernel stack is corrupted in: %pB\n", + __builtin_return_address(0)); + } + EXPORT_SYMBOL(__stack_chk_fail); +diff --git a/lib/bug.c b/lib/bug.c +index c1b0fad..1077366 100644 +--- a/lib/bug.c ++++ b/lib/bug.c +@@ -150,6 +150,8 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) + return BUG_TRAP_TYPE_NONE; + + bug = find_bug(bugaddr); ++ if (!bug) ++ return BUG_TRAP_TYPE_NONE; + + file = NULL; + line = 0; +@@ -191,7 +193,7 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) + if (file) + pr_crit("kernel BUG at %s:%u!\n", file, line); + else +- pr_crit("Kernel BUG at %p [verbose debug info unavailable]\n", ++ pr_crit("Kernel BUG at %pB [verbose debug info unavailable]\n", + (void *)bugaddr); + + return BUG_TRAP_TYPE_BUG; +diff --git a/lib/test_kmod.c b/lib/test_kmod.c +index e372b97..0e5b7a6 100644 +--- a/lib/test_kmod.c ++++ b/lib/test_kmod.c +@@ -1141,7 +1141,7 @@ static struct kmod_test_device *register_test_dev_kmod(void) + mutex_lock(®_dev_mutex); + + /* int should suffice for number of devices, test for wrap */ +- if (unlikely(num_test_devs + 1) < 0) { ++ if (num_test_devs + 1 == INT_MAX) { + pr_err("reached limit of number of test devices\n"); + goto out; + } +diff --git a/mm/gup.c b/mm/gup.c +index 1b46e6e..6afae32 100644 +--- a/mm/gup.c ++++ b/mm/gup.c +@@ -516,7 +516,7 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma, + } + + if (ret & VM_FAULT_RETRY) { +- if (nonblocking) ++ if (nonblocking && !(fault_flags & FAULT_FLAG_RETRY_NOWAIT)) + *nonblocking = 0; + return -EBUSY; + } +@@ -890,7 +890,10 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk, + break; + } + if (*locked) { +- /* VM_FAULT_RETRY didn't trigger */ ++ /* ++ * VM_FAULT_RETRY didn't trigger or it was a ++ * FOLL_NOWAIT. ++ */ + if (!pages_done) + pages_done = ret; + break; +diff --git a/mm/memblock.c b/mm/memblock.c +index 5a9ca2a..b6ba6b7 100644 +--- a/mm/memblock.c ++++ b/mm/memblock.c +@@ -1107,7 +1107,7 @@ unsigned long __init_memblock memblock_next_valid_pfn(unsigned long pfn, + struct memblock_type *type = &memblock.memory; + unsigned int right = type->cnt; + unsigned int mid, left = 0; +- phys_addr_t addr = PFN_PHYS(pfn + 1); ++ phys_addr_t addr = PFN_PHYS(++pfn); + + do { + mid = (right + left) / 2; +@@ -1118,15 +1118,15 @@ unsigned long __init_memblock memblock_next_valid_pfn(unsigned long pfn, + type->regions[mid].size)) + left = mid + 1; + else { +- /* addr is within the region, so pfn + 1 is valid */ +- return min(pfn + 1, max_pfn); ++ /* addr is within the region, so pfn is valid */ ++ return pfn; + } + } while (left < right); + + if (right == type->cnt) +- return max_pfn; ++ return -1UL; + else +- return min(PHYS_PFN(type->regions[right].base), max_pfn); ++ return PHYS_PFN(type->regions[right].base); + } + + /** +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index cb41672..3d974cb 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -5359,9 +5359,14 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone, + /* + * Skip to the pfn preceding the next valid one (or + * end_pfn), such that we hit a valid pfn (or end_pfn) +- * on our next iteration of the loop. ++ * on our next iteration of the loop. Note that it needs ++ * to be pageblock aligned even when the region itself ++ * is not. move_freepages_block() can shift ahead of ++ * the valid region but still depends on correct page ++ * metadata. + */ +- pfn = memblock_next_valid_pfn(pfn, end_pfn) - 1; ++ pfn = (memblock_next_valid_pfn(pfn, end_pfn) & ++ ~(pageblock_nr_pages-1)) - 1; + #endif + continue; + } +diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib +index 5589bae..a6f538b 100644 +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -297,11 +297,11 @@ cmd_dt_S_dtb= \ + echo '\#include '; \ + echo '.section .dtb.init.rodata,"a"'; \ + echo '.balign STRUCT_ALIGNMENT'; \ +- echo '.global __dtb_$(*F)_begin'; \ +- echo '__dtb_$(*F)_begin:'; \ ++ echo '.global __dtb_$(subst -,_,$(*F))_begin'; \ ++ echo '__dtb_$(subst -,_,$(*F))_begin:'; \ + echo '.incbin "$<" '; \ +- echo '__dtb_$(*F)_end:'; \ +- echo '.global __dtb_$(*F)_end'; \ ++ echo '__dtb_$(subst -,_,$(*F))_end:'; \ ++ echo '.global __dtb_$(subst -,_,$(*F))_end'; \ + echo '.balign STRUCT_ALIGNMENT'; \ + ) > $@ + +diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c +index fa3d39b6..449b68c 100644 +--- a/scripts/basic/fixdep.c ++++ b/scripts/basic/fixdep.c +@@ -93,14 +93,6 @@ + * (Note: it'd be easy to port over the complete mkdep state machine, + * but I don't think the added complexity is worth it) + */ +-/* +- * Note 2: if somebody writes HELLO_CONFIG_BOOM in a file, it will depend onto +- * CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not +- * fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as +- * UML_CONFIG_BOOM, to avoid conflicts with /usr/include/linux/autoconf.h, +- * through arch/um/include/uml-config.h; this fixdep "bug" makes sure that +- * those files will have correct dependencies. +- */ + + #include + #include +@@ -233,8 +225,13 @@ static int str_ends_with(const char *s, int slen, const char *sub) + static void parse_config_file(const char *p) + { + const char *q, *r; ++ const char *start = p; + + while ((p = strstr(p, "CONFIG_"))) { ++ if (p > start && (isalnum(p[-1]) || p[-1] == '_')) { ++ p += 7; ++ continue; ++ } + p += 7; + q = p; + while (*q && (isalnum(*q) || *q == '_')) +@@ -286,8 +283,6 @@ static int is_ignored_file(const char *s, int len) + { + return str_ends_with(s, len, "include/generated/autoconf.h") || + str_ends_with(s, len, "include/generated/autoksyms.h") || +- str_ends_with(s, len, "arch/um/include/uml-config.h") || +- str_ends_with(s, len, "include/linux/kconfig.h") || + str_ends_with(s, len, ".ver"); + } + +diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter +index 94b6648..d84a567 100755 +--- a/scripts/bloat-o-meter ++++ b/scripts/bloat-o-meter +@@ -15,7 +15,7 @@ signal(SIGPIPE, SIG_DFL) + if len(sys.argv) < 3: + sys.stderr.write("usage: %s [option] file1 file2\n" % sys.argv[0]) + sys.stderr.write("The options are:\n") +- sys.stderr.write("-c cateogrize output based on symbole type\n") ++ sys.stderr.write("-c categorize output based on symbol type\n") + sys.stderr.write("-d Show delta of Data Section\n") + sys.stderr.write("-t Show delta of text Section\n") + sys.exit(-1) +diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c +index 04d4db4..918338d 100644 +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -910,7 +910,8 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop) + static int snd_seq_client_enqueue_event(struct snd_seq_client *client, + struct snd_seq_event *event, + struct file *file, int blocking, +- int atomic, int hop) ++ int atomic, int hop, ++ struct mutex *mutexp) + { + struct snd_seq_event_cell *cell; + int err; +@@ -948,7 +949,8 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client, + return -ENXIO; /* queue is not allocated */ + + /* allocate an event cell */ +- err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, file); ++ err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, ++ file, mutexp); + if (err < 0) + return err; + +@@ -1017,12 +1019,11 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, + return -ENXIO; + + /* allocate the pool now if the pool is not allocated yet */ ++ mutex_lock(&client->ioctl_mutex); + if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) { +- mutex_lock(&client->ioctl_mutex); + err = snd_seq_pool_init(client->pool); +- mutex_unlock(&client->ioctl_mutex); + if (err < 0) +- return -ENOMEM; ++ goto out; + } + + /* only process whole events */ +@@ -1073,7 +1074,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, + /* ok, enqueue it */ + err = snd_seq_client_enqueue_event(client, &event, file, + !(file->f_flags & O_NONBLOCK), +- 0, 0); ++ 0, 0, &client->ioctl_mutex); + if (err < 0) + break; + +@@ -1084,6 +1085,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, + written += len; + } + ++ out: ++ mutex_unlock(&client->ioctl_mutex); + return written ? written : err; + } + +@@ -1838,9 +1841,11 @@ static int snd_seq_ioctl_set_client_pool(struct snd_seq_client *client, + (! snd_seq_write_pool_allocated(client) || + info->output_pool != client->pool->size)) { + if (snd_seq_write_pool_allocated(client)) { ++ /* is the pool in use? */ ++ if (atomic_read(&client->pool->counter)) ++ return -EBUSY; + /* remove all existing cells */ + snd_seq_pool_mark_closing(client->pool); +- snd_seq_queue_client_leave_cells(client->number); + snd_seq_pool_done(client->pool); + } + client->pool->size = info->output_pool; +@@ -2260,7 +2265,8 @@ static int kernel_client_enqueue(int client, struct snd_seq_event *ev, + if (! cptr->accept_output) + result = -EPERM; + else /* send it */ +- result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, atomic, hop); ++ result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, ++ atomic, hop, NULL); + + snd_seq_client_unlock(cptr); + return result; +diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c +index a8c2822..72c0302 100644 +--- a/sound/core/seq/seq_fifo.c ++++ b/sound/core/seq/seq_fifo.c +@@ -125,7 +125,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, + return -EINVAL; + + snd_use_lock_use(&f->use_lock); +- err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL); /* always non-blocking */ ++ err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL, NULL); /* always non-blocking */ + if (err < 0) { + if ((err == -ENOMEM) || (err == -EAGAIN)) + atomic_inc(&f->overflow); +diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c +index f763682..ab1112e9 100644 +--- a/sound/core/seq/seq_memory.c ++++ b/sound/core/seq/seq_memory.c +@@ -220,7 +220,8 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell) + */ + static int snd_seq_cell_alloc(struct snd_seq_pool *pool, + struct snd_seq_event_cell **cellp, +- int nonblock, struct file *file) ++ int nonblock, struct file *file, ++ struct mutex *mutexp) + { + struct snd_seq_event_cell *cell; + unsigned long flags; +@@ -244,7 +245,11 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool, + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&pool->output_sleep, &wait); + spin_unlock_irq(&pool->lock); ++ if (mutexp) ++ mutex_unlock(mutexp); + schedule(); ++ if (mutexp) ++ mutex_lock(mutexp); + spin_lock_irq(&pool->lock); + remove_wait_queue(&pool->output_sleep, &wait); + /* interrupted? */ +@@ -287,7 +292,7 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool, + */ + int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, + struct snd_seq_event_cell **cellp, int nonblock, +- struct file *file) ++ struct file *file, struct mutex *mutexp) + { + int ncells, err; + unsigned int extlen; +@@ -304,7 +309,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, + if (ncells >= pool->total_elements) + return -ENOMEM; + +- err = snd_seq_cell_alloc(pool, &cell, nonblock, file); ++ err = snd_seq_cell_alloc(pool, &cell, nonblock, file, mutexp); + if (err < 0) + return err; + +@@ -330,7 +335,8 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, + int size = sizeof(struct snd_seq_event); + if (len < size) + size = len; +- err = snd_seq_cell_alloc(pool, &tmp, nonblock, file); ++ err = snd_seq_cell_alloc(pool, &tmp, nonblock, file, ++ mutexp); + if (err < 0) + goto __error; + if (cell->event.data.ext.ptr == NULL) +diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h +index 32f959c..3abe306 100644 +--- a/sound/core/seq/seq_memory.h ++++ b/sound/core/seq/seq_memory.h +@@ -66,7 +66,8 @@ struct snd_seq_pool { + void snd_seq_cell_free(struct snd_seq_event_cell *cell); + + int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, +- struct snd_seq_event_cell **cellp, int nonblock, struct file *file); ++ struct snd_seq_event_cell **cellp, int nonblock, ++ struct file *file, struct mutex *mutexp); + + /* return number of unused (free) cells */ + static inline int snd_seq_unused_cells(struct snd_seq_pool *pool) +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index 37e1cf8..5b4dbce 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -957,6 +957,8 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { + SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC), + SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC), + SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK), ++ SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK), ++ SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), + SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), + SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO), +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index b9c93fa..9af301c 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -5274,6 +5274,16 @@ static void alc298_fixup_speaker_volume(struct hda_codec *codec, + } + } + ++/* disable DAC3 (0x06) selection on NID 0x17 as it has no volume amp control */ ++static void alc295_fixup_disable_dac3(struct hda_codec *codec, ++ const struct hda_fixup *fix, int action) ++{ ++ if (action == HDA_FIXUP_ACT_PRE_PROBE) { ++ hda_nid_t conn[2] = { 0x02, 0x03 }; ++ snd_hda_override_conn_list(codec, 0x17, 2, conn); ++ } ++} ++ + /* Hook to update amp GPIO4 for automute */ + static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec, + struct hda_jack_callback *jack) +@@ -5466,6 +5476,7 @@ enum { + ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, + ALC255_FIXUP_DELL_SPK_NOISE, + ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, ++ ALC295_FIXUP_DISABLE_DAC3, + ALC280_FIXUP_HP_HEADSET_MIC, + ALC221_FIXUP_HP_FRONT_MIC, + ALC292_FIXUP_TPT460, +@@ -5480,10 +5491,12 @@ enum { + ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE, + ALC233_FIXUP_LENOVO_MULTI_CODECS, + ALC294_FIXUP_LENOVO_MIC_LOCATION, ++ ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE, + ALC700_FIXUP_INTEL_REFERENCE, + ALC274_FIXUP_DELL_BIND_DACS, + ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, + ALC298_FIXUP_TPT470_DOCK, ++ ALC255_FIXUP_DUMMY_LINEOUT_VERB, + }; + + static const struct hda_fixup alc269_fixups[] = { +@@ -6198,6 +6211,10 @@ static const struct hda_fixup alc269_fixups[] = { + .chained = true, + .chain_id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE, + }, ++ [ALC295_FIXUP_DISABLE_DAC3] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc295_fixup_disable_dac3, ++ }, + [ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { +@@ -6283,6 +6300,18 @@ static const struct hda_fixup alc269_fixups[] = { + { } + }, + }, ++ [ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE] = { ++ .type = HDA_FIXUP_PINS, ++ .v.pins = (const struct hda_pintbl[]) { ++ { 0x16, 0x0101102f }, /* Rear Headset HP */ ++ { 0x19, 0x02a1913c }, /* use as Front headset mic, without its own jack detect */ ++ { 0x1a, 0x01a19030 }, /* Rear Headset MIC */ ++ { 0x1b, 0x02011020 }, ++ { } ++ }, ++ .chained = true, ++ .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC ++ }, + [ALC700_FIXUP_INTEL_REFERENCE] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { +@@ -6319,6 +6348,15 @@ static const struct hda_fixup alc269_fixups[] = { + .chained = true, + .chain_id = ALC293_FIXUP_LENOVO_SPK_NOISE + }, ++ [ALC255_FIXUP_DUMMY_LINEOUT_VERB] = { ++ .type = HDA_FIXUP_PINS, ++ .v.pins = (const struct hda_pintbl[]) { ++ { 0x14, 0x0201101f }, ++ { } ++ }, ++ .chained = true, ++ .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE ++ }, + }; + + static const struct snd_pci_quirk alc269_fixup_tbl[] = { +@@ -6367,10 +6405,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE), + SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), + SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME), ++ SND_PCI_QUIRK(0x1028, 0x07b0, "Dell Precision 7520", ALC295_FIXUP_DISABLE_DAC3), + SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER), ++ SND_PCI_QUIRK(0x1028, 0x080c, "Dell WYSE", ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x082a, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), + SND_PCI_QUIRK(0x1028, 0x084b, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), + SND_PCI_QUIRK(0x1028, 0x084e, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), ++ SND_PCI_QUIRK(0x1028, 0x0873, "Dell Precision 3930", ALC255_FIXUP_DUMMY_LINEOUT_VERB), + SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), +@@ -6508,9 +6549,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x17aa, 0x2245, "Thinkpad T470", ALC298_FIXUP_TPT470_DOCK), + SND_PCI_QUIRK(0x17aa, 0x2246, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), + SND_PCI_QUIRK(0x17aa, 0x2247, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), ++ SND_PCI_QUIRK(0x17aa, 0x2249, "Thinkpad", ALC292_FIXUP_TPT460), + SND_PCI_QUIRK(0x17aa, 0x224b, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), + SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), + SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), ++ SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), + SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), + SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), +@@ -6872,7 +6915,7 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { + {0x12, 0x90a60120}, + {0x14, 0x90170110}, + {0x21, 0x0321101f}), +- SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, ++ SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, + {0x12, 0xb7a60130}, + {0x14, 0x90170110}, + {0x21, 0x04211020}), +diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h +index 0dfe4d3..f41079d 100644 +--- a/tools/arch/x86/include/asm/cpufeatures.h ++++ b/tools/arch/x86/include/asm/cpufeatures.h +@@ -213,6 +213,7 @@ + #define X86_FEATURE_SEV ( 7*32+20) /* AMD Secure Encrypted Virtualization */ + + #define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */ ++#define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* "" Use IBRS during runtime firmware calls */ + + /* Virtualization flags: Linux defined, word 8 */ + #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ +diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h +index 0fb5ef9..7b26d4b 100644 +--- a/tools/include/uapi/linux/kvm.h ++++ b/tools/include/uapi/linux/kvm.h +@@ -761,6 +761,7 @@ struct kvm_ppc_resize_hpt { + #define KVM_TRACE_PAUSE __KVM_DEPRECATED_MAIN_0x07 + #define KVM_TRACE_DISABLE __KVM_DEPRECATED_MAIN_0x08 + #define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2) ++#define KVM_GET_MSR_FEATURE_INDEX_LIST _IOWR(KVMIO, 0x0a, struct kvm_msr_list) + + /* + * Extension capability list. +@@ -934,6 +935,7 @@ struct kvm_ppc_resize_hpt { + #define KVM_CAP_S390_AIS_MIGRATION 150 + #define KVM_CAP_PPC_GET_CPU_CHAR 151 + #define KVM_CAP_S390_BPB 152 ++#define KVM_CAP_GET_MSR_FEATURES 153 + + #ifdef KVM_CAP_IRQ_ROUTING + +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index 46c1d23..92b6a2c 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -1116,42 +1116,29 @@ static int read_unwind_hints(struct objtool_file *file) + + static int read_retpoline_hints(struct objtool_file *file) + { +- struct section *sec, *relasec; ++ struct section *sec; + struct instruction *insn; + struct rela *rela; +- int i; + +- sec = find_section_by_name(file->elf, ".discard.retpoline_safe"); ++ sec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe"); + if (!sec) + return 0; + +- relasec = sec->rela; +- if (!relasec) { +- WARN("missing .rela.discard.retpoline_safe section"); +- return -1; +- } +- +- if (sec->len % sizeof(unsigned long)) { +- WARN("retpoline_safe size mismatch: %d %ld", sec->len, sizeof(unsigned long)); +- return -1; +- } +- +- for (i = 0; i < sec->len / sizeof(unsigned long); i++) { +- rela = find_rela_by_dest(sec, i * sizeof(unsigned long)); +- if (!rela) { +- WARN("can't find rela for retpoline_safe[%d]", i); ++ list_for_each_entry(rela, &sec->rela_list, list) { ++ if (rela->sym->type != STT_SECTION) { ++ WARN("unexpected relocation symbol type in %s", sec->name); + return -1; + } + + insn = find_insn(file, rela->sym->sec, rela->addend); + if (!insn) { +- WARN("can't find insn for retpoline_safe[%d]", i); ++ WARN("bad .discard.retpoline_safe entry"); + return -1; + } + + if (insn->type != INSN_JUMP_DYNAMIC && + insn->type != INSN_CALL_DYNAMIC) { +- WARN_FUNC("retpoline_safe hint not a indirect jump/call", ++ WARN_FUNC("retpoline_safe hint not an indirect jump/call", + insn->sec, insn->offset); + return -1; + } +diff --git a/tools/perf/Documentation/perf-kallsyms.txt b/tools/perf/Documentation/perf-kallsyms.txt +index 954ea9e..cf9f404 100644 +--- a/tools/perf/Documentation/perf-kallsyms.txt ++++ b/tools/perf/Documentation/perf-kallsyms.txt +@@ -8,7 +8,7 @@ perf-kallsyms - Searches running kernel for symbols + SYNOPSIS + -------- + [verse] +-'perf kallsyms symbol_name[,symbol_name...]' ++'perf kallsyms' [] symbol_name[,symbol_name...] + + DESCRIPTION + ----------- +diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c +index bf4ca74..a217623 100644 +--- a/tools/perf/builtin-record.c ++++ b/tools/perf/builtin-record.c +@@ -881,6 +881,15 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) + } + } + ++ /* ++ * If we have just single event and are sending data ++ * through pipe, we need to force the ids allocation, ++ * because we synthesize event name through the pipe ++ * and need the id for that. ++ */ ++ if (data->is_pipe && rec->evlist->nr_entries == 1) ++ rec->opts.sample_id = true; ++ + if (record__open(rec) != 0) { + err = -1; + goto out_child; +diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c +index 98bf9d3..54a4c15 100644 +--- a/tools/perf/builtin-stat.c ++++ b/tools/perf/builtin-stat.c +@@ -917,7 +917,7 @@ static void print_metric_csv(void *ctx, + char buf[64], *vals, *ends; + + if (unit == NULL || fmt == NULL) { +- fprintf(out, "%s%s%s%s", csv_sep, csv_sep, csv_sep, csv_sep); ++ fprintf(out, "%s%s", csv_sep, csv_sep); + return; + } + snprintf(buf, sizeof(buf), fmt, val); +diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c +index b7c823b..35ac016 100644 +--- a/tools/perf/builtin-top.c ++++ b/tools/perf/builtin-top.c +@@ -991,7 +991,7 @@ static int perf_top_overwrite_fallback(struct perf_top *top, + evlist__for_each_entry(evlist, counter) + counter->attr.write_backward = false; + opts->overwrite = false; +- ui__warning("fall back to non-overwrite mode\n"); ++ pr_debug2("fall back to non-overwrite mode\n"); + return 1; + } + +diff --git a/tools/perf/perf.h b/tools/perf/perf.h +index cfe4623..57b9b34 100644 +--- a/tools/perf/perf.h ++++ b/tools/perf/perf.h +@@ -61,6 +61,7 @@ struct record_opts { + bool tail_synthesize; + bool overwrite; + bool ignore_missing_thread; ++ bool sample_id; + unsigned int freq; + unsigned int mmap_pages; + unsigned int auxtrace_mmap_pages; +diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c +index 2864279..fbf927c 100644 +--- a/tools/perf/ui/browsers/annotate.c ++++ b/tools/perf/ui/browsers/annotate.c +@@ -327,7 +327,32 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) + if (!disasm_line__is_valid_jump(cursor, sym)) + return; + ++ /* ++ * This first was seen with a gcc function, _cpp_lex_token, that ++ * has the usual jumps: ++ * ++ * │1159e6c: ↓ jne 115aa32 <_cpp_lex_token@@Base+0xf92> ++ * ++ * I.e. jumps to a label inside that function (_cpp_lex_token), and ++ * those works, but also this kind: ++ * ++ * │1159e8b: ↓ jne c469be ++ * ++ * I.e. jumps to another function, outside _cpp_lex_token, which ++ * are not being correctly handled generating as a side effect references ++ * to ab->offset[] entries that are set to NULL, so to make this code ++ * more robust, check that here. ++ * ++ * A proper fix for will be put in place, looking at the function ++ * name right after the '<' token and probably treating this like a ++ * 'call' instruction. ++ */ + target = ab->offsets[cursor->ops.target.offset]; ++ if (target == NULL) { ++ ui_helpline__printf("WARN: jump target inconsistency, press 'o', ab->offsets[%#x] = NULL\n", ++ cursor->ops.target.offset); ++ return; ++ } + + bcursor = browser_line(&cursor->al); + btarget = browser_line(target); +diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c +index 9faf3b5..6470ea2 100644 +--- a/tools/perf/util/auxtrace.c ++++ b/tools/perf/util/auxtrace.c +@@ -60,6 +60,12 @@ + #include "sane_ctype.h" + #include "symbol/kallsyms.h" + ++static bool auxtrace__dont_decode(struct perf_session *session) ++{ ++ return !session->itrace_synth_opts || ++ session->itrace_synth_opts->dont_decode; ++} ++ + int auxtrace_mmap__mmap(struct auxtrace_mmap *mm, + struct auxtrace_mmap_params *mp, + void *userpg, int fd) +@@ -762,6 +768,9 @@ int auxtrace_queues__process_index(struct auxtrace_queues *queues, + size_t i; + int err; + ++ if (auxtrace__dont_decode(session)) ++ return 0; ++ + list_for_each_entry(auxtrace_index, &session->auxtrace_index, list) { + for (i = 0; i < auxtrace_index->nr; i++) { + ent = &auxtrace_index->entries[i]; +@@ -892,12 +901,6 @@ int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr, + return err; + } + +-static bool auxtrace__dont_decode(struct perf_session *session) +-{ +- return !session->itrace_synth_opts || +- session->itrace_synth_opts->dont_decode; +-} +- + int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_session *session) +diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c +index 1e97937..6f09e49 100644 +--- a/tools/perf/util/record.c ++++ b/tools/perf/util/record.c +@@ -137,6 +137,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, + struct perf_evsel *evsel; + bool use_sample_identifier = false; + bool use_comm_exec; ++ bool sample_id = opts->sample_id; + + /* + * Set the evsel leader links before we configure attributes, +@@ -163,8 +164,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, + * match the id. + */ + use_sample_identifier = perf_can_sample_identifier(); +- evlist__for_each_entry(evlist, evsel) +- perf_evsel__set_sample_id(evsel, use_sample_identifier); ++ sample_id = true; + } else if (evlist->nr_entries > 1) { + struct perf_evsel *first = perf_evlist__first(evlist); + +@@ -174,6 +174,10 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, + use_sample_identifier = perf_can_sample_identifier(); + break; + } ++ sample_id = true; ++ } ++ ++ if (sample_id) { + evlist__for_each_entry(evlist, evsel) + perf_evsel__set_sample_id(evsel, use_sample_identifier); + } +diff --git a/tools/perf/util/trigger.h b/tools/perf/util/trigger.h +index 370138e..88223bc 100644 +--- a/tools/perf/util/trigger.h ++++ b/tools/perf/util/trigger.h +@@ -12,7 +12,7 @@ + * States and transits: + * + * +- * OFF--(on)--> READY --(hit)--> HIT ++ * OFF--> ON --> READY --(hit)--> HIT + * ^ | + * | (ready) + * | | +@@ -27,8 +27,9 @@ struct trigger { + volatile enum { + TRIGGER_ERROR = -2, + TRIGGER_OFF = -1, +- TRIGGER_READY = 0, +- TRIGGER_HIT = 1, ++ TRIGGER_ON = 0, ++ TRIGGER_READY = 1, ++ TRIGGER_HIT = 2, + } state; + const char *name; + }; +@@ -50,7 +51,7 @@ static inline bool trigger_is_error(struct trigger *t) + static inline void trigger_on(struct trigger *t) + { + TRIGGER_WARN_ONCE(t, TRIGGER_OFF); +- t->state = TRIGGER_READY; ++ t->state = TRIGGER_ON; + } + + static inline void trigger_ready(struct trigger *t) +diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests +index d256189..22d5646 100755 +--- a/tools/testing/selftests/vm/run_vmtests ++++ b/tools/testing/selftests/vm/run_vmtests +@@ -2,25 +2,33 @@ + # SPDX-License-Identifier: GPL-2.0 + #please run as root + +-#we need 256M, below is the size in kB +-needmem=262144 + mnt=./huge + exitcode=0 + +-#get pagesize and freepages from /proc/meminfo ++#get huge pagesize and freepages from /proc/meminfo + while read name size unit; do + if [ "$name" = "HugePages_Free:" ]; then + freepgs=$size + fi + if [ "$name" = "Hugepagesize:" ]; then +- pgsize=$size ++ hpgsize_KB=$size + fi + done < /proc/meminfo + ++# Simple hugetlbfs tests have a hardcoded minimum requirement of ++# huge pages totaling 256MB (262144KB) in size. The userfaultfd ++# hugetlb test requires a minimum of 2 * nr_cpus huge pages. Take ++# both of these requirements into account and attempt to increase ++# number of huge pages available. ++nr_cpus=$(nproc) ++hpgsize_MB=$((hpgsize_KB / 1024)) ++half_ufd_size_MB=$((((nr_cpus * hpgsize_MB + 127) / 128) * 128)) ++needmem_KB=$((half_ufd_size_MB * 2 * 1024)) ++ + #set proper nr_hugepages +-if [ -n "$freepgs" ] && [ -n "$pgsize" ]; then ++if [ -n "$freepgs" ] && [ -n "$hpgsize_KB" ]; then + nr_hugepgs=`cat /proc/sys/vm/nr_hugepages` +- needpgs=`expr $needmem / $pgsize` ++ needpgs=$((needmem_KB / hpgsize_KB)) + tries=2 + while [ $tries -gt 0 ] && [ $freepgs -lt $needpgs ]; do + lackpgs=$(( $needpgs - $freepgs )) +@@ -107,8 +115,9 @@ fi + echo "---------------------------" + echo "running userfaultfd_hugetlb" + echo "---------------------------" +-# 256MB total huge pages == 128MB src and 128MB dst +-./userfaultfd hugetlb 128 32 $mnt/ufd_test_file ++# Test requires source and destination huge pages. Size of source ++# (half_ufd_size_MB) is passed as argument to test. ++./userfaultfd hugetlb $half_ufd_size_MB 32 $mnt/ufd_test_file + if [ $? -ne 0 ]; then + echo "[FAIL]" + exitcode=1 +diff --git a/tools/testing/selftests/x86/test_vsyscall.c b/tools/testing/selftests/x86/test_vsyscall.c +index be81621..0b4f1cc 100644 +--- a/tools/testing/selftests/x86/test_vsyscall.c ++++ b/tools/testing/selftests/x86/test_vsyscall.c +@@ -450,7 +450,7 @@ static void sigtrap(int sig, siginfo_t *info, void *ctx_void) + num_vsyscall_traps++; + } + +-static int test_native_vsyscall(void) ++static int test_emulation(void) + { + time_t tmp; + bool is_native; +@@ -458,7 +458,7 @@ static int test_native_vsyscall(void) + if (!vtime) + return 0; + +- printf("[RUN]\tchecking for native vsyscall\n"); ++ printf("[RUN]\tchecking that vsyscalls are emulated\n"); + sethandler(SIGTRAP, sigtrap, 0); + set_eflags(get_eflags() | X86_EFLAGS_TF); + vtime(&tmp); +@@ -474,11 +474,12 @@ static int test_native_vsyscall(void) + */ + is_native = (num_vsyscall_traps > 1); + +- printf("\tvsyscalls are %s (%d instructions in vsyscall page)\n", ++ printf("[%s]\tvsyscalls are %s (%d instructions in vsyscall page)\n", ++ (is_native ? "FAIL" : "OK"), + (is_native ? "native" : "emulated"), + (int)num_vsyscall_traps); + +- return 0; ++ return is_native; + } + #endif + +@@ -498,7 +499,7 @@ int main(int argc, char **argv) + nerrs += test_vsys_r(); + + #ifdef __x86_64__ +- nerrs += test_native_vsyscall(); ++ nerrs += test_emulation(); + #endif + + return nerrs ? 1 : 0; diff --git a/diffs/diff3.diff b/diffs/diff3.diff new file mode 100644 index 0000000..24f8abf --- /dev/null +++ b/diffs/diff3.diff @@ -0,0 +1,14734 @@ +diff --git a/Documentation/accelerators/ocxl.rst b/Documentation/accelerators/ocxl.rst +index 4f7af84..ddcc58d 100644 +--- a/Documentation/accelerators/ocxl.rst ++++ b/Documentation/accelerators/ocxl.rst +@@ -152,6 +152,11 @@ OCXL_IOCTL_IRQ_SET_FD: + Associate an event fd to an AFU interrupt so that the user process + can be notified when the AFU sends an interrupt. + ++OCXL_IOCTL_GET_METADATA: ++ ++ Obtains configuration information from the card, such at the size of ++ MMIO areas, the AFU version, and the PASID for the current context. ++ + + mmap + ---- +diff --git a/Documentation/devicetree/bindings/dma/mv-xor-v2.txt b/Documentation/devicetree/bindings/dma/mv-xor-v2.txt +index 217a90e..9c38bbe 100644 +--- a/Documentation/devicetree/bindings/dma/mv-xor-v2.txt ++++ b/Documentation/devicetree/bindings/dma/mv-xor-v2.txt +@@ -11,7 +11,11 @@ Required properties: + interrupts. + + Optional properties: +-- clocks: Optional reference to the clock used by the XOR engine. ++- clocks: Optional reference to the clocks used by the XOR engine. ++- clock-names: mandatory if there is a second clock, in this case the ++ name must be "core" for the first clock and "reg" for the second ++ one ++ + + Example: + +diff --git a/Documentation/devicetree/bindings/net/renesas,ravb.txt b/Documentation/devicetree/bindings/net/renesas,ravb.txt +index c902261..92fd4b2 100644 +--- a/Documentation/devicetree/bindings/net/renesas,ravb.txt ++++ b/Documentation/devicetree/bindings/net/renesas,ravb.txt +@@ -18,6 +18,7 @@ Required properties: + - "renesas,etheravb-r8a7795" for the R8A7795 SoC. + - "renesas,etheravb-r8a7796" for the R8A7796 SoC. + - "renesas,etheravb-r8a77970" for the R8A77970 SoC. ++ - "renesas,etheravb-r8a77980" for the R8A77980 SoC. + - "renesas,etheravb-r8a77995" for the R8A77995 SoC. + - "renesas,etheravb-rcar-gen3" as a fallback for the above + R-Car Gen3 devices. +diff --git a/Documentation/ia64/serial.txt b/Documentation/ia64/serial.txt +index 6869c73..a63d2c5 100644 +--- a/Documentation/ia64/serial.txt ++++ b/Documentation/ia64/serial.txt +@@ -111,7 +111,7 @@ TROUBLESHOOTING SERIAL CONSOLE PROBLEMS + + - If you don't have an HCDP, the kernel doesn't know where + your console lives until the driver discovers serial +- devices. Use "console=uart, io,0x3f8" (or appropriate ++ devices. Use "console=uart,io,0x3f8" (or appropriate + address for your machine). + + Kernel and init script output works fine, but no "login:" prompt: +diff --git a/Documentation/sphinx/kerneldoc.py b/Documentation/sphinx/kerneldoc.py +index 39aa9e8..fbedcc3 100644 +--- a/Documentation/sphinx/kerneldoc.py ++++ b/Documentation/sphinx/kerneldoc.py +@@ -36,8 +36,7 @@ import glob + + from docutils import nodes, statemachine + from docutils.statemachine import ViewList +-from docutils.parsers.rst import directives +-from sphinx.util.compat import Directive ++from docutils.parsers.rst import directives, Directive + from sphinx.ext.autodoc import AutodocReporter + + __version__ = '1.0' +diff --git a/Makefile b/Makefile +index c4322de..e02d092 100644 +--- a/Makefile ++++ b/Makefile +@@ -2,7 +2,7 @@ + VERSION = 4 + PATCHLEVEL = 16 + SUBLEVEL = 0 +-EXTRAVERSION = -rc4 ++EXTRAVERSION = -rc5 + NAME = Fearless Coyote + + # *DOCUMENTATION* +diff --git a/arch/arm/mach-orion5x/Kconfig b/arch/arm/mach-orion5x/Kconfig +index 2a7bb6c..a810f4d 100644 +--- a/arch/arm/mach-orion5x/Kconfig ++++ b/arch/arm/mach-orion5x/Kconfig +@@ -58,7 +58,6 @@ config MACH_KUROBOX_PRO + + config MACH_DNS323 + bool "D-Link DNS-323" +- select GENERIC_NET_UTILS + select I2C_BOARDINFO if I2C + help + Say 'Y' here if you want your kernel to support the +@@ -66,7 +65,6 @@ config MACH_DNS323 + + config MACH_TS209 + bool "QNAP TS-109/TS-209" +- select GENERIC_NET_UTILS + help + Say 'Y' here if you want your kernel to support the + QNAP TS-109/TS-209 platform. +@@ -101,7 +99,6 @@ config MACH_LINKSTATION_LS_HGL + + config MACH_TS409 + bool "QNAP TS-409" +- select GENERIC_NET_UTILS + help + Say 'Y' here if you want your kernel to support the + QNAP TS-409 platform. +diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c +index cd483bf..d13344b 100644 +--- a/arch/arm/mach-orion5x/dns323-setup.c ++++ b/arch/arm/mach-orion5x/dns323-setup.c +@@ -173,10 +173,42 @@ static struct mv643xx_eth_platform_data dns323_eth_data = { + .phy_addr = MV643XX_ETH_PHY_ADDR(8), + }; + ++/* dns323_parse_hex_*() taken from tsx09-common.c; should a common copy of these ++ * functions be kept somewhere? ++ */ ++static int __init dns323_parse_hex_nibble(char n) ++{ ++ if (n >= '0' && n <= '9') ++ return n - '0'; ++ ++ if (n >= 'A' && n <= 'F') ++ return n - 'A' + 10; ++ ++ if (n >= 'a' && n <= 'f') ++ return n - 'a' + 10; ++ ++ return -1; ++} ++ ++static int __init dns323_parse_hex_byte(const char *b) ++{ ++ int hi; ++ int lo; ++ ++ hi = dns323_parse_hex_nibble(b[0]); ++ lo = dns323_parse_hex_nibble(b[1]); ++ ++ if (hi < 0 || lo < 0) ++ return -1; ++ ++ return (hi << 4) | lo; ++} ++ + static int __init dns323_read_mac_addr(void) + { + u_int8_t addr[6]; +- void __iomem *mac_page; ++ int i; ++ char *mac_page; + + /* MAC address is stored as a regular ol' string in /dev/mtdblock4 + * (0x007d0000-0x00800000) starting at offset 196480 (0x2ff80). +@@ -185,8 +217,23 @@ static int __init dns323_read_mac_addr(void) + if (!mac_page) + return -ENOMEM; + +- if (!mac_pton((__force const char *) mac_page, addr)) +- goto error_fail; ++ /* Sanity check the string we're looking at */ ++ for (i = 0; i < 5; i++) { ++ if (*(mac_page + (i * 3) + 2) != ':') { ++ goto error_fail; ++ } ++ } ++ ++ for (i = 0; i < 6; i++) { ++ int byte; ++ ++ byte = dns323_parse_hex_byte(mac_page + (i * 3)); ++ if (byte < 0) { ++ goto error_fail; ++ } ++ ++ addr[i] = byte; ++ } + + iounmap(mac_page); + printk("DNS-323: Found ethernet MAC address: %pM\n", addr); +diff --git a/arch/arm/mach-orion5x/tsx09-common.c b/arch/arm/mach-orion5x/tsx09-common.c +index 8977498..905d4f2 100644 +--- a/arch/arm/mach-orion5x/tsx09-common.c ++++ b/arch/arm/mach-orion5x/tsx09-common.c +@@ -53,12 +53,53 @@ struct mv643xx_eth_platform_data qnap_tsx09_eth_data = { + .phy_addr = MV643XX_ETH_PHY_ADDR(8), + }; + ++static int __init qnap_tsx09_parse_hex_nibble(char n) ++{ ++ if (n >= '0' && n <= '9') ++ return n - '0'; ++ ++ if (n >= 'A' && n <= 'F') ++ return n - 'A' + 10; ++ ++ if (n >= 'a' && n <= 'f') ++ return n - 'a' + 10; ++ ++ return -1; ++} ++ ++static int __init qnap_tsx09_parse_hex_byte(const char *b) ++{ ++ int hi; ++ int lo; ++ ++ hi = qnap_tsx09_parse_hex_nibble(b[0]); ++ lo = qnap_tsx09_parse_hex_nibble(b[1]); ++ ++ if (hi < 0 || lo < 0) ++ return -1; ++ ++ return (hi << 4) | lo; ++} ++ + static int __init qnap_tsx09_check_mac_addr(const char *addr_str) + { + u_int8_t addr[6]; ++ int i; + +- if (!mac_pton(addr_str, addr)) +- return -1; ++ for (i = 0; i < 6; i++) { ++ int byte; ++ ++ /* ++ * Enforce "xx:xx:xx:xx:xx:xx\n" format. ++ */ ++ if (addr_str[(i * 3) + 2] != ((i < 5) ? ':' : '\n')) ++ return -1; ++ ++ byte = qnap_tsx09_parse_hex_byte(addr_str + (i * 3)); ++ if (byte < 0) ++ return -1; ++ addr[i] = byte; ++ } + + printk(KERN_INFO "tsx09: found ethernet mac address %pM\n", addr); + +@@ -77,12 +118,12 @@ void __init qnap_tsx09_find_mac_addr(u32 mem_base, u32 size) + unsigned long addr; + + for (addr = mem_base; addr < (mem_base + size); addr += 1024) { +- void __iomem *nor_page; ++ char *nor_page; + int ret = 0; + + nor_page = ioremap(addr, 1024); + if (nor_page != NULL) { +- ret = qnap_tsx09_check_mac_addr((__force const char *)nor_page); ++ ret = qnap_tsx09_check_mac_addr(nor_page); + iounmap(nor_page); + } + +diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c +index 52f15cd..b5a2833 100644 +--- a/arch/arm64/kernel/cpu_errata.c ++++ b/arch/arm64/kernel/cpu_errata.c +@@ -178,7 +178,7 @@ static int enable_smccc_arch_workaround_1(void *data) + case PSCI_CONDUIT_HVC: + arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_ARCH_WORKAROUND_1, &res); +- if (res.a0) ++ if ((int)res.a0 < 0) + return 0; + cb = call_hvc_arch_workaround_1; + smccc_start = __smccc_workaround_1_hvc_start; +@@ -188,7 +188,7 @@ static int enable_smccc_arch_workaround_1(void *data) + case PSCI_CONDUIT_SMC: + arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_ARCH_WORKAROUND_1, &res); +- if (res.a0) ++ if ((int)res.a0 < 0) + return 0; + cb = call_smc_arch_workaround_1; + smccc_start = __smccc_workaround_1_smc_start; +diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c +index 84a019f..8c704f1 100644 +--- a/arch/arm64/mm/mmu.c ++++ b/arch/arm64/mm/mmu.c +@@ -108,7 +108,7 @@ static bool pgattr_change_is_safe(u64 old, u64 new) + * The following mapping attributes may be updated in live + * kernel mappings without the need for break-before-make. + */ +- static const pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE; ++ static const pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE | PTE_NG; + + /* creating or taking down mappings is always safe */ + if (old == 0 || new == 0) +@@ -118,9 +118,9 @@ static bool pgattr_change_is_safe(u64 old, u64 new) + if ((old | new) & PTE_CONT) + return false; + +- /* Transitioning from Global to Non-Global is safe */ +- if (((old ^ new) == PTE_NG) && (new & PTE_NG)) +- return true; ++ /* Transitioning from Non-Global to Global is unsafe */ ++ if (old & ~new & PTE_NG) ++ return false; + + return ((old ^ new) & ~mask) == 0; + } +diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h +index 762eeb0f..2524fb6 100644 +--- a/arch/ia64/include/asm/atomic.h ++++ b/arch/ia64/include/asm/atomic.h +@@ -66,38 +66,35 @@ ATOMIC_OPS(add, +) + ATOMIC_OPS(sub, -) + + #ifdef __OPTIMIZE__ +-#define __ia64_atomic_const(i) __builtin_constant_p(i) ? \ ++#define __ia64_atomic_const(i) \ ++ static const int __ia64_atomic_p = __builtin_constant_p(i) ? \ + ((i) == 1 || (i) == 4 || (i) == 8 || (i) == 16 || \ +- (i) == -1 || (i) == -4 || (i) == -8 || (i) == -16) : 0 ++ (i) == -1 || (i) == -4 || (i) == -8 || (i) == -16) : 0;\ ++ __ia64_atomic_p ++#else ++#define __ia64_atomic_const(i) 0 ++#endif + +-#define atomic_add_return(i, v) \ ++#define atomic_add_return(i,v) \ + ({ \ +- int __i = (i); \ +- static const int __ia64_atomic_p = __ia64_atomic_const(i); \ +- __ia64_atomic_p ? ia64_fetch_and_add(__i, &(v)->counter) : \ +- ia64_atomic_add(__i, v); \ ++ int __ia64_aar_i = (i); \ ++ __ia64_atomic_const(i) \ ++ ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \ ++ : ia64_atomic_add(__ia64_aar_i, v); \ + }) + +-#define atomic_sub_return(i, v) \ ++#define atomic_sub_return(i,v) \ + ({ \ +- int __i = (i); \ +- static const int __ia64_atomic_p = __ia64_atomic_const(i); \ +- __ia64_atomic_p ? ia64_fetch_and_add(-__i, &(v)->counter) : \ +- ia64_atomic_sub(__i, v); \ ++ int __ia64_asr_i = (i); \ ++ __ia64_atomic_const(i) \ ++ ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter) \ ++ : ia64_atomic_sub(__ia64_asr_i, v); \ + }) +-#else +-#define atomic_add_return(i, v) ia64_atomic_add(i, v) +-#define atomic_sub_return(i, v) ia64_atomic_sub(i, v) +-#endif + + #define atomic_fetch_add(i,v) \ + ({ \ + int __ia64_aar_i = (i); \ +- (__builtin_constant_p(i) \ +- && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ +- || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ +- || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ +- || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ ++ __ia64_atomic_const(i) \ + ? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq) \ + : ia64_atomic_fetch_add(__ia64_aar_i, v); \ + }) +@@ -105,11 +102,7 @@ ATOMIC_OPS(sub, -) + #define atomic_fetch_sub(i,v) \ + ({ \ + int __ia64_asr_i = (i); \ +- (__builtin_constant_p(i) \ +- && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ +- || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ +- || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ +- || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ ++ __ia64_atomic_const(i) \ + ? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq) \ + : ia64_atomic_fetch_sub(__ia64_asr_i, v); \ + }) +@@ -170,11 +163,7 @@ ATOMIC64_OPS(sub, -) + #define atomic64_add_return(i,v) \ + ({ \ + long __ia64_aar_i = (i); \ +- (__builtin_constant_p(i) \ +- && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ +- || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ +- || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ +- || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ ++ __ia64_atomic_const(i) \ + ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \ + : ia64_atomic64_add(__ia64_aar_i, v); \ + }) +@@ -182,11 +171,7 @@ ATOMIC64_OPS(sub, -) + #define atomic64_sub_return(i,v) \ + ({ \ + long __ia64_asr_i = (i); \ +- (__builtin_constant_p(i) \ +- && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ +- || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ +- || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ +- || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ ++ __ia64_atomic_const(i) \ + ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter) \ + : ia64_atomic64_sub(__ia64_asr_i, v); \ + }) +@@ -194,11 +179,7 @@ ATOMIC64_OPS(sub, -) + #define atomic64_fetch_add(i,v) \ + ({ \ + long __ia64_aar_i = (i); \ +- (__builtin_constant_p(i) \ +- && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ +- || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ +- || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ +- || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ ++ __ia64_atomic_const(i) \ + ? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq) \ + : ia64_atomic64_fetch_add(__ia64_aar_i, v); \ + }) +@@ -206,11 +187,7 @@ ATOMIC64_OPS(sub, -) + #define atomic64_fetch_sub(i,v) \ + ({ \ + long __ia64_asr_i = (i); \ +- (__builtin_constant_p(i) \ +- && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ +- || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ +- || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ +- || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ ++ __ia64_atomic_const(i) \ + ? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq) \ + : ia64_atomic64_fetch_sub(__ia64_asr_i, v); \ + }) +diff --git a/arch/ia64/kernel/err_inject.c b/arch/ia64/kernel/err_inject.c +index 85bba43..8b5b8e6b 100644 +--- a/arch/ia64/kernel/err_inject.c ++++ b/arch/ia64/kernel/err_inject.c +@@ -117,7 +117,7 @@ store_call_start(struct device *dev, struct device_attribute *attr, + + #ifdef ERR_INJ_DEBUG + printk(KERN_DEBUG "Returns: status=%d,\n", (int)status[cpu]); +- printk(KERN_DEBUG "capapbilities=%lx,\n", capabilities[cpu]); ++ printk(KERN_DEBUG "capabilities=%lx,\n", capabilities[cpu]); + printk(KERN_DEBUG "resources=%lx\n", resources[cpu]); + #endif + return size; +@@ -142,7 +142,7 @@ store_virtual_to_phys(struct device *dev, struct device_attribute *attr, + u64 virt_addr=simple_strtoull(buf, NULL, 16); + int ret; + +- ret = get_user_pages(virt_addr, 1, FOLL_WRITE, NULL, NULL); ++ ret = get_user_pages_fast(virt_addr, 1, FOLL_WRITE, NULL); + if (ret<=0) { + #ifdef ERR_INJ_DEBUG + printk("Virtual address %lx is not existing.\n",virt_addr); +diff --git a/arch/ia64/scripts/unwcheck.py b/arch/ia64/scripts/unwcheck.py +index 89f3a148..c55276e 100644 +--- a/arch/ia64/scripts/unwcheck.py ++++ b/arch/ia64/scripts/unwcheck.py +@@ -16,7 +16,7 @@ import re + import sys + + if len(sys.argv) != 2: +- print "Usage: %s FILE" % sys.argv[0] ++ print("Usage: %s FILE" % sys.argv[0]) + sys.exit(2) + + readelf = os.getenv("READELF", "readelf") +@@ -29,7 +29,7 @@ def check_func (func, slots, rlen_sum): + global num_errors + num_errors += 1 + if not func: func = "[%#x-%#x]" % (start, end) +- print "ERROR: %s: %lu slots, total region length = %lu" % (func, slots, rlen_sum) ++ print("ERROR: %s: %lu slots, total region length = %lu" % (func, slots, rlen_sum)) + return + + num_funcs = 0 +@@ -43,23 +43,23 @@ for line in os.popen("%s -u %s" % (readelf, sys.argv[1])): + check_func(func, slots, rlen_sum) + + func = m.group(1) +- start = long(m.group(2), 16) +- end = long(m.group(3), 16) ++ start = int(m.group(2), 16) ++ end = int(m.group(3), 16) + slots = 3 * (end - start) / 16 +- rlen_sum = 0L ++ rlen_sum = 0 + num_funcs += 1 + else: + m = rlen_pattern.match(line) + if m: +- rlen_sum += long(m.group(1)) ++ rlen_sum += int(m.group(1)) + check_func(func, slots, rlen_sum) + + if num_errors == 0: +- print "No errors detected in %u functions." % num_funcs ++ print("No errors detected in %u functions." % num_funcs) + else: + if num_errors > 1: + err="errors" + else: + err="error" +- print "%u %s detected in %u functions." % (num_errors, err, num_funcs) ++ print("%u %s detected in %u functions." % (num_errors, err, num_funcs)) + sys.exit(1) +diff --git a/arch/mips/ath25/board.c b/arch/mips/ath25/board.c +index 9ab48ff..6d11ae5 100644 +--- a/arch/mips/ath25/board.c ++++ b/arch/mips/ath25/board.c +@@ -135,6 +135,8 @@ int __init ath25_find_config(phys_addr_t base, unsigned long size) + } + + board_data = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL); ++ if (!board_data) ++ goto error; + ath25_board.config = (struct ath25_boarddata *)board_data; + memcpy_fromio(board_data, bcfg, 0x100); + if (broken_boarddata) { +diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c +index 5b3a3f6..d99f524 100644 +--- a/arch/mips/cavium-octeon/octeon-irq.c ++++ b/arch/mips/cavium-octeon/octeon-irq.c +@@ -2277,6 +2277,8 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, + } + + host_data = kzalloc(sizeof(*host_data), GFP_KERNEL); ++ if (!host_data) ++ return -ENOMEM; + raw_spin_lock_init(&host_data->lock); + + addr = of_get_address(ciu_node, 0, NULL, NULL); +diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c +index 9d41732..159e83a 100644 +--- a/arch/mips/kernel/smp-bmips.c ++++ b/arch/mips/kernel/smp-bmips.c +@@ -168,11 +168,11 @@ static void bmips_prepare_cpus(unsigned int max_cpus) + return; + } + +- if (request_irq(IPI0_IRQ, bmips_ipi_interrupt, IRQF_PERCPU, +- "smp_ipi0", NULL)) ++ if (request_irq(IPI0_IRQ, bmips_ipi_interrupt, ++ IRQF_PERCPU | IRQF_NO_SUSPEND, "smp_ipi0", NULL)) + panic("Can't request IPI0 interrupt"); +- if (request_irq(IPI1_IRQ, bmips_ipi_interrupt, IRQF_PERCPU, +- "smp_ipi1", NULL)) ++ if (request_irq(IPI1_IRQ, bmips_ipi_interrupt, ++ IRQF_PERCPU | IRQF_NO_SUSPEND, "smp_ipi1", NULL)) + panic("Can't request IPI1 interrupt"); + } + +diff --git a/arch/mips/loongson64/Kconfig b/arch/mips/loongson64/Kconfig +index bc2fdbf..72af0c1 100644 +--- a/arch/mips/loongson64/Kconfig ++++ b/arch/mips/loongson64/Kconfig +@@ -7,6 +7,8 @@ choice + config LEMOTE_FULOONG2E + bool "Lemote Fuloong(2e) mini-PC" + select ARCH_SPARSEMEM_ENABLE ++ select ARCH_MIGHT_HAVE_PC_PARPORT ++ select ARCH_MIGHT_HAVE_PC_SERIO + select CEVT_R4K + select CSRC_R4K + select SYS_HAS_CPU_LOONGSON2E +@@ -33,6 +35,8 @@ config LEMOTE_FULOONG2E + config LEMOTE_MACH2F + bool "Lemote Loongson 2F family machines" + select ARCH_SPARSEMEM_ENABLE ++ select ARCH_MIGHT_HAVE_PC_PARPORT ++ select ARCH_MIGHT_HAVE_PC_SERIO + select BOARD_SCACHE + select BOOT_ELF32 + select CEVT_R4K if ! MIPS_EXTERNAL_TIMER +@@ -62,6 +66,8 @@ config LEMOTE_MACH2F + config LOONGSON_MACH3X + bool "Generic Loongson 3 family machines" + select ARCH_SPARSEMEM_ENABLE ++ select ARCH_MIGHT_HAVE_PC_PARPORT ++ select ARCH_MIGHT_HAVE_PC_SERIO + select GENERIC_ISA_DMA_SUPPORT_BROKEN + select BOOT_ELF32 + select BOARD_SCACHE +diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile +index ef6549e..26d5d2a 100644 +--- a/arch/powerpc/boot/Makefile ++++ b/arch/powerpc/boot/Makefile +@@ -101,7 +101,8 @@ $(addprefix $(obj)/,$(zlib-y)): \ + libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c + libfdtheader := fdt.h libfdt.h libfdt_internal.h + +-$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o): \ ++$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o \ ++ treeboot-akebono.o treeboot-currituck.o treeboot-iss4xx.o): \ + $(addprefix $(obj)/,$(libfdtheader)) + + src-wlib-y := string.S crt0.S stdio.c decompress.c main.c \ +diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c +index d22c41c..acf4b2e 100644 +--- a/arch/powerpc/kernel/prom_init.c ++++ b/arch/powerpc/kernel/prom_init.c +@@ -874,7 +874,6 @@ struct ibm_arch_vec __cacheline_aligned ibm_architecture_vec = { + .mmu = 0, + .hash_ext = 0, + .radix_ext = 0, +- .byte22 = 0, + }, + + /* option vector 6: IBM PAPR hints */ +diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c +index 0c85481..5cb4e46 100644 +--- a/arch/powerpc/kvm/book3s_64_mmu_radix.c ++++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c +@@ -195,6 +195,12 @@ static void kvmppc_pte_free(pte_t *ptep) + kmem_cache_free(kvm_pte_cache, ptep); + } + ++/* Like pmd_huge() and pmd_large(), but works regardless of config options */ ++static inline int pmd_is_leaf(pmd_t pmd) ++{ ++ return !!(pmd_val(pmd) & _PAGE_PTE); ++} ++ + static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa, + unsigned int level, unsigned long mmu_seq) + { +@@ -219,7 +225,7 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa, + else + new_pmd = pmd_alloc_one(kvm->mm, gpa); + +- if (level == 0 && !(pmd && pmd_present(*pmd))) ++ if (level == 0 && !(pmd && pmd_present(*pmd) && !pmd_is_leaf(*pmd))) + new_ptep = kvmppc_pte_alloc(); + + /* Check if we might have been invalidated; let the guest retry if so */ +@@ -244,12 +250,30 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa, + new_pmd = NULL; + } + pmd = pmd_offset(pud, gpa); +- if (pmd_large(*pmd)) { +- /* Someone else has instantiated a large page here; retry */ +- ret = -EAGAIN; +- goto out_unlock; +- } +- if (level == 1 && !pmd_none(*pmd)) { ++ if (pmd_is_leaf(*pmd)) { ++ unsigned long lgpa = gpa & PMD_MASK; ++ ++ /* ++ * If we raced with another CPU which has just put ++ * a 2MB pte in after we saw a pte page, try again. ++ */ ++ if (level == 0 && !new_ptep) { ++ ret = -EAGAIN; ++ goto out_unlock; ++ } ++ /* Valid 2MB page here already, remove it */ ++ old = kvmppc_radix_update_pte(kvm, pmdp_ptep(pmd), ++ ~0UL, 0, lgpa, PMD_SHIFT); ++ kvmppc_radix_tlbie_page(kvm, lgpa, PMD_SHIFT); ++ if (old & _PAGE_DIRTY) { ++ unsigned long gfn = lgpa >> PAGE_SHIFT; ++ struct kvm_memory_slot *memslot; ++ memslot = gfn_to_memslot(kvm, gfn); ++ if (memslot && memslot->dirty_bitmap) ++ kvmppc_update_dirty_map(memslot, ++ gfn, PMD_SIZE); ++ } ++ } else if (level == 1 && !pmd_none(*pmd)) { + /* + * There's a page table page here, but we wanted + * to install a large page. Tell the caller and let +@@ -412,28 +436,24 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, + } else { + page = pages[0]; + pfn = page_to_pfn(page); +- if (PageHuge(page)) { +- page = compound_head(page); +- pte_size <<= compound_order(page); ++ if (PageCompound(page)) { ++ pte_size <<= compound_order(compound_head(page)); + /* See if we can insert a 2MB large-page PTE here */ + if (pte_size >= PMD_SIZE && +- (gpa & PMD_MASK & PAGE_MASK) == +- (hva & PMD_MASK & PAGE_MASK)) { ++ (gpa & (PMD_SIZE - PAGE_SIZE)) == ++ (hva & (PMD_SIZE - PAGE_SIZE))) { + level = 1; + pfn &= ~((PMD_SIZE >> PAGE_SHIFT) - 1); + } + } + /* See if we can provide write access */ + if (writing) { +- /* +- * We assume gup_fast has set dirty on the host PTE. +- */ + pgflags |= _PAGE_WRITE; + } else { + local_irq_save(flags); + ptep = find_current_mm_pte(current->mm->pgd, + hva, NULL, NULL); +- if (ptep && pte_write(*ptep) && pte_dirty(*ptep)) ++ if (ptep && pte_write(*ptep)) + pgflags |= _PAGE_WRITE; + local_irq_restore(flags); + } +@@ -459,18 +479,15 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, + pte = pfn_pte(pfn, __pgprot(pgflags)); + ret = kvmppc_create_pte(kvm, pte, gpa, level, mmu_seq); + } +- if (ret == 0 || ret == -EAGAIN) +- ret = RESUME_GUEST; + + if (page) { +- /* +- * We drop pages[0] here, not page because page might +- * have been set to the head page of a compound, but +- * we have to drop the reference on the correct tail +- * page to match the get inside gup() +- */ +- put_page(pages[0]); ++ if (!ret && (pgflags & _PAGE_WRITE)) ++ set_page_dirty_lock(page); ++ put_page(page); + } ++ ++ if (ret == 0 || ret == -EAGAIN) ++ ret = RESUME_GUEST; + return ret; + } + +@@ -644,7 +661,7 @@ void kvmppc_free_radix(struct kvm *kvm) + continue; + pmd = pmd_offset(pud, 0); + for (im = 0; im < PTRS_PER_PMD; ++im, ++pmd) { +- if (pmd_huge(*pmd)) { ++ if (pmd_is_leaf(*pmd)) { + pmd_clear(pmd); + continue; + } +diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c +index 8970735..9cb9448 100644 +--- a/arch/powerpc/kvm/book3s_hv.c ++++ b/arch/powerpc/kvm/book3s_hv.c +@@ -2885,7 +2885,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) + */ + trace_hardirqs_on(); + +- guest_enter(); ++ guest_enter_irqoff(); + + srcu_idx = srcu_read_lock(&vc->kvm->srcu); + +@@ -2893,8 +2893,6 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) + + srcu_read_unlock(&vc->kvm->srcu, srcu_idx); + +- guest_exit(); +- + trace_hardirqs_off(); + set_irq_happened(trap); + +@@ -2937,6 +2935,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) + kvmppc_set_host_core(pcpu); + + local_irq_enable(); ++ guest_exit(); + + /* Let secondaries go back to the offline loop */ + for (i = 0; i < controlled_threads; ++i) { +@@ -3656,15 +3655,17 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu) + goto up_out; + + psize = vma_kernel_pagesize(vma); +- porder = __ilog2(psize); + + up_read(¤t->mm->mmap_sem); + + /* We can handle 4k, 64k or 16M pages in the VRMA */ +- err = -EINVAL; +- if (!(psize == 0x1000 || psize == 0x10000 || +- psize == 0x1000000)) +- goto out_srcu; ++ if (psize >= 0x1000000) ++ psize = 0x1000000; ++ else if (psize >= 0x10000) ++ psize = 0x10000; ++ else ++ psize = 0x1000; ++ porder = __ilog2(psize); + + senc = slb_pgsize_encoding(psize); + kvm->arch.vrma_slb_v = senc | SLB_VSID_B_1T | +diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c +index 403e642..52c2053 100644 +--- a/arch/powerpc/kvm/powerpc.c ++++ b/arch/powerpc/kvm/powerpc.c +@@ -1345,7 +1345,7 @@ static int kvmppc_emulate_mmio_vsx_loadstore(struct kvm_vcpu *vcpu, + int kvmppc_handle_load128_by2x64(struct kvm_run *run, struct kvm_vcpu *vcpu, + unsigned int rt, int is_default_endian) + { +- enum emulation_result emulated; ++ enum emulation_result emulated = EMULATE_DONE; + + while (vcpu->arch.mmio_vmx_copy_nums) { + emulated = __kvmppc_handle_load(run, vcpu, rt, 8, +@@ -1608,7 +1608,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) + + kvm_sigset_deactivate(vcpu); + ++#ifdef CONFIG_ALTIVEC + out: ++#endif + vcpu_put(vcpu); + return r; + } +diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c +index 0a34b0c..0ef3d95 100644 +--- a/arch/powerpc/net/bpf_jit_comp64.c ++++ b/arch/powerpc/net/bpf_jit_comp64.c +@@ -240,6 +240,7 @@ static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 + * goto out; + */ + PPC_LWZ(b2p[TMP_REG_1], b2p_bpf_array, offsetof(struct bpf_array, map.max_entries)); ++ PPC_RLWINM(b2p_index, b2p_index, 0, 0, 31); + PPC_CMPLW(b2p_index, b2p[TMP_REG_1]); + PPC_BCC(COND_GE, out); + +diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h +index 65154ea..6c8ce15 100644 +--- a/arch/s390/include/asm/mmu_context.h ++++ b/arch/s390/include/asm/mmu_context.h +@@ -63,6 +63,7 @@ static inline int init_new_context(struct task_struct *tsk, + _ASCE_USER_BITS | _ASCE_TYPE_SEGMENT; + /* pgd_alloc() did not account this pmd */ + mm_inc_nr_pmds(mm); ++ mm_inc_nr_puds(mm); + } + crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm)); + return 0; +diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S +index 13a133a..a5621ea 100644 +--- a/arch/s390/kernel/entry.S ++++ b/arch/s390/kernel/entry.S +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -230,7 +231,7 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART) + .hidden \name + .type \name,@function + \name: +- .cfi_startproc ++ CFI_STARTPROC + #ifdef CONFIG_HAVE_MARCH_Z10_FEATURES + exrl 0,0f + #else +@@ -239,7 +240,7 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART) + #endif + j . + 0: br \reg +- .cfi_endproc ++ CFI_ENDPROC + .endm + + GEN_BR_THUNK __s390x_indirect_jump_r1use_r9,%r9,%r1 +@@ -426,13 +427,13 @@ ENTRY(system_call) + UPDATE_VTIME %r8,%r9,__LC_SYNC_ENTER_TIMER + BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP + stmg %r0,%r7,__PT_R0(%r11) +- # clear user controlled register to prevent speculative use +- xgr %r0,%r0 + mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC + mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW + mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC + stg %r14,__PT_FLAGS(%r11) + .Lsysc_do_svc: ++ # clear user controlled register to prevent speculative use ++ xgr %r0,%r0 + # load address of system call table + lg %r10,__THREAD_sysc_table(%r13,%r12) + llgh %r8,__PT_INT_CODE+2(%r11) +@@ -1439,6 +1440,7 @@ cleanup_critical: + stg %r15,__LC_SYSTEM_TIMER + 0: # update accounting time stamp + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER ++ BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP + # set up saved register r11 + lg %r15,__LC_KERNEL_STACK + la %r9,STACK_FRAME_OVERHEAD(%r15) +diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c +index 69d7fcf..9aff72d 100644 +--- a/arch/s390/kernel/nospec-branch.c ++++ b/arch/s390/kernel/nospec-branch.c +@@ -2,8 +2,8 @@ + #include + #include + +-int nospec_call_disable = IS_ENABLED(EXPOLINE_OFF); +-int nospec_return_disable = !IS_ENABLED(EXPOLINE_FULL); ++int nospec_call_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); ++int nospec_return_disable = !IS_ENABLED(CONFIG_EXPOLINE_FULL); + + static int __init nospectre_v2_setup_early(char *str) + { +diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c +index 77d7818..339ac09 100644 +--- a/arch/s390/kvm/kvm-s390.c ++++ b/arch/s390/kvm/kvm-s390.c +@@ -86,6 +86,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { + { "deliver_prefix_signal", VCPU_STAT(deliver_prefix_signal) }, + { "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) }, + { "deliver_program_interruption", VCPU_STAT(deliver_program_int) }, ++ { "deliver_io_interrupt", VCPU_STAT(deliver_io_int) }, + { "exit_wait_state", VCPU_STAT(exit_wait_state) }, + { "instruction_epsw", VCPU_STAT(instruction_epsw) }, + { "instruction_gs", VCPU_STAT(instruction_gs) }, +@@ -2146,6 +2147,7 @@ static void sca_add_vcpu(struct kvm_vcpu *vcpu) + /* we still need the basic sca for the ipte control */ + vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32); + vcpu->arch.sie_block->scaol = (__u32)(__u64)sca; ++ return; + } + read_lock(&vcpu->kvm->arch.sca_lock); + if (vcpu->kvm->arch.use_esca) { +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index eb7f43f..0fa71a7 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -2307,7 +2307,7 @@ choice + it can be used to assist security vulnerability exploitation. + + This setting can be changed at boot time via the kernel command +- line parameter vsyscall=[native|emulate|none]. ++ line parameter vsyscall=[emulate|none]. + + On a system with recent enough glibc (2.14 or newer) and no + static binaries, you can say None without a performance penalty +@@ -2315,15 +2315,6 @@ choice + + If unsure, select "Emulate". + +- config LEGACY_VSYSCALL_NATIVE +- bool "Native" +- help +- Actual executable code is located in the fixed vsyscall +- address mapping, implementing time() efficiently. Since +- this makes the mapping executable, it can be used during +- security vulnerability exploitation (traditionally as +- ROP gadgets). This configuration is not recommended. +- + config LEGACY_VSYSCALL_EMULATE + bool "Emulate" + help +diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S +index e811dd9..08425c4 100644 +--- a/arch/x86/entry/entry_64_compat.S ++++ b/arch/x86/entry/entry_64_compat.S +@@ -363,9 +363,7 @@ ENTRY(entry_INT80_compat) + pushq 2*8(%rdi) /* regs->ip */ + pushq 1*8(%rdi) /* regs->orig_ax */ + +- movq (%rdi), %rdi /* restore %rdi */ +- +- pushq %rdi /* pt_regs->di */ ++ pushq (%rdi) /* pt_regs->di */ + pushq %rsi /* pt_regs->si */ + pushq %rdx /* pt_regs->dx */ + pushq %rcx /* pt_regs->cx */ +@@ -406,15 +404,3 @@ ENTRY(entry_INT80_compat) + TRACE_IRQS_ON + jmp swapgs_restore_regs_and_return_to_usermode + END(entry_INT80_compat) +- +-ENTRY(stub32_clone) +- /* +- * The 32-bit clone ABI is: clone(..., int tls_val, int *child_tidptr). +- * The 64-bit clone ABI is: clone(..., int *child_tidptr, int tls_val). +- * +- * The native 64-bit kernel's sys_clone() implements the latter, +- * so we need to swap arguments here before calling it: +- */ +- xchg %r8, %rcx +- jmp sys_clone +-ENDPROC(stub32_clone) +diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl +index 448ac21..2a5e99c 100644 +--- a/arch/x86/entry/syscalls/syscall_32.tbl ++++ b/arch/x86/entry/syscalls/syscall_32.tbl +@@ -8,12 +8,12 @@ + # + 0 i386 restart_syscall sys_restart_syscall + 1 i386 exit sys_exit +-2 i386 fork sys_fork sys_fork ++2 i386 fork sys_fork + 3 i386 read sys_read + 4 i386 write sys_write + 5 i386 open sys_open compat_sys_open + 6 i386 close sys_close +-7 i386 waitpid sys_waitpid sys32_waitpid ++7 i386 waitpid sys_waitpid compat_sys_x86_waitpid + 8 i386 creat sys_creat + 9 i386 link sys_link + 10 i386 unlink sys_unlink +@@ -78,7 +78,7 @@ + 69 i386 ssetmask sys_ssetmask + 70 i386 setreuid sys_setreuid16 + 71 i386 setregid sys_setregid16 +-72 i386 sigsuspend sys_sigsuspend sys_sigsuspend ++72 i386 sigsuspend sys_sigsuspend + 73 i386 sigpending sys_sigpending compat_sys_sigpending + 74 i386 sethostname sys_sethostname + 75 i386 setrlimit sys_setrlimit compat_sys_setrlimit +@@ -96,7 +96,7 @@ + 87 i386 swapon sys_swapon + 88 i386 reboot sys_reboot + 89 i386 readdir sys_old_readdir compat_sys_old_readdir +-90 i386 mmap sys_old_mmap sys32_mmap ++90 i386 mmap sys_old_mmap compat_sys_x86_mmap + 91 i386 munmap sys_munmap + 92 i386 truncate sys_truncate compat_sys_truncate + 93 i386 ftruncate sys_ftruncate compat_sys_ftruncate +@@ -126,7 +126,7 @@ + 117 i386 ipc sys_ipc compat_sys_ipc + 118 i386 fsync sys_fsync + 119 i386 sigreturn sys_sigreturn sys32_sigreturn +-120 i386 clone sys_clone stub32_clone ++120 i386 clone sys_clone compat_sys_x86_clone + 121 i386 setdomainname sys_setdomainname + 122 i386 uname sys_newuname + 123 i386 modify_ldt sys_modify_ldt +@@ -186,8 +186,8 @@ + 177 i386 rt_sigtimedwait sys_rt_sigtimedwait compat_sys_rt_sigtimedwait + 178 i386 rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo + 179 i386 rt_sigsuspend sys_rt_sigsuspend +-180 i386 pread64 sys_pread64 sys32_pread +-181 i386 pwrite64 sys_pwrite64 sys32_pwrite ++180 i386 pread64 sys_pread64 compat_sys_x86_pread ++181 i386 pwrite64 sys_pwrite64 compat_sys_x86_pwrite + 182 i386 chown sys_chown16 + 183 i386 getcwd sys_getcwd + 184 i386 capget sys_capget +@@ -196,14 +196,14 @@ + 187 i386 sendfile sys_sendfile compat_sys_sendfile + 188 i386 getpmsg + 189 i386 putpmsg +-190 i386 vfork sys_vfork sys_vfork ++190 i386 vfork sys_vfork + 191 i386 ugetrlimit sys_getrlimit compat_sys_getrlimit + 192 i386 mmap2 sys_mmap_pgoff +-193 i386 truncate64 sys_truncate64 sys32_truncate64 +-194 i386 ftruncate64 sys_ftruncate64 sys32_ftruncate64 +-195 i386 stat64 sys_stat64 sys32_stat64 +-196 i386 lstat64 sys_lstat64 sys32_lstat64 +-197 i386 fstat64 sys_fstat64 sys32_fstat64 ++193 i386 truncate64 sys_truncate64 compat_sys_x86_truncate64 ++194 i386 ftruncate64 sys_ftruncate64 compat_sys_x86_ftruncate64 ++195 i386 stat64 sys_stat64 compat_sys_x86_stat64 ++196 i386 lstat64 sys_lstat64 compat_sys_x86_lstat64 ++197 i386 fstat64 sys_fstat64 compat_sys_x86_fstat64 + 198 i386 lchown32 sys_lchown + 199 i386 getuid32 sys_getuid + 200 i386 getgid32 sys_getgid +@@ -231,7 +231,7 @@ + # 222 is unused + # 223 is unused + 224 i386 gettid sys_gettid +-225 i386 readahead sys_readahead sys32_readahead ++225 i386 readahead sys_readahead compat_sys_x86_readahead + 226 i386 setxattr sys_setxattr + 227 i386 lsetxattr sys_lsetxattr + 228 i386 fsetxattr sys_fsetxattr +@@ -256,7 +256,7 @@ + 247 i386 io_getevents sys_io_getevents compat_sys_io_getevents + 248 i386 io_submit sys_io_submit compat_sys_io_submit + 249 i386 io_cancel sys_io_cancel +-250 i386 fadvise64 sys_fadvise64 sys32_fadvise64 ++250 i386 fadvise64 sys_fadvise64 compat_sys_x86_fadvise64 + # 251 is available for reuse (was briefly sys_set_zone_reclaim) + 252 i386 exit_group sys_exit_group + 253 i386 lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie +@@ -278,7 +278,7 @@ + 269 i386 fstatfs64 sys_fstatfs64 compat_sys_fstatfs64 + 270 i386 tgkill sys_tgkill + 271 i386 utimes sys_utimes compat_sys_utimes +-272 i386 fadvise64_64 sys_fadvise64_64 sys32_fadvise64_64 ++272 i386 fadvise64_64 sys_fadvise64_64 compat_sys_x86_fadvise64_64 + 273 i386 vserver + 274 i386 mbind sys_mbind + 275 i386 get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy +@@ -306,7 +306,7 @@ + 297 i386 mknodat sys_mknodat + 298 i386 fchownat sys_fchownat + 299 i386 futimesat sys_futimesat compat_sys_futimesat +-300 i386 fstatat64 sys_fstatat64 sys32_fstatat ++300 i386 fstatat64 sys_fstatat64 compat_sys_x86_fstatat + 301 i386 unlinkat sys_unlinkat + 302 i386 renameat sys_renameat + 303 i386 linkat sys_linkat +@@ -320,7 +320,7 @@ + 311 i386 set_robust_list sys_set_robust_list compat_sys_set_robust_list + 312 i386 get_robust_list sys_get_robust_list compat_sys_get_robust_list + 313 i386 splice sys_splice +-314 i386 sync_file_range sys_sync_file_range sys32_sync_file_range ++314 i386 sync_file_range sys_sync_file_range compat_sys_x86_sync_file_range + 315 i386 tee sys_tee + 316 i386 vmsplice sys_vmsplice compat_sys_vmsplice + 317 i386 move_pages sys_move_pages compat_sys_move_pages +@@ -330,7 +330,7 @@ + 321 i386 signalfd sys_signalfd compat_sys_signalfd + 322 i386 timerfd_create sys_timerfd_create + 323 i386 eventfd sys_eventfd +-324 i386 fallocate sys_fallocate sys32_fallocate ++324 i386 fallocate sys_fallocate compat_sys_x86_fallocate + 325 i386 timerfd_settime sys_timerfd_settime compat_sys_timerfd_settime + 326 i386 timerfd_gettime sys_timerfd_gettime compat_sys_timerfd_gettime + 327 i386 signalfd4 sys_signalfd4 compat_sys_signalfd4 +diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c +index 577fa8a..8560ef6 100644 +--- a/arch/x86/entry/vsyscall/vsyscall_64.c ++++ b/arch/x86/entry/vsyscall/vsyscall_64.c +@@ -42,10 +42,8 @@ + #define CREATE_TRACE_POINTS + #include "vsyscall_trace.h" + +-static enum { EMULATE, NATIVE, NONE } vsyscall_mode = +-#if defined(CONFIG_LEGACY_VSYSCALL_NATIVE) +- NATIVE; +-#elif defined(CONFIG_LEGACY_VSYSCALL_NONE) ++static enum { EMULATE, NONE } vsyscall_mode = ++#ifdef CONFIG_LEGACY_VSYSCALL_NONE + NONE; + #else + EMULATE; +@@ -56,8 +54,6 @@ static int __init vsyscall_setup(char *str) + if (str) { + if (!strcmp("emulate", str)) + vsyscall_mode = EMULATE; +- else if (!strcmp("native", str)) +- vsyscall_mode = NATIVE; + else if (!strcmp("none", str)) + vsyscall_mode = NONE; + else +@@ -139,10 +135,6 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) + + WARN_ON_ONCE(address != regs->ip); + +- /* This should be unreachable in NATIVE mode. */ +- if (WARN_ON(vsyscall_mode == NATIVE)) +- return false; +- + if (vsyscall_mode == NONE) { + warn_bad_vsyscall(KERN_INFO, regs, + "vsyscall attempted with vsyscall=none"); +@@ -370,9 +362,7 @@ void __init map_vsyscall(void) + + if (vsyscall_mode != NONE) { + __set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall, +- vsyscall_mode == NATIVE +- ? PAGE_KERNEL_VSYSCALL +- : PAGE_KERNEL_VVAR); ++ PAGE_KERNEL_VVAR); + set_vsyscall_pgtable_user_bits(swapper_pg_dir); + } + +diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c +index 6d8044a..22ec65b 100644 +--- a/arch/x86/events/intel/uncore_snbep.c ++++ b/arch/x86/events/intel/uncore_snbep.c +@@ -3606,7 +3606,7 @@ static struct intel_uncore_type skx_uncore_imc = { + }; + + static struct attribute *skx_upi_uncore_formats_attr[] = { +- &format_attr_event_ext.attr, ++ &format_attr_event.attr, + &format_attr_umask_ext.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, +diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c +index 96cd33b..6512498 100644 +--- a/arch/x86/ia32/sys_ia32.c ++++ b/arch/x86/ia32/sys_ia32.c +@@ -51,15 +51,14 @@ + #define AA(__x) ((unsigned long)(__x)) + + +-asmlinkage long sys32_truncate64(const char __user *filename, +- unsigned long offset_low, +- unsigned long offset_high) ++COMPAT_SYSCALL_DEFINE3(x86_truncate64, const char __user *, filename, ++ unsigned long, offset_low, unsigned long, offset_high) + { + return sys_truncate(filename, ((loff_t) offset_high << 32) | offset_low); + } + +-asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long offset_low, +- unsigned long offset_high) ++COMPAT_SYSCALL_DEFINE3(x86_ftruncate64, unsigned int, fd, ++ unsigned long, offset_low, unsigned long, offset_high) + { + return sys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low); + } +@@ -96,8 +95,8 @@ static int cp_stat64(struct stat64 __user *ubuf, struct kstat *stat) + return 0; + } + +-asmlinkage long sys32_stat64(const char __user *filename, +- struct stat64 __user *statbuf) ++COMPAT_SYSCALL_DEFINE2(x86_stat64, const char __user *, filename, ++ struct stat64 __user *, statbuf) + { + struct kstat stat; + int ret = vfs_stat(filename, &stat); +@@ -107,8 +106,8 @@ asmlinkage long sys32_stat64(const char __user *filename, + return ret; + } + +-asmlinkage long sys32_lstat64(const char __user *filename, +- struct stat64 __user *statbuf) ++COMPAT_SYSCALL_DEFINE2(x86_lstat64, const char __user *, filename, ++ struct stat64 __user *, statbuf) + { + struct kstat stat; + int ret = vfs_lstat(filename, &stat); +@@ -117,7 +116,8 @@ asmlinkage long sys32_lstat64(const char __user *filename, + return ret; + } + +-asmlinkage long sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf) ++COMPAT_SYSCALL_DEFINE2(x86_fstat64, unsigned int, fd, ++ struct stat64 __user *, statbuf) + { + struct kstat stat; + int ret = vfs_fstat(fd, &stat); +@@ -126,8 +126,9 @@ asmlinkage long sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf) + return ret; + } + +-asmlinkage long sys32_fstatat(unsigned int dfd, const char __user *filename, +- struct stat64 __user *statbuf, int flag) ++COMPAT_SYSCALL_DEFINE4(x86_fstatat, unsigned int, dfd, ++ const char __user *, filename, ++ struct stat64 __user *, statbuf, int, flag) + { + struct kstat stat; + int error; +@@ -153,7 +154,7 @@ struct mmap_arg_struct32 { + unsigned int offset; + }; + +-asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *arg) ++COMPAT_SYSCALL_DEFINE1(x86_mmap, struct mmap_arg_struct32 __user *, arg) + { + struct mmap_arg_struct32 a; + +@@ -167,22 +168,22 @@ asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *arg) + a.offset>>PAGE_SHIFT); + } + +-asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int __user *stat_addr, +- int options) ++COMPAT_SYSCALL_DEFINE3(x86_waitpid, compat_pid_t, pid, unsigned int __user *, ++ stat_addr, int, options) + { + return compat_sys_wait4(pid, stat_addr, options, NULL); + } + + /* warning: next two assume little endian */ +-asmlinkage long sys32_pread(unsigned int fd, char __user *ubuf, u32 count, +- u32 poslo, u32 poshi) ++COMPAT_SYSCALL_DEFINE5(x86_pread, unsigned int, fd, char __user *, ubuf, ++ u32, count, u32, poslo, u32, poshi) + { + return sys_pread64(fd, ubuf, count, + ((loff_t)AA(poshi) << 32) | AA(poslo)); + } + +-asmlinkage long sys32_pwrite(unsigned int fd, const char __user *ubuf, +- u32 count, u32 poslo, u32 poshi) ++COMPAT_SYSCALL_DEFINE5(x86_pwrite, unsigned int, fd, const char __user *, ubuf, ++ u32, count, u32, poslo, u32, poshi) + { + return sys_pwrite64(fd, ubuf, count, + ((loff_t)AA(poshi) << 32) | AA(poslo)); +@@ -193,8 +194,9 @@ asmlinkage long sys32_pwrite(unsigned int fd, const char __user *ubuf, + * Some system calls that need sign extended arguments. This could be + * done by a generic wrapper. + */ +-long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, +- __u32 len_low, __u32 len_high, int advice) ++COMPAT_SYSCALL_DEFINE6(x86_fadvise64_64, int, fd, __u32, offset_low, ++ __u32, offset_high, __u32, len_low, __u32, len_high, ++ int, advice) + { + return sys_fadvise64_64(fd, + (((u64)offset_high)<<32) | offset_low, +@@ -202,31 +204,43 @@ long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, + advice); + } + +-asmlinkage ssize_t sys32_readahead(int fd, unsigned off_lo, unsigned off_hi, +- size_t count) ++COMPAT_SYSCALL_DEFINE4(x86_readahead, int, fd, unsigned int, off_lo, ++ unsigned int, off_hi, size_t, count) + { + return sys_readahead(fd, ((u64)off_hi << 32) | off_lo, count); + } + +-asmlinkage long sys32_sync_file_range(int fd, unsigned off_low, unsigned off_hi, +- unsigned n_low, unsigned n_hi, int flags) ++COMPAT_SYSCALL_DEFINE6(x86_sync_file_range, int, fd, unsigned int, off_low, ++ unsigned int, off_hi, unsigned int, n_low, ++ unsigned int, n_hi, int, flags) + { + return sys_sync_file_range(fd, + ((u64)off_hi << 32) | off_low, + ((u64)n_hi << 32) | n_low, flags); + } + +-asmlinkage long sys32_fadvise64(int fd, unsigned offset_lo, unsigned offset_hi, +- size_t len, int advice) ++COMPAT_SYSCALL_DEFINE5(x86_fadvise64, int, fd, unsigned int, offset_lo, ++ unsigned int, offset_hi, size_t, len, int, advice) + { + return sys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo, + len, advice); + } + +-asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo, +- unsigned offset_hi, unsigned len_lo, +- unsigned len_hi) ++COMPAT_SYSCALL_DEFINE6(x86_fallocate, int, fd, int, mode, ++ unsigned int, offset_lo, unsigned int, offset_hi, ++ unsigned int, len_lo, unsigned int, len_hi) + { + return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo, + ((u64)len_hi << 32) | len_lo); + } ++ ++/* ++ * The 32-bit clone ABI is CONFIG_CLONE_BACKWARDS ++ */ ++COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags, ++ unsigned long, newsp, int __user *, parent_tidptr, ++ unsigned long, tls_val, int __user *, child_tidptr) ++{ ++ return sys_clone(clone_flags, newsp, parent_tidptr, child_tidptr, ++ tls_val); ++} +diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h +index 246f15b..acfe755 100644 +--- a/arch/x86/include/asm/pgtable_types.h ++++ b/arch/x86/include/asm/pgtable_types.h +@@ -174,7 +174,6 @@ enum page_cache_mode { + #define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) + #define __PAGE_KERNEL_RX (__PAGE_KERNEL_EXEC & ~_PAGE_RW) + #define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_NOCACHE) +-#define __PAGE_KERNEL_VSYSCALL (__PAGE_KERNEL_RX | _PAGE_USER) + #define __PAGE_KERNEL_VVAR (__PAGE_KERNEL_RO | _PAGE_USER) + #define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) + #define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) +@@ -206,7 +205,6 @@ enum page_cache_mode { + #define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE | _PAGE_ENC) + #define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE | _PAGE_ENC) + #define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC | _PAGE_ENC) +-#define PAGE_KERNEL_VSYSCALL __pgprot(__PAGE_KERNEL_VSYSCALL | _PAGE_ENC) + #define PAGE_KERNEL_VVAR __pgprot(__PAGE_KERNEL_VVAR | _PAGE_ENC) + + #define PAGE_KERNEL_IO __pgprot(__PAGE_KERNEL_IO) +diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h +index d6baf23..5c019d2 100644 +--- a/arch/x86/include/asm/sections.h ++++ b/arch/x86/include/asm/sections.h +@@ -10,6 +10,7 @@ extern struct exception_table_entry __stop___ex_table[]; + + #if defined(CONFIG_X86_64) + extern char __end_rodata_hpage_align[]; ++extern char __entry_trampoline_start[], __entry_trampoline_end[]; + #endif + + #endif /* _ASM_X86_SECTIONS_H */ +diff --git a/arch/x86/include/asm/sys_ia32.h b/arch/x86/include/asm/sys_ia32.h +index 82c34ee..906794a 100644 +--- a/arch/x86/include/asm/sys_ia32.h ++++ b/arch/x86/include/asm/sys_ia32.h +@@ -20,31 +20,43 @@ + #include + + /* ia32/sys_ia32.c */ +-asmlinkage long sys32_truncate64(const char __user *, unsigned long, unsigned long); +-asmlinkage long sys32_ftruncate64(unsigned int, unsigned long, unsigned long); ++asmlinkage long compat_sys_x86_truncate64(const char __user *, unsigned long, ++ unsigned long); ++asmlinkage long compat_sys_x86_ftruncate64(unsigned int, unsigned long, ++ unsigned long); + +-asmlinkage long sys32_stat64(const char __user *, struct stat64 __user *); +-asmlinkage long sys32_lstat64(const char __user *, struct stat64 __user *); +-asmlinkage long sys32_fstat64(unsigned int, struct stat64 __user *); +-asmlinkage long sys32_fstatat(unsigned int, const char __user *, ++asmlinkage long compat_sys_x86_stat64(const char __user *, ++ struct stat64 __user *); ++asmlinkage long compat_sys_x86_lstat64(const char __user *, ++ struct stat64 __user *); ++asmlinkage long compat_sys_x86_fstat64(unsigned int, struct stat64 __user *); ++asmlinkage long compat_sys_x86_fstatat(unsigned int, const char __user *, + struct stat64 __user *, int); + struct mmap_arg_struct32; +-asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *); ++asmlinkage long compat_sys_x86_mmap(struct mmap_arg_struct32 __user *); + +-asmlinkage long sys32_waitpid(compat_pid_t, unsigned int __user *, int); ++asmlinkage long compat_sys_x86_waitpid(compat_pid_t, unsigned int __user *, ++ int); + +-asmlinkage long sys32_pread(unsigned int, char __user *, u32, u32, u32); +-asmlinkage long sys32_pwrite(unsigned int, const char __user *, u32, u32, u32); ++asmlinkage long compat_sys_x86_pread(unsigned int, char __user *, u32, u32, ++ u32); ++asmlinkage long compat_sys_x86_pwrite(unsigned int, const char __user *, u32, ++ u32, u32); + +-long sys32_fadvise64_64(int, __u32, __u32, __u32, __u32, int); +-long sys32_vm86_warning(void); ++asmlinkage long compat_sys_x86_fadvise64_64(int, __u32, __u32, __u32, __u32, ++ int); + +-asmlinkage ssize_t sys32_readahead(int, unsigned, unsigned, size_t); +-asmlinkage long sys32_sync_file_range(int, unsigned, unsigned, +- unsigned, unsigned, int); +-asmlinkage long sys32_fadvise64(int, unsigned, unsigned, size_t, int); +-asmlinkage long sys32_fallocate(int, int, unsigned, +- unsigned, unsigned, unsigned); ++asmlinkage ssize_t compat_sys_x86_readahead(int, unsigned int, unsigned int, ++ size_t); ++asmlinkage long compat_sys_x86_sync_file_range(int, unsigned int, unsigned int, ++ unsigned int, unsigned int, ++ int); ++asmlinkage long compat_sys_x86_fadvise64(int, unsigned int, unsigned int, ++ size_t, int); ++asmlinkage long compat_sys_x86_fallocate(int, int, unsigned int, unsigned int, ++ unsigned int, unsigned int); ++asmlinkage long compat_sys_x86_clone(unsigned long, unsigned long, int __user *, ++ unsigned long, int __user *); + + /* ia32/ia32_signal.c */ + asmlinkage long sys32_sigreturn(void); +diff --git a/arch/x86/include/uapi/asm/mce.h b/arch/x86/include/uapi/asm/mce.h +index 91723461..435db58 100644 +--- a/arch/x86/include/uapi/asm/mce.h ++++ b/arch/x86/include/uapi/asm/mce.h +@@ -30,6 +30,7 @@ struct mce { + __u64 synd; /* MCA_SYND MSR: only valid on SMCA systems */ + __u64 ipid; /* MCA_IPID MSR: only valid on SMCA systems */ + __u64 ppin; /* Protected Processor Inventory Number */ ++ __u32 microcode;/* Microcode revision */ + }; + + #define MCE_GET_RECORD_LEN _IOR('M', 1, int) +diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c +index d19e903..4aa9fd3 100644 +--- a/arch/x86/kernel/cpu/intel.c ++++ b/arch/x86/kernel/cpu/intel.c +@@ -144,6 +144,13 @@ static bool bad_spectre_microcode(struct cpuinfo_x86 *c) + { + int i; + ++ /* ++ * We know that the hypervisor lie to us on the microcode version so ++ * we may as well hope that it is running the correct version. ++ */ ++ if (cpu_has(c, X86_FEATURE_HYPERVISOR)) ++ return false; ++ + for (i = 0; i < ARRAY_SIZE(spectre_bad_microcodes); i++) { + if (c->x86_model == spectre_bad_microcodes[i].model && + c->x86_stepping == spectre_bad_microcodes[i].stepping) +diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c +index 8ff94d1..466f473 100644 +--- a/arch/x86/kernel/cpu/mcheck/mce.c ++++ b/arch/x86/kernel/cpu/mcheck/mce.c +@@ -56,6 +56,9 @@ + + static DEFINE_MUTEX(mce_log_mutex); + ++/* sysfs synchronization */ ++static DEFINE_MUTEX(mce_sysfs_mutex); ++ + #define CREATE_TRACE_POINTS + #include + +@@ -130,6 +133,8 @@ void mce_setup(struct mce *m) + + if (this_cpu_has(X86_FEATURE_INTEL_PPIN)) + rdmsrl(MSR_PPIN, m->ppin); ++ ++ m->microcode = boot_cpu_data.microcode; + } + + DEFINE_PER_CPU(struct mce, injectm); +@@ -262,7 +267,7 @@ static void __print_mce(struct mce *m) + */ + pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x microcode %x\n", + m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid, +- cpu_data(m->extcpu).microcode); ++ m->microcode); + } + + static void print_mce(struct mce *m) +@@ -2086,6 +2091,7 @@ static ssize_t set_ignore_ce(struct device *s, + if (kstrtou64(buf, 0, &new) < 0) + return -EINVAL; + ++ mutex_lock(&mce_sysfs_mutex); + if (mca_cfg.ignore_ce ^ !!new) { + if (new) { + /* disable ce features */ +@@ -2098,6 +2104,8 @@ static ssize_t set_ignore_ce(struct device *s, + on_each_cpu(mce_enable_ce, (void *)1, 1); + } + } ++ mutex_unlock(&mce_sysfs_mutex); ++ + return size; + } + +@@ -2110,6 +2118,7 @@ static ssize_t set_cmci_disabled(struct device *s, + if (kstrtou64(buf, 0, &new) < 0) + return -EINVAL; + ++ mutex_lock(&mce_sysfs_mutex); + if (mca_cfg.cmci_disabled ^ !!new) { + if (new) { + /* disable cmci */ +@@ -2121,6 +2130,8 @@ static ssize_t set_cmci_disabled(struct device *s, + on_each_cpu(mce_enable_ce, NULL, 1); + } + } ++ mutex_unlock(&mce_sysfs_mutex); ++ + return size; + } + +@@ -2128,8 +2139,19 @@ static ssize_t store_int_with_restart(struct device *s, + struct device_attribute *attr, + const char *buf, size_t size) + { +- ssize_t ret = device_store_int(s, attr, buf, size); ++ unsigned long old_check_interval = check_interval; ++ ssize_t ret = device_store_ulong(s, attr, buf, size); ++ ++ if (check_interval == old_check_interval) ++ return ret; ++ ++ if (check_interval < 1) ++ check_interval = 1; ++ ++ mutex_lock(&mce_sysfs_mutex); + mce_restart(); ++ mutex_unlock(&mce_sysfs_mutex); ++ + return ret; + } + +diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c +index aa1b9a4..70ecbc8 100644 +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -22,13 +22,16 @@ + #define pr_fmt(fmt) "microcode: " fmt + + #include ++#include + #include + #include + #include + #include + #include ++#include + #include + #include ++#include + #include + #include + +@@ -64,6 +67,11 @@ LIST_HEAD(microcode_cache); + */ + static DEFINE_MUTEX(microcode_mutex); + ++/* ++ * Serialize late loading so that CPUs get updated one-by-one. ++ */ ++static DEFINE_SPINLOCK(update_lock); ++ + struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; + + struct cpu_info_ctx { +@@ -373,26 +381,23 @@ static int collect_cpu_info(int cpu) + return ret; + } + +-struct apply_microcode_ctx { +- enum ucode_state err; +-}; +- + static void apply_microcode_local(void *arg) + { +- struct apply_microcode_ctx *ctx = arg; ++ enum ucode_state *err = arg; + +- ctx->err = microcode_ops->apply_microcode(smp_processor_id()); ++ *err = microcode_ops->apply_microcode(smp_processor_id()); + } + + static int apply_microcode_on_target(int cpu) + { +- struct apply_microcode_ctx ctx = { .err = 0 }; ++ enum ucode_state err; + int ret; + +- ret = smp_call_function_single(cpu, apply_microcode_local, &ctx, 1); +- if (!ret) +- ret = ctx.err; +- ++ ret = smp_call_function_single(cpu, apply_microcode_local, &err, 1); ++ if (!ret) { ++ if (err == UCODE_ERROR) ++ ret = 1; ++ } + return ret; + } + +@@ -489,19 +494,100 @@ static void __exit microcode_dev_exit(void) + /* fake device for request_firmware */ + static struct platform_device *microcode_pdev; + +-static enum ucode_state reload_for_cpu(int cpu) ++/* ++ * Late loading dance. Why the heavy-handed stomp_machine effort? ++ * ++ * - HT siblings must be idle and not execute other code while the other sibling ++ * is loading microcode in order to avoid any negative interactions caused by ++ * the loading. ++ * ++ * - In addition, microcode update on the cores must be serialized until this ++ * requirement can be relaxed in the future. Right now, this is conservative ++ * and good. ++ */ ++#define SPINUNIT 100 /* 100 nsec */ ++ ++static int check_online_cpus(void) + { +- struct ucode_cpu_info *uci = ucode_cpu_info + cpu; +- enum ucode_state ustate; ++ if (num_online_cpus() == num_present_cpus()) ++ return 0; + +- if (!uci->valid) +- return UCODE_OK; ++ pr_err("Not all CPUs online, aborting microcode update.\n"); ++ ++ return -EINVAL; ++} ++ ++static atomic_t late_cpus; ++ ++/* ++ * Returns: ++ * < 0 - on error ++ * 0 - no update done ++ * 1 - microcode was updated ++ */ ++static int __reload_late(void *info) ++{ ++ unsigned int timeout = NSEC_PER_SEC; ++ int all_cpus = num_online_cpus(); ++ int cpu = smp_processor_id(); ++ enum ucode_state err; ++ int ret = 0; ++ ++ atomic_dec(&late_cpus); ++ ++ /* ++ * Wait for all CPUs to arrive. A load will not be attempted unless all ++ * CPUs show up. ++ * */ ++ while (atomic_read(&late_cpus)) { ++ if (timeout < SPINUNIT) { ++ pr_err("Timeout while waiting for CPUs rendezvous, remaining: %d\n", ++ atomic_read(&late_cpus)); ++ return -1; ++ } + +- ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, true); +- if (ustate != UCODE_OK) +- return ustate; ++ ndelay(SPINUNIT); ++ timeout -= SPINUNIT; + +- return apply_microcode_on_target(cpu); ++ touch_nmi_watchdog(); ++ } ++ ++ spin_lock(&update_lock); ++ apply_microcode_local(&err); ++ spin_unlock(&update_lock); ++ ++ if (err > UCODE_NFOUND) { ++ pr_warn("Error reloading microcode on CPU %d\n", cpu); ++ ret = -1; ++ } else if (err == UCODE_UPDATED) { ++ ret = 1; ++ } ++ ++ atomic_inc(&late_cpus); ++ ++ while (atomic_read(&late_cpus) != all_cpus) ++ cpu_relax(); ++ ++ return ret; ++} ++ ++/* ++ * Reload microcode late on all CPUs. Wait for a sec until they ++ * all gather together. ++ */ ++static int microcode_reload_late(void) ++{ ++ int ret; ++ ++ atomic_set(&late_cpus, num_online_cpus()); ++ ++ ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask); ++ if (ret < 0) ++ return ret; ++ else if (ret > 0) ++ microcode_check(); ++ ++ return ret; + } + + static ssize_t reload_store(struct device *dev, +@@ -509,10 +595,9 @@ static ssize_t reload_store(struct device *dev, + const char *buf, size_t size) + { + enum ucode_state tmp_ret = UCODE_OK; +- bool do_callback = false; ++ int bsp = boot_cpu_data.cpu_index; + unsigned long val; + ssize_t ret = 0; +- int cpu; + + ret = kstrtoul(buf, 0, &val); + if (ret) +@@ -521,29 +606,24 @@ static ssize_t reload_store(struct device *dev, + if (val != 1) + return size; + +- get_online_cpus(); +- mutex_lock(µcode_mutex); +- for_each_online_cpu(cpu) { +- tmp_ret = reload_for_cpu(cpu); +- if (tmp_ret > UCODE_NFOUND) { +- pr_warn("Error reloading microcode on CPU %d\n", cpu); +- +- /* set retval for the first encountered reload error */ +- if (!ret) +- ret = -EINVAL; +- } ++ tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev, true); ++ if (tmp_ret != UCODE_OK) ++ return size; + +- if (tmp_ret == UCODE_UPDATED) +- do_callback = true; +- } ++ get_online_cpus(); + +- if (!ret && do_callback) +- microcode_check(); ++ ret = check_online_cpus(); ++ if (ret) ++ goto put; + ++ mutex_lock(µcode_mutex); ++ ret = microcode_reload_late(); + mutex_unlock(µcode_mutex); ++ ++put: + put_online_cpus(); + +- if (!ret) ++ if (ret >= 0) + ret = size; + + return ret; +diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c +index 923054a..2aded9d 100644 +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -589,6 +589,23 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early) + if (!mc) + return 0; + ++ /* ++ * Save us the MSR write below - which is a particular expensive ++ * operation - when the other hyperthread has updated the microcode ++ * already. ++ */ ++ rev = intel_get_microcode_revision(); ++ if (rev >= mc->hdr.rev) { ++ uci->cpu_sig.rev = rev; ++ return UCODE_OK; ++ } ++ ++ /* ++ * Writeback and invalidate caches before updating microcode to avoid ++ * internal issues depending on what the microcode is updating. ++ */ ++ native_wbinvd(); ++ + /* write microcode via MSR 0x79 */ + native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); + +@@ -774,9 +791,9 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) + + static enum ucode_state apply_microcode_intel(int cpu) + { ++ struct ucode_cpu_info *uci = ucode_cpu_info + cpu; ++ struct cpuinfo_x86 *c = &cpu_data(cpu); + struct microcode_intel *mc; +- struct ucode_cpu_info *uci; +- struct cpuinfo_x86 *c; + static int prev_rev; + u32 rev; + +@@ -784,15 +801,32 @@ static enum ucode_state apply_microcode_intel(int cpu) + if (WARN_ON(raw_smp_processor_id() != cpu)) + return UCODE_ERROR; + +- uci = ucode_cpu_info + cpu; +- mc = uci->mc; ++ /* Look for a newer patch in our cache: */ ++ mc = find_patch(uci); + if (!mc) { +- /* Look for a newer patch in our cache: */ +- mc = find_patch(uci); ++ mc = uci->mc; + if (!mc) + return UCODE_NFOUND; + } + ++ /* ++ * Save us the MSR write below - which is a particular expensive ++ * operation - when the other hyperthread has updated the microcode ++ * already. ++ */ ++ rev = intel_get_microcode_revision(); ++ if (rev >= mc->hdr.rev) { ++ uci->cpu_sig.rev = rev; ++ c->microcode = rev; ++ return UCODE_OK; ++ } ++ ++ /* ++ * Writeback and invalidate caches before updating microcode to avoid ++ * internal issues depending on what the microcode is updating. ++ */ ++ native_wbinvd(); ++ + /* write microcode via MSR 0x79 */ + wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); + +@@ -813,8 +847,6 @@ static enum ucode_state apply_microcode_intel(int cpu) + prev_rev = rev; + } + +- c = &cpu_data(cpu); +- + uci->cpu_sig.rev = rev; + c->microcode = rev; + +diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c +index 2f72330..38deafe 100644 +--- a/arch/x86/kernel/ioport.c ++++ b/arch/x86/kernel/ioport.c +@@ -23,7 +23,7 @@ + /* + * this changes the io permissions bitmap in the current task. + */ +-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) ++SYSCALL_DEFINE3(ioperm, unsigned long, from, unsigned long, num, int, turn_on) + { + struct thread_struct *t = ¤t->thread; + struct tss_struct *tss; +diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c +index bd36f3c..0715f82 100644 +--- a/arch/x86/kernel/kprobes/core.c ++++ b/arch/x86/kernel/kprobes/core.c +@@ -1168,10 +1168,18 @@ NOKPROBE_SYMBOL(longjmp_break_handler); + + bool arch_within_kprobe_blacklist(unsigned long addr) + { ++ bool is_in_entry_trampoline_section = false; ++ ++#ifdef CONFIG_X86_64 ++ is_in_entry_trampoline_section = ++ (addr >= (unsigned long)__entry_trampoline_start && ++ addr < (unsigned long)__entry_trampoline_end); ++#endif + return (addr >= (unsigned long)__kprobes_text_start && + addr < (unsigned long)__kprobes_text_end) || + (addr >= (unsigned long)__entry_text_start && +- addr < (unsigned long)__entry_text_end); ++ addr < (unsigned long)__entry_text_end) || ++ is_in_entry_trampoline_section; + } + + int __init arch_init_kprobes(void) +diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c +index ac057f9..0d930d8 100644 +--- a/arch/x86/kernel/signal_compat.c ++++ b/arch/x86/kernel/signal_compat.c +@@ -43,6 +43,13 @@ static inline void signal_compat_build_tests(void) + BUILD_BUG_ON(offsetof(compat_siginfo_t, _sifields) != 3 * sizeof(int)); + #define CHECK_CSI_OFFSET(name) BUILD_BUG_ON(_sifields_offset != offsetof(compat_siginfo_t, _sifields.name)) + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_signo) != 0); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_errno) != 4); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_code) != 8); ++ ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_signo) != 0); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_errno) != 4); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_code) != 8); + /* + * Ensure that the size of each si_field never changes. + * If it does, it is a sign that the +@@ -63,36 +70,94 @@ static inline void signal_compat_build_tests(void) + CHECK_CSI_SIZE (_kill, 2*sizeof(int)); + CHECK_SI_SIZE (_kill, 2*sizeof(int)); + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_pid) != 0x10); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_uid) != 0x14); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_pid) != 0xC); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_uid) != 0x10); ++ + CHECK_CSI_OFFSET(_timer); + CHECK_CSI_SIZE (_timer, 3*sizeof(int)); + CHECK_SI_SIZE (_timer, 6*sizeof(int)); + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_tid) != 0x10); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_overrun) != 0x14); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_value) != 0x18); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_tid) != 0x0C); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_overrun) != 0x10); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_value) != 0x14); ++ + CHECK_CSI_OFFSET(_rt); + CHECK_CSI_SIZE (_rt, 3*sizeof(int)); + CHECK_SI_SIZE (_rt, 4*sizeof(int)); + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_pid) != 0x10); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_uid) != 0x14); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_value) != 0x18); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_pid) != 0x0C); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_uid) != 0x10); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_value) != 0x14); ++ + CHECK_CSI_OFFSET(_sigchld); + CHECK_CSI_SIZE (_sigchld, 5*sizeof(int)); + CHECK_SI_SIZE (_sigchld, 8*sizeof(int)); + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_pid) != 0x10); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_uid) != 0x14); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_status) != 0x18); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_utime) != 0x20); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_stime) != 0x28); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_pid) != 0x0C); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_uid) != 0x10); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_status) != 0x14); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_utime) != 0x18); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_stime) != 0x1C); ++ + #ifdef CONFIG_X86_X32_ABI + CHECK_CSI_OFFSET(_sigchld_x32); + CHECK_CSI_SIZE (_sigchld_x32, 7*sizeof(int)); + /* no _sigchld_x32 in the generic siginfo_t */ ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, _sifields._sigchld_x32._utime) != 0x18); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, _sifields._sigchld_x32._stime) != 0x20); + #endif + + CHECK_CSI_OFFSET(_sigfault); + CHECK_CSI_SIZE (_sigfault, 4*sizeof(int)); + CHECK_SI_SIZE (_sigfault, 8*sizeof(int)); + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_addr) != 0x10); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_addr) != 0x0C); ++ ++ BUILD_BUG_ON(offsetof(siginfo_t, si_addr_lsb) != 0x18); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_addr_lsb) != 0x10); ++ ++ BUILD_BUG_ON(offsetof(siginfo_t, si_lower) != 0x20); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_upper) != 0x28); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_lower) != 0x14); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_upper) != 0x18); ++ ++ BUILD_BUG_ON(offsetof(siginfo_t, si_pkey) != 0x20); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_pkey) != 0x14); ++ + CHECK_CSI_OFFSET(_sigpoll); + CHECK_CSI_SIZE (_sigpoll, 2*sizeof(int)); + CHECK_SI_SIZE (_sigpoll, 4*sizeof(int)); + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_band) != 0x10); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_fd) != 0x18); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_band) != 0x0C); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_fd) != 0x10); ++ + CHECK_CSI_OFFSET(_sigsys); + CHECK_CSI_SIZE (_sigsys, 3*sizeof(int)); + CHECK_SI_SIZE (_sigsys, 4*sizeof(int)); + ++ BUILD_BUG_ON(offsetof(siginfo_t, si_call_addr) != 0x10); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_syscall) != 0x18); ++ BUILD_BUG_ON(offsetof(siginfo_t, si_arch) != 0x1C); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_call_addr) != 0x0C); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_syscall) != 0x10); ++ BUILD_BUG_ON(offsetof(compat_siginfo_t, si_arch) != 0x14); ++ + /* any new si_fields should be added here */ + } + +diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S +index 9b138a0..b854ebf 100644 +--- a/arch/x86/kernel/vmlinux.lds.S ++++ b/arch/x86/kernel/vmlinux.lds.S +@@ -118,9 +118,11 @@ SECTIONS + + #ifdef CONFIG_X86_64 + . = ALIGN(PAGE_SIZE); ++ VMLINUX_SYMBOL(__entry_trampoline_start) = .; + _entry_trampoline = .; + *(.entry_trampoline) + . = ALIGN(PAGE_SIZE); ++ VMLINUX_SYMBOL(__entry_trampoline_end) = .; + ASSERT(. - _entry_trampoline == PAGE_SIZE, "entry trampoline is too big"); + #endif + +diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c +index ce38f16..631507f 100644 +--- a/arch/x86/mm/pti.c ++++ b/arch/x86/mm/pti.c +@@ -332,7 +332,7 @@ static void __init pti_clone_user_shared(void) + } + + /* +- * Clone the ESPFIX P4D into the user space visinble page table ++ * Clone the ESPFIX P4D into the user space visible page table + */ + static void __init pti_setup_espfix64(void) + { +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 2a55380..60bf04b 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -21,6 +21,7 @@ + * + */ + ++#include + #include + #include + #include +@@ -379,6 +380,21 @@ static const struct usb_device_id blacklist_table[] = { + { } /* Terminating entry */ + }; + ++/* The Bluetooth USB module build into some devices needs to be reset on resume, ++ * this is a problem with the platform (likely shutting off all power) not with ++ * the module itself. So we use a DMI list to match known broken platforms. ++ */ ++static const struct dmi_system_id btusb_needs_reset_resume_table[] = { ++ { ++ /* Lenovo Yoga 920 (QCA Rome device 0cf3:e300) */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), ++ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 920"), ++ }, ++ }, ++ {} ++}; ++ + #define BTUSB_MAX_ISOC_FRAMES 10 + + #define BTUSB_INTR_RUNNING 0 +@@ -2945,6 +2961,9 @@ static int btusb_probe(struct usb_interface *intf, + hdev->send = btusb_send_frame; + hdev->notify = btusb_notify; + ++ if (dmi_check_system(btusb_needs_reset_resume_table)) ++ interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME; ++ + #ifdef CONFIG_PM + err = btusb_config_oob_wake(hdev); + if (err) +@@ -3031,12 +3050,6 @@ static int btusb_probe(struct usb_interface *intf, + if (id->driver_info & BTUSB_QCA_ROME) { + data->setup_on_usb = btusb_setup_qca; + hdev->set_bdaddr = btusb_set_bdaddr_ath3012; +- +- /* QCA Rome devices lose their updated firmware over suspend, +- * but the USB hub doesn't notice any status change. +- * explicitly request a device reset on resume. +- */ +- interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME; + } + + #ifdef CONFIG_BT_HCIBTUSB_RTL +diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c +index 0438a64..6314dfb 100644 +--- a/drivers/bluetooth/hci_bcm.c ++++ b/drivers/bluetooth/hci_bcm.c +@@ -922,12 +922,13 @@ static int bcm_get_resources(struct bcm_device *dev) + + dev->clk = devm_clk_get(dev->dev, NULL); + +- dev->device_wakeup = devm_gpiod_get(dev->dev, "device-wakeup", +- GPIOD_OUT_LOW); ++ dev->device_wakeup = devm_gpiod_get_optional(dev->dev, "device-wakeup", ++ GPIOD_OUT_LOW); + if (IS_ERR(dev->device_wakeup)) + return PTR_ERR(dev->device_wakeup); + +- dev->shutdown = devm_gpiod_get(dev->dev, "shutdown", GPIOD_OUT_LOW); ++ dev->shutdown = devm_gpiod_get_optional(dev->dev, "shutdown", ++ GPIOD_OUT_LOW); + if (IS_ERR(dev->shutdown)) + return PTR_ERR(dev->shutdown); + +diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig +index b3b4ed9..d2e5382 100644 +--- a/drivers/clocksource/Kconfig ++++ b/drivers/clocksource/Kconfig +@@ -386,6 +386,7 @@ config ATMEL_PIT + + config ATMEL_ST + bool "Atmel ST timer support" if COMPILE_TEST ++ depends on HAS_IOMEM + select TIMER_OF + select MFD_SYSCON + help +diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c +index f652a0e..3548caa 100644 +--- a/drivers/dma/mv_xor_v2.c ++++ b/drivers/dma/mv_xor_v2.c +@@ -163,6 +163,7 @@ struct mv_xor_v2_device { + void __iomem *dma_base; + void __iomem *glob_base; + struct clk *clk; ++ struct clk *reg_clk; + struct tasklet_struct irq_tasklet; + struct list_head free_sw_desc; + struct dma_device dmadev; +@@ -749,13 +750,26 @@ static int mv_xor_v2_probe(struct platform_device *pdev) + if (ret) + return ret; + ++ xor_dev->reg_clk = devm_clk_get(&pdev->dev, "reg"); ++ if (PTR_ERR(xor_dev->reg_clk) != -ENOENT) { ++ if (!IS_ERR(xor_dev->reg_clk)) { ++ ret = clk_prepare_enable(xor_dev->reg_clk); ++ if (ret) ++ return ret; ++ } else { ++ return PTR_ERR(xor_dev->reg_clk); ++ } ++ } ++ + xor_dev->clk = devm_clk_get(&pdev->dev, NULL); +- if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER) +- return -EPROBE_DEFER; ++ if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER) { ++ ret = EPROBE_DEFER; ++ goto disable_reg_clk; ++ } + if (!IS_ERR(xor_dev->clk)) { + ret = clk_prepare_enable(xor_dev->clk); + if (ret) +- return ret; ++ goto disable_reg_clk; + } + + ret = platform_msi_domain_alloc_irqs(&pdev->dev, 1, +@@ -866,8 +880,9 @@ static int mv_xor_v2_probe(struct platform_device *pdev) + free_msi_irqs: + platform_msi_domain_free_irqs(&pdev->dev); + disable_clk: +- if (!IS_ERR(xor_dev->clk)) +- clk_disable_unprepare(xor_dev->clk); ++ clk_disable_unprepare(xor_dev->clk); ++disable_reg_clk: ++ clk_disable_unprepare(xor_dev->reg_clk); + return ret; + } + +diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c +index e3ff162..d0cacdb 100644 +--- a/drivers/dma/sh/rcar-dmac.c ++++ b/drivers/dma/sh/rcar-dmac.c +@@ -917,7 +917,7 @@ rcar_dmac_chan_prep_sg(struct rcar_dmac_chan *chan, struct scatterlist *sgl, + + rcar_dmac_chan_configure_desc(chan, desc); + +- max_chunk_size = (RCAR_DMATCR_MASK + 1) << desc->xfer_shift; ++ max_chunk_size = RCAR_DMATCR_MASK << desc->xfer_shift; + + /* + * Allocate and fill the transfer chunk descriptors. We own the only +diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c +index e76de57..ebaea8b 100644 +--- a/drivers/gpio/gpio-rcar.c ++++ b/drivers/gpio/gpio-rcar.c +@@ -14,7 +14,6 @@ + * GNU General Public License for more details. + */ + +-#include + #include + #include + #include +@@ -37,10 +36,9 @@ struct gpio_rcar_priv { + struct platform_device *pdev; + struct gpio_chip gpio_chip; + struct irq_chip irq_chip; +- struct clk *clk; + unsigned int irq_parent; ++ atomic_t wakeup_path; + bool has_both_edge_trigger; +- bool needs_clk; + }; + + #define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */ +@@ -186,13 +184,10 @@ static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on) + } + } + +- if (!p->clk) +- return 0; +- + if (on) +- clk_enable(p->clk); ++ atomic_inc(&p->wakeup_path); + else +- clk_disable(p->clk); ++ atomic_dec(&p->wakeup_path); + + return 0; + } +@@ -330,17 +325,14 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset, + + struct gpio_rcar_info { + bool has_both_edge_trigger; +- bool needs_clk; + }; + + static const struct gpio_rcar_info gpio_rcar_info_gen1 = { + .has_both_edge_trigger = false, +- .needs_clk = false, + }; + + static const struct gpio_rcar_info gpio_rcar_info_gen2 = { + .has_both_edge_trigger = true, +- .needs_clk = true, + }; + + static const struct of_device_id gpio_rcar_of_table[] = { +@@ -403,7 +395,6 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins) + ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args); + *npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK; + p->has_both_edge_trigger = info->has_both_edge_trigger; +- p->needs_clk = info->needs_clk; + + if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) { + dev_warn(&p->pdev->dev, +@@ -440,16 +431,6 @@ static int gpio_rcar_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, p); + +- p->clk = devm_clk_get(dev, NULL); +- if (IS_ERR(p->clk)) { +- if (p->needs_clk) { +- dev_err(dev, "unable to get clock\n"); +- ret = PTR_ERR(p->clk); +- goto err0; +- } +- p->clk = NULL; +- } +- + pm_runtime_enable(dev); + + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); +@@ -531,11 +512,24 @@ static int gpio_rcar_remove(struct platform_device *pdev) + return 0; + } + ++static int __maybe_unused gpio_rcar_suspend(struct device *dev) ++{ ++ struct gpio_rcar_priv *p = dev_get_drvdata(dev); ++ ++ if (atomic_read(&p->wakeup_path)) ++ device_set_wakeup_path(dev); ++ ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, NULL); ++ + static struct platform_driver gpio_rcar_device_driver = { + .probe = gpio_rcar_probe, + .remove = gpio_rcar_remove, + .driver = { + .name = "gpio_rcar", ++ .pm = &gpio_rcar_pm_ops, + .of_match_table = of_match_ptr(gpio_rcar_of_table), + } + }; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +index 57afad7..8fa850a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +@@ -540,6 +540,9 @@ int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev, + size_t size; + u32 retry = 3; + ++ if (amdgpu_acpi_pcie_notify_device_ready(adev)) ++ return -EINVAL; ++ + /* Get the device handle */ + handle = ACPI_HANDLE(&adev->pdev->dev); + if (!handle) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +index 13044e6..561d331 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +@@ -481,7 +481,7 @@ static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf, + result = 0; + + if (*pos < 12) { +- early[0] = amdgpu_ring_get_rptr(ring); ++ early[0] = amdgpu_ring_get_rptr(ring) & ring->buf_mask; + early[1] = amdgpu_ring_get_wptr(ring) & ring->buf_mask; + early[2] = ring->wptr & ring->buf_mask; + for (i = *pos / 4; i < 3 && size; i++) { +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +index b2eae86..5c26a8e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +@@ -299,12 +299,15 @@ int amdgpu_uvd_suspend(struct amdgpu_device *adev) + + cancel_delayed_work_sync(&adev->uvd.idle_work); + +- for (i = 0; i < adev->uvd.max_handles; ++i) +- if (atomic_read(&adev->uvd.handles[i])) +- break; ++ /* only valid for physical mode */ ++ if (adev->asic_type < CHIP_POLARIS10) { ++ for (i = 0; i < adev->uvd.max_handles; ++i) ++ if (atomic_read(&adev->uvd.handles[i])) ++ break; + +- if (i == AMDGPU_MAX_UVD_HANDLES) +- return 0; ++ if (i == adev->uvd.max_handles) ++ return 0; ++ } + + size = amdgpu_bo_size(adev->uvd.vcpu_bo); + ptr = adev->uvd.cpu_addr; +diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +index bd2c4f7..a712f4b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +@@ -3093,7 +3093,7 @@ static int dce_v6_0_hpd_irq(struct amdgpu_device *adev, + tmp |= DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK; + WREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd], tmp); + schedule_work(&adev->hotplug_work); +- DRM_INFO("IH: HPD%d\n", hpd + 1); ++ DRM_DEBUG("IH: HPD%d\n", hpd + 1); + } + + return 0; +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +index a066c5e..a430969 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +@@ -4384,34 +4384,8 @@ static void gfx_v7_0_gpu_early_init(struct amdgpu_device *adev) + case CHIP_KAVERI: + adev->gfx.config.max_shader_engines = 1; + adev->gfx.config.max_tile_pipes = 4; +- if ((adev->pdev->device == 0x1304) || +- (adev->pdev->device == 0x1305) || +- (adev->pdev->device == 0x130C) || +- (adev->pdev->device == 0x130F) || +- (adev->pdev->device == 0x1310) || +- (adev->pdev->device == 0x1311) || +- (adev->pdev->device == 0x131C)) { +- adev->gfx.config.max_cu_per_sh = 8; +- adev->gfx.config.max_backends_per_se = 2; +- } else if ((adev->pdev->device == 0x1309) || +- (adev->pdev->device == 0x130A) || +- (adev->pdev->device == 0x130D) || +- (adev->pdev->device == 0x1313) || +- (adev->pdev->device == 0x131D)) { +- adev->gfx.config.max_cu_per_sh = 6; +- adev->gfx.config.max_backends_per_se = 2; +- } else if ((adev->pdev->device == 0x1306) || +- (adev->pdev->device == 0x1307) || +- (adev->pdev->device == 0x130B) || +- (adev->pdev->device == 0x130E) || +- (adev->pdev->device == 0x1315) || +- (adev->pdev->device == 0x131B)) { +- adev->gfx.config.max_cu_per_sh = 4; +- adev->gfx.config.max_backends_per_se = 1; +- } else { +- adev->gfx.config.max_cu_per_sh = 3; +- adev->gfx.config.max_backends_per_se = 1; +- } ++ adev->gfx.config.max_cu_per_sh = 8; ++ adev->gfx.config.max_backends_per_se = 2; + adev->gfx.config.max_sh_per_se = 1; + adev->gfx.config.max_texture_channel_caches = 4; + adev->gfx.config.max_gprs = 256; +diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c +index 543101d..2095173 100644 +--- a/drivers/gpu/drm/amd/amdgpu/si.c ++++ b/drivers/gpu/drm/amd/amdgpu/si.c +@@ -31,6 +31,7 @@ + #include "amdgpu_uvd.h" + #include "amdgpu_vce.h" + #include "atom.h" ++#include "amd_pcie.h" + #include "amdgpu_powerplay.h" + #include "sid.h" + #include "si_ih.h" +@@ -1461,8 +1462,8 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) + { + struct pci_dev *root = adev->pdev->bus->self; + int bridge_pos, gpu_pos; +- u32 speed_cntl, mask, current_data_rate; +- int ret, i; ++ u32 speed_cntl, current_data_rate; ++ int i; + u16 tmp16; + + if (pci_is_root_bus(adev->pdev->bus)) +@@ -1474,23 +1475,20 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) + if (adev->flags & AMD_IS_APU) + return; + +- ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask); +- if (ret != 0) +- return; +- +- if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80))) ++ if (!(adev->pm.pcie_gen_mask & (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 | ++ CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3))) + return; + + speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); + current_data_rate = (speed_cntl & LC_CURRENT_DATA_RATE_MASK) >> + LC_CURRENT_DATA_RATE_SHIFT; +- if (mask & DRM_PCIE_SPEED_80) { ++ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) { + if (current_data_rate == 2) { + DRM_INFO("PCIE gen 3 link speeds already enabled\n"); + return; + } + DRM_INFO("enabling PCIE gen 3 link speeds, disable with amdgpu.pcie_gen2=0\n"); +- } else if (mask & DRM_PCIE_SPEED_50) { ++ } else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) { + if (current_data_rate == 1) { + DRM_INFO("PCIE gen 2 link speeds already enabled\n"); + return; +@@ -1506,7 +1504,7 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) + if (!gpu_pos) + return; + +- if (mask & DRM_PCIE_SPEED_80) { ++ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) { + if (current_data_rate != 2) { + u16 bridge_cfg, gpu_cfg; + u16 bridge_cfg2, gpu_cfg2; +@@ -1589,9 +1587,9 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev) + + pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16); + tmp16 &= ~0xf; +- if (mask & DRM_PCIE_SPEED_80) ++ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) + tmp16 |= 3; +- else if (mask & DRM_PCIE_SPEED_50) ++ else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) + tmp16 |= 2; + else + tmp16 |= 1; +diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c +index ce675a7..22f0b7f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c ++++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c +@@ -26,6 +26,7 @@ + #include "amdgpu_pm.h" + #include "amdgpu_dpm.h" + #include "amdgpu_atombios.h" ++#include "amd_pcie.h" + #include "sid.h" + #include "r600_dpm.h" + #include "si_dpm.h" +@@ -3331,29 +3332,6 @@ static void btc_apply_voltage_delta_rules(struct amdgpu_device *adev, + } + } + +-static enum amdgpu_pcie_gen r600_get_pcie_gen_support(struct amdgpu_device *adev, +- u32 sys_mask, +- enum amdgpu_pcie_gen asic_gen, +- enum amdgpu_pcie_gen default_gen) +-{ +- switch (asic_gen) { +- case AMDGPU_PCIE_GEN1: +- return AMDGPU_PCIE_GEN1; +- case AMDGPU_PCIE_GEN2: +- return AMDGPU_PCIE_GEN2; +- case AMDGPU_PCIE_GEN3: +- return AMDGPU_PCIE_GEN3; +- default: +- if ((sys_mask & DRM_PCIE_SPEED_80) && (default_gen == AMDGPU_PCIE_GEN3)) +- return AMDGPU_PCIE_GEN3; +- else if ((sys_mask & DRM_PCIE_SPEED_50) && (default_gen == AMDGPU_PCIE_GEN2)) +- return AMDGPU_PCIE_GEN2; +- else +- return AMDGPU_PCIE_GEN1; +- } +- return AMDGPU_PCIE_GEN1; +-} +- + static void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b, + u32 *p, u32 *u) + { +@@ -5028,10 +5006,11 @@ static int si_populate_smc_acpi_state(struct amdgpu_device *adev, + table->ACPIState.levels[0].vddc.index, + &table->ACPIState.levels[0].std_vddc); + } +- table->ACPIState.levels[0].gen2PCIE = (u8)r600_get_pcie_gen_support(adev, +- si_pi->sys_pcie_mask, +- si_pi->boot_pcie_gen, +- AMDGPU_PCIE_GEN1); ++ table->ACPIState.levels[0].gen2PCIE = ++ (u8)amdgpu_get_pcie_gen_support(adev, ++ si_pi->sys_pcie_mask, ++ si_pi->boot_pcie_gen, ++ AMDGPU_PCIE_GEN1); + + if (si_pi->vddc_phase_shed_control) + si_populate_phase_shedding_value(adev, +@@ -7168,10 +7147,10 @@ static void si_parse_pplib_clock_info(struct amdgpu_device *adev, + pl->vddc = le16_to_cpu(clock_info->si.usVDDC); + pl->vddci = le16_to_cpu(clock_info->si.usVDDCI); + pl->flags = le32_to_cpu(clock_info->si.ulFlags); +- pl->pcie_gen = r600_get_pcie_gen_support(adev, +- si_pi->sys_pcie_mask, +- si_pi->boot_pcie_gen, +- clock_info->si.ucPCIEGen); ++ pl->pcie_gen = amdgpu_get_pcie_gen_support(adev, ++ si_pi->sys_pcie_mask, ++ si_pi->boot_pcie_gen, ++ clock_info->si.ucPCIEGen); + + /* patch up vddc if necessary */ + ret = si_get_leakage_voltage_from_leakage_index(adev, pl->vddc, +@@ -7326,7 +7305,6 @@ static int si_dpm_init(struct amdgpu_device *adev) + struct si_power_info *si_pi; + struct atom_clock_dividers dividers; + int ret; +- u32 mask; + + si_pi = kzalloc(sizeof(struct si_power_info), GFP_KERNEL); + if (si_pi == NULL) +@@ -7336,11 +7314,9 @@ static int si_dpm_init(struct amdgpu_device *adev) + eg_pi = &ni_pi->eg; + pi = &eg_pi->rv7xx; + +- ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask); +- if (ret) +- si_pi->sys_pcie_mask = 0; +- else +- si_pi->sys_pcie_mask = mask; ++ si_pi->sys_pcie_mask = ++ (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK) >> ++ CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT; + si_pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID; + si_pi->boot_pcie_gen = si_get_current_pcie_speed(adev); + +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 862835d..c345e64 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -1037,6 +1037,10 @@ static void handle_hpd_rx_irq(void *param) + !is_mst_root_connector) { + /* Downstream Port status changed. */ + if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) { ++ ++ if (aconnector->fake_enable) ++ aconnector->fake_enable = false; ++ + amdgpu_dm_update_connector_after_detect(aconnector); + + +@@ -2012,30 +2016,32 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, + dst.width = stream->timing.h_addressable; + dst.height = stream->timing.v_addressable; + +- rmx_type = dm_state->scaling; +- if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) { +- if (src.width * dst.height < +- src.height * dst.width) { +- /* height needs less upscaling/more downscaling */ +- dst.width = src.width * +- dst.height / src.height; +- } else { +- /* width needs less upscaling/more downscaling */ +- dst.height = src.height * +- dst.width / src.width; ++ if (dm_state) { ++ rmx_type = dm_state->scaling; ++ if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) { ++ if (src.width * dst.height < ++ src.height * dst.width) { ++ /* height needs less upscaling/more downscaling */ ++ dst.width = src.width * ++ dst.height / src.height; ++ } else { ++ /* width needs less upscaling/more downscaling */ ++ dst.height = src.height * ++ dst.width / src.width; ++ } ++ } else if (rmx_type == RMX_CENTER) { ++ dst = src; + } +- } else if (rmx_type == RMX_CENTER) { +- dst = src; +- } + +- dst.x = (stream->timing.h_addressable - dst.width) / 2; +- dst.y = (stream->timing.v_addressable - dst.height) / 2; ++ dst.x = (stream->timing.h_addressable - dst.width) / 2; ++ dst.y = (stream->timing.v_addressable - dst.height) / 2; + +- if (dm_state->underscan_enable) { +- dst.x += dm_state->underscan_hborder / 2; +- dst.y += dm_state->underscan_vborder / 2; +- dst.width -= dm_state->underscan_hborder; +- dst.height -= dm_state->underscan_vborder; ++ if (dm_state->underscan_enable) { ++ dst.x += dm_state->underscan_hborder / 2; ++ dst.y += dm_state->underscan_vborder / 2; ++ dst.width -= dm_state->underscan_hborder; ++ dst.height -= dm_state->underscan_vborder; ++ } + } + + stream->src = src; +@@ -2360,12 +2366,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + + if (aconnector == NULL) { + DRM_ERROR("aconnector is NULL!\n"); +- goto drm_connector_null; +- } +- +- if (dm_state == NULL) { +- DRM_ERROR("dm_state is NULL!\n"); +- goto dm_state_null; ++ return stream; + } + + drm_connector = &aconnector->base; +@@ -2377,18 +2378,18 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + */ + if (aconnector->mst_port) { + dm_dp_mst_dc_sink_create(drm_connector); +- goto mst_dc_sink_create_done; ++ return stream; + } + + if (create_fake_sink(aconnector)) +- goto stream_create_fail; ++ return stream; + } + + stream = dc_create_stream_for_sink(aconnector->dc_sink); + + if (stream == NULL) { + DRM_ERROR("Failed to create stream for sink!\n"); +- goto stream_create_fail; ++ return stream; + } + + list_for_each_entry(preferred_mode, &aconnector->base.modes, head) { +@@ -2414,9 +2415,12 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + } else { + decide_crtc_timing_for_drm_display_mode( + &mode, preferred_mode, +- dm_state->scaling != RMX_OFF); ++ dm_state ? (dm_state->scaling != RMX_OFF) : false); + } + ++ if (!dm_state) ++ drm_mode_set_crtcinfo(&mode, 0); ++ + fill_stream_properties_from_drm_display_mode(stream, + &mode, &aconnector->base); + update_stream_scaling_settings(&mode, dm_state, stream); +@@ -2426,10 +2430,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + drm_connector, + aconnector->dc_sink); + +-stream_create_fail: +-dm_state_null: +-drm_connector_null: +-mst_dc_sink_create_done: ++ update_stream_signal(stream); ++ + return stream; + } + +@@ -2497,6 +2499,27 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc) + return &state->base; + } + ++ ++static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable) ++{ ++ enum dc_irq_source irq_source; ++ struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); ++ struct amdgpu_device *adev = crtc->dev->dev_private; ++ ++ irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst; ++ return dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY; ++} ++ ++static int dm_enable_vblank(struct drm_crtc *crtc) ++{ ++ return dm_set_vblank(crtc, true); ++} ++ ++static void dm_disable_vblank(struct drm_crtc *crtc) ++{ ++ dm_set_vblank(crtc, false); ++} ++ + /* Implemented only the options currently availible for the driver */ + static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { + .reset = dm_crtc_reset_state, +@@ -2506,6 +2529,8 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = dm_crtc_duplicate_state, + .atomic_destroy_state = dm_crtc_destroy_state, ++ .enable_vblank = dm_enable_vblank, ++ .disable_vblank = dm_disable_vblank, + }; + + static enum drm_connector_status +@@ -2800,7 +2825,7 @@ int amdgpu_dm_connector_mode_valid(struct drm_connector *connector, + goto fail; + } + +- stream = dc_create_stream_for_sink(dc_sink); ++ stream = create_stream_for_sink(aconnector, mode, NULL); + if (stream == NULL) { + DRM_ERROR("Failed to create stream for sink!\n"); + goto fail; +@@ -3060,6 +3085,9 @@ static int dm_plane_atomic_check(struct drm_plane *plane, + if (!dm_plane_state->dc_state) + return 0; + ++ if (!fill_rects_from_plane_state(state, dm_plane_state->dc_state)) ++ return -EINVAL; ++ + if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK) + return 0; + +@@ -4632,8 +4660,6 @@ static int dm_update_planes_state(struct dc *dc, + bool pflip_needed = !state->allow_modeset; + int ret = 0; + +- if (pflip_needed) +- return ret; + + /* Add new planes */ + for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { +@@ -4648,6 +4674,8 @@ static int dm_update_planes_state(struct dc *dc, + + /* Remove any changed/removed planes */ + if (!enable) { ++ if (pflip_needed) ++ continue; + + if (!old_plane_crtc) + continue; +@@ -4679,6 +4707,7 @@ static int dm_update_planes_state(struct dc *dc, + *lock_and_validation_needed = true; + + } else { /* Add new planes */ ++ struct dc_plane_state *dc_new_plane_state; + + if (drm_atomic_plane_disabling(plane->state, new_plane_state)) + continue; +@@ -4692,38 +4721,50 @@ static int dm_update_planes_state(struct dc *dc, + if (!dm_new_crtc_state->stream) + continue; + ++ if (pflip_needed) ++ continue; + + WARN_ON(dm_new_plane_state->dc_state); + +- dm_new_plane_state->dc_state = dc_create_plane_state(dc); +- +- DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n", +- plane->base.id, new_plane_crtc->base.id); +- +- if (!dm_new_plane_state->dc_state) { ++ dc_new_plane_state = dc_create_plane_state(dc); ++ if (!dc_new_plane_state) { + ret = -EINVAL; + return ret; + } + ++ DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n", ++ plane->base.id, new_plane_crtc->base.id); ++ + ret = fill_plane_attributes( + new_plane_crtc->dev->dev_private, +- dm_new_plane_state->dc_state, ++ dc_new_plane_state, + new_plane_state, + new_crtc_state); +- if (ret) ++ if (ret) { ++ dc_plane_state_release(dc_new_plane_state); + return ret; ++ } + +- ++ /* ++ * Any atomic check errors that occur after this will ++ * not need a release. The plane state will be attached ++ * to the stream, and therefore part of the atomic ++ * state. It'll be released when the atomic state is ++ * cleaned. ++ */ + if (!dc_add_plane_to_context( + dc, + dm_new_crtc_state->stream, +- dm_new_plane_state->dc_state, ++ dc_new_plane_state, + dm_state->context)) { + ++ dc_plane_state_release(dc_new_plane_state); + ret = -EINVAL; + return ret; + } + ++ dm_new_plane_state->dc_state = dc_new_plane_state; ++ + /* Tell DC to do a full surface update every time there + * is a plane change. Inefficient, but works for now. + */ +@@ -4737,6 +4778,30 @@ static int dm_update_planes_state(struct dc *dc, + return ret; + } + ++static int dm_atomic_check_plane_state_fb(struct drm_atomic_state *state, ++ struct drm_crtc *crtc) ++{ ++ struct drm_plane *plane; ++ struct drm_crtc_state *crtc_state; ++ ++ WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc)); ++ ++ drm_for_each_plane_mask(plane, state->dev, crtc->state->plane_mask) { ++ struct drm_plane_state *plane_state = ++ drm_atomic_get_plane_state(state, plane); ++ ++ if (IS_ERR(plane_state)) ++ return -EDEADLK; ++ ++ crtc_state = drm_atomic_get_crtc_state(plane_state->state, crtc); ++ if (crtc->primary == plane && crtc_state->active) { ++ if (!plane_state->fb) ++ return -EINVAL; ++ } ++ } ++ return 0; ++} ++ + static int amdgpu_dm_atomic_check(struct drm_device *dev, + struct drm_atomic_state *state) + { +@@ -4760,6 +4825,10 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, + goto fail; + + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { ++ ret = dm_atomic_check_plane_state_fb(state, crtc); ++ if (ret) ++ goto fail; ++ + if (!drm_atomic_crtc_needs_modeset(new_crtc_state) && + !new_crtc_state->color_mgmt_changed) + continue; +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +index 1874b6c..4220550 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +@@ -683,10 +683,8 @@ static const struct amdgpu_irq_src_funcs dm_hpd_irq_funcs = { + + void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev) + { +- if (adev->mode_info.num_crtc > 0) +- adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_VLINE1 + adev->mode_info.num_crtc; +- else +- adev->crtc_irq.num_types = 0; ++ ++ adev->crtc_irq.num_types = adev->mode_info.num_crtc; + adev->crtc_irq.funcs = &dm_crtc_irq_funcs; + + adev->pageflip_irq.num_types = adev->mode_info.num_crtc; +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 f3d87f4..93421da 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 +@@ -189,6 +189,12 @@ void dm_dp_mst_dc_sink_create(struct drm_connector *connector) + .link = aconnector->dc_link, + .sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST }; + ++ /* ++ * TODO: Need to further figure out why ddc.algo is NULL while MST port exists ++ */ ++ if (!aconnector->port || !aconnector->port->aux.ddc.algo) ++ return; ++ + edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port); + + if (!edid) { +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index 35e84ed..12868c7 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -1358,13 +1358,13 @@ enum dc_irq_source dc_interrupt_to_irq_source( + return dal_irq_service_to_irq_source(dc->res_pool->irqs, src_id, ext_id); + } + +-void dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable) ++bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable) + { + + if (dc == NULL) +- return; ++ return false; + +- dal_irq_service_set(dc->res_pool->irqs, src, enable); ++ return dal_irq_service_set(dc->res_pool->irqs, src, enable); + } + + void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src) +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c +index a374282..be55461 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c +@@ -1749,8 +1749,7 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) + link->link_enc, + pipe_ctx->clock_source->id, + display_color_depth, +- pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A, +- pipe_ctx->stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK, ++ pipe_ctx->stream->signal, + stream->phy_pix_clk); + + if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) +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 95b8dd0..4d07ffe 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -1360,9 +1360,6 @@ bool dc_is_stream_scaling_unchanged( + return true; + } + +-/* Maximum TMDS single link pixel clock 165MHz */ +-#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ 165000 +- + static void update_stream_engine_usage( + struct resource_context *res_ctx, + const struct resource_pool *pool, +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 539c3e0..cd58197 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +@@ -33,8 +33,7 @@ + /******************************************************************************* + * Private functions + ******************************************************************************/ +-#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST 297000 +-static void update_stream_signal(struct dc_stream_state *stream) ++void update_stream_signal(struct dc_stream_state *stream) + { + + struct dc_sink *dc_sink = stream->sink; +@@ -45,8 +44,9 @@ static void update_stream_signal(struct dc_stream_state *stream) + stream->signal = dc_sink->sink_signal; + + if (dc_is_dvi_signal(stream->signal)) { +- if (stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST && +- stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) ++ if (stream->ctx->dc->caps.dual_link_dvi && ++ stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK && ++ stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) + stream->signal = SIGNAL_TYPE_DVI_DUAL_LINK; + else + stream->signal = SIGNAL_TYPE_DVI_SINGLE_LINK; +@@ -193,6 +193,7 @@ bool dc_stream_set_cursor_attributes( + + core_dc = stream->ctx->dc; + res_ctx = &core_dc->current_state->res_ctx; ++ stream->cursor_attributes = *attributes; + + for (i = 0; i < MAX_PIPES; i++) { + struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; +@@ -204,34 +205,8 @@ bool dc_stream_set_cursor_attributes( + continue; + + +- if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes != NULL) +- pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes( +- pipe_ctx->plane_res.ipp, attributes); +- +- if (pipe_ctx->plane_res.hubp != NULL && +- pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes != NULL) +- pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( +- pipe_ctx->plane_res.hubp, attributes); +- +- if (pipe_ctx->plane_res.mi != NULL && +- pipe_ctx->plane_res.mi->funcs->set_cursor_attributes != NULL) +- pipe_ctx->plane_res.mi->funcs->set_cursor_attributes( +- pipe_ctx->plane_res.mi, attributes); +- +- +- if (pipe_ctx->plane_res.xfm != NULL && +- pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes != NULL) +- pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes( +- pipe_ctx->plane_res.xfm, attributes); +- +- if (pipe_ctx->plane_res.dpp != NULL && +- pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes != NULL) +- pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( +- pipe_ctx->plane_res.dpp, attributes->color_format); ++ core_dc->hwss.set_cursor_attribute(pipe_ctx); + } +- +- stream->cursor_attributes = *attributes; +- + return true; + } + +@@ -255,21 +230,10 @@ bool dc_stream_set_cursor_position( + + core_dc = stream->ctx->dc; + res_ctx = &core_dc->current_state->res_ctx; ++ stream->cursor_position = *position; + + for (i = 0; i < MAX_PIPES; i++) { + struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; +- struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; +- struct mem_input *mi = pipe_ctx->plane_res.mi; +- struct hubp *hubp = pipe_ctx->plane_res.hubp; +- struct dpp *dpp = pipe_ctx->plane_res.dpp; +- struct dc_cursor_position pos_cpy = *position; +- struct dc_cursor_mi_param param = { +- .pixel_clk_khz = stream->timing.pix_clk_khz, +- .ref_clk_khz = core_dc->res_pool->ref_clock_inKhz, +- .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, +- .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, +- .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz +- }; + + if (pipe_ctx->stream != stream || + (!pipe_ctx->plane_res.mi && !pipe_ctx->plane_res.hubp) || +@@ -278,33 +242,9 @@ bool dc_stream_set_cursor_position( + !pipe_ctx->plane_res.ipp) + continue; + +- if (pipe_ctx->plane_state->address.type +- == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) +- pos_cpy.enable = false; +- +- if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) +- pos_cpy.enable = false; +- +- +- if (ipp != NULL && ipp->funcs->ipp_cursor_set_position != NULL) +- ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, ¶m); +- +- if (mi != NULL && mi->funcs->set_cursor_position != NULL) +- mi->funcs->set_cursor_position(mi, &pos_cpy, ¶m); +- +- if (!hubp) +- continue; +- +- if (hubp->funcs->set_cursor_position != NULL) +- hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); +- +- if (dpp != NULL && dpp->funcs->set_cursor_position != NULL) +- dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width); +- ++ core_dc->hwss.set_cursor_position(pipe_ctx); + } + +- stream->cursor_position = *position; +- + return true; + } + +diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h +index e2e3c9d..d6d5661 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc.h ++++ b/drivers/gpu/drm/amd/display/dc/dc.h +@@ -62,6 +62,7 @@ struct dc_caps { + bool dcc_const_color; + bool dynamic_audio; + bool is_apu; ++ bool dual_link_dvi; + }; + + struct dc_dcc_surface_param { +@@ -672,7 +673,7 @@ enum dc_irq_source dc_interrupt_to_irq_source( + struct dc *dc, + uint32_t src_id, + uint32_t ext_id); +-void dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable); ++bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable); + void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src); + enum dc_irq_source dc_get_hpd_irq_source_at_index( + struct dc *dc, uint32_t link_index); +diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h +index 01c60f1..456e4d2 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h +@@ -237,6 +237,8 @@ enum surface_update_type dc_check_update_surfaces_for_stream( + */ + struct dc_stream_state *dc_create_stream_for_sink(struct dc_sink *dc_sink); + ++void update_stream_signal(struct dc_stream_state *stream); ++ + void dc_stream_retain(struct dc_stream_state *dc_stream); + void dc_stream_release(struct dc_stream_state *dc_stream); + +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +index b73db9e..a993279 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +@@ -236,6 +236,7 @@ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ ++ SR(VGA_TEST_CONTROL), \ + SR(DC_IP_REQUEST_CNTL), \ + BL_REG_LIST() + +@@ -337,6 +338,7 @@ struct dce_hwseq_registers { + uint32_t D2VGA_CONTROL; + uint32_t D3VGA_CONTROL; + uint32_t D4VGA_CONTROL; ++ uint32_t VGA_TEST_CONTROL; + /* MMHUB registers. read only. temporary hack */ + uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32; + uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32; +@@ -493,6 +495,9 @@ struct dce_hwseq_registers { + HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ ++ HWS_SF(, D1VGA_CONTROL, D1VGA_MODE_ENABLE, mask_sh),\ ++ HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_ENABLE, mask_sh),\ ++ HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_RENDER_START, mask_sh),\ + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \ + HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) + +@@ -583,7 +588,10 @@ struct dce_hwseq_registers { + type DCFCLK_GATE_DIS; \ + type DCHUBBUB_GLOBAL_TIMER_REFDIV; \ + type DENTIST_DPPCLK_WDIVIDER; \ +- type DENTIST_DISPCLK_WDIVIDER; ++ type DENTIST_DISPCLK_WDIVIDER; \ ++ type VGA_TEST_ENABLE; \ ++ type VGA_TEST_RENDER_START; \ ++ type D1VGA_MODE_ENABLE; + + struct dce_hwseq_shift { + HWSEQ_REG_FIELD_LIST(uint8_t) +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +index a266e3f..e4741f1 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +@@ -82,13 +82,6 @@ + #define DCE110_DIG_FE_SOURCE_SELECT_DIGF 0x20 + #define DCE110_DIG_FE_SOURCE_SELECT_DIGG 0x40 + +-/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */ +-#define TMDS_MIN_PIXEL_CLOCK 25000 +-/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */ +-#define TMDS_MAX_PIXEL_CLOCK 165000 +-/* For current ASICs pixel clock - 600MHz */ +-#define MAX_ENCODER_CLOCK 600000 +- + enum { + DP_MST_UPDATE_MAX_RETRY = 50 + }; +@@ -683,6 +676,7 @@ void dce110_link_encoder_construct( + { + struct bp_encoder_cap_info bp_cap_info = {0}; + const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs; ++ enum bp_result result = BP_RESULT_OK; + + enc110->base.funcs = &dce110_lnk_enc_funcs; + enc110->base.ctx = init_data->ctx; +@@ -757,15 +751,24 @@ void dce110_link_encoder_construct( + enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; + } + ++ /* default to one to mirror Windows behavior */ ++ enc110->base.features.flags.bits.HDMI_6GB_EN = 1; ++ ++ result = bp_funcs->get_encoder_cap_info(enc110->base.ctx->dc_bios, ++ enc110->base.id, &bp_cap_info); ++ + /* Override features with DCE-specific values */ +- if (BP_RESULT_OK == bp_funcs->get_encoder_cap_info( +- enc110->base.ctx->dc_bios, enc110->base.id, +- &bp_cap_info)) { ++ if (BP_RESULT_OK == result) { + enc110->base.features.flags.bits.IS_HBR2_CAPABLE = + bp_cap_info.DP_HBR2_EN; + enc110->base.features.flags.bits.IS_HBR3_CAPABLE = + bp_cap_info.DP_HBR3_EN; + enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN; ++ } else { ++ dm_logger_write(enc110->base.ctx->logger, LOG_WARNING, ++ "%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", ++ __func__, ++ result); + } + } + +@@ -904,8 +907,7 @@ void dce110_link_encoder_enable_tmds_output( + struct link_encoder *enc, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, +- bool hdmi, +- bool dual_link, ++ enum signal_type signal, + uint32_t pixel_clock) + { + struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); +@@ -919,16 +921,12 @@ void dce110_link_encoder_enable_tmds_output( + cntl.engine_id = enc->preferred_engine; + cntl.transmitter = enc110->base.transmitter; + cntl.pll_id = clock_source; +- if (hdmi) { +- cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A; +- cntl.lanes_number = 4; +- } else if (dual_link) { +- cntl.signal = SIGNAL_TYPE_DVI_DUAL_LINK; ++ cntl.signal = signal; ++ if (cntl.signal == SIGNAL_TYPE_DVI_DUAL_LINK) + cntl.lanes_number = 8; +- } else { +- cntl.signal = SIGNAL_TYPE_DVI_SINGLE_LINK; ++ else + cntl.lanes_number = 4; +- } ++ + cntl.hpd_sel = enc110->base.hpd_source; + + cntl.pixel_clock = pixel_clock; +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h +index 8ca9afe..0ec3433 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h +@@ -210,8 +210,7 @@ void dce110_link_encoder_enable_tmds_output( + struct link_encoder *enc, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, +- bool hdmi, +- bool dual_link, ++ enum signal_type signal, + uint32_t pixel_clock); + + /* enables DP PHY output */ +diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +index 3ea43e2..442dd2d 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +@@ -852,6 +852,7 @@ static bool construct( + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 40; + dc->caps.max_cursor_size = 128; ++ dc->caps.dual_link_dvi = true; + + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.timing_generators[i] = +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 86cdd7b4..6f382a3 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 +@@ -688,15 +688,22 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) + struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; + struct dc_link *link = pipe_ctx->stream->sink->link; + +- /* 1. update AVI info frame (HDMI, DP) +- * we always need to update info frame +- */ ++ + uint32_t active_total_with_borders; + uint32_t early_control = 0; + struct timing_generator *tg = pipe_ctx->stream_res.tg; + +- /* TODOFPGA may change to hwss.update_info_frame */ ++ /* For MST, there are multiply stream go to only one link. ++ * connect DIG back_end to front_end while enable_stream and ++ * disconnect them during disable_stream ++ * BY this, it is logic clean to separate stream and link */ ++ link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, ++ pipe_ctx->stream_res.stream_enc->id, true); ++ ++ /* update AVI info frame (HDMI, DP)*/ ++ /* TODO: FPGA may change to hwss.update_info_frame */ + dce110_update_info_frame(pipe_ctx); ++ + /* enable early control to avoid corruption on DP monitor*/ + active_total_with_borders = + timing->h_addressable +@@ -717,12 +724,8 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) + pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc); + } + +- /* For MST, there are multiply stream go to only one link. +- * connect DIG back_end to front_end while enable_stream and +- * disconnect them during disable_stream +- * BY this, it is logic clean to separate stream and link */ +- link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, +- pipe_ctx->stream_res.stream_enc->id, true); ++ ++ + + } + +@@ -1690,9 +1693,13 @@ static void apply_min_clocks( + * Check if FBC can be enabled + */ + static bool should_enable_fbc(struct dc *dc, +- struct dc_state *context) ++ struct dc_state *context, ++ uint32_t *pipe_idx) + { +- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[0]; ++ uint32_t i; ++ struct pipe_ctx *pipe_ctx = NULL; ++ struct resource_context *res_ctx = &context->res_ctx; ++ + + ASSERT(dc->fbc_compressor); + +@@ -1704,6 +1711,14 @@ static bool should_enable_fbc(struct dc *dc, + if (context->stream_count != 1) + return false; + ++ for (i = 0; i < dc->res_pool->pipe_count; i++) { ++ if (res_ctx->pipe_ctx[i].stream) { ++ pipe_ctx = &res_ctx->pipe_ctx[i]; ++ *pipe_idx = i; ++ break; ++ } ++ } ++ + /* Only supports eDP */ + if (pipe_ctx->stream->sink->link->connector_signal != SIGNAL_TYPE_EDP) + return false; +@@ -1729,11 +1744,14 @@ static bool should_enable_fbc(struct dc *dc, + static void enable_fbc(struct dc *dc, + struct dc_state *context) + { +- if (should_enable_fbc(dc, context)) { ++ uint32_t pipe_idx = 0; ++ ++ if (should_enable_fbc(dc, context, &pipe_idx)) { + /* Program GRPH COMPRESSED ADDRESS and PITCH */ + struct compr_addr_and_pitch_params params = {0, 0, 0}; + struct compressor *compr = dc->fbc_compressor; +- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[0]; ++ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx]; ++ + + params.source_view_width = pipe_ctx->stream->timing.h_addressable; + params.source_view_height = pipe_ctx->stream->timing.v_addressable; +@@ -2915,6 +2933,49 @@ static void program_csc_matrix(struct pipe_ctx *pipe_ctx, + } + } + ++void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx) ++{ ++ struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; ++ struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; ++ struct mem_input *mi = pipe_ctx->plane_res.mi; ++ struct dc_cursor_mi_param param = { ++ .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, ++ .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, ++ .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, ++ .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, ++ .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz ++ }; ++ ++ if (pipe_ctx->plane_state->address.type ++ == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) ++ pos_cpy.enable = false; ++ ++ if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) ++ pos_cpy.enable = false; ++ ++ if (ipp->funcs->ipp_cursor_set_position) ++ ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, ¶m); ++ if (mi->funcs->set_cursor_position) ++ mi->funcs->set_cursor_position(mi, &pos_cpy, ¶m); ++} ++ ++void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx) ++{ ++ struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; ++ ++ if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes) ++ pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes( ++ pipe_ctx->plane_res.ipp, attributes); ++ ++ if (pipe_ctx->plane_res.mi->funcs->set_cursor_attributes) ++ pipe_ctx->plane_res.mi->funcs->set_cursor_attributes( ++ pipe_ctx->plane_res.mi, attributes); ++ ++ if (pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes) ++ pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes( ++ pipe_ctx->plane_res.xfm, attributes); ++} ++ + static void ready_shared_resources(struct dc *dc, struct dc_state *context) {} + + static void optimize_shared_resources(struct dc *dc) {} +@@ -2957,6 +3018,8 @@ static const struct hw_sequencer_funcs dce110_funcs = { + .edp_backlight_control = hwss_edp_backlight_control, + .edp_power_control = hwss_edp_power_control, + .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, ++ .set_cursor_position = dce110_set_cursor_position, ++ .set_cursor_attribute = dce110_set_cursor_attribute + }; + + void dce110_hw_sequencer_construct(struct dc *dc) +diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +index 7c47795..00f18c4 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +@@ -846,6 +846,16 @@ static bool dce110_validate_bandwidth( + return result; + } + ++enum dc_status dce110_validate_plane(const struct dc_plane_state *plane_state, ++ struct dc_caps *caps) ++{ ++ if (((plane_state->dst_rect.width * 2) < plane_state->src_rect.width) || ++ ((plane_state->dst_rect.height * 2) < plane_state->src_rect.height)) ++ return DC_FAIL_SURFACE_VALIDATE; ++ ++ return DC_OK; ++} ++ + static bool dce110_validate_surface_sets( + struct dc_state *context) + { +@@ -869,6 +879,13 @@ static bool dce110_validate_surface_sets( + plane->src_rect.height > 1080)) + return false; + ++ /* we don't have the logic to support underlay ++ * only yet so block the use case where we get ++ * NV12 plane as top layer ++ */ ++ if (j == 0) ++ return false; ++ + /* irrespective of plane format, + * stream should be RGB encoded + */ +@@ -1021,6 +1038,7 @@ static const struct resource_funcs dce110_res_pool_funcs = { + .link_enc_create = dce110_link_encoder_create, + .validate_guaranteed = dce110_validate_guaranteed, + .validate_bandwidth = dce110_validate_bandwidth, ++ .validate_plane = dce110_validate_plane, + .acquire_idle_pipe_for_layer = dce110_acquire_underlay, + .add_stream_to_ctx = dce110_add_stream_to_ctx, + .validate_global = dce110_validate_global +diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +index 663e0a0..98d9cd0 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +@@ -1103,6 +1103,8 @@ static bool construct( + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.max_cursor_size = 128; ++ dc->caps.dual_link_dvi = true; ++ + + /************************************************* + * Create resources * +diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +index 57cd673..5aab01d 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +@@ -835,6 +835,8 @@ static bool construct( + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.max_cursor_size = 128; ++ dc->caps.dual_link_dvi = true; ++ + dc->debug = debug_defaults; + + /************************************************* +diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +index 8f2bd56..25d7eb1 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +@@ -793,6 +793,7 @@ static bool dce80_construct( + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 40; + dc->caps.max_cursor_size = 128; ++ dc->caps.dual_link_dvi = true; + + /************************************************* + * Create resources * +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 8257286..072e448 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 +@@ -238,10 +238,24 @@ static void enable_power_gating_plane( + static void disable_vga( + struct dce_hwseq *hws) + { ++ unsigned int in_vga_mode = 0; ++ ++ REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga_mode); ++ ++ if (in_vga_mode == 0) ++ return; ++ + REG_WRITE(D1VGA_CONTROL, 0); +- REG_WRITE(D2VGA_CONTROL, 0); +- REG_WRITE(D3VGA_CONTROL, 0); +- REG_WRITE(D4VGA_CONTROL, 0); ++ ++ /* HW Engineer's Notes: ++ * During switch from vga->extended, if we set the VGA_TEST_ENABLE and ++ * then hit the VGA_TEST_RENDER_START, then the DCHUBP timing gets updated correctly. ++ * ++ * Then vBIOS will have it poll for the VGA_TEST_RENDER_DONE and unset ++ * VGA_TEST_ENABLE, to leave it in the same state as before. ++ */ ++ REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_ENABLE, 1); ++ REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1); + } + + static void dpp_pg_control( +@@ -1761,6 +1775,11 @@ static void update_dchubp_dpp( + &pipe_ctx->plane_res.scl_data.viewport_c); + } + ++ if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { ++ dc->hwss.set_cursor_position(pipe_ctx); ++ dc->hwss.set_cursor_attribute(pipe_ctx); ++ } ++ + if (plane_state->update_flags.bits.full_update) { + /*gamut remap*/ + program_gamut_remap(pipe_ctx); +@@ -2296,7 +2315,7 @@ static bool dcn10_dummy_display_power_gating( + return true; + } + +-void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) ++static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) + { + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + struct timing_generator *tg = pipe_ctx->stream_res.tg; +@@ -2316,12 +2335,46 @@ void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) + } + } + +-void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) ++static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) + { + if (hws->ctx->dc->res_pool->hubbub != NULL) + hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data); + } + ++static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) ++{ ++ struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; ++ struct hubp *hubp = pipe_ctx->plane_res.hubp; ++ struct dpp *dpp = pipe_ctx->plane_res.dpp; ++ struct dc_cursor_mi_param param = { ++ .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, ++ .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, ++ .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, ++ .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, ++ .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz ++ }; ++ ++ if (pipe_ctx->plane_state->address.type ++ == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) ++ pos_cpy.enable = false; ++ ++ if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) ++ pos_cpy.enable = false; ++ ++ hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); ++ dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width); ++} ++ ++static void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) ++{ ++ struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; ++ ++ pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( ++ pipe_ctx->plane_res.hubp, attributes); ++ pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( ++ pipe_ctx->plane_res.dpp, attributes->color_format); ++} ++ + static const struct hw_sequencer_funcs dcn10_funcs = { + .program_gamut_remap = program_gamut_remap, + .program_csc_matrix = program_csc_matrix, +@@ -2362,6 +2415,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = { + .edp_backlight_control = hwss_edp_backlight_control, + .edp_power_control = hwss_edp_power_control, + .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, ++ .set_cursor_position = dcn10_set_cursor_position, ++ .set_cursor_attribute = dcn10_set_cursor_attribute + }; + + +diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +index 0fd329d..54d8a13 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +@@ -123,8 +123,7 @@ struct link_encoder_funcs { + void (*enable_tmds_output)(struct link_encoder *enc, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, +- bool hdmi, +- bool dual_link, ++ enum signal_type signal, + uint32_t pixel_clock); + void (*enable_dp_output)(struct link_encoder *enc, + const struct dc_link_settings *link_settings, +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 4c0aa56..379c6ec 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +@@ -198,6 +198,9 @@ struct hw_sequencer_funcs { + bool enable); + void (*edp_wait_for_hpd_ready)(struct dc_link *link, bool power_up); + ++ void (*set_cursor_position)(struct pipe_ctx *pipe); ++ void (*set_cursor_attribute)(struct pipe_ctx *pipe); ++ + }; + + void color_space_to_black_color( +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 f7e40b2..d3e1923 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 +@@ -217,7 +217,7 @@ bool dce110_vblank_set( + core_dc->current_state->res_ctx.pipe_ctx[pipe_offset].stream_res.tg; + + if (enable) { +- if (!tg->funcs->arm_vert_intr(tg, 2)) { ++ if (!tg || !tg->funcs->arm_vert_intr(tg, 2)) { + DC_ERROR("Failed to get VBLANK!\n"); + return false; + } +diff --git a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c +index 57a54a7..1c079ba 100644 +--- a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c +@@ -42,8 +42,7 @@ static void virtual_link_encoder_enable_tmds_output( + struct link_encoder *enc, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, +- bool hdmi, +- bool dual_link, ++ enum signal_type signal, + uint32_t pixel_clock) {} + + static void virtual_link_encoder_enable_dp_output( +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 7a9b43f..36bbad5 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 +@@ -419,11 +419,6 @@ struct bios_event_info { + bool backlight_changed; + }; + +-enum { +- HDMI_PIXEL_CLOCK_IN_KHZ_297 = 297000, +- TMDS_PIXEL_CLOCK_IN_KHZ_165 = 165000 +-}; +- + /* + * DFS-bypass flag + */ +diff --git a/drivers/gpu/drm/amd/display/include/signal_types.h b/drivers/gpu/drm/amd/display/include/signal_types.h +index b5ebde6..199c5db 100644 +--- a/drivers/gpu/drm/amd/display/include/signal_types.h ++++ b/drivers/gpu/drm/amd/display/include/signal_types.h +@@ -26,6 +26,11 @@ + #ifndef __DC_SIGNAL_TYPES_H__ + #define __DC_SIGNAL_TYPES_H__ + ++/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */ ++#define TMDS_MIN_PIXEL_CLOCK 25000 ++/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */ ++#define TMDS_MAX_PIXEL_CLOCK 165000 ++ + enum signal_type { + SIGNAL_TYPE_NONE = 0L, /* no signal */ + SIGNAL_TYPE_DVI_SINGLE_LINK = (1 << 0), +diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c +index dd89abd..66ee9d8 100644 +--- a/drivers/gpu/drm/i915/i915_gem.c ++++ b/drivers/gpu/drm/i915/i915_gem.c +@@ -3205,8 +3205,10 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) + * rolling the global seqno forward (since this would complete requests + * for which we haven't set the fence error to EIO yet). + */ +- for_each_engine(engine, i915, id) ++ for_each_engine(engine, i915, id) { ++ i915_gem_reset_prepare_engine(engine); + engine->submit_request = nop_submit_request; ++ } + + /* + * Make sure no one is running the old callback before we proceed with +@@ -3244,6 +3246,8 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) + intel_engine_init_global_seqno(engine, + intel_engine_last_submit(engine)); + spin_unlock_irqrestore(&engine->timeline->lock, flags); ++ ++ i915_gem_reset_finish_engine(engine); + } + + set_bit(I915_WEDGED, &i915->gpu_error.flags); +diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c +index 0be50e4..f8fe5ff 100644 +--- a/drivers/gpu/drm/i915/i915_perf.c ++++ b/drivers/gpu/drm/i915/i915_perf.c +@@ -1303,9 +1303,8 @@ static void i915_oa_stream_destroy(struct i915_perf_stream *stream) + */ + mutex_lock(&dev_priv->drm.struct_mutex); + dev_priv->perf.oa.exclusive_stream = NULL; +- mutex_unlock(&dev_priv->drm.struct_mutex); +- + dev_priv->perf.oa.ops.disable_metric_set(dev_priv); ++ mutex_unlock(&dev_priv->drm.struct_mutex); + + free_oa_buffer(dev_priv); + +@@ -1756,22 +1755,13 @@ static int gen8_switch_to_updated_kernel_context(struct drm_i915_private *dev_pr + * Note: it's only the RCS/Render context that has any OA state. + */ + static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv, +- const struct i915_oa_config *oa_config, +- bool interruptible) ++ const struct i915_oa_config *oa_config) + { + struct i915_gem_context *ctx; + int ret; + unsigned int wait_flags = I915_WAIT_LOCKED; + +- if (interruptible) { +- ret = i915_mutex_lock_interruptible(&dev_priv->drm); +- if (ret) +- return ret; +- +- wait_flags |= I915_WAIT_INTERRUPTIBLE; +- } else { +- mutex_lock(&dev_priv->drm.struct_mutex); +- } ++ lockdep_assert_held(&dev_priv->drm.struct_mutex); + + /* Switch away from any user context. */ + ret = gen8_switch_to_updated_kernel_context(dev_priv, oa_config); +@@ -1819,8 +1809,6 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv, + } + + out: +- mutex_unlock(&dev_priv->drm.struct_mutex); +- + return ret; + } + +@@ -1863,7 +1851,7 @@ static int gen8_enable_metric_set(struct drm_i915_private *dev_priv, + * to make sure all slices/subslices are ON before writing to NOA + * registers. + */ +- ret = gen8_configure_all_contexts(dev_priv, oa_config, true); ++ ret = gen8_configure_all_contexts(dev_priv, oa_config); + if (ret) + return ret; + +@@ -1878,7 +1866,7 @@ static int gen8_enable_metric_set(struct drm_i915_private *dev_priv, + static void gen8_disable_metric_set(struct drm_i915_private *dev_priv) + { + /* Reset all contexts' slices/subslices configurations. */ +- gen8_configure_all_contexts(dev_priv, NULL, false); ++ gen8_configure_all_contexts(dev_priv, NULL); + + I915_WRITE(GDT_CHICKEN_BITS, (I915_READ(GDT_CHICKEN_BITS) & + ~GT_NOA_ENABLE)); +@@ -1888,7 +1876,7 @@ static void gen8_disable_metric_set(struct drm_i915_private *dev_priv) + static void gen10_disable_metric_set(struct drm_i915_private *dev_priv) + { + /* Reset all contexts' slices/subslices configurations. */ +- gen8_configure_all_contexts(dev_priv, NULL, false); ++ gen8_configure_all_contexts(dev_priv, NULL); + + /* Make sure we disable noa to save power. */ + I915_WRITE(RPM_CONFIG1, +@@ -2138,6 +2126,10 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, + if (ret) + goto err_oa_buf_alloc; + ++ ret = i915_mutex_lock_interruptible(&dev_priv->drm); ++ if (ret) ++ goto err_lock; ++ + ret = dev_priv->perf.oa.ops.enable_metric_set(dev_priv, + stream->oa_config); + if (ret) +@@ -2145,23 +2137,17 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, + + stream->ops = &i915_oa_stream_ops; + +- /* Lock device for exclusive_stream access late because +- * enable_metric_set() might lock as well on gen8+. +- */ +- ret = i915_mutex_lock_interruptible(&dev_priv->drm); +- if (ret) +- goto err_lock; +- + dev_priv->perf.oa.exclusive_stream = stream; + + mutex_unlock(&dev_priv->drm.struct_mutex); + + return 0; + +-err_lock: ++err_enable: + dev_priv->perf.oa.ops.disable_metric_set(dev_priv); ++ mutex_unlock(&dev_priv->drm.struct_mutex); + +-err_enable: ++err_lock: + free_oa_buffer(dev_priv); + + err_oa_buf_alloc: +diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c +index 7ece2f0..e0fca03 100644 +--- a/drivers/gpu/drm/i915/intel_lrc.c ++++ b/drivers/gpu/drm/i915/intel_lrc.c +@@ -719,6 +719,8 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) + struct rb_node *rb; + unsigned long flags; + ++ GEM_TRACE("%s\n", engine->name); ++ + spin_lock_irqsave(&engine->timeline->lock, flags); + + /* Cancel the requests on the HW and clear the ELSP tracker. */ +@@ -765,6 +767,9 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) + */ + clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); + ++ /* Mark all CS interrupts as complete */ ++ execlists->active = 0; ++ + spin_unlock_irqrestore(&engine->timeline->lock, flags); + } + +diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c +index d3045a3..7c73bc7 100644 +--- a/drivers/gpu/drm/radeon/cik.c ++++ b/drivers/gpu/drm/radeon/cik.c +@@ -3221,35 +3221,8 @@ static void cik_gpu_init(struct radeon_device *rdev) + case CHIP_KAVERI: + rdev->config.cik.max_shader_engines = 1; + rdev->config.cik.max_tile_pipes = 4; +- if ((rdev->pdev->device == 0x1304) || +- (rdev->pdev->device == 0x1305) || +- (rdev->pdev->device == 0x130C) || +- (rdev->pdev->device == 0x130F) || +- (rdev->pdev->device == 0x1310) || +- (rdev->pdev->device == 0x1311) || +- (rdev->pdev->device == 0x131C)) { +- rdev->config.cik.max_cu_per_sh = 8; +- rdev->config.cik.max_backends_per_se = 2; +- } else if ((rdev->pdev->device == 0x1309) || +- (rdev->pdev->device == 0x130A) || +- (rdev->pdev->device == 0x130D) || +- (rdev->pdev->device == 0x1313) || +- (rdev->pdev->device == 0x131D)) { +- rdev->config.cik.max_cu_per_sh = 6; +- rdev->config.cik.max_backends_per_se = 2; +- } else if ((rdev->pdev->device == 0x1306) || +- (rdev->pdev->device == 0x1307) || +- (rdev->pdev->device == 0x130B) || +- (rdev->pdev->device == 0x130E) || +- (rdev->pdev->device == 0x1315) || +- (rdev->pdev->device == 0x1318) || +- (rdev->pdev->device == 0x131B)) { +- rdev->config.cik.max_cu_per_sh = 4; +- rdev->config.cik.max_backends_per_se = 1; +- } else { +- rdev->config.cik.max_cu_per_sh = 3; +- rdev->config.cik.max_backends_per_se = 1; +- } ++ rdev->config.cik.max_cu_per_sh = 8; ++ rdev->config.cik.max_backends_per_se = 2; + rdev->config.cik.max_sh_per_se = 1; + rdev->config.cik.max_texture_channel_caches = 4; + rdev->config.cik.max_gprs = 256; +diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c +index 5decae0..78cbc31 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c ++++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c +@@ -93,6 +93,8 @@ static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc, + + DRM_DEBUG_DRIVER("Disabling the CRTC\n"); + ++ drm_crtc_vblank_off(crtc); ++ + sun4i_tcon_set_status(scrtc->tcon, encoder, false); + + if (crtc->state->event && !crtc->state->active) { +@@ -113,6 +115,8 @@ static void sun4i_crtc_atomic_enable(struct drm_crtc *crtc, + DRM_DEBUG_DRIVER("Enabling the CRTC\n"); + + sun4i_tcon_set_status(scrtc->tcon, encoder, true); ++ ++ drm_crtc_vblank_on(crtc); + } + + static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc) +diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c +index 023f39b..e36004f 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c ++++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c +@@ -132,10 +132,13 @@ static int sun4i_dclk_get_phase(struct clk_hw *hw) + static int sun4i_dclk_set_phase(struct clk_hw *hw, int degrees) + { + struct sun4i_dclk *dclk = hw_to_dclk(hw); ++ u32 val = degrees / 120; ++ ++ val <<= 28; + + regmap_update_bits(dclk->regmap, SUN4I_TCON0_IO_POL_REG, + GENMASK(29, 28), +- degrees / 120); ++ val); + + return 0; + } +diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c +index 832f8f9..b8da5a5 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c ++++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c +@@ -92,6 +92,8 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector, + + DRM_DEBUG_DRIVER("Vertical parameters OK\n"); + ++ tcon->dclk_min_div = 6; ++ tcon->dclk_max_div = 127; + rounded_rate = clk_round_rate(tcon->dclk, rate); + if (rounded_rate < rate) + return MODE_CLOCK_LOW; +diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c +index b396011..2de586b 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c ++++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c +@@ -101,10 +101,12 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel, + return; + } + +- if (enabled) ++ if (enabled) { + clk_prepare_enable(clk); +- else ++ } else { ++ clk_rate_exclusive_put(clk); + clk_disable_unprepare(clk); ++ } + } + + static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon, +@@ -873,52 +875,56 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, + return ret; + } + +- /* +- * This can only be made optional since we've had DT nodes +- * without the LVDS reset properties. +- * +- * If the property is missing, just disable LVDS, and print a +- * warning. +- */ +- tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds"); +- if (IS_ERR(tcon->lvds_rst)) { +- dev_err(dev, "Couldn't get our reset line\n"); +- return PTR_ERR(tcon->lvds_rst); +- } else if (tcon->lvds_rst) { +- has_lvds_rst = true; +- reset_control_reset(tcon->lvds_rst); +- } else { +- has_lvds_rst = false; +- } ++ if (tcon->quirks->supports_lvds) { ++ /* ++ * This can only be made optional since we've had DT ++ * nodes without the LVDS reset properties. ++ * ++ * If the property is missing, just disable LVDS, and ++ * print a warning. ++ */ ++ tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds"); ++ if (IS_ERR(tcon->lvds_rst)) { ++ dev_err(dev, "Couldn't get our reset line\n"); ++ return PTR_ERR(tcon->lvds_rst); ++ } else if (tcon->lvds_rst) { ++ has_lvds_rst = true; ++ reset_control_reset(tcon->lvds_rst); ++ } else { ++ has_lvds_rst = false; ++ } + +- /* +- * This can only be made optional since we've had DT nodes +- * without the LVDS reset properties. +- * +- * If the property is missing, just disable LVDS, and print a +- * warning. +- */ +- if (tcon->quirks->has_lvds_alt) { +- tcon->lvds_pll = devm_clk_get(dev, "lvds-alt"); +- if (IS_ERR(tcon->lvds_pll)) { +- if (PTR_ERR(tcon->lvds_pll) == -ENOENT) { +- has_lvds_alt = false; ++ /* ++ * This can only be made optional since we've had DT ++ * nodes without the LVDS reset properties. ++ * ++ * If the property is missing, just disable LVDS, and ++ * print a warning. ++ */ ++ if (tcon->quirks->has_lvds_alt) { ++ tcon->lvds_pll = devm_clk_get(dev, "lvds-alt"); ++ if (IS_ERR(tcon->lvds_pll)) { ++ if (PTR_ERR(tcon->lvds_pll) == -ENOENT) { ++ has_lvds_alt = false; ++ } else { ++ dev_err(dev, "Couldn't get the LVDS PLL\n"); ++ return PTR_ERR(tcon->lvds_pll); ++ } + } else { +- dev_err(dev, "Couldn't get the LVDS PLL\n"); +- return PTR_ERR(tcon->lvds_pll); ++ has_lvds_alt = true; + } +- } else { +- has_lvds_alt = true; + } +- } + +- if (!has_lvds_rst || (tcon->quirks->has_lvds_alt && !has_lvds_alt)) { +- dev_warn(dev, +- "Missing LVDS properties, Please upgrade your DT\n"); +- dev_warn(dev, "LVDS output disabled\n"); +- can_lvds = false; ++ if (!has_lvds_rst || ++ (tcon->quirks->has_lvds_alt && !has_lvds_alt)) { ++ dev_warn(dev, "Missing LVDS properties, Please upgrade your DT\n"); ++ dev_warn(dev, "LVDS output disabled\n"); ++ can_lvds = false; ++ } else { ++ can_lvds = true; ++ } + } else { +- can_lvds = true; ++ can_lvds = false; + } + + ret = sun4i_tcon_init_clocks(dev, tcon); +@@ -1137,7 +1143,7 @@ static const struct sun4i_tcon_quirks sun8i_a33_quirks = { + }; + + static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = { +- /* nothing is supported */ ++ .supports_lvds = true, + }; + + static const struct sun4i_tcon_quirks sun8i_v3s_quirks = { +diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h +index b761c7b..278700c 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h ++++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h +@@ -175,6 +175,7 @@ struct sun4i_tcon_quirks { + bool has_channel_1; /* a33 does not have channel 1 */ + bool has_lvds_alt; /* Does the LVDS clock have a parent other than the TCON clock? */ + bool needs_de_be_mux; /* sun6i needs mux to select backend */ ++ bool supports_lvds; /* Does the TCON support an LVDS output? */ + + /* callback to handle tcon muxing options */ + int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *); +diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c +index a5b4cf0..9183d148d 100644 +--- a/drivers/infiniband/core/addr.c ++++ b/drivers/infiniband/core/addr.c +@@ -550,18 +550,13 @@ static int addr_resolve(struct sockaddr *src_in, + dst_release(dst); + } + +- if (ndev->flags & IFF_LOOPBACK) { +- ret = rdma_translate_ip(dst_in, addr); +- /* +- * Put the loopback device and get the translated +- * device instead. +- */ ++ if (ndev) { ++ if (ndev->flags & IFF_LOOPBACK) ++ ret = rdma_translate_ip(dst_in, addr); ++ else ++ addr->bound_dev_if = ndev->ifindex; + dev_put(ndev); +- ndev = dev_get_by_index(addr->net, addr->bound_dev_if); +- } else { +- addr->bound_dev_if = ndev->ifindex; + } +- dev_put(ndev); + + return ret; + } +diff --git a/drivers/infiniband/core/cq.c b/drivers/infiniband/core/cq.c +index bc79ca8..af5ad6a 100644 +--- a/drivers/infiniband/core/cq.c ++++ b/drivers/infiniband/core/cq.c +@@ -17,6 +17,7 @@ + + /* # of WCs to poll for with a single call to ib_poll_cq */ + #define IB_POLL_BATCH 16 ++#define IB_POLL_BATCH_DIRECT 8 + + /* # of WCs to iterate over before yielding */ + #define IB_POLL_BUDGET_IRQ 256 +@@ -25,18 +26,18 @@ + #define IB_POLL_FLAGS \ + (IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS) + +-static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) ++static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *wcs, ++ int batch) + { + int i, n, completed = 0; +- struct ib_wc *wcs = poll_wc ? : cq->wc; + + /* + * budget might be (-1) if the caller does not + * want to bound this call, thus we need unsigned + * minimum here. + */ +- while ((n = ib_poll_cq(cq, min_t(u32, IB_POLL_BATCH, +- budget - completed), wcs)) > 0) { ++ while ((n = ib_poll_cq(cq, min_t(u32, batch, ++ budget - completed), wcs)) > 0) { + for (i = 0; i < n; i++) { + struct ib_wc *wc = &wcs[i]; + +@@ -48,8 +49,7 @@ static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) + + completed += n; + +- if (n != IB_POLL_BATCH || +- (budget != -1 && completed >= budget)) ++ if (n != batch || (budget != -1 && completed >= budget)) + break; + } + +@@ -72,9 +72,9 @@ static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) + */ + int ib_process_cq_direct(struct ib_cq *cq, int budget) + { +- struct ib_wc wcs[IB_POLL_BATCH]; ++ struct ib_wc wcs[IB_POLL_BATCH_DIRECT]; + +- return __ib_process_cq(cq, budget, wcs); ++ return __ib_process_cq(cq, budget, wcs, IB_POLL_BATCH_DIRECT); + } + EXPORT_SYMBOL(ib_process_cq_direct); + +@@ -88,7 +88,7 @@ static int ib_poll_handler(struct irq_poll *iop, int budget) + struct ib_cq *cq = container_of(iop, struct ib_cq, iop); + int completed; + +- completed = __ib_process_cq(cq, budget, NULL); ++ completed = __ib_process_cq(cq, budget, cq->wc, IB_POLL_BATCH); + if (completed < budget) { + irq_poll_complete(&cq->iop); + if (ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0) +@@ -108,7 +108,8 @@ static void ib_cq_poll_work(struct work_struct *work) + struct ib_cq *cq = container_of(work, struct ib_cq, work); + int completed; + +- completed = __ib_process_cq(cq, IB_POLL_BUDGET_WORKQUEUE, NULL); ++ completed = __ib_process_cq(cq, IB_POLL_BUDGET_WORKQUEUE, cq->wc, ++ IB_POLL_BATCH); + if (completed >= IB_POLL_BUDGET_WORKQUEUE || + ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0) + queue_work(ib_comp_wq, &cq->work); +diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c +index e8010e7..bb065c9 100644 +--- a/drivers/infiniband/core/device.c ++++ b/drivers/infiniband/core/device.c +@@ -536,14 +536,14 @@ int ib_register_device(struct ib_device *device, + ret = device->query_device(device, &device->attrs, &uhw); + if (ret) { + pr_warn("Couldn't query the device attributes\n"); +- goto cache_cleanup; ++ goto cg_cleanup; + } + + ret = ib_device_register_sysfs(device, port_callback); + if (ret) { + pr_warn("Couldn't register device %s with driver model\n", + device->name); +- goto cache_cleanup; ++ goto cg_cleanup; + } + + device->reg_state = IB_DEV_REGISTERED; +@@ -559,6 +559,8 @@ int ib_register_device(struct ib_device *device, + mutex_unlock(&device_mutex); + return 0; + ++cg_cleanup: ++ ib_device_unregister_rdmacg(device); + cache_cleanup: + ib_cache_cleanup_one(device); + ib_cache_release_one(device); +diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c +index 8cf15d4..9f029a1 100644 +--- a/drivers/infiniband/core/sa_query.c ++++ b/drivers/infiniband/core/sa_query.c +@@ -1291,10 +1291,9 @@ int ib_init_ah_attr_from_path(struct ib_device *device, u8 port_num, + + resolved_dev = dev_get_by_index(dev_addr.net, + dev_addr.bound_dev_if); +- if (resolved_dev->flags & IFF_LOOPBACK) { +- dev_put(resolved_dev); +- resolved_dev = idev; +- dev_hold(resolved_dev); ++ if (!resolved_dev) { ++ dev_put(idev); ++ return -ENODEV; + } + ndev = ib_get_ndev_from_path(rec); + rcu_read_lock(); +diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c +index f015f1b..3a9d0f5 100644 +--- a/drivers/infiniband/core/ucma.c ++++ b/drivers/infiniband/core/ucma.c +@@ -1149,6 +1149,9 @@ static ssize_t ucma_init_qp_attr(struct ucma_file *file, + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + ++ if (cmd.qp_state > IB_QPS_ERR) ++ return -EINVAL; ++ + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); +@@ -1294,6 +1297,9 @@ static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf, + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + ++ if (unlikely(cmd.optval > KMALLOC_MAX_SIZE)) ++ return -EINVAL; ++ + optval = memdup_user((void __user *) (unsigned long) cmd.optval, + cmd.optlen); + if (IS_ERR(optval)) { +diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +index 643174d..0dd75f4 100644 +--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c ++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c +@@ -785,7 +785,7 @@ int bnxt_re_query_ah(struct ib_ah *ib_ah, struct rdma_ah_attr *ah_attr) + return 0; + } + +-static unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp) ++unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp) + __acquires(&qp->scq->cq_lock) __acquires(&qp->rcq->cq_lock) + { + unsigned long flags; +@@ -799,8 +799,8 @@ static unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp) + return flags; + } + +-static void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp, +- unsigned long flags) ++void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp, ++ unsigned long flags) + __releases(&qp->scq->cq_lock) __releases(&qp->rcq->cq_lock) + { + if (qp->rcq != qp->scq) +@@ -1606,6 +1606,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, + int status; + union ib_gid sgid; + struct ib_gid_attr sgid_attr; ++ unsigned int flags; + u8 nw_type; + + qp->qplib_qp.modify_flags = 0; +@@ -1634,14 +1635,18 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, + dev_dbg(rdev_to_dev(rdev), + "Move QP = %p to flush list\n", + qp); ++ flags = bnxt_re_lock_cqs(qp); + bnxt_qplib_add_flush_qp(&qp->qplib_qp); ++ bnxt_re_unlock_cqs(qp, flags); + } + if (!qp->sumem && + qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_RESET) { + dev_dbg(rdev_to_dev(rdev), + "Move QP = %p out of flush list\n", + qp); ++ flags = bnxt_re_lock_cqs(qp); + bnxt_qplib_clean_qp(&qp->qplib_qp); ++ bnxt_re_unlock_cqs(qp, flags); + } + } + if (qp_attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) { +@@ -2227,10 +2232,13 @@ static int bnxt_re_build_inv_wqe(struct ib_send_wr *wr, + wqe->type = BNXT_QPLIB_SWQE_TYPE_LOCAL_INV; + wqe->local_inv.inv_l_key = wr->ex.invalidate_rkey; + ++ /* Need unconditional fence for local invalidate ++ * opcode to work as expected. ++ */ ++ wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; ++ + if (wr->send_flags & IB_SEND_SIGNALED) + wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP; +- if (wr->send_flags & IB_SEND_FENCE) +- wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; + if (wr->send_flags & IB_SEND_SOLICITED) + wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SOLICIT_EVENT; + +@@ -2251,8 +2259,12 @@ static int bnxt_re_build_reg_wqe(struct ib_reg_wr *wr, + wqe->frmr.levels = qplib_frpl->hwq.level + 1; + wqe->type = BNXT_QPLIB_SWQE_TYPE_REG_MR; + +- if (wr->wr.send_flags & IB_SEND_FENCE) +- wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; ++ /* Need unconditional fence for reg_mr ++ * opcode to function as expected. ++ */ ++ ++ wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE; ++ + if (wr->wr.send_flags & IB_SEND_SIGNALED) + wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP; + +diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h +index b88a48d..e62b7c2 100644 +--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h ++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h +@@ -222,4 +222,7 @@ struct ib_ucontext *bnxt_re_alloc_ucontext(struct ib_device *ibdev, + struct ib_udata *udata); + int bnxt_re_dealloc_ucontext(struct ib_ucontext *context); + int bnxt_re_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); ++ ++unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp); ++void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp, unsigned long flags); + #endif /* __BNXT_RE_IB_VERBS_H__ */ +diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c +index 33a4480..f6e3617 100644 +--- a/drivers/infiniband/hw/bnxt_re/main.c ++++ b/drivers/infiniband/hw/bnxt_re/main.c +@@ -730,6 +730,13 @@ static int bnxt_re_handle_qp_async_event(struct creq_qp_event *qp_event, + struct bnxt_re_qp *qp) + { + struct ib_event event; ++ unsigned int flags; ++ ++ if (qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR) { ++ flags = bnxt_re_lock_cqs(qp); ++ bnxt_qplib_add_flush_qp(&qp->qplib_qp); ++ bnxt_re_unlock_cqs(qp, flags); ++ } + + memset(&event, 0, sizeof(event)); + if (qp->qplib_qp.srq) { +@@ -1416,9 +1423,12 @@ static void bnxt_re_task(struct work_struct *work) + switch (re_work->event) { + case NETDEV_REGISTER: + rc = bnxt_re_ib_reg(rdev); +- if (rc) ++ if (rc) { + dev_err(rdev_to_dev(rdev), + "Failed to register with IB: %#x", rc); ++ bnxt_re_remove_one(rdev); ++ bnxt_re_dev_unreg(rdev); ++ } + break; + case NETDEV_UP: + bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1, +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c +index 3ea5b96..06b42c8 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c +@@ -88,75 +88,35 @@ static void __bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp) + } + } + +-void bnxt_qplib_acquire_cq_locks(struct bnxt_qplib_qp *qp, +- unsigned long *flags) +- __acquires(&qp->scq->hwq.lock) __acquires(&qp->rcq->hwq.lock) ++static void bnxt_qplib_acquire_cq_flush_locks(struct bnxt_qplib_qp *qp, ++ unsigned long *flags) ++ __acquires(&qp->scq->flush_lock) __acquires(&qp->rcq->flush_lock) + { +- spin_lock_irqsave(&qp->scq->hwq.lock, *flags); ++ spin_lock_irqsave(&qp->scq->flush_lock, *flags); + if (qp->scq == qp->rcq) +- __acquire(&qp->rcq->hwq.lock); ++ __acquire(&qp->rcq->flush_lock); + else +- spin_lock(&qp->rcq->hwq.lock); ++ spin_lock(&qp->rcq->flush_lock); + } + +-void bnxt_qplib_release_cq_locks(struct bnxt_qplib_qp *qp, +- unsigned long *flags) +- __releases(&qp->scq->hwq.lock) __releases(&qp->rcq->hwq.lock) ++static void bnxt_qplib_release_cq_flush_locks(struct bnxt_qplib_qp *qp, ++ unsigned long *flags) ++ __releases(&qp->scq->flush_lock) __releases(&qp->rcq->flush_lock) + { + if (qp->scq == qp->rcq) +- __release(&qp->rcq->hwq.lock); ++ __release(&qp->rcq->flush_lock); + else +- spin_unlock(&qp->rcq->hwq.lock); +- spin_unlock_irqrestore(&qp->scq->hwq.lock, *flags); +-} +- +-static struct bnxt_qplib_cq *bnxt_qplib_find_buddy_cq(struct bnxt_qplib_qp *qp, +- struct bnxt_qplib_cq *cq) +-{ +- struct bnxt_qplib_cq *buddy_cq = NULL; +- +- if (qp->scq == qp->rcq) +- buddy_cq = NULL; +- else if (qp->scq == cq) +- buddy_cq = qp->rcq; +- else +- buddy_cq = qp->scq; +- return buddy_cq; +-} +- +-static void bnxt_qplib_lock_buddy_cq(struct bnxt_qplib_qp *qp, +- struct bnxt_qplib_cq *cq) +- __acquires(&buddy_cq->hwq.lock) +-{ +- struct bnxt_qplib_cq *buddy_cq = NULL; +- +- buddy_cq = bnxt_qplib_find_buddy_cq(qp, cq); +- if (!buddy_cq) +- __acquire(&cq->hwq.lock); +- else +- spin_lock(&buddy_cq->hwq.lock); +-} +- +-static void bnxt_qplib_unlock_buddy_cq(struct bnxt_qplib_qp *qp, +- struct bnxt_qplib_cq *cq) +- __releases(&buddy_cq->hwq.lock) +-{ +- struct bnxt_qplib_cq *buddy_cq = NULL; +- +- buddy_cq = bnxt_qplib_find_buddy_cq(qp, cq); +- if (!buddy_cq) +- __release(&cq->hwq.lock); +- else +- spin_unlock(&buddy_cq->hwq.lock); ++ spin_unlock(&qp->rcq->flush_lock); ++ spin_unlock_irqrestore(&qp->scq->flush_lock, *flags); + } + + void bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp) + { + unsigned long flags; + +- bnxt_qplib_acquire_cq_locks(qp, &flags); ++ bnxt_qplib_acquire_cq_flush_locks(qp, &flags); + __bnxt_qplib_add_flush_qp(qp); +- bnxt_qplib_release_cq_locks(qp, &flags); ++ bnxt_qplib_release_cq_flush_locks(qp, &flags); + } + + static void __bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp) +@@ -177,7 +137,7 @@ void bnxt_qplib_clean_qp(struct bnxt_qplib_qp *qp) + { + unsigned long flags; + +- bnxt_qplib_acquire_cq_locks(qp, &flags); ++ bnxt_qplib_acquire_cq_flush_locks(qp, &flags); + __clean_cq(qp->scq, (u64)(unsigned long)qp); + qp->sq.hwq.prod = 0; + qp->sq.hwq.cons = 0; +@@ -186,7 +146,7 @@ void bnxt_qplib_clean_qp(struct bnxt_qplib_qp *qp) + qp->rq.hwq.cons = 0; + + __bnxt_qplib_del_flush_qp(qp); +- bnxt_qplib_release_cq_locks(qp, &flags); ++ bnxt_qplib_release_cq_flush_locks(qp, &flags); + } + + static void bnxt_qpn_cqn_sched_task(struct work_struct *work) +@@ -2107,9 +2067,6 @@ void bnxt_qplib_mark_qp_error(void *qp_handle) + /* Must block new posting of SQ and RQ */ + qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; + bnxt_qplib_cancel_phantom_processing(qp); +- +- /* Add qp to flush list of the CQ */ +- __bnxt_qplib_add_flush_qp(qp); + } + + /* Note: SQE is valid from sw_sq_cons up to cqe_sq_cons (exclusive) +@@ -2285,9 +2242,9 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq, + sw_sq_cons, cqe->wr_id, cqe->status); + cqe++; + (*budget)--; +- bnxt_qplib_lock_buddy_cq(qp, cq); + bnxt_qplib_mark_qp_error(qp); +- bnxt_qplib_unlock_buddy_cq(qp, cq); ++ /* Add qp to flush list of the CQ */ ++ bnxt_qplib_add_flush_qp(qp); + } else { + if (swq->flags & SQ_SEND_FLAGS_SIGNAL_COMP) { + /* Before we complete, do WA 9060 */ +@@ -2403,9 +2360,7 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq, + if (hwcqe->status != CQ_RES_RC_STATUS_OK) { + qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; + /* Add qp to flush list of the CQ */ +- bnxt_qplib_lock_buddy_cq(qp, cq); +- __bnxt_qplib_add_flush_qp(qp); +- bnxt_qplib_unlock_buddy_cq(qp, cq); ++ bnxt_qplib_add_flush_qp(qp); + } + } + +@@ -2489,9 +2444,7 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq, + if (hwcqe->status != CQ_RES_RC_STATUS_OK) { + qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; + /* Add qp to flush list of the CQ */ +- bnxt_qplib_lock_buddy_cq(qp, cq); +- __bnxt_qplib_add_flush_qp(qp); +- bnxt_qplib_unlock_buddy_cq(qp, cq); ++ bnxt_qplib_add_flush_qp(qp); + } + } + done: +@@ -2501,11 +2454,9 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq, + bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq) + { + struct cq_base *hw_cqe, **hw_cqe_ptr; +- unsigned long flags; + u32 sw_cons, raw_cons; + bool rc = true; + +- spin_lock_irqsave(&cq->hwq.lock, flags); + raw_cons = cq->hwq.cons; + sw_cons = HWQ_CMP(raw_cons, &cq->hwq); + hw_cqe_ptr = (struct cq_base **)cq->hwq.pbl_ptr; +@@ -2513,7 +2464,6 @@ bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq) + + /* Check for Valid bit. If the CQE is valid, return false */ + rc = !CQE_CMP_VALID(hw_cqe, raw_cons, cq->hwq.max_elements); +- spin_unlock_irqrestore(&cq->hwq.lock, flags); + return rc; + } + +@@ -2602,9 +2552,7 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq, + if (hwcqe->status != CQ_RES_RC_STATUS_OK) { + qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR; + /* Add qp to flush list of the CQ */ +- bnxt_qplib_lock_buddy_cq(qp, cq); +- __bnxt_qplib_add_flush_qp(qp); +- bnxt_qplib_unlock_buddy_cq(qp, cq); ++ bnxt_qplib_add_flush_qp(qp); + } + } + +@@ -2719,9 +2667,7 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq, + */ + + /* Add qp to flush list of the CQ */ +- bnxt_qplib_lock_buddy_cq(qp, cq); +- __bnxt_qplib_add_flush_qp(qp); +- bnxt_qplib_unlock_buddy_cq(qp, cq); ++ bnxt_qplib_add_flush_qp(qp); + done: + return rc; + } +@@ -2750,7 +2696,7 @@ int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq, + u32 budget = num_cqes; + unsigned long flags; + +- spin_lock_irqsave(&cq->hwq.lock, flags); ++ spin_lock_irqsave(&cq->flush_lock, flags); + list_for_each_entry(qp, &cq->sqf_head, sq_flush) { + dev_dbg(&cq->hwq.pdev->dev, + "QPLIB: FP: Flushing SQ QP= %p", +@@ -2764,7 +2710,7 @@ int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq, + qp); + __flush_rq(&qp->rq, qp, &cqe, &budget); + } +- spin_unlock_irqrestore(&cq->hwq.lock, flags); ++ spin_unlock_irqrestore(&cq->flush_lock, flags); + + return num_cqes - budget; + } +@@ -2773,11 +2719,9 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, + int num_cqes, struct bnxt_qplib_qp **lib_qp) + { + struct cq_base *hw_cqe, **hw_cqe_ptr; +- unsigned long flags; + u32 sw_cons, raw_cons; + int budget, rc = 0; + +- spin_lock_irqsave(&cq->hwq.lock, flags); + raw_cons = cq->hwq.cons; + budget = num_cqes; + +@@ -2853,20 +2797,15 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, + bnxt_qplib_arm_cq(cq, DBR_DBR_TYPE_CQ); + } + exit: +- spin_unlock_irqrestore(&cq->hwq.lock, flags); + return num_cqes - budget; + } + + void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type) + { +- unsigned long flags; +- +- spin_lock_irqsave(&cq->hwq.lock, flags); + if (arm_type) + bnxt_qplib_arm_cq(cq, arm_type); + /* Using cq->arm_state variable to track whether to issue cq handler */ + atomic_set(&cq->arm_state, 1); +- spin_unlock_irqrestore(&cq->hwq.lock, flags); + } + + void bnxt_qplib_flush_cqn_wq(struct bnxt_qplib_qp *qp) +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h +index ca0a2ff..ade9f13 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h ++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h +@@ -389,6 +389,18 @@ struct bnxt_qplib_cq { + struct list_head sqf_head, rqf_head; + atomic_t arm_state; + spinlock_t compl_lock; /* synch CQ handlers */ ++/* Locking Notes: ++ * QP can move to error state from modify_qp, async error event or error ++ * CQE as part of poll_cq. When QP is moved to error state, it gets added ++ * to two flush lists, one each for SQ and RQ. ++ * Each flush list is protected by qplib_cq->flush_lock. Both scq and rcq ++ * flush_locks should be acquired when QP is moved to error. The control path ++ * operations(modify_qp and async error events) are synchronized with poll_cq ++ * using upper level CQ locks (bnxt_re_cq->cq_lock) of both SCQ and RCQ. ++ * The qplib_cq->flush_lock is required to synchronize two instances of poll_cq ++ * of the same QP while manipulating the flush list. ++ */ ++ spinlock_t flush_lock; /* QP flush management */ + }; + + #define BNXT_QPLIB_MAX_IRRQE_ENTRY_SIZE sizeof(struct xrrq_irrq) +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +index 8329ec6..80027a4 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +@@ -305,9 +305,8 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw, + err_event->res_err_state_reason); + if (!qp) + break; +- bnxt_qplib_acquire_cq_locks(qp, &flags); + bnxt_qplib_mark_qp_error(qp); +- bnxt_qplib_release_cq_locks(qp, &flags); ++ rcfw->aeq_handler(rcfw, qp_event, qp); + break; + default: + /* Command Response */ +@@ -460,7 +459,11 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, + int rc; + + RCFW_CMD_PREP(req, INITIALIZE_FW, cmd_flags); +- ++ /* Supply (log-base-2-of-host-page-size - base-page-shift) ++ * to bono to adjust the doorbell page sizes. ++ */ ++ req.log2_dbr_pg_size = cpu_to_le16(PAGE_SHIFT - ++ RCFW_DBR_BASE_PAGE_SHIFT); + /* + * VFs need not setup the HW context area, PF + * shall setup this area for VF. Skipping the +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +index 6bee6e3..c7cce2e 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h ++++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +@@ -49,6 +49,7 @@ + #define RCFW_COMM_SIZE 0x104 + + #define RCFW_DBR_PCI_BAR_REGION 2 ++#define RCFW_DBR_BASE_PAGE_SHIFT 12 + + #define RCFW_CMD_PREP(req, CMD, cmd_flags) \ + do { \ +diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c +index 0305798..ee98e5e 100644 +--- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c ++++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c +@@ -139,7 +139,8 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, + attr->max_pkey = le32_to_cpu(sb->max_pkeys); + + attr->max_inline_data = le32_to_cpu(sb->max_inline_data); +- attr->l2_db_size = (sb->l2_db_space_size + 1) * PAGE_SIZE; ++ attr->l2_db_size = (sb->l2_db_space_size + 1) * ++ (0x01 << RCFW_DBR_BASE_PAGE_SHIFT); + attr->max_sgid = le32_to_cpu(sb->max_gid); + + bnxt_qplib_query_version(rcfw, attr->fw_ver); +diff --git a/drivers/infiniband/hw/bnxt_re/roce_hsi.h b/drivers/infiniband/hw/bnxt_re/roce_hsi.h +index 2d7ea09..3e5a4f7 100644 +--- a/drivers/infiniband/hw/bnxt_re/roce_hsi.h ++++ b/drivers/infiniband/hw/bnxt_re/roce_hsi.h +@@ -1761,7 +1761,30 @@ struct cmdq_initialize_fw { + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_2M (0x3UL << 4) + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_8M (0x4UL << 4) + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_1G (0x5UL << 4) +- __le16 reserved16; ++ /* This value is (log-base-2-of-DBR-page-size - 12). ++ * 0 for 4KB. HW supported values are enumerated below. ++ */ ++ __le16 log2_dbr_pg_size; ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_MASK 0xfUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_SFT 0 ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4K 0x0UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8K 0x1UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16K 0x2UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32K 0x3UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64K 0x4UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128K 0x5UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_256K 0x6UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_512K 0x7UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_1M 0x8UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_2M 0x9UL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4M 0xaUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8M 0xbUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16M 0xcUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32M 0xdUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64M 0xeUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M 0xfUL ++ #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_LAST \ ++ CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M + __le64 qpc_page_dir; + __le64 mrw_page_dir; + __le64 srq_page_dir; +diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c +index 9a566ee..82adc0d 100644 +--- a/drivers/infiniband/hw/mlx4/cq.c ++++ b/drivers/infiniband/hw/mlx4/cq.c +@@ -601,6 +601,7 @@ static void use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct + wc->dlid_path_bits = 0; + + if (is_eth) { ++ wc->slid = 0; + wc->vlan_id = be16_to_cpu(hdr->tun.sl_vid); + memcpy(&(wc->smac[0]), (char *)&hdr->tun.mac_31_0, 4); + memcpy(&(wc->smac[4]), (char *)&hdr->tun.slid_mac_47_32, 2); +@@ -851,7 +852,6 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, + } + } + +- wc->slid = be16_to_cpu(cqe->rlid); + g_mlpath_rqpn = be32_to_cpu(cqe->g_mlpath_rqpn); + wc->src_qp = g_mlpath_rqpn & 0xffffff; + wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f; +@@ -860,6 +860,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, + wc->wc_flags |= mlx4_ib_ipoib_csum_ok(cqe->status, + cqe->checksum) ? IB_WC_IP_CSUM_OK : 0; + if (is_eth) { ++ wc->slid = 0; + wc->sl = be16_to_cpu(cqe->sl_vid) >> 13; + if (be32_to_cpu(cqe->vlan_my_qpn) & + MLX4_CQE_CVLAN_PRESENT_MASK) { +@@ -871,6 +872,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, + memcpy(wc->smac, cqe->smac, ETH_ALEN); + wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC); + } else { ++ wc->slid = be16_to_cpu(cqe->rlid); + wc->sl = be16_to_cpu(cqe->sl_vid) >> 12; + wc->vlan_id = 0xffff; + } +diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c +index 8d2ee93..5a0e4fc 100644 +--- a/drivers/infiniband/hw/mlx4/main.c ++++ b/drivers/infiniband/hw/mlx4/main.c +@@ -219,8 +219,6 @@ static int mlx4_ib_update_gids_v1_v2(struct gid_entry *gids, + gid_tbl[i].version = 2; + if (!ipv6_addr_v4mapped((struct in6_addr *)&gids[i].gid)) + gid_tbl[i].type = 1; +- else +- memset(&gid_tbl[i].gid, 0, 12); + } + } + +@@ -366,8 +364,13 @@ static int mlx4_ib_del_gid(struct ib_device *device, + if (!gids) { + ret = -ENOMEM; + } else { +- for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) +- memcpy(&gids[i].gid, &port_gid_table->gids[i].gid, sizeof(union ib_gid)); ++ for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) { ++ memcpy(&gids[i].gid, ++ &port_gid_table->gids[i].gid, ++ sizeof(union ib_gid)); ++ gids[i].gid_type = ++ port_gid_table->gids[i].gid_type; ++ } + } + } + spin_unlock_bh(&iboe->lock); +diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c +index 5b974fb..15457c9 100644 +--- a/drivers/infiniband/hw/mlx5/cq.c ++++ b/drivers/infiniband/hw/mlx5/cq.c +@@ -226,7 +226,6 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, + wc->ex.invalidate_rkey = be32_to_cpu(cqe->imm_inval_pkey); + break; + } +- wc->slid = be16_to_cpu(cqe->slid); + wc->src_qp = be32_to_cpu(cqe->flags_rqpn) & 0xffffff; + wc->dlid_path_bits = cqe->ml_path; + g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3; +@@ -241,10 +240,12 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, + } + + if (ll != IB_LINK_LAYER_ETHERNET) { ++ wc->slid = be16_to_cpu(cqe->slid); + wc->sl = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0xf; + return; + } + ++ wc->slid = 0; + vlan_present = cqe->l4_l3_hdr_type & 0x1; + roce_packet_type = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0x3; + if (vlan_present) { +@@ -1177,7 +1178,12 @@ static int resize_user(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, + if (ucmd.reserved0 || ucmd.reserved1) + return -EINVAL; + +- umem = ib_umem_get(context, ucmd.buf_addr, entries * ucmd.cqe_size, ++ /* check multiplication overflow */ ++ if (ucmd.cqe_size && SIZE_MAX / ucmd.cqe_size <= entries - 1) ++ return -EINVAL; ++ ++ umem = ib_umem_get(context, ucmd.buf_addr, ++ (size_t)ucmd.cqe_size * entries, + IB_ACCESS_LOCAL_WRITE, 1); + if (IS_ERR(umem)) { + err = PTR_ERR(umem); +diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c +index 4236c80..033b6af 100644 +--- a/drivers/infiniband/hw/mlx5/main.c ++++ b/drivers/infiniband/hw/mlx5/main.c +@@ -245,12 +245,16 @@ struct mlx5_core_dev *mlx5_ib_get_native_port_mdev(struct mlx5_ib_dev *ibdev, + struct mlx5_ib_multiport_info *mpi; + struct mlx5_ib_port *port; + ++ if (!mlx5_core_mp_enabled(ibdev->mdev) || ++ ll != IB_LINK_LAYER_ETHERNET) { ++ if (native_port_num) ++ *native_port_num = ib_port_num; ++ return ibdev->mdev; ++ } ++ + if (native_port_num) + *native_port_num = 1; + +- if (!mlx5_core_mp_enabled(ibdev->mdev) || ll != IB_LINK_LAYER_ETHERNET) +- return ibdev->mdev; +- + port = &ibdev->port[ib_port_num - 1]; + if (!port) + return NULL; +@@ -3263,7 +3267,7 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + struct mlx5_ib_dev *ibdev; + struct ib_event ibev; + bool fatal = false; +- u8 port = 0; ++ u8 port = (u8)work->param; + + if (mlx5_core_is_mp_slave(work->dev)) { + ibdev = mlx5_ib_get_ibdev_from_mpi(work->context); +@@ -3283,8 +3287,6 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + case MLX5_DEV_EVENT_PORT_UP: + case MLX5_DEV_EVENT_PORT_DOWN: + case MLX5_DEV_EVENT_PORT_INITIALIZED: +- port = (u8)work->param; +- + /* In RoCE, port up/down events are handled in + * mlx5_netdev_event(). + */ +@@ -3298,24 +3300,19 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + + case MLX5_DEV_EVENT_LID_CHANGE: + ibev.event = IB_EVENT_LID_CHANGE; +- port = (u8)work->param; + break; + + case MLX5_DEV_EVENT_PKEY_CHANGE: + ibev.event = IB_EVENT_PKEY_CHANGE; +- port = (u8)work->param; +- + schedule_work(&ibdev->devr.ports[port - 1].pkey_change_work); + break; + + case MLX5_DEV_EVENT_GUID_CHANGE: + ibev.event = IB_EVENT_GID_CHANGE; +- port = (u8)work->param; + break; + + case MLX5_DEV_EVENT_CLIENT_REREG: + ibev.event = IB_EVENT_CLIENT_REREGISTER; +- port = (u8)work->param; + break; + case MLX5_DEV_EVENT_DELAY_DROP_TIMEOUT: + schedule_work(&ibdev->delay_drop.delay_drop_work); +@@ -3327,7 +3324,7 @@ static void mlx5_ib_handle_event(struct work_struct *_work) + ibev.device = &ibdev->ib_dev; + ibev.element.port_num = port; + +- if (port < 1 || port > ibdev->num_ports) { ++ if (!rdma_is_port_valid(&ibdev->ib_dev, port)) { + mlx5_ib_warn(ibdev, "warning: event on port %d\n", port); + goto out; + } +diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c +index 556e015..1961c6a 100644 +--- a/drivers/infiniband/hw/mlx5/mr.c ++++ b/drivers/infiniband/hw/mlx5/mr.c +@@ -1816,7 +1816,6 @@ mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr, + + mr->ibmr.iova = sg_dma_address(sg) + sg_offset; + mr->ibmr.length = 0; +- mr->ndescs = sg_nents; + + for_each_sg(sgl, sg, sg_nents, i) { + if (unlikely(i >= mr->max_descs)) +@@ -1828,6 +1827,7 @@ mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr, + + sg_offset = 0; + } ++ mr->ndescs = i; + + if (sg_offset_p) + *sg_offset_p = sg_offset; +diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c +index 39d24bf..36197fb 100644 +--- a/drivers/infiniband/hw/mlx5/qp.c ++++ b/drivers/infiniband/hw/mlx5/qp.c +@@ -1584,6 +1584,7 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, + u32 uidx = MLX5_IB_DEFAULT_UIDX; + struct mlx5_ib_create_qp ucmd; + struct mlx5_ib_qp_base *base; ++ int mlx5_st; + void *qpc; + u32 *in; + int err; +@@ -1592,6 +1593,10 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, + spin_lock_init(&qp->sq.lock); + spin_lock_init(&qp->rq.lock); + ++ mlx5_st = to_mlx5_st(init_attr->qp_type); ++ if (mlx5_st < 0) ++ return -EINVAL; ++ + if (init_attr->rwq_ind_tbl) { + if (!udata) + return -ENOSYS; +@@ -1753,7 +1758,7 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, + + qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); + +- MLX5_SET(qpc, qpc, st, to_mlx5_st(init_attr->qp_type)); ++ MLX5_SET(qpc, qpc, st, mlx5_st); + MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); + + if (init_attr->qp_type != MLX5_IB_QPT_REG_UMR) +@@ -3095,8 +3100,10 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, + goto out; + + if (mlx5_cur >= MLX5_QP_NUM_STATE || mlx5_new >= MLX5_QP_NUM_STATE || +- !optab[mlx5_cur][mlx5_new]) ++ !optab[mlx5_cur][mlx5_new]) { ++ err = -EINVAL; + goto out; ++ } + + op = optab[mlx5_cur][mlx5_new]; + optpar = ib_mask_to_mlx5_opt(attr_mask); +diff --git a/drivers/infiniband/hw/qedr/qedr_iw_cm.c b/drivers/infiniband/hw/qedr/qedr_iw_cm.c +index 478b731..26dc374 100644 +--- a/drivers/infiniband/hw/qedr/qedr_iw_cm.c ++++ b/drivers/infiniband/hw/qedr/qedr_iw_cm.c +@@ -458,8 +458,7 @@ qedr_addr6_resolve(struct qedr_dev *dev, + } + return -EINVAL; + } +- neigh = dst_neigh_lookup(dst, &dst_in); +- ++ neigh = dst_neigh_lookup(dst, &fl6.daddr); + if (neigh) { + rcu_read_lock(); + if (neigh->nud_state & NUD_VALID) { +@@ -494,10 +493,14 @@ int qedr_iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) + + qp = idr_find(&dev->qpidr, conn_param->qpn); + +- laddr = (struct sockaddr_in *)&cm_id->local_addr; +- raddr = (struct sockaddr_in *)&cm_id->remote_addr; +- laddr6 = (struct sockaddr_in6 *)&cm_id->local_addr; +- raddr6 = (struct sockaddr_in6 *)&cm_id->remote_addr; ++ laddr = (struct sockaddr_in *)&cm_id->m_local_addr; ++ raddr = (struct sockaddr_in *)&cm_id->m_remote_addr; ++ laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr; ++ raddr6 = (struct sockaddr_in6 *)&cm_id->m_remote_addr; ++ ++ DP_DEBUG(dev, QEDR_MSG_IWARP, "MAPPED %d %d\n", ++ ntohs(((struct sockaddr_in *)&cm_id->remote_addr)->sin_port), ++ ntohs(raddr->sin_port)); + + DP_DEBUG(dev, QEDR_MSG_IWARP, + "Connect source address: %pISpc, remote address: %pISpc\n", +@@ -599,8 +602,8 @@ int qedr_iw_create_listen(struct iw_cm_id *cm_id, int backlog) + int rc; + int i; + +- laddr = (struct sockaddr_in *)&cm_id->local_addr; +- laddr6 = (struct sockaddr_in6 *)&cm_id->local_addr; ++ laddr = (struct sockaddr_in *)&cm_id->m_local_addr; ++ laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr; + + DP_DEBUG(dev, QEDR_MSG_IWARP, + "Create Listener address: %pISpc\n", &cm_id->local_addr); +diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c +index 53f00db..875b172 100644 +--- a/drivers/infiniband/hw/qedr/verbs.c ++++ b/drivers/infiniband/hw/qedr/verbs.c +@@ -3034,6 +3034,11 @@ static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + + switch (wr->opcode) { + case IB_WR_SEND_WITH_IMM: ++ if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) { ++ rc = -EINVAL; ++ *bad_wr = wr; ++ break; ++ } + wqe->req_type = RDMA_SQ_REQ_TYPE_SEND_WITH_IMM; + swqe = (struct rdma_sq_send_wqe_1st *)wqe; + swqe->wqe_size = 2; +@@ -3075,6 +3080,11 @@ static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + break; + + case IB_WR_RDMA_WRITE_WITH_IMM: ++ if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) { ++ rc = -EINVAL; ++ *bad_wr = wr; ++ break; ++ } + wqe->req_type = RDMA_SQ_REQ_TYPE_RDMA_WR_WITH_IMM; + rwqe = (struct rdma_sq_rdma_wqe_1st *)wqe; + +@@ -3724,7 +3734,7 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) + { + struct qedr_dev *dev = get_qedr_dev(ibcq->device); + struct qedr_cq *cq = get_qedr_cq(ibcq); +- union rdma_cqe *cqe = cq->latest_cqe; ++ union rdma_cqe *cqe; + u32 old_cons, new_cons; + unsigned long flags; + int update = 0; +@@ -3741,6 +3751,7 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) + return qedr_gsi_poll_cq(ibcq, num_entries, wc); + + spin_lock_irqsave(&cq->cq_lock, flags); ++ cqe = cq->latest_cqe; + old_cons = qed_chain_get_cons_idx_u32(&cq->pbl); + while (num_entries && is_valid_cqe(cq, cqe)) { + struct qedr_qp *qp; +diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c +index 1f316d6..41614c1 100644 +--- a/drivers/input/keyboard/matrix_keypad.c ++++ b/drivers/input/keyboard/matrix_keypad.c +@@ -218,8 +218,10 @@ static void matrix_keypad_stop(struct input_dev *dev) + { + struct matrix_keypad *keypad = input_get_drvdata(dev); + ++ spin_lock_irq(&keypad->lock); + keypad->stopped = true; +- mb(); ++ spin_unlock_irq(&keypad->lock); ++ + flush_work(&keypad->work.work); + /* + * matrix_keypad_scan() will leave IRQs enabled; +diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c +index 3d2e23a..a246fc6 100644 +--- a/drivers/input/mouse/synaptics.c ++++ b/drivers/input/mouse/synaptics.c +@@ -173,7 +173,6 @@ static const char * const smbus_pnp_ids[] = { + "LEN0046", /* X250 */ + "LEN004a", /* W541 */ + "LEN200f", /* T450s */ +- "LEN2018", /* T460p */ + NULL + }; + +diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c +index db4f6bb..a5ab774 100644 +--- a/drivers/input/touchscreen/mms114.c ++++ b/drivers/input/touchscreen/mms114.c +@@ -1,11 +1,8 @@ +-/* +- * Copyright (C) 2012 Samsung Electronics Co.Ltd +- * Author: Joonyoung Shim +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ ++// SPDX-License-Identifier: GPL-2.0 ++// Melfas MMS114/MMS152 touchscreen device driver ++// ++// Copyright (c) 2012 Samsung Electronics Co., Ltd. ++// Author: Joonyoung Shim + + #include + #include +@@ -624,4 +621,4 @@ module_i2c_driver(mms114_driver); + /* Module information */ + MODULE_AUTHOR("Joonyoung Shim "); + MODULE_DESCRIPTION("MELFAS mms114 Touchscreen driver"); +-MODULE_LICENSE("GPL"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c +index 414c9af..aa2032f 100644 +--- a/drivers/md/dm-bufio.c ++++ b/drivers/md/dm-bufio.c +@@ -386,9 +386,6 @@ static void __cache_size_refresh(void) + static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, + enum data_mode *data_mode) + { +- unsigned noio_flag; +- void *ptr; +- + if (c->block_size <= DM_BUFIO_BLOCK_SIZE_SLAB_LIMIT) { + *data_mode = DATA_MODE_SLAB; + return kmem_cache_alloc(DM_BUFIO_CACHE(c), gfp_mask); +@@ -412,16 +409,15 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, + * all allocations done by this process (including pagetables) are done + * as if GFP_NOIO was specified. + */ ++ if (gfp_mask & __GFP_NORETRY) { ++ unsigned noio_flag = memalloc_noio_save(); ++ void *ptr = __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL); + +- if (gfp_mask & __GFP_NORETRY) +- noio_flag = memalloc_noio_save(); +- +- ptr = __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL); +- +- if (gfp_mask & __GFP_NORETRY) + memalloc_noio_restore(noio_flag); ++ return ptr; ++ } + +- return ptr; ++ return __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL); + } + + /* +diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c +index 7d3e572..3fde9e9 100644 +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -211,25 +212,13 @@ static int alloc_multipath_stage2(struct dm_target *ti, struct multipath *m) + else + m->queue_mode = DM_TYPE_REQUEST_BASED; + +- } else if (m->queue_mode == DM_TYPE_BIO_BASED || +- m->queue_mode == DM_TYPE_NVME_BIO_BASED) { ++ } else if (m->queue_mode == DM_TYPE_BIO_BASED) { + INIT_WORK(&m->process_queued_bios, process_queued_bios); +- +- if (m->queue_mode == DM_TYPE_BIO_BASED) { +- /* +- * bio-based doesn't support any direct scsi_dh management; +- * it just discovers if a scsi_dh is attached. +- */ +- set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags); +- } +- } +- +- if (m->queue_mode != DM_TYPE_NVME_BIO_BASED) { +- set_bit(MPATHF_QUEUE_IO, &m->flags); +- atomic_set(&m->pg_init_in_progress, 0); +- atomic_set(&m->pg_init_count, 0); +- m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT; +- init_waitqueue_head(&m->pg_init_wait); ++ /* ++ * bio-based doesn't support any direct scsi_dh management; ++ * it just discovers if a scsi_dh is attached. ++ */ ++ set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags); + } + + dm_table_set_type(ti->table, m->queue_mode); +@@ -337,14 +326,12 @@ static void __switch_pg(struct multipath *m, struct priority_group *pg) + { + m->current_pg = pg; + +- if (m->queue_mode == DM_TYPE_NVME_BIO_BASED) +- return; +- + /* Must we initialise the PG first, and queue I/O till it's ready? */ + if (m->hw_handler_name) { + set_bit(MPATHF_PG_INIT_REQUIRED, &m->flags); + set_bit(MPATHF_QUEUE_IO, &m->flags); + } else { ++ /* FIXME: not needed if no scsi_dh is attached */ + clear_bit(MPATHF_PG_INIT_REQUIRED, &m->flags); + clear_bit(MPATHF_QUEUE_IO, &m->flags); + } +@@ -385,8 +372,7 @@ static struct pgpath *choose_pgpath(struct multipath *m, size_t nr_bytes) + unsigned bypassed = 1; + + if (!atomic_read(&m->nr_valid_paths)) { +- if (m->queue_mode != DM_TYPE_NVME_BIO_BASED) +- clear_bit(MPATHF_QUEUE_IO, &m->flags); ++ clear_bit(MPATHF_QUEUE_IO, &m->flags); + goto failed; + } + +@@ -599,7 +585,7 @@ static struct pgpath *__map_bio(struct multipath *m, struct bio *bio) + return pgpath; + } + +-static struct pgpath *__map_bio_nvme(struct multipath *m, struct bio *bio) ++static struct pgpath *__map_bio_fast(struct multipath *m, struct bio *bio) + { + struct pgpath *pgpath; + unsigned long flags; +@@ -634,8 +620,8 @@ static int __multipath_map_bio(struct multipath *m, struct bio *bio, + { + struct pgpath *pgpath; + +- if (m->queue_mode == DM_TYPE_NVME_BIO_BASED) +- pgpath = __map_bio_nvme(m, bio); ++ if (!m->hw_handler_name) ++ pgpath = __map_bio_fast(m, bio); + else + pgpath = __map_bio(m, bio); + +@@ -675,8 +661,7 @@ static void process_queued_io_list(struct multipath *m) + { + if (m->queue_mode == DM_TYPE_MQ_REQUEST_BASED) + dm_mq_kick_requeue_list(dm_table_get_md(m->ti->table)); +- else if (m->queue_mode == DM_TYPE_BIO_BASED || +- m->queue_mode == DM_TYPE_NVME_BIO_BASED) ++ else if (m->queue_mode == DM_TYPE_BIO_BASED) + queue_work(kmultipathd, &m->process_queued_bios); + } + +@@ -838,6 +823,16 @@ static int setup_scsi_dh(struct block_device *bdev, struct multipath *m, char ** + */ + kfree(m->hw_handler_name); + m->hw_handler_name = attached_handler_name; ++ ++ /* ++ * Init fields that are only used when a scsi_dh is attached ++ */ ++ if (!test_and_set_bit(MPATHF_QUEUE_IO, &m->flags)) { ++ atomic_set(&m->pg_init_in_progress, 0); ++ atomic_set(&m->pg_init_count, 0); ++ m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT; ++ init_waitqueue_head(&m->pg_init_wait); ++ } + } + } + +@@ -873,6 +868,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps + int r; + struct pgpath *p; + struct multipath *m = ti->private; ++ struct scsi_device *sdev; + + /* we need at least a path arg */ + if (as->argc < 1) { +@@ -891,7 +887,9 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps + goto bad; + } + +- if (m->queue_mode != DM_TYPE_NVME_BIO_BASED) { ++ sdev = scsi_device_from_queue(bdev_get_queue(p->path.dev->bdev)); ++ if (sdev) { ++ put_device(&sdev->sdev_gendev); + INIT_DELAYED_WORK(&p->activate_path, activate_path_work); + r = setup_scsi_dh(p->path.dev->bdev, m, &ti->error); + if (r) { +@@ -1001,8 +999,7 @@ static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m) + if (!hw_argc) + return 0; + +- if (m->queue_mode == DM_TYPE_BIO_BASED || +- m->queue_mode == DM_TYPE_NVME_BIO_BASED) { ++ if (m->queue_mode == DM_TYPE_BIO_BASED) { + dm_consume_args(as, hw_argc); + DMERR("bio-based multipath doesn't allow hardware handler args"); + return 0; +@@ -1091,8 +1088,6 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) + + if (!strcasecmp(queue_mode_name, "bio")) + m->queue_mode = DM_TYPE_BIO_BASED; +- else if (!strcasecmp(queue_mode_name, "nvme")) +- m->queue_mode = DM_TYPE_NVME_BIO_BASED; + else if (!strcasecmp(queue_mode_name, "rq")) + m->queue_mode = DM_TYPE_REQUEST_BASED; + else if (!strcasecmp(queue_mode_name, "mq")) +@@ -1193,7 +1188,7 @@ static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv) + ti->num_discard_bios = 1; + ti->num_write_same_bios = 1; + ti->num_write_zeroes_bios = 1; +- if (m->queue_mode == DM_TYPE_BIO_BASED || m->queue_mode == DM_TYPE_NVME_BIO_BASED) ++ if (m->queue_mode == DM_TYPE_BIO_BASED) + ti->per_io_data_size = multipath_per_bio_data_size(); + else + ti->per_io_data_size = sizeof(struct dm_mpath_io); +@@ -1730,9 +1725,6 @@ static void multipath_status(struct dm_target *ti, status_type_t type, + case DM_TYPE_BIO_BASED: + DMEMIT("queue_mode bio "); + break; +- case DM_TYPE_NVME_BIO_BASED: +- DMEMIT("queue_mode nvme "); +- break; + case DM_TYPE_MQ_REQUEST_BASED: + DMEMIT("queue_mode mq "); + break; +diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c +index 7ef469e..c1d1034 100644 +--- a/drivers/md/dm-raid.c ++++ b/drivers/md/dm-raid.c +@@ -3408,9 +3408,10 @@ static sector_t rs_get_progress(struct raid_set *rs, unsigned long recovery, + set_bit(RT_FLAG_RS_IN_SYNC, &rs->runtime_flags); + + } else { +- if (test_bit(MD_RECOVERY_NEEDED, &recovery) || +- test_bit(MD_RECOVERY_RESHAPE, &recovery) || +- test_bit(MD_RECOVERY_RUNNING, &recovery)) ++ if (!test_bit(MD_RECOVERY_INTR, &recovery) && ++ (test_bit(MD_RECOVERY_NEEDED, &recovery) || ++ test_bit(MD_RECOVERY_RESHAPE, &recovery) || ++ test_bit(MD_RECOVERY_RUNNING, &recovery))) + r = mddev->curr_resync_completed; + else + r = mddev->recovery_cp; +diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c +index 5fe7ec3..7eb3e2a 100644 +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -942,17 +942,12 @@ static int dm_table_determine_type(struct dm_table *t) + + if (t->type != DM_TYPE_NONE) { + /* target already set the table's type */ +- if (t->type == DM_TYPE_BIO_BASED) +- return 0; +- else if (t->type == DM_TYPE_NVME_BIO_BASED) { +- if (!dm_table_does_not_support_partial_completion(t)) { +- DMERR("nvme bio-based is only possible with devices" +- " that don't support partial completion"); +- return -EINVAL; +- } +- /* Fallthru, also verify all devices are blk-mq */ ++ if (t->type == DM_TYPE_BIO_BASED) { ++ /* possibly upgrade to a variant of bio-based */ ++ goto verify_bio_based; + } + BUG_ON(t->type == DM_TYPE_DAX_BIO_BASED); ++ BUG_ON(t->type == DM_TYPE_NVME_BIO_BASED); + goto verify_rq_based; + } + +@@ -985,6 +980,7 @@ static int dm_table_determine_type(struct dm_table *t) + } + + if (bio_based) { ++verify_bio_based: + /* We must use this table as bio-based */ + t->type = DM_TYPE_BIO_BASED; + if (dm_table_supports_dax(t) || +@@ -1755,7 +1751,7 @@ static int device_no_partial_completion(struct dm_target *ti, struct dm_dev *dev + char b[BDEVNAME_SIZE]; + + /* For now, NVMe devices are the only devices of this class */ +- return (strncmp(bdevname(dev->bdev, b), "nvme", 3) == 0); ++ return (strncmp(bdevname(dev->bdev, b), "nvme", 4) == 0); + } + + static bool dm_table_does_not_support_partial_completion(struct dm_table *t) +diff --git a/drivers/md/dm.c b/drivers/md/dm.c +index 6813680..45328d8 100644 +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -458,9 +458,11 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) + return dm_get_geometry(md, geo); + } + +-static int dm_grab_bdev_for_ioctl(struct mapped_device *md, +- struct block_device **bdev, +- fmode_t *mode) ++static char *_dm_claim_ptr = "I belong to device-mapper"; ++ ++static int dm_get_bdev_for_ioctl(struct mapped_device *md, ++ struct block_device **bdev, ++ fmode_t *mode) + { + struct dm_target *tgt; + struct dm_table *map; +@@ -490,6 +492,10 @@ static int dm_grab_bdev_for_ioctl(struct mapped_device *md, + goto out; + + bdgrab(*bdev); ++ r = blkdev_get(*bdev, *mode, _dm_claim_ptr); ++ if (r < 0) ++ goto out; ++ + dm_put_live_table(md, srcu_idx); + return r; + +@@ -508,7 +514,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, + struct mapped_device *md = bdev->bd_disk->private_data; + int r; + +- r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); ++ r = dm_get_bdev_for_ioctl(md, &bdev, &mode); + if (r < 0) + return r; + +@@ -528,7 +534,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, + + r = __blkdev_driver_ioctl(bdev, mode, cmd, arg); + out: +- bdput(bdev); ++ blkdev_put(bdev, mode); + return r; + } + +@@ -708,14 +714,13 @@ static void dm_put_live_table_fast(struct mapped_device *md) __releases(RCU) + static int open_table_device(struct table_device *td, dev_t dev, + struct mapped_device *md) + { +- static char *_claim_ptr = "I belong to device-mapper"; + struct block_device *bdev; + + int r; + + BUG_ON(td->dm_dev.bdev); + +- bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _claim_ptr); ++ bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _dm_claim_ptr); + if (IS_ERR(bdev)) + return PTR_ERR(bdev); + +@@ -3011,7 +3016,7 @@ static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type, + fmode_t mode; + int r; + +- r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); ++ r = dm_get_bdev_for_ioctl(md, &bdev, &mode); + if (r < 0) + return r; + +@@ -3021,7 +3026,7 @@ static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type, + else + r = -EOPNOTSUPP; + +- bdput(bdev); ++ blkdev_put(bdev, mode); + return r; + } + +@@ -3032,7 +3037,7 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type) + fmode_t mode; + int r; + +- r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); ++ r = dm_get_bdev_for_ioctl(md, &bdev, &mode); + if (r < 0) + return r; + +@@ -3042,7 +3047,7 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type) + else + r = -EOPNOTSUPP; + +- bdput(bdev); ++ blkdev_put(bdev, mode); + return r; + } + +@@ -3054,7 +3059,7 @@ static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key, + fmode_t mode; + int r; + +- r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); ++ r = dm_get_bdev_for_ioctl(md, &bdev, &mode); + if (r < 0) + return r; + +@@ -3064,7 +3069,7 @@ static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key, + else + r = -EOPNOTSUPP; + +- bdput(bdev); ++ blkdev_put(bdev, mode); + return r; + } + +@@ -3075,7 +3080,7 @@ static int dm_pr_clear(struct block_device *bdev, u64 key) + fmode_t mode; + int r; + +- r = dm_grab_bdev_for_ioctl(md, &bdev, &mode); ++ r = dm_get_bdev_for_ioctl(md, &bdev, &mode); + if (r < 0) + return r; + +@@ -3085,7 +3090,7 @@ static int dm_pr_clear(struct block_device *bdev, u64 key) + else + r = -EOPNOTSUPP; + +- bdput(bdev); ++ blkdev_put(bdev, mode); + return r; + } + +diff --git a/drivers/misc/ocxl/file.c b/drivers/misc/ocxl/file.c +index 337462e..038509e 100644 +--- a/drivers/misc/ocxl/file.c ++++ b/drivers/misc/ocxl/file.c +@@ -102,10 +102,32 @@ static long afu_ioctl_attach(struct ocxl_context *ctx, + return rc; + } + ++static long afu_ioctl_get_metadata(struct ocxl_context *ctx, ++ struct ocxl_ioctl_metadata __user *uarg) ++{ ++ struct ocxl_ioctl_metadata arg; ++ ++ memset(&arg, 0, sizeof(arg)); ++ ++ arg.version = 0; ++ ++ arg.afu_version_major = ctx->afu->config.version_major; ++ arg.afu_version_minor = ctx->afu->config.version_minor; ++ arg.pasid = ctx->pasid; ++ arg.pp_mmio_size = ctx->afu->config.pp_mmio_stride; ++ arg.global_mmio_size = ctx->afu->config.global_mmio_size; ++ ++ if (copy_to_user(uarg, &arg, sizeof(arg))) ++ return -EFAULT; ++ ++ return 0; ++} ++ + #define CMD_STR(x) (x == OCXL_IOCTL_ATTACH ? "ATTACH" : \ + x == OCXL_IOCTL_IRQ_ALLOC ? "IRQ_ALLOC" : \ + x == OCXL_IOCTL_IRQ_FREE ? "IRQ_FREE" : \ + x == OCXL_IOCTL_IRQ_SET_FD ? "IRQ_SET_FD" : \ ++ x == OCXL_IOCTL_GET_METADATA ? "GET_METADATA" : \ + "UNKNOWN") + + static long afu_ioctl(struct file *file, unsigned int cmd, +@@ -159,6 +181,11 @@ static long afu_ioctl(struct file *file, unsigned int cmd, + irq_fd.eventfd); + break; + ++ case OCXL_IOCTL_GET_METADATA: ++ rc = afu_ioctl_get_metadata(ctx, ++ (struct ocxl_ioctl_metadata __user *) args); ++ break; ++ + default: + rc = -EINVAL; + } +diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c +index f5c87bd..f27f9ba 100644 +--- a/drivers/net/ethernet/freescale/gianfar.c ++++ b/drivers/net/ethernet/freescale/gianfar.c +@@ -3063,9 +3063,6 @@ static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb) + if (ndev->features & NETIF_F_RXCSUM) + gfar_rx_checksum(skb, fcb); + +- /* Tell the skb what kind of packet this is */ +- skb->protocol = eth_type_trans(skb, ndev); +- + /* There's need to check for NETIF_F_HW_VLAN_CTAG_RX here. + * Even if vlan rx accel is disabled, on some chips + * RXFCB_VLN is pseudo randomly set. +@@ -3136,13 +3133,15 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) + continue; + } + ++ gfar_process_frame(ndev, skb); ++ + /* Increment the number of packets */ + total_pkts++; + total_bytes += skb->len; + + skb_record_rx_queue(skb, rx_queue->qindex); + +- gfar_process_frame(ndev, skb); ++ skb->protocol = eth_type_trans(skb, ndev); + + /* Send the packet up the stack */ + napi_gro_receive(&rx_queue->grp->napi_rx, skb); +diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +index 0da5aa2..9fc063a 100644 +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +@@ -1888,6 +1888,14 @@ static void ixgbe_dma_sync_frag(struct ixgbe_ring *rx_ring, + ixgbe_rx_pg_size(rx_ring), + DMA_FROM_DEVICE, + IXGBE_RX_DMA_ATTR); ++ } else if (ring_uses_build_skb(rx_ring)) { ++ unsigned long offset = (unsigned long)(skb->data) & ~PAGE_MASK; ++ ++ dma_sync_single_range_for_cpu(rx_ring->dev, ++ IXGBE_CB(skb)->dma, ++ offset, ++ skb_headlen(skb), ++ DMA_FROM_DEVICE); + } else { + struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0]; + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c +index 21d29f7..d39b0b7 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c +@@ -124,7 +124,7 @@ void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force) + trigger_cmd_completions(dev); + } + +- mlx5_core_event(dev, MLX5_DEV_EVENT_SYS_ERROR, 0); ++ mlx5_core_event(dev, MLX5_DEV_EVENT_SYS_ERROR, 1); + mlx5_core_err(dev, "end\n"); + + unlock: +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +index f6963b0..122506d 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +@@ -107,20 +107,20 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = { + MLXSW_AFK_ELEMENT_INFO_U32(VID, 0x10, 8, 12), + MLXSW_AFK_ELEMENT_INFO_U32(PCP, 0x10, 20, 3), + MLXSW_AFK_ELEMENT_INFO_U32(TCP_FLAGS, 0x10, 23, 9), +- MLXSW_AFK_ELEMENT_INFO_U32(IP_TTL_, 0x14, 0, 8), +- MLXSW_AFK_ELEMENT_INFO_U32(IP_ECN, 0x14, 9, 2), +- MLXSW_AFK_ELEMENT_INFO_U32(IP_DSCP, 0x14, 11, 6), +- MLXSW_AFK_ELEMENT_INFO_U32(SRC_IP4, 0x18, 0, 32), +- MLXSW_AFK_ELEMENT_INFO_U32(DST_IP4, 0x1C, 0, 32), +- MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_HI, 0x18, 8), +- MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_LO, 0x20, 8), +- MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_HI, 0x28, 8), +- MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_LO, 0x30, 8), + MLXSW_AFK_ELEMENT_INFO_U32(DST_L4_PORT, 0x14, 0, 16), + MLXSW_AFK_ELEMENT_INFO_U32(SRC_L4_PORT, 0x14, 16, 16), ++ MLXSW_AFK_ELEMENT_INFO_U32(IP_TTL_, 0x18, 0, 8), ++ MLXSW_AFK_ELEMENT_INFO_U32(IP_ECN, 0x18, 9, 2), ++ MLXSW_AFK_ELEMENT_INFO_U32(IP_DSCP, 0x18, 11, 6), ++ MLXSW_AFK_ELEMENT_INFO_U32(SRC_IP4, 0x20, 0, 32), ++ MLXSW_AFK_ELEMENT_INFO_U32(DST_IP4, 0x24, 0, 32), ++ MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_HI, 0x20, 8), ++ MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_LO, 0x28, 8), ++ MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_HI, 0x30, 8), ++ MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_LO, 0x38, 8), + }; + +-#define MLXSW_AFK_ELEMENT_STORAGE_SIZE 0x38 ++#define MLXSW_AFK_ELEMENT_STORAGE_SIZE 0x40 + + struct mlxsw_afk_element_inst { /* element instance in actual block */ + const struct mlxsw_afk_element_info *info; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +index 3dcc58d..c7e941a 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +@@ -1459,6 +1459,7 @@ mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) + } + + mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port; ++ mlxsw_sp_port_vlan->ref_count = 1; + mlxsw_sp_port_vlan->vid = vid; + list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list); + +@@ -1486,8 +1487,10 @@ mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); +- if (mlxsw_sp_port_vlan) ++ if (mlxsw_sp_port_vlan) { ++ mlxsw_sp_port_vlan->ref_count++; + return mlxsw_sp_port_vlan; ++ } + + return mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid); + } +@@ -1496,6 +1499,9 @@ void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) + { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + ++ if (--mlxsw_sp_port_vlan->ref_count != 0) ++ return; ++ + if (mlxsw_sp_port_vlan->bridge_port) + mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); + else if (fid) +@@ -4207,13 +4213,12 @@ static struct devlink_resource_ops mlxsw_sp_resource_kvd_hash_double_ops = { + .size_validate = mlxsw_sp_resource_kvd_hash_double_size_validate, + }; + +-static struct devlink_resource_size_params mlxsw_sp_kvd_size_params; +-static struct devlink_resource_size_params mlxsw_sp_linear_size_params; +-static struct devlink_resource_size_params mlxsw_sp_hash_single_size_params; +-static struct devlink_resource_size_params mlxsw_sp_hash_double_size_params; +- + static void +-mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core) ++mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core, ++ struct devlink_resource_size_params *kvd_size_params, ++ struct devlink_resource_size_params *linear_size_params, ++ struct devlink_resource_size_params *hash_double_size_params, ++ struct devlink_resource_size_params *hash_single_size_params) + { + u32 single_size_min = MLXSW_CORE_RES_GET(mlxsw_core, + KVD_SINGLE_MIN_SIZE); +@@ -4222,37 +4227,35 @@ mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core) + u32 kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE); + u32 linear_size_min = 0; + +- /* KVD top resource */ +- mlxsw_sp_kvd_size_params.size_min = kvd_size; +- mlxsw_sp_kvd_size_params.size_max = kvd_size; +- mlxsw_sp_kvd_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY; +- mlxsw_sp_kvd_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY; +- +- /* Linear part init */ +- mlxsw_sp_linear_size_params.size_min = linear_size_min; +- mlxsw_sp_linear_size_params.size_max = kvd_size - single_size_min - +- double_size_min; +- mlxsw_sp_linear_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY; +- mlxsw_sp_linear_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY; +- +- /* Hash double part init */ +- mlxsw_sp_hash_double_size_params.size_min = double_size_min; +- mlxsw_sp_hash_double_size_params.size_max = kvd_size - single_size_min - +- linear_size_min; +- mlxsw_sp_hash_double_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY; +- mlxsw_sp_hash_double_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY; +- +- /* Hash single part init */ +- mlxsw_sp_hash_single_size_params.size_min = single_size_min; +- mlxsw_sp_hash_single_size_params.size_max = kvd_size - double_size_min - +- linear_size_min; +- mlxsw_sp_hash_single_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY; +- mlxsw_sp_hash_single_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY; ++ devlink_resource_size_params_init(kvd_size_params, kvd_size, kvd_size, ++ MLXSW_SP_KVD_GRANULARITY, ++ DEVLINK_RESOURCE_UNIT_ENTRY); ++ devlink_resource_size_params_init(linear_size_params, linear_size_min, ++ kvd_size - single_size_min - ++ double_size_min, ++ MLXSW_SP_KVD_GRANULARITY, ++ DEVLINK_RESOURCE_UNIT_ENTRY); ++ devlink_resource_size_params_init(hash_double_size_params, ++ double_size_min, ++ kvd_size - single_size_min - ++ linear_size_min, ++ MLXSW_SP_KVD_GRANULARITY, ++ DEVLINK_RESOURCE_UNIT_ENTRY); ++ devlink_resource_size_params_init(hash_single_size_params, ++ single_size_min, ++ kvd_size - double_size_min - ++ linear_size_min, ++ MLXSW_SP_KVD_GRANULARITY, ++ DEVLINK_RESOURCE_UNIT_ENTRY); + } + + static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) + { + struct devlink *devlink = priv_to_devlink(mlxsw_core); ++ struct devlink_resource_size_params hash_single_size_params; ++ struct devlink_resource_size_params hash_double_size_params; ++ struct devlink_resource_size_params linear_size_params; ++ struct devlink_resource_size_params kvd_size_params; + u32 kvd_size, single_size, double_size, linear_size; + const struct mlxsw_config_profile *profile; + int err; +@@ -4261,13 +4264,17 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) + if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE)) + return -EIO; + +- mlxsw_sp_resource_size_params_prepare(mlxsw_core); ++ mlxsw_sp_resource_size_params_prepare(mlxsw_core, &kvd_size_params, ++ &linear_size_params, ++ &hash_double_size_params, ++ &hash_single_size_params); ++ + kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE); + err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD, + true, kvd_size, + MLXSW_SP_RESOURCE_KVD, + DEVLINK_RESOURCE_ID_PARENT_TOP, +- &mlxsw_sp_kvd_size_params, ++ &kvd_size_params, + &mlxsw_sp_resource_kvd_ops); + if (err) + return err; +@@ -4277,7 +4284,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) + false, linear_size, + MLXSW_SP_RESOURCE_KVD_LINEAR, + MLXSW_SP_RESOURCE_KVD, +- &mlxsw_sp_linear_size_params, ++ &linear_size_params, + &mlxsw_sp_resource_kvd_linear_ops); + if (err) + return err; +@@ -4291,7 +4298,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) + false, double_size, + MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, + MLXSW_SP_RESOURCE_KVD, +- &mlxsw_sp_hash_double_size_params, ++ &hash_double_size_params, + &mlxsw_sp_resource_kvd_hash_double_ops); + if (err) + return err; +@@ -4301,7 +4308,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core) + false, single_size, + MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, + MLXSW_SP_RESOURCE_KVD, +- &mlxsw_sp_hash_single_size_params, ++ &hash_single_size_params, + &mlxsw_sp_resource_kvd_hash_single_ops); + if (err) + return err; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +index bdd8f94a..4ec1ca3 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +@@ -211,6 +211,7 @@ struct mlxsw_sp_port_vlan { + struct list_head list; + struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp_fid *fid; ++ unsigned int ref_count; + u16 vid; + struct mlxsw_sp_bridge_port *bridge_port; + struct list_head bridge_vlan_node; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +index bbd238e..54262af 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +@@ -112,11 +112,11 @@ static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1, + [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1, + [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1, ++ [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, + }; + + static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1, +- [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, + }; + + static const int *mlxsw_sp_packet_type_sfgc_types[] = { +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +index 593ad31..161bcdc 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +@@ -1203,6 +1203,7 @@ static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port, + bool dynamic) + { + char *sfd_pl; ++ u8 num_rec; + int err; + + sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); +@@ -1212,9 +1213,16 @@ static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port, + mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0); + mlxsw_reg_sfd_uc_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic), + mac, fid, action, local_port); ++ num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); +- kfree(sfd_pl); ++ if (err) ++ goto out; ++ ++ if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl)) ++ err = -EBUSY; + ++out: ++ kfree(sfd_pl); + return err; + } + +@@ -1239,6 +1247,7 @@ static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id, + bool adding, bool dynamic) + { + char *sfd_pl; ++ u8 num_rec; + int err; + + sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); +@@ -1249,9 +1258,16 @@ static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id, + mlxsw_reg_sfd_uc_lag_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic), + mac, fid, MLXSW_REG_SFD_REC_ACTION_NOP, + lag_vid, lag_id); ++ num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); +- kfree(sfd_pl); ++ if (err) ++ goto out; ++ ++ if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl)) ++ err = -EBUSY; + ++out: ++ kfree(sfd_pl); + return err; + } + +@@ -1296,6 +1312,7 @@ static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr, + u16 fid, u16 mid_idx, bool adding) + { + char *sfd_pl; ++ u8 num_rec; + int err; + + sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); +@@ -1305,7 +1322,15 @@ static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr, + mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0); + mlxsw_reg_sfd_mc_pack(sfd_pl, 0, addr, fid, + MLXSW_REG_SFD_REC_ACTION_NOP, mid_idx); ++ num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); ++ if (err) ++ goto out; ++ ++ if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl)) ++ err = -EBUSY; ++ ++out: + kfree(sfd_pl); + return err; + } +diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c +index 92dcf87..14c839b 100644 +--- a/drivers/net/ethernet/renesas/sh_eth.c ++++ b/drivers/net/ethernet/renesas/sh_eth.c +@@ -439,6 +439,17 @@ static void sh_eth_modify(struct net_device *ndev, int enum_index, u32 clear, + enum_index); + } + ++static void sh_eth_tsu_write(struct sh_eth_private *mdp, u32 data, ++ int enum_index) ++{ ++ iowrite32(data, mdp->tsu_addr + mdp->reg_offset[enum_index]); ++} ++ ++static u32 sh_eth_tsu_read(struct sh_eth_private *mdp, int enum_index) ++{ ++ return ioread32(mdp->tsu_addr + mdp->reg_offset[enum_index]); ++} ++ + static bool sh_eth_is_gether(struct sh_eth_private *mdp) + { + return mdp->reg_offset == sh_eth_offset_gigabit; +diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h +index a6753cc..e5fe701 100644 +--- a/drivers/net/ethernet/renesas/sh_eth.h ++++ b/drivers/net/ethernet/renesas/sh_eth.h +@@ -567,15 +567,4 @@ static inline void *sh_eth_tsu_get_offset(struct sh_eth_private *mdp, + return mdp->tsu_addr + mdp->reg_offset[enum_index]; + } + +-static inline void sh_eth_tsu_write(struct sh_eth_private *mdp, u32 data, +- int enum_index) +-{ +- iowrite32(data, mdp->tsu_addr + mdp->reg_offset[enum_index]); +-} +- +-static inline u32 sh_eth_tsu_read(struct sh_eth_private *mdp, int enum_index) +-{ +- return ioread32(mdp->tsu_addr + mdp->reg_offset[enum_index]); +-} +- + #endif /* #ifndef __SH_ETH_H__ */ +diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c +index 17e529a..0265d70 100644 +--- a/drivers/net/hyperv/netvsc.c ++++ b/drivers/net/hyperv/netvsc.c +@@ -852,13 +852,6 @@ int netvsc_send(struct net_device *ndev, + if (unlikely(!net_device || net_device->destroy)) + return -ENODEV; + +- /* We may race with netvsc_connect_vsp()/netvsc_init_buf() and get +- * here before the negotiation with the host is finished and +- * send_section_map may not be allocated yet. +- */ +- if (unlikely(!net_device->send_section_map)) +- return -EAGAIN; +- + nvchan = &net_device->chan_table[packet->q_idx]; + packet->send_buf_index = NETVSC_INVALID_INDEX; + packet->cp_partial = false; +@@ -866,10 +859,8 @@ int netvsc_send(struct net_device *ndev, + /* Send control message directly without accessing msd (Multi-Send + * Data) field which may be changed during data packet processing. + */ +- if (!skb) { +- cur_send = packet; +- goto send_now; +- } ++ if (!skb) ++ return netvsc_send_pkt(device, packet, net_device, pb, skb); + + /* batch packets in send buffer if possible */ + msdp = &nvchan->msd; +@@ -953,7 +944,6 @@ int netvsc_send(struct net_device *ndev, + } + } + +-send_now: + if (cur_send) + ret = netvsc_send_pkt(device, cur_send, net_device, pb, skb); + +@@ -1217,9 +1207,10 @@ int netvsc_poll(struct napi_struct *napi, int budget) + if (send_recv_completions(ndev, net_device, nvchan) == 0 && + work_done < budget && + napi_complete_done(napi, work_done) && +- hv_end_read(&channel->inbound)) { ++ hv_end_read(&channel->inbound) && ++ napi_schedule_prep(napi)) { + hv_begin_read(&channel->inbound); +- napi_reschedule(napi); ++ __napi_schedule(napi); + } + + /* Driver may overshoot since multiple packets per descriptor */ +@@ -1242,7 +1233,7 @@ void netvsc_channel_cb(void *context) + /* disable interupts from host */ + hv_begin_read(rbi); + +- __napi_schedule(&nvchan->napi); ++ __napi_schedule_irqoff(&nvchan->napi); + } + } + +@@ -1296,7 +1287,6 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, + netvsc_channel_cb, net_device->chan_table); + + if (ret != 0) { +- netif_napi_del(&net_device->chan_table[0].napi); + netdev_err(ndev, "unable to open channel: %d\n", ret); + goto cleanup; + } +@@ -1306,11 +1296,6 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, + + napi_enable(&net_device->chan_table[0].napi); + +- /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is +- * populated. +- */ +- rcu_assign_pointer(net_device_ctx->nvdev, net_device); +- + /* Connect with the NetVsp */ + ret = netvsc_connect_vsp(device, net_device, device_info); + if (ret != 0) { +@@ -1319,6 +1304,11 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, + goto close; + } + ++ /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is ++ * populated. ++ */ ++ rcu_assign_pointer(net_device_ctx->nvdev, net_device); ++ + return net_device; + + close: +@@ -1329,6 +1319,7 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, + vmbus_close(device->channel); + + cleanup: ++ netif_napi_del(&net_device->chan_table[0].napi); + free_netvsc_device(&net_device->rcu); + + return ERR_PTR(ret); +diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c +index c5584c2..cdb78ee 100644 +--- a/drivers/net/hyperv/netvsc_drv.c ++++ b/drivers/net/hyperv/netvsc_drv.c +@@ -66,10 +66,36 @@ static int debug = -1; + module_param(debug, int, S_IRUGO); + MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + +-static void netvsc_set_multicast_list(struct net_device *net) ++static void netvsc_change_rx_flags(struct net_device *net, int change) + { +- struct net_device_context *net_device_ctx = netdev_priv(net); +- struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); ++ struct net_device_context *ndev_ctx = netdev_priv(net); ++ struct net_device *vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev); ++ int inc; ++ ++ if (!vf_netdev) ++ return; ++ ++ if (change & IFF_PROMISC) { ++ inc = (net->flags & IFF_PROMISC) ? 1 : -1; ++ dev_set_promiscuity(vf_netdev, inc); ++ } ++ ++ if (change & IFF_ALLMULTI) { ++ inc = (net->flags & IFF_ALLMULTI) ? 1 : -1; ++ dev_set_allmulti(vf_netdev, inc); ++ } ++} ++ ++static void netvsc_set_rx_mode(struct net_device *net) ++{ ++ struct net_device_context *ndev_ctx = netdev_priv(net); ++ struct net_device *vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev); ++ struct netvsc_device *nvdev = rtnl_dereference(ndev_ctx->nvdev); ++ ++ if (vf_netdev) { ++ dev_uc_sync(vf_netdev, net); ++ dev_mc_sync(vf_netdev, net); ++ } + + rndis_filter_update(nvdev); + } +@@ -91,12 +117,11 @@ static int netvsc_open(struct net_device *net) + return ret; + } + +- netif_tx_wake_all_queues(net); +- + rdev = nvdev->extension; +- +- if (!rdev->link_state) ++ if (!rdev->link_state) { + netif_carrier_on(net); ++ netif_tx_wake_all_queues(net); ++ } + + if (vf_netdev) { + /* Setting synthetic device up transparently sets +@@ -299,8 +324,19 @@ static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb, + rcu_read_lock(); + vf_netdev = rcu_dereference(ndc->vf_netdev); + if (vf_netdev) { +- txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0; +- qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping; ++ const struct net_device_ops *vf_ops = vf_netdev->netdev_ops; ++ ++ if (vf_ops->ndo_select_queue) ++ txq = vf_ops->ndo_select_queue(vf_netdev, skb, ++ accel_priv, fallback); ++ else ++ txq = fallback(vf_netdev, skb); ++ ++ /* Record the queue selected by VF so that it can be ++ * used for common case where VF has more queues than ++ * the synthetic device. ++ */ ++ qdisc_skb_cb(skb)->slave_dev_queue_mapping = txq; + } else { + txq = netvsc_pick_tx(ndev, skb); + } +@@ -1576,7 +1612,8 @@ static const struct net_device_ops device_ops = { + .ndo_open = netvsc_open, + .ndo_stop = netvsc_close, + .ndo_start_xmit = netvsc_start_xmit, +- .ndo_set_rx_mode = netvsc_set_multicast_list, ++ .ndo_change_rx_flags = netvsc_change_rx_flags, ++ .ndo_set_rx_mode = netvsc_set_rx_mode, + .ndo_change_mtu = netvsc_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = netvsc_set_mac_addr, +@@ -1807,6 +1844,11 @@ static void __netvsc_vf_setup(struct net_device *ndev, + netdev_warn(vf_netdev, + "unable to change mtu to %u\n", ndev->mtu); + ++ /* set multicast etc flags on VF */ ++ dev_change_flags(vf_netdev, ndev->flags | IFF_SLAVE); ++ dev_uc_sync(vf_netdev, ndev); ++ dev_mc_sync(vf_netdev, ndev); ++ + if (netif_running(ndev)) { + ret = dev_open(vf_netdev); + if (ret) +diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c +index c3ca191..8927c48 100644 +--- a/drivers/net/hyperv/rndis_filter.c ++++ b/drivers/net/hyperv/rndis_filter.c +@@ -854,15 +854,19 @@ static void rndis_set_multicast(struct work_struct *w) + { + struct rndis_device *rdev + = container_of(w, struct rndis_device, mcast_work); ++ u32 filter = NDIS_PACKET_TYPE_DIRECTED; ++ unsigned int flags = rdev->ndev->flags; + +- if (rdev->ndev->flags & IFF_PROMISC) +- rndis_filter_set_packet_filter(rdev, +- NDIS_PACKET_TYPE_PROMISCUOUS); +- else +- rndis_filter_set_packet_filter(rdev, +- NDIS_PACKET_TYPE_BROADCAST | +- NDIS_PACKET_TYPE_ALL_MULTICAST | +- NDIS_PACKET_TYPE_DIRECTED); ++ if (flags & IFF_PROMISC) { ++ filter = NDIS_PACKET_TYPE_PROMISCUOUS; ++ } else { ++ if (flags & IFF_ALLMULTI) ++ flags |= NDIS_PACKET_TYPE_ALL_MULTICAST; ++ if (flags & IFF_BROADCAST) ++ flags |= NDIS_PACKET_TYPE_BROADCAST; ++ } ++ ++ rndis_filter_set_packet_filter(rdev, filter); + } + + void rndis_filter_update(struct netvsc_device *nvdev) +@@ -1340,6 +1344,9 @@ void rndis_filter_device_remove(struct hv_device *dev, + { + struct rndis_device *rndis_dev = net_dev->extension; + ++ /* Don't try and setup sub channels if about to halt */ ++ cancel_work_sync(&net_dev->subchan_work); ++ + /* Halt and release the rndis device */ + rndis_filter_halt_device(rndis_dev); + +diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c +index e3e29c2..a6f924f 100644 +--- a/drivers/net/phy/phy.c ++++ b/drivers/net/phy/phy.c +@@ -819,7 +819,7 @@ void phy_start(struct phy_device *phydev) + break; + case PHY_HALTED: + /* if phy was suspended, bring the physical link up again */ +- phy_resume(phydev); ++ __phy_resume(phydev); + + /* make sure interrupts are re-enabled for the PHY */ + if (phy_interrupt_is_valid(phydev)) { +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index d39ae77..478405e 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -135,9 +135,7 @@ static int mdio_bus_phy_resume(struct device *dev) + if (!mdio_bus_phy_may_suspend(phydev)) + goto no_resume; + +- mutex_lock(&phydev->lock); + ret = phy_resume(phydev); +- mutex_unlock(&phydev->lock); + if (ret < 0) + return ret; + +@@ -1041,9 +1039,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, + if (err) + goto error; + +- mutex_lock(&phydev->lock); + phy_resume(phydev); +- mutex_unlock(&phydev->lock); + phy_led_triggers_register(phydev); + + return err; +@@ -1172,7 +1168,7 @@ int phy_suspend(struct phy_device *phydev) + } + EXPORT_SYMBOL(phy_suspend); + +-int phy_resume(struct phy_device *phydev) ++int __phy_resume(struct phy_device *phydev) + { + struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver); + int ret = 0; +@@ -1189,6 +1185,18 @@ int phy_resume(struct phy_device *phydev) + + return ret; + } ++EXPORT_SYMBOL(__phy_resume); ++ ++int phy_resume(struct phy_device *phydev) ++{ ++ int ret; ++ ++ mutex_lock(&phydev->lock); ++ ret = __phy_resume(phydev); ++ mutex_unlock(&phydev->lock); ++ ++ return ret; ++} + EXPORT_SYMBOL(phy_resume); + + int phy_loopback(struct phy_device *phydev, bool enable) +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index 255a5de..fa2a9bd 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -3161,6 +3161,15 @@ ppp_connect_channel(struct channel *pch, int unit) + goto outl; + + ppp_lock(ppp); ++ spin_lock_bh(&pch->downl); ++ if (!pch->chan) { ++ /* Don't connect unregistered channels */ ++ spin_unlock_bh(&pch->downl); ++ ppp_unlock(ppp); ++ ret = -ENOTCONN; ++ goto outl; ++ } ++ spin_unlock_bh(&pch->downl); + if (pch->file.hdrlen > ppp->file.hdrlen) + ppp->file.hdrlen = pch->file.hdrlen; + hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */ +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index b52258c..7433bb2 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -181,7 +181,6 @@ struct tun_file { + struct tun_struct *detached; + struct ptr_ring tx_ring; + struct xdp_rxq_info xdp_rxq; +- int xdp_pending_pkts; + }; + + struct tun_flow_entry { +@@ -1643,6 +1642,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, + else + *skb_xdp = 0; + ++ preempt_disable(); + rcu_read_lock(); + xdp_prog = rcu_dereference(tun->xdp_prog); + if (xdp_prog && !*skb_xdp) { +@@ -1662,11 +1662,12 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, + case XDP_REDIRECT: + get_page(alloc_frag->page); + alloc_frag->offset += buflen; +- ++tfile->xdp_pending_pkts; + err = xdp_do_redirect(tun->dev, &xdp, xdp_prog); ++ xdp_do_flush_map(); + if (err) + goto err_redirect; + rcu_read_unlock(); ++ preempt_enable(); + return NULL; + case XDP_TX: + xdp_xmit = true; +@@ -1688,6 +1689,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, + skb = build_skb(buf, buflen); + if (!skb) { + rcu_read_unlock(); ++ preempt_enable(); + return ERR_PTR(-ENOMEM); + } + +@@ -1700,10 +1702,12 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, + skb->dev = tun->dev; + generic_xdp_tx(skb, xdp_prog); + rcu_read_unlock(); ++ preempt_enable(); + return NULL; + } + + rcu_read_unlock(); ++ preempt_enable(); + + return skb; + +@@ -1711,6 +1715,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, + put_page(alloc_frag->page); + err_xdp: + rcu_read_unlock(); ++ preempt_enable(); + this_cpu_inc(tun->pcpu_stats->rx_dropped); + return NULL; + } +@@ -1984,11 +1989,6 @@ static ssize_t tun_chr_write_iter(struct kiocb *iocb, struct iov_iter *from) + result = tun_get_user(tun, tfile, NULL, from, + file->f_flags & O_NONBLOCK, false); + +- if (tfile->xdp_pending_pkts) { +- tfile->xdp_pending_pkts = 0; +- xdp_do_flush_map(); +- } +- + tun_put(tun); + return result; + } +@@ -2325,13 +2325,6 @@ static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len) + ret = tun_get_user(tun, tfile, m->msg_control, &m->msg_iter, + m->msg_flags & MSG_DONTWAIT, + m->msg_flags & MSG_MORE); +- +- if (tfile->xdp_pending_pkts >= NAPI_POLL_WEIGHT || +- !(m->msg_flags & MSG_MORE)) { +- tfile->xdp_pending_pkts = 0; +- xdp_do_flush_map(); +- } +- + tun_put(tun); + return ret; + } +@@ -3163,7 +3156,6 @@ static int tun_chr_open(struct inode *inode, struct file * file) + sock_set_flag(&tfile->sk, SOCK_ZEROCOPY); + + memset(&tfile->tx_ring, 0, sizeof(tfile->tx_ring)); +- tfile->xdp_pending_pkts = 0; + + return 0; + } +diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c +index 05dca3e..fff4b13 100644 +--- a/drivers/net/usb/cdc_ether.c ++++ b/drivers/net/usb/cdc_ether.c +@@ -896,6 +896,12 @@ static const struct usb_device_id products[] = { + USB_CDC_PROTO_NONE), + .driver_info = (unsigned long)&wwan_info, + }, { ++ /* Cinterion PLS8 modem by GEMALTO */ ++ USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0061, USB_CLASS_COMM, ++ USB_CDC_SUBCLASS_ETHERNET, ++ USB_CDC_PROTO_NONE), ++ .driver_info = (unsigned long)&wwan_info, ++}, { + USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, + USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 958b2e8..86f7196 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -1794,7 +1794,7 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) + + tx_data += len; + agg->skb_len += len; +- agg->skb_num++; ++ agg->skb_num += skb_shinfo(skb)->gso_segs ?: 1; + + dev_kfree_skb_any(skb); + +diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c +index 9bb9e56..2337460 100644 +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -504,6 +504,7 @@ static struct page *xdp_linearize_page(struct receive_queue *rq, + page_off += *len; + + while (--*num_buf) { ++ int tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + unsigned int buflen; + void *buf; + int off; +@@ -518,7 +519,7 @@ static struct page *xdp_linearize_page(struct receive_queue *rq, + /* guard against a misconfigured or uncooperative backend that + * is sending packet larger than the MTU. + */ +- if ((page_off + buflen) > PAGE_SIZE) { ++ if ((page_off + buflen + tailroom) > PAGE_SIZE) { + put_page(p); + goto err_buf; + } +@@ -690,6 +691,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, + unsigned int truesize; + unsigned int headroom = mergeable_ctx_to_headroom(ctx); + bool sent; ++ int err; + + head_skb = NULL; + +@@ -701,7 +703,12 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, + void *data; + u32 act; + +- /* This happens when rx buffer size is underestimated */ ++ /* This happens when rx buffer size is underestimated ++ * or headroom is not enough because of the buffer ++ * was refilled before XDP is set. This should only ++ * happen for the first several packets, so we don't ++ * care much about its performance. ++ */ + if (unlikely(num_buf > 1 || + headroom < virtnet_get_headroom(vi))) { + /* linearize data for XDP */ +@@ -736,9 +743,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, + + act = bpf_prog_run_xdp(xdp_prog, &xdp); + +- if (act != XDP_PASS) +- ewma_pkt_len_add(&rq->mrg_avg_pkt_len, len); +- + switch (act) { + case XDP_PASS: + /* recalculate offset to account for any header +@@ -770,6 +774,18 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, + goto err_xdp; + rcu_read_unlock(); + goto xdp_xmit; ++ case XDP_REDIRECT: ++ err = xdp_do_redirect(dev, &xdp, xdp_prog); ++ if (err) { ++ if (unlikely(xdp_page != page)) ++ put_page(xdp_page); ++ goto err_xdp; ++ } ++ *xdp_xmit = true; ++ if (unlikely(xdp_page != page)) ++ goto err_xdp; ++ rcu_read_unlock(); ++ goto xdp_xmit; + default: + bpf_warn_invalid_xdp_action(act); + case XDP_ABORTED: +@@ -1013,13 +1029,18 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq, + } + + static unsigned int get_mergeable_buf_len(struct receive_queue *rq, +- struct ewma_pkt_len *avg_pkt_len) ++ struct ewma_pkt_len *avg_pkt_len, ++ unsigned int room) + { + const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); + unsigned int len; + +- len = hdr_len + clamp_t(unsigned int, ewma_pkt_len_read(avg_pkt_len), ++ if (room) ++ return PAGE_SIZE - room; ++ ++ len = hdr_len + clamp_t(unsigned int, ewma_pkt_len_read(avg_pkt_len), + rq->min_buf_len, PAGE_SIZE - hdr_len); ++ + return ALIGN(len, L1_CACHE_BYTES); + } + +@@ -1028,21 +1049,27 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, + { + struct page_frag *alloc_frag = &rq->alloc_frag; + unsigned int headroom = virtnet_get_headroom(vi); ++ unsigned int tailroom = headroom ? sizeof(struct skb_shared_info) : 0; ++ unsigned int room = SKB_DATA_ALIGN(headroom + tailroom); + char *buf; + void *ctx; + int err; + unsigned int len, hole; + +- len = get_mergeable_buf_len(rq, &rq->mrg_avg_pkt_len); +- if (unlikely(!skb_page_frag_refill(len + headroom, alloc_frag, gfp))) ++ /* Extra tailroom is needed to satisfy XDP's assumption. This ++ * means rx frags coalescing won't work, but consider we've ++ * disabled GSO for XDP, it won't be a big issue. ++ */ ++ len = get_mergeable_buf_len(rq, &rq->mrg_avg_pkt_len, room); ++ if (unlikely(!skb_page_frag_refill(len + room, alloc_frag, gfp))) + return -ENOMEM; + + buf = (char *)page_address(alloc_frag->page) + alloc_frag->offset; + buf += headroom; /* advance address leaving hole at front of pkt */ + get_page(alloc_frag->page); +- alloc_frag->offset += len + headroom; ++ alloc_frag->offset += len + room; + hole = alloc_frag->size - alloc_frag->offset; +- if (hole < len + headroom) { ++ if (hole < len + room) { + /* To avoid internal fragmentation, if there is very likely not + * enough space for another buffer, add the remaining space to + * the current buffer. +@@ -2185,8 +2212,9 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog, + } + + /* Make sure NAPI is not using any XDP TX queues for RX. */ +- for (i = 0; i < vi->max_queue_pairs; i++) +- napi_disable(&vi->rq[i].napi); ++ if (netif_running(dev)) ++ for (i = 0; i < vi->max_queue_pairs; i++) ++ napi_disable(&vi->rq[i].napi); + + netif_set_real_num_rx_queues(dev, curr_qp + xdp_qp); + err = _virtnet_set_queues(vi, curr_qp + xdp_qp); +@@ -2205,7 +2233,8 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog, + } + if (old_prog) + bpf_prog_put(old_prog); +- virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi); ++ if (netif_running(dev)) ++ virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi); + } + + return 0; +@@ -2576,12 +2605,15 @@ static ssize_t mergeable_rx_buffer_size_show(struct netdev_rx_queue *queue, + { + struct virtnet_info *vi = netdev_priv(queue->dev); + unsigned int queue_index = get_netdev_rx_queue_index(queue); ++ unsigned int headroom = virtnet_get_headroom(vi); ++ unsigned int tailroom = headroom ? sizeof(struct skb_shared_info) : 0; + struct ewma_pkt_len *avg; + + BUG_ON(queue_index >= vi->max_queue_pairs); + avg = &vi->rq[queue_index].mrg_avg_pkt_len; + return sprintf(buf, "%u\n", +- get_mergeable_buf_len(&vi->rq[queue_index], avg)); ++ get_mergeable_buf_len(&vi->rq[queue_index], avg, ++ SKB_DATA_ALIGN(headroom + tailroom))); + } + + static struct rx_queue_attribute mergeable_rx_buffer_size_attribute = +diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c +index afeca6b..ab8b3cb 100644 +--- a/drivers/net/wan/hdlc_ppp.c ++++ b/drivers/net/wan/hdlc_ppp.c +@@ -574,7 +574,10 @@ static void ppp_timer(struct timer_list *t) + ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0, + 0, NULL); + proto->restart_counter--; +- } else ++ } else if (netif_carrier_ok(proto->dev)) ++ ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0, ++ 0, NULL); ++ else + ppp_cp_event(proto->dev, proto->pid, TO_BAD, 0, 0, + 0, NULL); + break; +diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c +index 8de2d5c..dc9303a 100644 +--- a/drivers/pci/dwc/pcie-designware-host.c ++++ b/drivers/pci/dwc/pcie-designware-host.c +@@ -613,7 +613,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp) + /* setup bus numbers */ + val = dw_pcie_readl_dbi(pci, PCI_PRIMARY_BUS); + val &= 0xff000000; +- val |= 0x00010100; ++ val |= 0x00ff0100; + dw_pcie_writel_dbi(pci, PCI_PRIMARY_BUS, val); + + /* setup command register */ +diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c +index 0c2ed11..f63db34 100644 +--- a/drivers/perf/arm_pmu.c ++++ b/drivers/perf/arm_pmu.c +@@ -638,7 +638,7 @@ static int arm_perf_teardown_cpu(unsigned int cpu, struct hlist_node *node) + if (irq_is_percpu_devid(irq)) + disable_percpu_irq(irq); + else +- disable_irq(irq); ++ disable_irq_nosync(irq); + } + + per_cpu(cpu_armpmu, cpu) = NULL; +diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c +index 6dec6ab..d859973 100644 +--- a/drivers/platform/chrome/chromeos_laptop.c ++++ b/drivers/platform/chrome/chromeos_laptop.c +@@ -423,7 +423,7 @@ static int chromeos_laptop_probe(struct platform_device *pdev) + return ret; + } + +-static const struct chromeos_laptop samsung_series_5_550 = { ++static struct chromeos_laptop samsung_series_5_550 = { + .i2c_peripherals = { + /* Touchpad. */ + { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, +@@ -432,14 +432,14 @@ static const struct chromeos_laptop samsung_series_5_550 = { + }, + }; + +-static const struct chromeos_laptop samsung_series_5 = { ++static struct chromeos_laptop samsung_series_5 = { + .i2c_peripherals = { + /* Light Sensor. */ + { .add = setup_tsl2583_als, I2C_ADAPTER_SMBUS }, + }, + }; + +-static const struct chromeos_laptop chromebook_pixel = { ++static struct chromeos_laptop chromebook_pixel = { + .i2c_peripherals = { + /* Touch Screen. */ + { .add = setup_atmel_1664s_ts, I2C_ADAPTER_PANEL }, +@@ -450,14 +450,14 @@ static const struct chromeos_laptop chromebook_pixel = { + }, + }; + +-static const struct chromeos_laptop hp_chromebook_14 = { ++static struct chromeos_laptop hp_chromebook_14 = { + .i2c_peripherals = { + /* Touchpad. */ + { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 }, + }, + }; + +-static const struct chromeos_laptop dell_chromebook_11 = { ++static struct chromeos_laptop dell_chromebook_11 = { + .i2c_peripherals = { + /* Touchpad. */ + { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 }, +@@ -466,28 +466,28 @@ static const struct chromeos_laptop dell_chromebook_11 = { + }, + }; + +-static const struct chromeos_laptop toshiba_cb35 = { ++static struct chromeos_laptop toshiba_cb35 = { + .i2c_peripherals = { + /* Touchpad. */ + { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 }, + }, + }; + +-static const struct chromeos_laptop acer_c7_chromebook = { ++static struct chromeos_laptop acer_c7_chromebook = { + .i2c_peripherals = { + /* Touchpad. */ + { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, + }, + }; + +-static const struct chromeos_laptop acer_ac700 = { ++static struct chromeos_laptop acer_ac700 = { + .i2c_peripherals = { + /* Light Sensor. */ + { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS }, + }, + }; + +-static const struct chromeos_laptop acer_c720 = { ++static struct chromeos_laptop acer_c720 = { + .i2c_peripherals = { + /* Touchscreen. */ + { .add = setup_atmel_1664s_ts, I2C_ADAPTER_DESIGNWARE_1 }, +@@ -500,14 +500,14 @@ static const struct chromeos_laptop acer_c720 = { + }, + }; + +-static const struct chromeos_laptop hp_pavilion_14_chromebook = { ++static struct chromeos_laptop hp_pavilion_14_chromebook = { + .i2c_peripherals = { + /* Touchpad. */ + { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, + }, + }; + +-static const struct chromeos_laptop cr48 = { ++static struct chromeos_laptop cr48 = { + .i2c_peripherals = { + /* Light Sensor. */ + { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS }, +diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig +index 9a8f964..d10ffe5 100644 +--- a/drivers/platform/x86/Kconfig ++++ b/drivers/platform/x86/Kconfig +@@ -105,31 +105,44 @@ config ASUS_LAPTOP + + If you have an ACPI-compatible ASUS laptop, say Y or M here. + ++# ++# If the DELL_SMBIOS_SMM feature is enabled, the DELL_SMBIOS driver ++# becomes dependent on the DCDBAS driver. The "depends" line prevents a ++# configuration where DELL_SMBIOS=y while DCDBAS=m. ++# + config DELL_SMBIOS +- tristate ++ tristate "Dell SMBIOS driver" ++ depends on DCDBAS || DCDBAS=n ++ ---help--- ++ This provides support for the Dell SMBIOS calling interface. ++ If you have a Dell computer you should enable this option. ++ ++ Be sure to select at least one backend for it to work properly. + + config DELL_SMBIOS_WMI +- tristate "Dell SMBIOS calling interface (WMI implementation)" ++ bool "Dell SMBIOS driver WMI backend" ++ default y + depends on ACPI_WMI + select DELL_WMI_DESCRIPTOR +- select DELL_SMBIOS ++ depends on DELL_SMBIOS + ---help--- + This provides an implementation for the Dell SMBIOS calling interface + communicated over ACPI-WMI. + +- If you have a Dell computer from >2007 you should say Y or M here. ++ If you have a Dell computer from >2007 you should say Y here. + If you aren't sure and this module doesn't work for your computer + it just won't load. + + config DELL_SMBIOS_SMM +- tristate "Dell SMBIOS calling interface (SMM implementation)" ++ bool "Dell SMBIOS driver SMM backend" ++ default y + depends on DCDBAS +- select DELL_SMBIOS ++ depends on DELL_SMBIOS + ---help--- + This provides an implementation for the Dell SMBIOS calling interface + communicated over SMI/SMM. + +- If you have a Dell computer from <=2017 you should say Y or M here. ++ If you have a Dell computer from <=2017 you should say Y here. + If you aren't sure and this module doesn't work for your computer + it just won't load. + +diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile +index c388608..2ba6cb7 100644 +--- a/drivers/platform/x86/Makefile ++++ b/drivers/platform/x86/Makefile +@@ -13,8 +13,9 @@ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o + obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o + obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o + obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o +-obj-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o +-obj-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o ++dell-smbios-objs := dell-smbios-base.o ++dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o ++dell-smbios-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o + obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o + obj-$(CONFIG_DELL_WMI) += dell-wmi.o + obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o +diff --git a/drivers/platform/x86/dell-smbios-base.c b/drivers/platform/x86/dell-smbios-base.c +new file mode 100644 +index 0000000..5bcf8a1 +--- /dev/null ++++ b/drivers/platform/x86/dell-smbios-base.c +@@ -0,0 +1,648 @@ ++/* ++ * Common functions for kernel modules using Dell SMBIOS ++ * ++ * Copyright (c) Red Hat ++ * Copyright (c) 2014 Gabriele Mazzotta ++ * Copyright (c) 2014 Pali Rohár ++ * ++ * Based on documentation in the libsmbios package: ++ * Copyright (C) 2005-2014 Dell Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "dell-smbios.h" ++ ++static u32 da_supported_commands; ++static int da_num_tokens; ++static struct platform_device *platform_device; ++static struct calling_interface_token *da_tokens; ++static struct device_attribute *token_location_attrs; ++static struct device_attribute *token_value_attrs; ++static struct attribute **token_attrs; ++static DEFINE_MUTEX(smbios_mutex); ++ ++struct smbios_device { ++ struct list_head list; ++ struct device *device; ++ int (*call_fn)(struct calling_interface_buffer *arg); ++}; ++ ++struct smbios_call { ++ u32 need_capability; ++ int cmd_class; ++ int cmd_select; ++}; ++ ++/* calls that are whitelisted for given capabilities */ ++static struct smbios_call call_whitelist[] = { ++ /* generally tokens are allowed, but may be further filtered or ++ * restricted by token blacklist or whitelist ++ */ ++ {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_STD}, ++ {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_AC}, ++ {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_BAT}, ++ {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD}, ++ {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_AC}, ++ {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT}, ++ /* used by userspace: fwupdate */ ++ {CAP_SYS_ADMIN, CLASS_ADMIN_PROP, SELECT_ADMIN_PROP}, ++ /* used by userspace: fwupd */ ++ {CAP_SYS_ADMIN, CLASS_INFO, SELECT_DOCK}, ++ {CAP_SYS_ADMIN, CLASS_FLASH_INTERFACE, SELECT_FLASH_INTERFACE}, ++}; ++ ++/* calls that are explicitly blacklisted */ ++static struct smbios_call call_blacklist[] = { ++ {0x0000, 1, 7}, /* manufacturing use */ ++ {0x0000, 6, 5}, /* manufacturing use */ ++ {0x0000, 11, 3}, /* write once */ ++ {0x0000, 11, 7}, /* write once */ ++ {0x0000, 11, 11}, /* write once */ ++ {0x0000, 19, -1}, /* diagnostics */ ++ /* handled by kernel: dell-laptop */ ++ {0x0000, CLASS_INFO, SELECT_RFKILL}, ++ {0x0000, CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT}, ++}; ++ ++struct token_range { ++ u32 need_capability; ++ u16 min; ++ u16 max; ++}; ++ ++/* tokens that are whitelisted for given capabilities */ ++static struct token_range token_whitelist[] = { ++ /* used by userspace: fwupdate */ ++ {CAP_SYS_ADMIN, CAPSULE_EN_TOKEN, CAPSULE_DIS_TOKEN}, ++ /* can indicate to userspace that WMI is needed */ ++ {0x0000, WSMT_EN_TOKEN, WSMT_DIS_TOKEN} ++}; ++ ++/* tokens that are explicitly blacklisted */ ++static struct token_range token_blacklist[] = { ++ {0x0000, 0x0058, 0x0059}, /* ME use */ ++ {0x0000, 0x00CD, 0x00D0}, /* raid shadow copy */ ++ {0x0000, 0x013A, 0x01FF}, /* sata shadow copy */ ++ {0x0000, 0x0175, 0x0176}, /* write once */ ++ {0x0000, 0x0195, 0x0197}, /* diagnostics */ ++ {0x0000, 0x01DC, 0x01DD}, /* manufacturing use */ ++ {0x0000, 0x027D, 0x0284}, /* diagnostics */ ++ {0x0000, 0x02E3, 0x02E3}, /* manufacturing use */ ++ {0x0000, 0x02FF, 0x02FF}, /* manufacturing use */ ++ {0x0000, 0x0300, 0x0302}, /* manufacturing use */ ++ {0x0000, 0x0325, 0x0326}, /* manufacturing use */ ++ {0x0000, 0x0332, 0x0335}, /* fan control */ ++ {0x0000, 0x0350, 0x0350}, /* manufacturing use */ ++ {0x0000, 0x0363, 0x0363}, /* manufacturing use */ ++ {0x0000, 0x0368, 0x0368}, /* manufacturing use */ ++ {0x0000, 0x03F6, 0x03F7}, /* manufacturing use */ ++ {0x0000, 0x049E, 0x049F}, /* manufacturing use */ ++ {0x0000, 0x04A0, 0x04A3}, /* disagnostics */ ++ {0x0000, 0x04E6, 0x04E7}, /* manufacturing use */ ++ {0x0000, 0x4000, 0x7FFF}, /* internal BIOS use */ ++ {0x0000, 0x9000, 0x9001}, /* internal BIOS use */ ++ {0x0000, 0xA000, 0xBFFF}, /* write only */ ++ {0x0000, 0xEFF0, 0xEFFF}, /* internal BIOS use */ ++ /* handled by kernel: dell-laptop */ ++ {0x0000, BRIGHTNESS_TOKEN, BRIGHTNESS_TOKEN}, ++ {0x0000, KBD_LED_OFF_TOKEN, KBD_LED_AUTO_TOKEN}, ++ {0x0000, KBD_LED_AC_TOKEN, KBD_LED_AC_TOKEN}, ++ {0x0000, KBD_LED_AUTO_25_TOKEN, KBD_LED_AUTO_75_TOKEN}, ++ {0x0000, KBD_LED_AUTO_100_TOKEN, KBD_LED_AUTO_100_TOKEN}, ++ {0x0000, GLOBAL_MIC_MUTE_ENABLE, GLOBAL_MIC_MUTE_DISABLE}, ++}; ++ ++static LIST_HEAD(smbios_device_list); ++ ++int dell_smbios_error(int value) ++{ ++ switch (value) { ++ case 0: /* Completed successfully */ ++ return 0; ++ case -1: /* Completed with error */ ++ return -EIO; ++ case -2: /* Function not supported */ ++ return -ENXIO; ++ default: /* Unknown error */ ++ return -EINVAL; ++ } ++} ++EXPORT_SYMBOL_GPL(dell_smbios_error); ++ ++int dell_smbios_register_device(struct device *d, void *call_fn) ++{ ++ struct smbios_device *priv; ++ ++ priv = devm_kzalloc(d, sizeof(struct smbios_device), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ get_device(d); ++ priv->device = d; ++ priv->call_fn = call_fn; ++ mutex_lock(&smbios_mutex); ++ list_add_tail(&priv->list, &smbios_device_list); ++ mutex_unlock(&smbios_mutex); ++ dev_dbg(d, "Added device: %s\n", d->driver->name); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(dell_smbios_register_device); ++ ++void dell_smbios_unregister_device(struct device *d) ++{ ++ struct smbios_device *priv; ++ ++ mutex_lock(&smbios_mutex); ++ list_for_each_entry(priv, &smbios_device_list, list) { ++ if (priv->device == d) { ++ list_del(&priv->list); ++ put_device(d); ++ break; ++ } ++ } ++ mutex_unlock(&smbios_mutex); ++ dev_dbg(d, "Remove device: %s\n", d->driver->name); ++} ++EXPORT_SYMBOL_GPL(dell_smbios_unregister_device); ++ ++int dell_smbios_call_filter(struct device *d, ++ struct calling_interface_buffer *buffer) ++{ ++ u16 t = 0; ++ int i; ++ ++ /* can't make calls over 30 */ ++ if (buffer->cmd_class > 30) { ++ dev_dbg(d, "class too big: %u\n", buffer->cmd_class); ++ return -EINVAL; ++ } ++ ++ /* supported calls on the particular system */ ++ if (!(da_supported_commands & (1 << buffer->cmd_class))) { ++ dev_dbg(d, "invalid command, supported commands: 0x%8x\n", ++ da_supported_commands); ++ return -EINVAL; ++ } ++ ++ /* match against call blacklist */ ++ for (i = 0; i < ARRAY_SIZE(call_blacklist); i++) { ++ if (buffer->cmd_class != call_blacklist[i].cmd_class) ++ continue; ++ if (buffer->cmd_select != call_blacklist[i].cmd_select && ++ call_blacklist[i].cmd_select != -1) ++ continue; ++ dev_dbg(d, "blacklisted command: %u/%u\n", ++ buffer->cmd_class, buffer->cmd_select); ++ return -EINVAL; ++ } ++ ++ /* if a token call, find token ID */ ++ ++ if ((buffer->cmd_class == CLASS_TOKEN_READ || ++ buffer->cmd_class == CLASS_TOKEN_WRITE) && ++ buffer->cmd_select < 3) { ++ /* find the matching token ID */ ++ for (i = 0; i < da_num_tokens; i++) { ++ if (da_tokens[i].location != buffer->input[0]) ++ continue; ++ t = da_tokens[i].tokenID; ++ break; ++ } ++ ++ /* token call; but token didn't exist */ ++ if (!t) { ++ dev_dbg(d, "token at location %04x doesn't exist\n", ++ buffer->input[0]); ++ return -EINVAL; ++ } ++ ++ /* match against token blacklist */ ++ for (i = 0; i < ARRAY_SIZE(token_blacklist); i++) { ++ if (!token_blacklist[i].min || !token_blacklist[i].max) ++ continue; ++ if (t >= token_blacklist[i].min && ++ t <= token_blacklist[i].max) ++ return -EINVAL; ++ } ++ ++ /* match against token whitelist */ ++ for (i = 0; i < ARRAY_SIZE(token_whitelist); i++) { ++ if (!token_whitelist[i].min || !token_whitelist[i].max) ++ continue; ++ if (t < token_whitelist[i].min || ++ t > token_whitelist[i].max) ++ continue; ++ if (!token_whitelist[i].need_capability || ++ capable(token_whitelist[i].need_capability)) { ++ dev_dbg(d, "whitelisted token: %x\n", t); ++ return 0; ++ } ++ ++ } ++ } ++ /* match against call whitelist */ ++ for (i = 0; i < ARRAY_SIZE(call_whitelist); i++) { ++ if (buffer->cmd_class != call_whitelist[i].cmd_class) ++ continue; ++ if (buffer->cmd_select != call_whitelist[i].cmd_select) ++ continue; ++ if (!call_whitelist[i].need_capability || ++ capable(call_whitelist[i].need_capability)) { ++ dev_dbg(d, "whitelisted capable command: %u/%u\n", ++ buffer->cmd_class, buffer->cmd_select); ++ return 0; ++ } ++ dev_dbg(d, "missing capability %d for %u/%u\n", ++ call_whitelist[i].need_capability, ++ buffer->cmd_class, buffer->cmd_select); ++ ++ } ++ ++ /* not in a whitelist, only allow processes with capabilities */ ++ if (capable(CAP_SYS_RAWIO)) { ++ dev_dbg(d, "Allowing %u/%u due to CAP_SYS_RAWIO\n", ++ buffer->cmd_class, buffer->cmd_select); ++ return 0; ++ } ++ ++ return -EACCES; ++} ++EXPORT_SYMBOL_GPL(dell_smbios_call_filter); ++ ++int dell_smbios_call(struct calling_interface_buffer *buffer) ++{ ++ int (*call_fn)(struct calling_interface_buffer *) = NULL; ++ struct device *selected_dev = NULL; ++ struct smbios_device *priv; ++ int ret; ++ ++ mutex_lock(&smbios_mutex); ++ list_for_each_entry(priv, &smbios_device_list, list) { ++ if (!selected_dev || priv->device->id >= selected_dev->id) { ++ dev_dbg(priv->device, "Trying device ID: %d\n", ++ priv->device->id); ++ call_fn = priv->call_fn; ++ selected_dev = priv->device; ++ } ++ } ++ ++ if (!selected_dev) { ++ ret = -ENODEV; ++ pr_err("No dell-smbios drivers are loaded\n"); ++ goto out_smbios_call; ++ } ++ ++ ret = call_fn(buffer); ++ ++out_smbios_call: ++ mutex_unlock(&smbios_mutex); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(dell_smbios_call); ++ ++struct calling_interface_token *dell_smbios_find_token(int tokenid) ++{ ++ int i; ++ ++ for (i = 0; i < da_num_tokens; i++) { ++ if (da_tokens[i].tokenID == tokenid) ++ return &da_tokens[i]; ++ } ++ ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(dell_smbios_find_token); ++ ++static BLOCKING_NOTIFIER_HEAD(dell_laptop_chain_head); ++ ++int dell_laptop_register_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_register(&dell_laptop_chain_head, nb); ++} ++EXPORT_SYMBOL_GPL(dell_laptop_register_notifier); ++ ++int dell_laptop_unregister_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_unregister(&dell_laptop_chain_head, nb); ++} ++EXPORT_SYMBOL_GPL(dell_laptop_unregister_notifier); ++ ++void dell_laptop_call_notifier(unsigned long action, void *data) ++{ ++ blocking_notifier_call_chain(&dell_laptop_chain_head, action, data); ++} ++EXPORT_SYMBOL_GPL(dell_laptop_call_notifier); ++ ++static void __init parse_da_table(const struct dmi_header *dm) ++{ ++ /* Final token is a terminator, so we don't want to copy it */ ++ int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; ++ struct calling_interface_token *new_da_tokens; ++ struct calling_interface_structure *table = ++ container_of(dm, struct calling_interface_structure, header); ++ ++ /* ++ * 4 bytes of table header, plus 7 bytes of Dell header ++ * plus at least 6 bytes of entry ++ */ ++ ++ if (dm->length < 17) ++ return; ++ ++ da_supported_commands = table->supportedCmds; ++ ++ new_da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) * ++ sizeof(struct calling_interface_token), ++ GFP_KERNEL); ++ ++ if (!new_da_tokens) ++ return; ++ da_tokens = new_da_tokens; ++ ++ memcpy(da_tokens+da_num_tokens, table->tokens, ++ sizeof(struct calling_interface_token) * tokens); ++ ++ da_num_tokens += tokens; ++} ++ ++static void zero_duplicates(struct device *dev) ++{ ++ int i, j; ++ ++ for (i = 0; i < da_num_tokens; i++) { ++ if (da_tokens[i].tokenID == 0) ++ continue; ++ for (j = i+1; j < da_num_tokens; j++) { ++ if (da_tokens[j].tokenID == 0) ++ continue; ++ if (da_tokens[i].tokenID == da_tokens[j].tokenID) { ++ dev_dbg(dev, "Zeroing dup token ID %x(%x/%x)\n", ++ da_tokens[j].tokenID, ++ da_tokens[j].location, ++ da_tokens[j].value); ++ da_tokens[j].tokenID = 0; ++ } ++ } ++ } ++} ++ ++static void __init find_tokens(const struct dmi_header *dm, void *dummy) ++{ ++ switch (dm->type) { ++ case 0xd4: /* Indexed IO */ ++ case 0xd5: /* Protected Area Type 1 */ ++ case 0xd6: /* Protected Area Type 2 */ ++ break; ++ case 0xda: /* Calling interface */ ++ parse_da_table(dm); ++ break; ++ } ++} ++ ++static int match_attribute(struct device *dev, ++ struct device_attribute *attr) ++{ ++ int i; ++ ++ for (i = 0; i < da_num_tokens * 2; i++) { ++ if (!token_attrs[i]) ++ continue; ++ if (strcmp(token_attrs[i]->name, attr->attr.name) == 0) ++ return i/2; ++ } ++ dev_dbg(dev, "couldn't match: %s\n", attr->attr.name); ++ return -EINVAL; ++} ++ ++static ssize_t location_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int i; ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ ++ i = match_attribute(dev, attr); ++ if (i > 0) ++ return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].location); ++ return 0; ++} ++ ++static ssize_t value_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int i; ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ ++ i = match_attribute(dev, attr); ++ if (i > 0) ++ return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].value); ++ return 0; ++} ++ ++static struct attribute_group smbios_attribute_group = { ++ .name = "tokens" ++}; ++ ++static struct platform_driver platform_driver = { ++ .driver = { ++ .name = "dell-smbios", ++ }, ++}; ++ ++static int build_tokens_sysfs(struct platform_device *dev) ++{ ++ char *location_name; ++ char *value_name; ++ size_t size; ++ int ret; ++ int i, j; ++ ++ /* (number of tokens + 1 for null terminated */ ++ size = sizeof(struct device_attribute) * (da_num_tokens + 1); ++ token_location_attrs = kzalloc(size, GFP_KERNEL); ++ if (!token_location_attrs) ++ return -ENOMEM; ++ token_value_attrs = kzalloc(size, GFP_KERNEL); ++ if (!token_value_attrs) ++ goto out_allocate_value; ++ ++ /* need to store both location and value + terminator*/ ++ size = sizeof(struct attribute *) * ((2 * da_num_tokens) + 1); ++ token_attrs = kzalloc(size, GFP_KERNEL); ++ if (!token_attrs) ++ goto out_allocate_attrs; ++ ++ for (i = 0, j = 0; i < da_num_tokens; i++) { ++ /* skip empty */ ++ if (da_tokens[i].tokenID == 0) ++ continue; ++ /* add location */ ++ location_name = kasprintf(GFP_KERNEL, "%04x_location", ++ da_tokens[i].tokenID); ++ if (location_name == NULL) ++ goto out_unwind_strings; ++ sysfs_attr_init(&token_location_attrs[i].attr); ++ token_location_attrs[i].attr.name = location_name; ++ token_location_attrs[i].attr.mode = 0444; ++ token_location_attrs[i].show = location_show; ++ token_attrs[j++] = &token_location_attrs[i].attr; ++ ++ /* add value */ ++ value_name = kasprintf(GFP_KERNEL, "%04x_value", ++ da_tokens[i].tokenID); ++ if (value_name == NULL) ++ goto loop_fail_create_value; ++ sysfs_attr_init(&token_value_attrs[i].attr); ++ token_value_attrs[i].attr.name = value_name; ++ token_value_attrs[i].attr.mode = 0444; ++ token_value_attrs[i].show = value_show; ++ token_attrs[j++] = &token_value_attrs[i].attr; ++ continue; ++ ++loop_fail_create_value: ++ kfree(value_name); ++ goto out_unwind_strings; ++ } ++ smbios_attribute_group.attrs = token_attrs; ++ ++ ret = sysfs_create_group(&dev->dev.kobj, &smbios_attribute_group); ++ if (ret) ++ goto out_unwind_strings; ++ return 0; ++ ++out_unwind_strings: ++ for (i = i-1; i > 0; i--) { ++ kfree(token_location_attrs[i].attr.name); ++ kfree(token_value_attrs[i].attr.name); ++ } ++ kfree(token_attrs); ++out_allocate_attrs: ++ kfree(token_value_attrs); ++out_allocate_value: ++ kfree(token_location_attrs); ++ ++ return -ENOMEM; ++} ++ ++static void free_group(struct platform_device *pdev) ++{ ++ int i; ++ ++ sysfs_remove_group(&pdev->dev.kobj, ++ &smbios_attribute_group); ++ for (i = 0; i < da_num_tokens; i++) { ++ kfree(token_location_attrs[i].attr.name); ++ kfree(token_value_attrs[i].attr.name); ++ } ++ kfree(token_attrs); ++ kfree(token_value_attrs); ++ kfree(token_location_attrs); ++} ++ ++static int __init dell_smbios_init(void) ++{ ++ const struct dmi_device *valid; ++ int ret, wmi, smm; ++ ++ valid = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL); ++ if (!valid) { ++ pr_err("Unable to run on non-Dell system\n"); ++ return -ENODEV; ++ } ++ ++ dmi_walk(find_tokens, NULL); ++ ++ if (!da_tokens) { ++ pr_info("Unable to find dmi tokens\n"); ++ return -ENODEV; ++ } ++ ++ ret = platform_driver_register(&platform_driver); ++ if (ret) ++ goto fail_platform_driver; ++ ++ platform_device = platform_device_alloc("dell-smbios", 0); ++ if (!platform_device) { ++ ret = -ENOMEM; ++ goto fail_platform_device_alloc; ++ } ++ ret = platform_device_add(platform_device); ++ if (ret) ++ goto fail_platform_device_add; ++ ++ /* duplicate tokens will cause problems building sysfs files */ ++ zero_duplicates(&platform_device->dev); ++ ++ ret = build_tokens_sysfs(platform_device); ++ if (ret) ++ goto fail_create_group; ++ ++ /* register backends */ ++ wmi = init_dell_smbios_wmi(); ++ if (wmi) ++ pr_debug("Failed to initialize WMI backend: %d\n", wmi); ++ smm = init_dell_smbios_smm(); ++ if (smm) ++ pr_debug("Failed to initialize SMM backend: %d\n", smm); ++ if (wmi && smm) { ++ pr_err("No SMBIOS backends available (wmi: %d, smm: %d)\n", ++ wmi, smm); ++ goto fail_sysfs; ++ } ++ ++ return 0; ++ ++fail_sysfs: ++ free_group(platform_device); ++ ++fail_create_group: ++ platform_device_del(platform_device); ++ ++fail_platform_device_add: ++ platform_device_put(platform_device); ++ ++fail_platform_device_alloc: ++ platform_driver_unregister(&platform_driver); ++ ++fail_platform_driver: ++ kfree(da_tokens); ++ return ret; ++} ++ ++static void __exit dell_smbios_exit(void) ++{ ++ exit_dell_smbios_wmi(); ++ exit_dell_smbios_smm(); ++ mutex_lock(&smbios_mutex); ++ if (platform_device) { ++ free_group(platform_device); ++ platform_device_unregister(platform_device); ++ platform_driver_unregister(&platform_driver); ++ } ++ kfree(da_tokens); ++ mutex_unlock(&smbios_mutex); ++} ++ ++subsys_initcall(dell_smbios_init); ++module_exit(dell_smbios_exit); ++ ++MODULE_AUTHOR("Matthew Garrett "); ++MODULE_AUTHOR("Gabriele Mazzotta "); ++MODULE_AUTHOR("Pali Rohár "); ++MODULE_AUTHOR("Mario Limonciello "); ++MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/x86/dell-smbios-smm.c b/drivers/platform/x86/dell-smbios-smm.c +index 89f65c4..e9e9da5 100644 +--- a/drivers/platform/x86/dell-smbios-smm.c ++++ b/drivers/platform/x86/dell-smbios-smm.c +@@ -58,7 +58,7 @@ static const struct dmi_system_id dell_device_table[] __initconst = { + }; + MODULE_DEVICE_TABLE(dmi, dell_device_table); + +-static void __init parse_da_table(const struct dmi_header *dm) ++static void parse_da_table(const struct dmi_header *dm) + { + struct calling_interface_structure *table = + container_of(dm, struct calling_interface_structure, header); +@@ -73,7 +73,7 @@ static void __init parse_da_table(const struct dmi_header *dm) + da_command_code = table->cmdIOCode; + } + +-static void __init find_cmd_address(const struct dmi_header *dm, void *dummy) ++static void find_cmd_address(const struct dmi_header *dm, void *dummy) + { + switch (dm->type) { + case 0xda: /* Calling interface */ +@@ -128,7 +128,7 @@ static bool test_wsmt_enabled(void) + return false; + } + +-static int __init dell_smbios_smm_init(void) ++int init_dell_smbios_smm(void) + { + int ret; + /* +@@ -176,7 +176,7 @@ static int __init dell_smbios_smm_init(void) + return ret; + } + +-static void __exit dell_smbios_smm_exit(void) ++void exit_dell_smbios_smm(void) + { + if (platform_device) { + dell_smbios_unregister_device(&platform_device->dev); +@@ -184,13 +184,3 @@ static void __exit dell_smbios_smm_exit(void) + free_page((unsigned long)buffer); + } + } +- +-subsys_initcall(dell_smbios_smm_init); +-module_exit(dell_smbios_smm_exit); +- +-MODULE_AUTHOR("Matthew Garrett "); +-MODULE_AUTHOR("Gabriele Mazzotta "); +-MODULE_AUTHOR("Pali Rohár "); +-MODULE_AUTHOR("Mario Limonciello "); +-MODULE_DESCRIPTION("Dell SMBIOS communications over SMI"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c +index 609557a..fbefedb 100644 +--- a/drivers/platform/x86/dell-smbios-wmi.c ++++ b/drivers/platform/x86/dell-smbios-wmi.c +@@ -228,7 +228,7 @@ static const struct wmi_device_id dell_smbios_wmi_id_table[] = { + { }, + }; + +-static void __init parse_b1_table(const struct dmi_header *dm) ++static void parse_b1_table(const struct dmi_header *dm) + { + struct misc_bios_flags_structure *flags = + container_of(dm, struct misc_bios_flags_structure, header); +@@ -242,7 +242,7 @@ static void __init parse_b1_table(const struct dmi_header *dm) + wmi_supported = 1; + } + +-static void __init find_b1(const struct dmi_header *dm, void *dummy) ++static void find_b1(const struct dmi_header *dm, void *dummy) + { + switch (dm->type) { + case 0xb1: /* misc bios flags */ +@@ -261,7 +261,7 @@ static struct wmi_driver dell_smbios_wmi_driver = { + .filter_callback = dell_smbios_wmi_filter, + }; + +-static int __init init_dell_smbios_wmi(void) ++int init_dell_smbios_wmi(void) + { + dmi_walk(find_b1, NULL); + +@@ -271,15 +271,9 @@ static int __init init_dell_smbios_wmi(void) + return wmi_driver_register(&dell_smbios_wmi_driver); + } + +-static void __exit exit_dell_smbios_wmi(void) ++void exit_dell_smbios_wmi(void) + { + wmi_driver_unregister(&dell_smbios_wmi_driver); + } + +-module_init(init_dell_smbios_wmi); +-module_exit(exit_dell_smbios_wmi); +- + MODULE_ALIAS("wmi:" DELL_WMI_SMBIOS_GUID); +-MODULE_AUTHOR("Mario Limonciello "); +-MODULE_DESCRIPTION("Dell SMBIOS communications over WMI"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c +deleted file mode 100644 +index 8541cde..0000000 +--- a/drivers/platform/x86/dell-smbios.c ++++ /dev/null +@@ -1,627 +0,0 @@ +-/* +- * Common functions for kernel modules using Dell SMBIOS +- * +- * Copyright (c) Red Hat +- * Copyright (c) 2014 Gabriele Mazzotta +- * Copyright (c) 2014 Pali Rohár +- * +- * Based on documentation in the libsmbios package: +- * Copyright (C) 2005-2014 Dell Inc. +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include "dell-smbios.h" +- +-static u32 da_supported_commands; +-static int da_num_tokens; +-static struct platform_device *platform_device; +-static struct calling_interface_token *da_tokens; +-static struct device_attribute *token_location_attrs; +-static struct device_attribute *token_value_attrs; +-static struct attribute **token_attrs; +-static DEFINE_MUTEX(smbios_mutex); +- +-struct smbios_device { +- struct list_head list; +- struct device *device; +- int (*call_fn)(struct calling_interface_buffer *); +-}; +- +-struct smbios_call { +- u32 need_capability; +- int cmd_class; +- int cmd_select; +-}; +- +-/* calls that are whitelisted for given capabilities */ +-static struct smbios_call call_whitelist[] = { +- /* generally tokens are allowed, but may be further filtered or +- * restricted by token blacklist or whitelist +- */ +- {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_STD}, +- {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_AC}, +- {CAP_SYS_ADMIN, CLASS_TOKEN_READ, SELECT_TOKEN_BAT}, +- {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD}, +- {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_AC}, +- {CAP_SYS_ADMIN, CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT}, +- /* used by userspace: fwupdate */ +- {CAP_SYS_ADMIN, CLASS_ADMIN_PROP, SELECT_ADMIN_PROP}, +- /* used by userspace: fwupd */ +- {CAP_SYS_ADMIN, CLASS_INFO, SELECT_DOCK}, +- {CAP_SYS_ADMIN, CLASS_FLASH_INTERFACE, SELECT_FLASH_INTERFACE}, +-}; +- +-/* calls that are explicitly blacklisted */ +-static struct smbios_call call_blacklist[] = { +- {0x0000, 1, 7}, /* manufacturing use */ +- {0x0000, 6, 5}, /* manufacturing use */ +- {0x0000, 11, 3}, /* write once */ +- {0x0000, 11, 7}, /* write once */ +- {0x0000, 11, 11}, /* write once */ +- {0x0000, 19, -1}, /* diagnostics */ +- /* handled by kernel: dell-laptop */ +- {0x0000, CLASS_INFO, SELECT_RFKILL}, +- {0x0000, CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT}, +-}; +- +-struct token_range { +- u32 need_capability; +- u16 min; +- u16 max; +-}; +- +-/* tokens that are whitelisted for given capabilities */ +-static struct token_range token_whitelist[] = { +- /* used by userspace: fwupdate */ +- {CAP_SYS_ADMIN, CAPSULE_EN_TOKEN, CAPSULE_DIS_TOKEN}, +- /* can indicate to userspace that WMI is needed */ +- {0x0000, WSMT_EN_TOKEN, WSMT_DIS_TOKEN} +-}; +- +-/* tokens that are explicitly blacklisted */ +-static struct token_range token_blacklist[] = { +- {0x0000, 0x0058, 0x0059}, /* ME use */ +- {0x0000, 0x00CD, 0x00D0}, /* raid shadow copy */ +- {0x0000, 0x013A, 0x01FF}, /* sata shadow copy */ +- {0x0000, 0x0175, 0x0176}, /* write once */ +- {0x0000, 0x0195, 0x0197}, /* diagnostics */ +- {0x0000, 0x01DC, 0x01DD}, /* manufacturing use */ +- {0x0000, 0x027D, 0x0284}, /* diagnostics */ +- {0x0000, 0x02E3, 0x02E3}, /* manufacturing use */ +- {0x0000, 0x02FF, 0x02FF}, /* manufacturing use */ +- {0x0000, 0x0300, 0x0302}, /* manufacturing use */ +- {0x0000, 0x0325, 0x0326}, /* manufacturing use */ +- {0x0000, 0x0332, 0x0335}, /* fan control */ +- {0x0000, 0x0350, 0x0350}, /* manufacturing use */ +- {0x0000, 0x0363, 0x0363}, /* manufacturing use */ +- {0x0000, 0x0368, 0x0368}, /* manufacturing use */ +- {0x0000, 0x03F6, 0x03F7}, /* manufacturing use */ +- {0x0000, 0x049E, 0x049F}, /* manufacturing use */ +- {0x0000, 0x04A0, 0x04A3}, /* disagnostics */ +- {0x0000, 0x04E6, 0x04E7}, /* manufacturing use */ +- {0x0000, 0x4000, 0x7FFF}, /* internal BIOS use */ +- {0x0000, 0x9000, 0x9001}, /* internal BIOS use */ +- {0x0000, 0xA000, 0xBFFF}, /* write only */ +- {0x0000, 0xEFF0, 0xEFFF}, /* internal BIOS use */ +- /* handled by kernel: dell-laptop */ +- {0x0000, BRIGHTNESS_TOKEN, BRIGHTNESS_TOKEN}, +- {0x0000, KBD_LED_OFF_TOKEN, KBD_LED_AUTO_TOKEN}, +- {0x0000, KBD_LED_AC_TOKEN, KBD_LED_AC_TOKEN}, +- {0x0000, KBD_LED_AUTO_25_TOKEN, KBD_LED_AUTO_75_TOKEN}, +- {0x0000, KBD_LED_AUTO_100_TOKEN, KBD_LED_AUTO_100_TOKEN}, +- {0x0000, GLOBAL_MIC_MUTE_ENABLE, GLOBAL_MIC_MUTE_DISABLE}, +-}; +- +-static LIST_HEAD(smbios_device_list); +- +-int dell_smbios_error(int value) +-{ +- switch (value) { +- case 0: /* Completed successfully */ +- return 0; +- case -1: /* Completed with error */ +- return -EIO; +- case -2: /* Function not supported */ +- return -ENXIO; +- default: /* Unknown error */ +- return -EINVAL; +- } +-} +-EXPORT_SYMBOL_GPL(dell_smbios_error); +- +-int dell_smbios_register_device(struct device *d, void *call_fn) +-{ +- struct smbios_device *priv; +- +- priv = devm_kzalloc(d, sizeof(struct smbios_device), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- get_device(d); +- priv->device = d; +- priv->call_fn = call_fn; +- mutex_lock(&smbios_mutex); +- list_add_tail(&priv->list, &smbios_device_list); +- mutex_unlock(&smbios_mutex); +- dev_dbg(d, "Added device: %s\n", d->driver->name); +- return 0; +-} +-EXPORT_SYMBOL_GPL(dell_smbios_register_device); +- +-void dell_smbios_unregister_device(struct device *d) +-{ +- struct smbios_device *priv; +- +- mutex_lock(&smbios_mutex); +- list_for_each_entry(priv, &smbios_device_list, list) { +- if (priv->device == d) { +- list_del(&priv->list); +- put_device(d); +- break; +- } +- } +- mutex_unlock(&smbios_mutex); +- dev_dbg(d, "Remove device: %s\n", d->driver->name); +-} +-EXPORT_SYMBOL_GPL(dell_smbios_unregister_device); +- +-int dell_smbios_call_filter(struct device *d, +- struct calling_interface_buffer *buffer) +-{ +- u16 t = 0; +- int i; +- +- /* can't make calls over 30 */ +- if (buffer->cmd_class > 30) { +- dev_dbg(d, "class too big: %u\n", buffer->cmd_class); +- return -EINVAL; +- } +- +- /* supported calls on the particular system */ +- if (!(da_supported_commands & (1 << buffer->cmd_class))) { +- dev_dbg(d, "invalid command, supported commands: 0x%8x\n", +- da_supported_commands); +- return -EINVAL; +- } +- +- /* match against call blacklist */ +- for (i = 0; i < ARRAY_SIZE(call_blacklist); i++) { +- if (buffer->cmd_class != call_blacklist[i].cmd_class) +- continue; +- if (buffer->cmd_select != call_blacklist[i].cmd_select && +- call_blacklist[i].cmd_select != -1) +- continue; +- dev_dbg(d, "blacklisted command: %u/%u\n", +- buffer->cmd_class, buffer->cmd_select); +- return -EINVAL; +- } +- +- /* if a token call, find token ID */ +- +- if ((buffer->cmd_class == CLASS_TOKEN_READ || +- buffer->cmd_class == CLASS_TOKEN_WRITE) && +- buffer->cmd_select < 3) { +- /* find the matching token ID */ +- for (i = 0; i < da_num_tokens; i++) { +- if (da_tokens[i].location != buffer->input[0]) +- continue; +- t = da_tokens[i].tokenID; +- break; +- } +- +- /* token call; but token didn't exist */ +- if (!t) { +- dev_dbg(d, "token at location %04x doesn't exist\n", +- buffer->input[0]); +- return -EINVAL; +- } +- +- /* match against token blacklist */ +- for (i = 0; i < ARRAY_SIZE(token_blacklist); i++) { +- if (!token_blacklist[i].min || !token_blacklist[i].max) +- continue; +- if (t >= token_blacklist[i].min && +- t <= token_blacklist[i].max) +- return -EINVAL; +- } +- +- /* match against token whitelist */ +- for (i = 0; i < ARRAY_SIZE(token_whitelist); i++) { +- if (!token_whitelist[i].min || !token_whitelist[i].max) +- continue; +- if (t < token_whitelist[i].min || +- t > token_whitelist[i].max) +- continue; +- if (!token_whitelist[i].need_capability || +- capable(token_whitelist[i].need_capability)) { +- dev_dbg(d, "whitelisted token: %x\n", t); +- return 0; +- } +- +- } +- } +- /* match against call whitelist */ +- for (i = 0; i < ARRAY_SIZE(call_whitelist); i++) { +- if (buffer->cmd_class != call_whitelist[i].cmd_class) +- continue; +- if (buffer->cmd_select != call_whitelist[i].cmd_select) +- continue; +- if (!call_whitelist[i].need_capability || +- capable(call_whitelist[i].need_capability)) { +- dev_dbg(d, "whitelisted capable command: %u/%u\n", +- buffer->cmd_class, buffer->cmd_select); +- return 0; +- } +- dev_dbg(d, "missing capability %d for %u/%u\n", +- call_whitelist[i].need_capability, +- buffer->cmd_class, buffer->cmd_select); +- +- } +- +- /* not in a whitelist, only allow processes with capabilities */ +- if (capable(CAP_SYS_RAWIO)) { +- dev_dbg(d, "Allowing %u/%u due to CAP_SYS_RAWIO\n", +- buffer->cmd_class, buffer->cmd_select); +- return 0; +- } +- +- return -EACCES; +-} +-EXPORT_SYMBOL_GPL(dell_smbios_call_filter); +- +-int dell_smbios_call(struct calling_interface_buffer *buffer) +-{ +- int (*call_fn)(struct calling_interface_buffer *) = NULL; +- struct device *selected_dev = NULL; +- struct smbios_device *priv; +- int ret; +- +- mutex_lock(&smbios_mutex); +- list_for_each_entry(priv, &smbios_device_list, list) { +- if (!selected_dev || priv->device->id >= selected_dev->id) { +- dev_dbg(priv->device, "Trying device ID: %d\n", +- priv->device->id); +- call_fn = priv->call_fn; +- selected_dev = priv->device; +- } +- } +- +- if (!selected_dev) { +- ret = -ENODEV; +- pr_err("No dell-smbios drivers are loaded\n"); +- goto out_smbios_call; +- } +- +- ret = call_fn(buffer); +- +-out_smbios_call: +- mutex_unlock(&smbios_mutex); +- return ret; +-} +-EXPORT_SYMBOL_GPL(dell_smbios_call); +- +-struct calling_interface_token *dell_smbios_find_token(int tokenid) +-{ +- int i; +- +- for (i = 0; i < da_num_tokens; i++) { +- if (da_tokens[i].tokenID == tokenid) +- return &da_tokens[i]; +- } +- +- return NULL; +-} +-EXPORT_SYMBOL_GPL(dell_smbios_find_token); +- +-static BLOCKING_NOTIFIER_HEAD(dell_laptop_chain_head); +- +-int dell_laptop_register_notifier(struct notifier_block *nb) +-{ +- return blocking_notifier_chain_register(&dell_laptop_chain_head, nb); +-} +-EXPORT_SYMBOL_GPL(dell_laptop_register_notifier); +- +-int dell_laptop_unregister_notifier(struct notifier_block *nb) +-{ +- return blocking_notifier_chain_unregister(&dell_laptop_chain_head, nb); +-} +-EXPORT_SYMBOL_GPL(dell_laptop_unregister_notifier); +- +-void dell_laptop_call_notifier(unsigned long action, void *data) +-{ +- blocking_notifier_call_chain(&dell_laptop_chain_head, action, data); +-} +-EXPORT_SYMBOL_GPL(dell_laptop_call_notifier); +- +-static void __init parse_da_table(const struct dmi_header *dm) +-{ +- /* Final token is a terminator, so we don't want to copy it */ +- int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; +- struct calling_interface_token *new_da_tokens; +- struct calling_interface_structure *table = +- container_of(dm, struct calling_interface_structure, header); +- +- /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least +- 6 bytes of entry */ +- +- if (dm->length < 17) +- return; +- +- da_supported_commands = table->supportedCmds; +- +- new_da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) * +- sizeof(struct calling_interface_token), +- GFP_KERNEL); +- +- if (!new_da_tokens) +- return; +- da_tokens = new_da_tokens; +- +- memcpy(da_tokens+da_num_tokens, table->tokens, +- sizeof(struct calling_interface_token) * tokens); +- +- da_num_tokens += tokens; +-} +- +-static void zero_duplicates(struct device *dev) +-{ +- int i, j; +- +- for (i = 0; i < da_num_tokens; i++) { +- if (da_tokens[i].tokenID == 0) +- continue; +- for (j = i+1; j < da_num_tokens; j++) { +- if (da_tokens[j].tokenID == 0) +- continue; +- if (da_tokens[i].tokenID == da_tokens[j].tokenID) { +- dev_dbg(dev, "Zeroing dup token ID %x(%x/%x)\n", +- da_tokens[j].tokenID, +- da_tokens[j].location, +- da_tokens[j].value); +- da_tokens[j].tokenID = 0; +- } +- } +- } +-} +- +-static void __init find_tokens(const struct dmi_header *dm, void *dummy) +-{ +- switch (dm->type) { +- case 0xd4: /* Indexed IO */ +- case 0xd5: /* Protected Area Type 1 */ +- case 0xd6: /* Protected Area Type 2 */ +- break; +- case 0xda: /* Calling interface */ +- parse_da_table(dm); +- break; +- } +-} +- +-static int match_attribute(struct device *dev, +- struct device_attribute *attr) +-{ +- int i; +- +- for (i = 0; i < da_num_tokens * 2; i++) { +- if (!token_attrs[i]) +- continue; +- if (strcmp(token_attrs[i]->name, attr->attr.name) == 0) +- return i/2; +- } +- dev_dbg(dev, "couldn't match: %s\n", attr->attr.name); +- return -EINVAL; +-} +- +-static ssize_t location_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- int i; +- +- if (!capable(CAP_SYS_ADMIN)) +- return -EPERM; +- +- i = match_attribute(dev, attr); +- if (i > 0) +- return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].location); +- return 0; +-} +- +-static ssize_t value_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- int i; +- +- if (!capable(CAP_SYS_ADMIN)) +- return -EPERM; +- +- i = match_attribute(dev, attr); +- if (i > 0) +- return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].value); +- return 0; +-} +- +-static struct attribute_group smbios_attribute_group = { +- .name = "tokens" +-}; +- +-static struct platform_driver platform_driver = { +- .driver = { +- .name = "dell-smbios", +- }, +-}; +- +-static int build_tokens_sysfs(struct platform_device *dev) +-{ +- char *location_name; +- char *value_name; +- size_t size; +- int ret; +- int i, j; +- +- /* (number of tokens + 1 for null terminated */ +- size = sizeof(struct device_attribute) * (da_num_tokens + 1); +- token_location_attrs = kzalloc(size, GFP_KERNEL); +- if (!token_location_attrs) +- return -ENOMEM; +- token_value_attrs = kzalloc(size, GFP_KERNEL); +- if (!token_value_attrs) +- goto out_allocate_value; +- +- /* need to store both location and value + terminator*/ +- size = sizeof(struct attribute *) * ((2 * da_num_tokens) + 1); +- token_attrs = kzalloc(size, GFP_KERNEL); +- if (!token_attrs) +- goto out_allocate_attrs; +- +- for (i = 0, j = 0; i < da_num_tokens; i++) { +- /* skip empty */ +- if (da_tokens[i].tokenID == 0) +- continue; +- /* add location */ +- location_name = kasprintf(GFP_KERNEL, "%04x_location", +- da_tokens[i].tokenID); +- if (location_name == NULL) +- goto out_unwind_strings; +- sysfs_attr_init(&token_location_attrs[i].attr); +- token_location_attrs[i].attr.name = location_name; +- token_location_attrs[i].attr.mode = 0444; +- token_location_attrs[i].show = location_show; +- token_attrs[j++] = &token_location_attrs[i].attr; +- +- /* add value */ +- value_name = kasprintf(GFP_KERNEL, "%04x_value", +- da_tokens[i].tokenID); +- if (value_name == NULL) +- goto loop_fail_create_value; +- sysfs_attr_init(&token_value_attrs[i].attr); +- token_value_attrs[i].attr.name = value_name; +- token_value_attrs[i].attr.mode = 0444; +- token_value_attrs[i].show = value_show; +- token_attrs[j++] = &token_value_attrs[i].attr; +- continue; +- +-loop_fail_create_value: +- kfree(value_name); +- goto out_unwind_strings; +- } +- smbios_attribute_group.attrs = token_attrs; +- +- ret = sysfs_create_group(&dev->dev.kobj, &smbios_attribute_group); +- if (ret) +- goto out_unwind_strings; +- return 0; +- +-out_unwind_strings: +- for (i = i-1; i > 0; i--) { +- kfree(token_location_attrs[i].attr.name); +- kfree(token_value_attrs[i].attr.name); +- } +- kfree(token_attrs); +-out_allocate_attrs: +- kfree(token_value_attrs); +-out_allocate_value: +- kfree(token_location_attrs); +- +- return -ENOMEM; +-} +- +-static void free_group(struct platform_device *pdev) +-{ +- int i; +- +- sysfs_remove_group(&pdev->dev.kobj, +- &smbios_attribute_group); +- for (i = 0; i < da_num_tokens; i++) { +- kfree(token_location_attrs[i].attr.name); +- kfree(token_value_attrs[i].attr.name); +- } +- kfree(token_attrs); +- kfree(token_value_attrs); +- kfree(token_location_attrs); +-} +- +-static int __init dell_smbios_init(void) +-{ +- const struct dmi_device *valid; +- int ret; +- +- valid = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL); +- if (!valid) { +- pr_err("Unable to run on non-Dell system\n"); +- return -ENODEV; +- } +- +- dmi_walk(find_tokens, NULL); +- +- if (!da_tokens) { +- pr_info("Unable to find dmi tokens\n"); +- return -ENODEV; +- } +- +- ret = platform_driver_register(&platform_driver); +- if (ret) +- goto fail_platform_driver; +- +- platform_device = platform_device_alloc("dell-smbios", 0); +- if (!platform_device) { +- ret = -ENOMEM; +- goto fail_platform_device_alloc; +- } +- ret = platform_device_add(platform_device); +- if (ret) +- goto fail_platform_device_add; +- +- /* duplicate tokens will cause problems building sysfs files */ +- zero_duplicates(&platform_device->dev); +- +- ret = build_tokens_sysfs(platform_device); +- if (ret) +- goto fail_create_group; +- +- return 0; +- +-fail_create_group: +- platform_device_del(platform_device); +- +-fail_platform_device_add: +- platform_device_put(platform_device); +- +-fail_platform_device_alloc: +- platform_driver_unregister(&platform_driver); +- +-fail_platform_driver: +- kfree(da_tokens); +- return ret; +-} +- +-static void __exit dell_smbios_exit(void) +-{ +- mutex_lock(&smbios_mutex); +- if (platform_device) { +- free_group(platform_device); +- platform_device_unregister(platform_device); +- platform_driver_unregister(&platform_driver); +- } +- kfree(da_tokens); +- mutex_unlock(&smbios_mutex); +-} +- +-subsys_initcall(dell_smbios_init); +-module_exit(dell_smbios_exit); +- +-MODULE_AUTHOR("Matthew Garrett "); +-MODULE_AUTHOR("Gabriele Mazzotta "); +-MODULE_AUTHOR("Pali Rohár "); +-MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h +index 138d478..d8adaf9 100644 +--- a/drivers/platform/x86/dell-smbios.h ++++ b/drivers/platform/x86/dell-smbios.h +@@ -75,4 +75,29 @@ int dell_laptop_register_notifier(struct notifier_block *nb); + int dell_laptop_unregister_notifier(struct notifier_block *nb); + void dell_laptop_call_notifier(unsigned long action, void *data); + +-#endif ++/* for the supported backends */ ++#ifdef CONFIG_DELL_SMBIOS_WMI ++int init_dell_smbios_wmi(void); ++void exit_dell_smbios_wmi(void); ++#else /* CONFIG_DELL_SMBIOS_WMI */ ++static inline int init_dell_smbios_wmi(void) ++{ ++ return -ENODEV; ++} ++static inline void exit_dell_smbios_wmi(void) ++{} ++#endif /* CONFIG_DELL_SMBIOS_WMI */ ++ ++#ifdef CONFIG_DELL_SMBIOS_SMM ++int init_dell_smbios_smm(void); ++void exit_dell_smbios_smm(void); ++#else /* CONFIG_DELL_SMBIOS_SMM */ ++static inline int init_dell_smbios_smm(void) ++{ ++ return -ENODEV; ++} ++static inline void exit_dell_smbios_smm(void) ++{} ++#endif /* CONFIG_DELL_SMBIOS_SMM */ ++ ++#endif /* _DELL_SMBIOS_H_ */ +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index dd4708c..1fc0c08 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -4310,7 +4310,7 @@ static int _regulator_resume_early(struct device *dev, void *data) + + rstate = regulator_get_suspend_state(rdev, *state); + if (rstate == NULL) +- return -EINVAL; ++ return 0; + + mutex_lock(&rdev->mutex); + +diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c +index 72c8b3e..e0a9c44 100644 +--- a/drivers/regulator/stm32-vrefbuf.c ++++ b/drivers/regulator/stm32-vrefbuf.c +@@ -51,7 +51,7 @@ static int stm32_vrefbuf_enable(struct regulator_dev *rdev) + * arbitrary timeout. + */ + ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val, +- !(val & STM32_VRR), 650, 10000); ++ val & STM32_VRR, 650, 10000); + if (ret) { + dev_err(&rdev->dev, "stm32 vrefbuf timed out!\n"); + val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); +diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c +index a7c15f0..ecef8e7 100644 +--- a/drivers/s390/block/dasd.c ++++ b/drivers/s390/block/dasd.c +@@ -2581,8 +2581,6 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr) + case DASD_CQR_QUEUED: + /* request was not started - just set to cleared */ + cqr->status = DASD_CQR_CLEARED; +- if (cqr->callback_data == DASD_SLEEPON_START_TAG) +- cqr->callback_data = DASD_SLEEPON_END_TAG; + break; + case DASD_CQR_IN_IO: + /* request in IO - terminate IO and release again */ +@@ -3902,9 +3900,12 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device) + wait_event(dasd_flush_wq, + (cqr->status != DASD_CQR_CLEAR_PENDING)); + +- /* mark sleepon requests as ended */ +- if (cqr->callback_data == DASD_SLEEPON_START_TAG) +- cqr->callback_data = DASD_SLEEPON_END_TAG; ++ /* ++ * requeue requests to blocklayer will only work ++ * for block device requests ++ */ ++ if (_dasd_requeue_request(cqr)) ++ continue; + + /* remove requests from device and block queue */ + list_del_init(&cqr->devlist); +@@ -3917,13 +3918,6 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device) + cqr = refers; + } + +- /* +- * requeue requests to blocklayer will only work +- * for block device requests +- */ +- if (_dasd_requeue_request(cqr)) +- continue; +- + if (cqr->block) + list_del_init(&cqr->blocklist); + cqr->block->base->discipline->free_cp( +@@ -3940,8 +3934,7 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device) + list_splice_tail(&requeue_queue, &device->ccw_queue); + spin_unlock_irq(get_ccwdev_lock(device->cdev)); + } +- /* wake up generic waitqueue for eventually ended sleepon requests */ +- wake_up(&generic_waitq); ++ dasd_schedule_device_bh(device); + return rc; + } + +diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c +index 1319122..9169af7 100644 +--- a/drivers/s390/cio/device_fsm.c ++++ b/drivers/s390/cio/device_fsm.c +@@ -795,6 +795,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) + + ccw_device_set_timeout(cdev, 0); + cdev->private->iretry = 255; ++ cdev->private->async_kill_io_rc = -ETIMEDOUT; + ret = ccw_device_cancel_halt_clear(cdev); + if (ret == -EBUSY) { + ccw_device_set_timeout(cdev, 3*HZ); +@@ -871,7 +872,7 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) + /* OK, i/o is dead now. Call interrupt handler. */ + if (cdev->handler) + cdev->handler(cdev, cdev->private->intparm, +- ERR_PTR(-EIO)); ++ ERR_PTR(cdev->private->async_kill_io_rc)); + } + + static void +@@ -888,14 +889,16 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event) + ccw_device_online_verify(cdev, 0); + if (cdev->handler) + cdev->handler(cdev, cdev->private->intparm, +- ERR_PTR(-EIO)); ++ ERR_PTR(cdev->private->async_kill_io_rc)); + } + + void ccw_device_kill_io(struct ccw_device *cdev) + { + int ret; + ++ ccw_device_set_timeout(cdev, 0); + cdev->private->iretry = 255; ++ cdev->private->async_kill_io_rc = -EIO; + ret = ccw_device_cancel_halt_clear(cdev); + if (ret == -EBUSY) { + ccw_device_set_timeout(cdev, 3*HZ); +diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c +index 1caf6a3..75ce12a 100644 +--- a/drivers/s390/cio/device_ops.c ++++ b/drivers/s390/cio/device_ops.c +@@ -159,7 +159,7 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) + } + + /** +- * ccw_device_start_key() - start a s390 channel program with key ++ * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to +@@ -170,10 +170,15 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) + * @key: storage key to be used for the I/O + * @flags: additional flags; defines the action to be performed for I/O + * processing. ++ * @expires: timeout value in jiffies + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). ++ * This function notifies the device driver if the channel program has not ++ * completed during the time specified by @expires. If a timeout occurs, the ++ * channel program is terminated via xsch, hsch or csch, and the device's ++ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; +@@ -182,9 +187,9 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) + * Context: + * Interrupts disabled, ccw device lock held + */ +-int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, +- unsigned long intparm, __u8 lpm, __u8 key, +- unsigned long flags) ++int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, ++ unsigned long intparm, __u8 lpm, __u8 key, ++ unsigned long flags, int expires) + { + struct subchannel *sch; + int ret; +@@ -224,6 +229,8 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + switch (ret) { + case 0: + cdev->private->intparm = intparm; ++ if (expires) ++ ccw_device_set_timeout(cdev, expires); + break; + case -EACCES: + case -ENODEV: +@@ -234,7 +241,7 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + } + + /** +- * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key ++ * ccw_device_start_key() - start a s390 channel program with key + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to +@@ -245,15 +252,10 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + * @key: storage key to be used for the I/O + * @flags: additional flags; defines the action to be performed for I/O + * processing. +- * @expires: timeout value in jiffies + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). +- * This function notifies the device driver if the channel program has not +- * completed during the time specified by @expires. If a timeout occurs, the +- * channel program is terminated via xsch, hsch or csch, and the device's +- * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; +@@ -262,19 +264,12 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + * Context: + * Interrupts disabled, ccw device lock held + */ +-int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, +- unsigned long intparm, __u8 lpm, __u8 key, +- unsigned long flags, int expires) ++int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, ++ unsigned long intparm, __u8 lpm, __u8 key, ++ unsigned long flags) + { +- int ret; +- +- if (!cdev) +- return -ENODEV; +- ccw_device_set_timeout(cdev, expires); +- ret = ccw_device_start_key(cdev, cpa, intparm, lpm, key, flags); +- if (ret != 0) +- ccw_device_set_timeout(cdev, 0); +- return ret; ++ return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm, key, ++ flags, 0); + } + + /** +@@ -489,18 +484,20 @@ void ccw_device_get_id(struct ccw_device *cdev, struct ccw_dev_id *dev_id) + EXPORT_SYMBOL(ccw_device_get_id); + + /** +- * ccw_device_tm_start_key() - perform start function ++ * ccw_device_tm_start_timeout_key() - perform start function + * @cdev: ccw device on which to perform the start function + * @tcw: transport-command word to be started + * @intparm: user defined parameter to be passed to the interrupt handler + * @lpm: mask of paths to use + * @key: storage key to use for storage access ++ * @expires: time span in jiffies after which to abort request + * + * Start the tcw on the given ccw device. Return zero on success, non-zero + * otherwise. + */ +-int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, +- unsigned long intparm, u8 lpm, u8 key) ++int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw, ++ unsigned long intparm, u8 lpm, u8 key, ++ int expires) + { + struct subchannel *sch; + int rc; +@@ -527,37 +524,32 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, + return -EACCES; + } + rc = cio_tm_start_key(sch, tcw, lpm, key); +- if (rc == 0) ++ if (rc == 0) { + cdev->private->intparm = intparm; ++ if (expires) ++ ccw_device_set_timeout(cdev, expires); ++ } + return rc; + } +-EXPORT_SYMBOL(ccw_device_tm_start_key); ++EXPORT_SYMBOL(ccw_device_tm_start_timeout_key); + + /** +- * ccw_device_tm_start_timeout_key() - perform start function ++ * ccw_device_tm_start_key() - perform start function + * @cdev: ccw device on which to perform the start function + * @tcw: transport-command word to be started + * @intparm: user defined parameter to be passed to the interrupt handler + * @lpm: mask of paths to use + * @key: storage key to use for storage access +- * @expires: time span in jiffies after which to abort request + * + * Start the tcw on the given ccw device. Return zero on success, non-zero + * otherwise. + */ +-int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw, +- unsigned long intparm, u8 lpm, u8 key, +- int expires) ++int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, ++ unsigned long intparm, u8 lpm, u8 key) + { +- int ret; +- +- ccw_device_set_timeout(cdev, expires); +- ret = ccw_device_tm_start_key(cdev, tcw, intparm, lpm, key); +- if (ret != 0) +- ccw_device_set_timeout(cdev, 0); +- return ret; ++ return ccw_device_tm_start_timeout_key(cdev, tcw, intparm, lpm, key, 0); + } +-EXPORT_SYMBOL(ccw_device_tm_start_timeout_key); ++EXPORT_SYMBOL(ccw_device_tm_start_key); + + /** + * ccw_device_tm_start() - perform start function +diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h +index af571d8..90e4e3a 100644 +--- a/drivers/s390/cio/io_sch.h ++++ b/drivers/s390/cio/io_sch.h +@@ -157,6 +157,7 @@ struct ccw_device_private { + unsigned long intparm; /* user interruption parameter */ + struct qdio_irq *qdio_data; + struct irb irb; /* device status */ ++ int async_kill_io_rc; + struct senseid senseid; /* SenseID info */ + struct pgid pgid[8]; /* path group IDs per chpid*/ + struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */ +diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c +index ca72f33..c8b308c 100644 +--- a/drivers/s390/net/qeth_core_main.c ++++ b/drivers/s390/net/qeth_core_main.c +@@ -2134,24 +2134,25 @@ int qeth_send_control_data(struct qeth_card *card, int len, + } + reply->callback = reply_cb; + reply->param = reply_param; +- if (card->state == CARD_STATE_DOWN) +- reply->seqno = QETH_IDX_COMMAND_SEQNO; +- else +- reply->seqno = card->seqno.ipa++; ++ + init_waitqueue_head(&reply->wait_q); +- spin_lock_irqsave(&card->lock, flags); +- list_add_tail(&reply->list, &card->cmd_waiter_list); +- spin_unlock_irqrestore(&card->lock, flags); + + while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ; +- qeth_prepare_control_data(card, len, iob); + + if (IS_IPA(iob->data)) { + cmd = __ipa_cmd(iob); ++ cmd->hdr.seqno = card->seqno.ipa++; ++ reply->seqno = cmd->hdr.seqno; + event_timeout = QETH_IPA_TIMEOUT; + } else { ++ reply->seqno = QETH_IDX_COMMAND_SEQNO; + event_timeout = QETH_TIMEOUT; + } ++ qeth_prepare_control_data(card, len, iob); ++ ++ spin_lock_irqsave(&card->lock, flags); ++ list_add_tail(&reply->list, &card->cmd_waiter_list); ++ spin_unlock_irqrestore(&card->lock, flags); + + timeout = jiffies + event_timeout; + +@@ -2933,7 +2934,7 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card, + memset(cmd, 0, sizeof(struct qeth_ipa_cmd)); + cmd->hdr.command = command; + cmd->hdr.initiator = IPA_CMD_INITIATOR_HOST; +- cmd->hdr.seqno = card->seqno.ipa; ++ /* cmd->hdr.seqno is set by qeth_send_control_data() */ + cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type); + cmd->hdr.rel_adapter_no = (__u8) card->info.portno; + if (card->options.layer2) +@@ -3898,10 +3899,12 @@ EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags); + int qeth_get_elements_no(struct qeth_card *card, + struct sk_buff *skb, int extra_elems, int data_offset) + { +- int elements = qeth_get_elements_for_range( +- (addr_t)skb->data + data_offset, +- (addr_t)skb->data + skb_headlen(skb)) + +- qeth_get_elements_for_frags(skb); ++ addr_t end = (addr_t)skb->data + skb_headlen(skb); ++ int elements = qeth_get_elements_for_frags(skb); ++ addr_t start = (addr_t)skb->data + data_offset; ++ ++ if (start != end) ++ elements += qeth_get_elements_for_range(start, end); + + if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { + QETH_DBF_MESSAGE(2, "Invalid size of IP packet " +diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h +index bdd45f4..498fe9a 100644 +--- a/drivers/s390/net/qeth_l3.h ++++ b/drivers/s390/net/qeth_l3.h +@@ -40,8 +40,40 @@ struct qeth_ipaddr { + unsigned int pfxlen; + } a6; + } u; +- + }; ++ ++static inline bool qeth_l3_addr_match_ip(struct qeth_ipaddr *a1, ++ struct qeth_ipaddr *a2) ++{ ++ if (a1->proto != a2->proto) ++ return false; ++ if (a1->proto == QETH_PROT_IPV6) ++ return ipv6_addr_equal(&a1->u.a6.addr, &a2->u.a6.addr); ++ return a1->u.a4.addr == a2->u.a4.addr; ++} ++ ++static inline bool qeth_l3_addr_match_all(struct qeth_ipaddr *a1, ++ struct qeth_ipaddr *a2) ++{ ++ /* Assumes that the pair was obtained via qeth_l3_addr_find_by_ip(), ++ * so 'proto' and 'addr' match for sure. ++ * ++ * For ucast: ++ * - 'mac' is always 0. ++ * - 'mask'/'pfxlen' for RXIP/VIPA is always 0. For NORMAL, matching ++ * values are required to avoid mixups in takeover eligibility. ++ * ++ * For mcast, ++ * - 'mac' is mapped from the IP, and thus always matches. ++ * - 'mask'/'pfxlen' is always 0. ++ */ ++ if (a1->type != a2->type) ++ return false; ++ if (a1->proto == QETH_PROT_IPV6) ++ return a1->u.a6.pfxlen == a2->u.a6.pfxlen; ++ return a1->u.a4.mask == a2->u.a4.mask; ++} ++ + static inline u64 qeth_l3_ipaddr_hash(struct qeth_ipaddr *addr) + { + u64 ret = 0; +diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c +index b0c888e8..962a04b 100644 +--- a/drivers/s390/net/qeth_l3_main.c ++++ b/drivers/s390/net/qeth_l3_main.c +@@ -67,6 +67,24 @@ void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr, + qeth_l3_ipaddr6_to_string(addr, buf); + } + ++static struct qeth_ipaddr *qeth_l3_find_addr_by_ip(struct qeth_card *card, ++ struct qeth_ipaddr *query) ++{ ++ u64 key = qeth_l3_ipaddr_hash(query); ++ struct qeth_ipaddr *addr; ++ ++ if (query->is_multicast) { ++ hash_for_each_possible(card->ip_mc_htable, addr, hnode, key) ++ if (qeth_l3_addr_match_ip(addr, query)) ++ return addr; ++ } else { ++ hash_for_each_possible(card->ip_htable, addr, hnode, key) ++ if (qeth_l3_addr_match_ip(addr, query)) ++ return addr; ++ } ++ return NULL; ++} ++ + static void qeth_l3_convert_addr_to_bits(u8 *addr, u8 *bits, int len) + { + int i, j; +@@ -120,34 +138,6 @@ static bool qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card, + return rc; + } + +-inline int +-qeth_l3_ipaddrs_is_equal(struct qeth_ipaddr *addr1, struct qeth_ipaddr *addr2) +-{ +- return addr1->proto == addr2->proto && +- !memcmp(&addr1->u, &addr2->u, sizeof(addr1->u)) && +- ether_addr_equal_64bits(addr1->mac, addr2->mac); +-} +- +-static struct qeth_ipaddr * +-qeth_l3_ip_from_hash(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) +-{ +- struct qeth_ipaddr *addr; +- +- if (tmp_addr->is_multicast) { +- hash_for_each_possible(card->ip_mc_htable, addr, +- hnode, qeth_l3_ipaddr_hash(tmp_addr)) +- if (qeth_l3_ipaddrs_is_equal(tmp_addr, addr)) +- return addr; +- } else { +- hash_for_each_possible(card->ip_htable, addr, +- hnode, qeth_l3_ipaddr_hash(tmp_addr)) +- if (qeth_l3_ipaddrs_is_equal(tmp_addr, addr)) +- return addr; +- } +- +- return NULL; +-} +- + int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) + { + int rc = 0; +@@ -162,23 +152,18 @@ int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) + QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8); + } + +- addr = qeth_l3_ip_from_hash(card, tmp_addr); +- if (!addr) ++ addr = qeth_l3_find_addr_by_ip(card, tmp_addr); ++ if (!addr || !qeth_l3_addr_match_all(addr, tmp_addr)) + return -ENOENT; + + addr->ref_counter--; +- if (addr->ref_counter > 0 && (addr->type == QETH_IP_TYPE_NORMAL || +- addr->type == QETH_IP_TYPE_RXIP)) ++ if (addr->type == QETH_IP_TYPE_NORMAL && addr->ref_counter > 0) + return rc; + if (addr->in_progress) + return -EINPROGRESS; + +- if (!qeth_card_hw_is_reachable(card)) { +- addr->disp_flag = QETH_DISP_ADDR_DELETE; +- return 0; +- } +- +- rc = qeth_l3_deregister_addr_entry(card, addr); ++ if (qeth_card_hw_is_reachable(card)) ++ rc = qeth_l3_deregister_addr_entry(card, addr); + + hash_del(&addr->hnode); + kfree(addr); +@@ -190,6 +175,7 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) + { + int rc = 0; + struct qeth_ipaddr *addr; ++ char buf[40]; + + QETH_CARD_TEXT(card, 4, "addip"); + +@@ -200,8 +186,20 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) + QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8); + } + +- addr = qeth_l3_ip_from_hash(card, tmp_addr); +- if (!addr) { ++ addr = qeth_l3_find_addr_by_ip(card, tmp_addr); ++ if (addr) { ++ if (tmp_addr->type != QETH_IP_TYPE_NORMAL) ++ return -EADDRINUSE; ++ if (qeth_l3_addr_match_all(addr, tmp_addr)) { ++ addr->ref_counter++; ++ return 0; ++ } ++ qeth_l3_ipaddr_to_string(tmp_addr->proto, (u8 *)&tmp_addr->u, ++ buf); ++ dev_warn(&card->gdev->dev, ++ "Registering IP address %s failed\n", buf); ++ return -EADDRINUSE; ++ } else { + addr = qeth_l3_get_addr_buffer(tmp_addr->proto); + if (!addr) + return -ENOMEM; +@@ -241,19 +239,15 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) + (rc == IPA_RC_LAN_OFFLINE)) { + addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING; + if (addr->ref_counter < 1) { +- qeth_l3_delete_ip(card, addr); ++ qeth_l3_deregister_addr_entry(card, addr); ++ hash_del(&addr->hnode); + kfree(addr); + } + } else { + hash_del(&addr->hnode); + kfree(addr); + } +- } else { +- if (addr->type == QETH_IP_TYPE_NORMAL || +- addr->type == QETH_IP_TYPE_RXIP) +- addr->ref_counter++; + } +- + return rc; + } + +@@ -321,11 +315,7 @@ static void qeth_l3_recover_ip(struct qeth_card *card) + spin_lock_bh(&card->ip_lock); + + hash_for_each_safe(card->ip_htable, i, tmp, addr, hnode) { +- if (addr->disp_flag == QETH_DISP_ADDR_DELETE) { +- qeth_l3_deregister_addr_entry(card, addr); +- hash_del(&addr->hnode); +- kfree(addr); +- } else if (addr->disp_flag == QETH_DISP_ADDR_ADD) { ++ if (addr->disp_flag == QETH_DISP_ADDR_ADD) { + if (addr->proto == QETH_PROT_IPV4) { + addr->in_progress = 1; + spin_unlock_bh(&card->ip_lock); +@@ -643,12 +633,7 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto, + return -ENOMEM; + + spin_lock_bh(&card->ip_lock); +- +- if (qeth_l3_ip_from_hash(card, ipaddr)) +- rc = -EEXIST; +- else +- rc = qeth_l3_add_ip(card, ipaddr); +- ++ rc = qeth_l3_add_ip(card, ipaddr); + spin_unlock_bh(&card->ip_lock); + + kfree(ipaddr); +@@ -713,12 +698,7 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto, + return -ENOMEM; + + spin_lock_bh(&card->ip_lock); +- +- if (qeth_l3_ip_from_hash(card, ipaddr)) +- rc = -EEXIST; +- else +- rc = qeth_l3_add_ip(card, ipaddr); +- ++ rc = qeth_l3_add_ip(card, ipaddr); + spin_unlock_bh(&card->ip_lock); + + kfree(ipaddr); +@@ -1239,8 +1219,9 @@ qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev) + tmp->u.a4.addr = be32_to_cpu(im4->multiaddr); + tmp->is_multicast = 1; + +- ipm = qeth_l3_ip_from_hash(card, tmp); ++ ipm = qeth_l3_find_addr_by_ip(card, tmp); + if (ipm) { ++ /* for mcast, by-IP match means full match */ + ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING; + } else { + ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4); +@@ -1319,8 +1300,9 @@ static void qeth_l3_add_mc6_to_hash(struct qeth_card *card, + sizeof(struct in6_addr)); + tmp->is_multicast = 1; + +- ipm = qeth_l3_ip_from_hash(card, tmp); ++ ipm = qeth_l3_find_addr_by_ip(card, tmp); + if (ipm) { ++ /* for mcast, by-IP match means full match */ + ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING; + continue; + } +@@ -2450,11 +2432,12 @@ static void qeth_tso_fill_header(struct qeth_card *card, + static int qeth_l3_get_elements_no_tso(struct qeth_card *card, + struct sk_buff *skb, int extra_elems) + { +- addr_t tcpdptr = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb); +- int elements = qeth_get_elements_for_range( +- tcpdptr, +- (addr_t)skb->data + skb_headlen(skb)) + +- qeth_get_elements_for_frags(skb); ++ addr_t start = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb); ++ addr_t end = (addr_t)skb->data + skb_headlen(skb); ++ int elements = qeth_get_elements_for_frags(skb); ++ ++ if (start != end) ++ elements += qeth_get_elements_for_range(start, end); + + if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { + QETH_DBF_MESSAGE(2, +diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c +index 57bf43e..dd94649 100644 +--- a/drivers/scsi/hosts.c ++++ b/drivers/scsi/hosts.c +@@ -328,8 +328,6 @@ static void scsi_host_dev_release(struct device *dev) + if (shost->work_q) + destroy_workqueue(shost->work_q); + +- destroy_rcu_head(&shost->rcu); +- + if (shost->shost_state == SHOST_CREATED) { + /* + * Free the shost_dev device name here if scsi_host_alloc() +@@ -404,7 +402,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) + INIT_LIST_HEAD(&shost->starved_list); + init_waitqueue_head(&shost->host_wait); + mutex_init(&shost->scan_mutex); +- init_rcu_head(&shost->rcu); + + index = ida_simple_get(&host_index_ida, 0, 0, GFP_KERNEL); + if (index < 0) +diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c +index 073ced0..dc8e850 100644 +--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c ++++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c +@@ -216,36 +216,30 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance, + /** + * megasas_fire_cmd_fusion - Sends command to the FW + * @instance: Adapter soft state +- * @req_desc: 32bit or 64bit Request descriptor ++ * @req_desc: 64bit Request descriptor + * +- * Perform PCI Write. Ventura supports 32 bit Descriptor. +- * Prior to Ventura (12G) MR controller supports 64 bit Descriptor. ++ * Perform PCI Write. + */ + + static void + megasas_fire_cmd_fusion(struct megasas_instance *instance, + union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc) + { +- if (instance->adapter_type == VENTURA_SERIES) +- writel(le32_to_cpu(req_desc->u.low), +- &instance->reg_set->inbound_single_queue_port); +- else { + #if defined(writeq) && defined(CONFIG_64BIT) +- u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) | +- le32_to_cpu(req_desc->u.low)); ++ u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) | ++ le32_to_cpu(req_desc->u.low)); + +- writeq(req_data, &instance->reg_set->inbound_low_queue_port); ++ writeq(req_data, &instance->reg_set->inbound_low_queue_port); + #else +- unsigned long flags; +- spin_lock_irqsave(&instance->hba_lock, flags); +- writel(le32_to_cpu(req_desc->u.low), +- &instance->reg_set->inbound_low_queue_port); +- writel(le32_to_cpu(req_desc->u.high), +- &instance->reg_set->inbound_high_queue_port); +- mmiowb(); +- spin_unlock_irqrestore(&instance->hba_lock, flags); ++ unsigned long flags; ++ spin_lock_irqsave(&instance->hba_lock, flags); ++ writel(le32_to_cpu(req_desc->u.low), ++ &instance->reg_set->inbound_low_queue_port); ++ writel(le32_to_cpu(req_desc->u.high), ++ &instance->reg_set->inbound_high_queue_port); ++ mmiowb(); ++ spin_unlock_irqrestore(&instance->hba_lock, flags); + #endif +- } + } + + /** +@@ -982,7 +976,6 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) + const char *sys_info; + MFI_CAPABILITIES *drv_ops; + u32 scratch_pad_2; +- unsigned long flags; + ktime_t time; + bool cur_fw_64bit_dma_capable; + +@@ -1121,14 +1114,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) + break; + } + +- /* For Ventura also IOC INIT required 64 bit Descriptor write. */ +- spin_lock_irqsave(&instance->hba_lock, flags); +- writel(le32_to_cpu(req_desc.u.low), +- &instance->reg_set->inbound_low_queue_port); +- writel(le32_to_cpu(req_desc.u.high), +- &instance->reg_set->inbound_high_queue_port); +- mmiowb(); +- spin_unlock_irqrestore(&instance->hba_lock, flags); ++ megasas_fire_cmd_fusion(instance, &req_desc); + + wait_and_poll(instance, cmd, MFI_POLL_TIMEOUT_SECS); + +diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c +index 59a87ca..0aafbfd 100644 +--- a/drivers/scsi/mpt3sas/mpt3sas_base.c ++++ b/drivers/scsi/mpt3sas/mpt3sas_base.c +@@ -6297,14 +6297,14 @@ _base_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase) + } + + /** +- * _wait_for_commands_to_complete - reset controller ++ * mpt3sas_wait_for_commands_to_complete - reset controller + * @ioc: Pointer to MPT_ADAPTER structure + * + * This function is waiting 10s for all pending commands to complete + * prior to putting controller in reset. + */ +-static void +-_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc) ++void ++mpt3sas_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc) + { + u32 ioc_state; + +@@ -6377,7 +6377,7 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, + is_fault = 1; + } + _base_reset_handler(ioc, MPT3_IOC_PRE_RESET); +- _wait_for_commands_to_complete(ioc); ++ mpt3sas_wait_for_commands_to_complete(ioc); + _base_mask_interrupts(ioc); + r = _base_make_ioc_ready(ioc, type); + if (r) +diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h +index 789bc42..99ccf83 100644 +--- a/drivers/scsi/mpt3sas/mpt3sas_base.h ++++ b/drivers/scsi/mpt3sas/mpt3sas_base.h +@@ -1433,6 +1433,9 @@ void mpt3sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc, + + int mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc); + ++void ++mpt3sas_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc); ++ + + /* scsih shared API */ + struct scsi_cmnd *mpt3sas_scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc, +diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c +index 74fca18..c2ea13c7 100644 +--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c ++++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c +@@ -2835,7 +2835,8 @@ scsih_abort(struct scsi_cmnd *scmd) + _scsih_tm_display_info(ioc, scmd); + + sas_device_priv_data = scmd->device->hostdata; +- if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { ++ if (!sas_device_priv_data || !sas_device_priv_data->sas_target || ++ ioc->remove_host) { + sdev_printk(KERN_INFO, scmd->device, + "device been deleted! scmd(%p)\n", scmd); + scmd->result = DID_NO_CONNECT << 16; +@@ -2898,7 +2899,8 @@ scsih_dev_reset(struct scsi_cmnd *scmd) + _scsih_tm_display_info(ioc, scmd); + + sas_device_priv_data = scmd->device->hostdata; +- if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { ++ if (!sas_device_priv_data || !sas_device_priv_data->sas_target || ++ ioc->remove_host) { + sdev_printk(KERN_INFO, scmd->device, + "device been deleted! scmd(%p)\n", scmd); + scmd->result = DID_NO_CONNECT << 16; +@@ -2961,7 +2963,8 @@ scsih_target_reset(struct scsi_cmnd *scmd) + _scsih_tm_display_info(ioc, scmd); + + sas_device_priv_data = scmd->device->hostdata; +- if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { ++ if (!sas_device_priv_data || !sas_device_priv_data->sas_target || ++ ioc->remove_host) { + starget_printk(KERN_INFO, starget, "target been deleted! scmd(%p)\n", + scmd); + scmd->result = DID_NO_CONNECT << 16; +@@ -3019,7 +3022,7 @@ scsih_host_reset(struct scsi_cmnd *scmd) + ioc->name, scmd); + scsi_print_command(scmd); + +- if (ioc->is_driver_loading) { ++ if (ioc->is_driver_loading || ioc->remove_host) { + pr_info(MPT3SAS_FMT "Blocking the host reset\n", + ioc->name); + r = FAILED; +@@ -4453,7 +4456,7 @@ _scsih_flush_running_cmds(struct MPT3SAS_ADAPTER *ioc) + st = scsi_cmd_priv(scmd); + mpt3sas_base_clear_st(ioc, st); + scsi_dma_unmap(scmd); +- if (ioc->pci_error_recovery) ++ if (ioc->pci_error_recovery || ioc->remove_host) + scmd->result = DID_NO_CONNECT << 16; + else + scmd->result = DID_RESET << 16; +@@ -9739,6 +9742,10 @@ static void scsih_remove(struct pci_dev *pdev) + unsigned long flags; + + ioc->remove_host = 1; ++ ++ mpt3sas_wait_for_commands_to_complete(ioc); ++ _scsih_flush_running_cmds(ioc); ++ + _scsih_fw_event_cleanup_queue(ioc); + + spin_lock_irqsave(&ioc->fw_event_lock, flags); +@@ -9815,6 +9822,10 @@ scsih_shutdown(struct pci_dev *pdev) + unsigned long flags; + + ioc->remove_host = 1; ++ ++ mpt3sas_wait_for_commands_to_complete(ioc); ++ _scsih_flush_running_cmds(ioc); ++ + _scsih_fw_event_cleanup_queue(ioc); + + spin_lock_irqsave(&ioc->fw_event_lock, flags); +diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c +index 667d769..d09afe1 100644 +--- a/drivers/scsi/qedi/qedi_fw.c ++++ b/drivers/scsi/qedi/qedi_fw.c +@@ -762,6 +762,11 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi, + + iscsi_cid = cqe->conn_id; + qedi_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid]; ++ if (!qedi_conn) { ++ QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, ++ "icid not found 0x%x\n", cqe->conn_id); ++ return; ++ } + + /* Based on this itt get the corresponding qedi_cmd */ + spin_lock_bh(&qedi_conn->tmf_work_lock); +diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h +index be7d682..c9689f9 100644 +--- a/drivers/scsi/qla2xxx/qla_def.h ++++ b/drivers/scsi/qla2xxx/qla_def.h +@@ -261,9 +261,9 @@ + struct name_list_extended { + struct get_name_list_extended *l; + dma_addr_t ldma; +- struct list_head fcports; /* protect by sess_list */ ++ struct list_head fcports; ++ spinlock_t fcports_lock; + u32 size; +- u8 sent; + }; + /* + * Timeout timer counts in seconds +@@ -2217,6 +2217,7 @@ typedef struct { + + /* FCP-4 types */ + #define FC4_TYPE_FCP_SCSI 0x08 ++#define FC4_TYPE_NVME 0x28 + #define FC4_TYPE_OTHER 0x0 + #define FC4_TYPE_UNKNOWN 0xff + +diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c +index 5bf9a59..403fa09 100644 +--- a/drivers/scsi/qla2xxx/qla_gs.c ++++ b/drivers/scsi/qla2xxx/qla_gs.c +@@ -3179,6 +3179,7 @@ int qla24xx_async_gidpn(scsi_qla_host_t *vha, fc_port_t *fcport) + sp->free(sp); + fcport->flags &= ~FCF_ASYNC_SENT; + done: ++ fcport->flags &= ~FCF_ASYNC_ACTIVE; + return rval; + } + +@@ -3370,6 +3371,7 @@ int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_t *fcport) + sp->free(sp); + fcport->flags &= ~FCF_ASYNC_SENT; + done: ++ fcport->flags &= ~FCF_ASYNC_ACTIVE; + return rval; + } + +@@ -3971,6 +3973,9 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) + spin_lock_irqsave(&vha->work_lock, flags); + vha->scan.scan_flags &= ~SF_SCANNING; + spin_unlock_irqrestore(&vha->work_lock, flags); ++ ++ if ((fc4type == FC4_TYPE_FCP_SCSI) && vha->flags.nvme_enabled) ++ qla24xx_async_gpnft(vha, FC4_TYPE_NVME); + } + + static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) +diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c +index 2dea112..00329dd 100644 +--- a/drivers/scsi/qla2xxx/qla_init.c ++++ b/drivers/scsi/qla2xxx/qla_init.c +@@ -213,6 +213,7 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, + sp->free(sp); + fcport->flags &= ~FCF_ASYNC_SENT; + done: ++ fcport->flags &= ~FCF_ASYNC_ACTIVE; + return rval; + } + +@@ -263,7 +264,7 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) + done_free_sp: + sp->free(sp); + done: +- fcport->flags &= ~FCF_ASYNC_SENT; ++ fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); + return rval; + } + +@@ -271,6 +272,7 @@ void + qla2x00_async_prlo_done(struct scsi_qla_host *vha, fc_port_t *fcport, + uint16_t *data) + { ++ fcport->flags &= ~FCF_ASYNC_ACTIVE; + /* Don't re-login in target mode */ + if (!fcport->tgt_session) + qla2x00_mark_device_lost(vha, fcport, 1, 0); +@@ -284,6 +286,7 @@ qla2x00_async_prlo_sp_done(void *s, int res) + struct srb_iocb *lio = &sp->u.iocb_cmd; + struct scsi_qla_host *vha = sp->vha; + ++ sp->fcport->flags &= ~FCF_ASYNC_ACTIVE; + if (!test_bit(UNLOADING, &vha->dpc_flags)) + qla2x00_post_async_prlo_done_work(sp->fcport->vha, sp->fcport, + lio->u.logio.data); +@@ -322,6 +325,7 @@ qla2x00_async_prlo(struct scsi_qla_host *vha, fc_port_t *fcport) + done_free_sp: + sp->free(sp); + done: ++ fcport->flags &= ~FCF_ASYNC_ACTIVE; + return rval; + } + +@@ -375,6 +379,8 @@ qla2x00_async_adisc_sp_done(void *ptr, int res) + "Async done-%s res %x %8phC\n", + sp->name, res, sp->fcport->port_name); + ++ sp->fcport->flags &= ~FCF_ASYNC_SENT; ++ + memset(&ea, 0, sizeof(ea)); + ea.event = FCME_ADISC_DONE; + ea.rc = res; +@@ -425,7 +431,7 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, + done_free_sp: + sp->free(sp); + done: +- fcport->flags &= ~FCF_ASYNC_SENT; ++ fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); + qla2x00_post_async_adisc_work(vha, fcport, data); + return rval; + } +@@ -643,8 +649,7 @@ qla24xx_async_gnl_sp_done(void *s, int res) + (loop_id & 0x7fff)); + } + +- spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); +- vha->gnl.sent = 0; ++ spin_lock_irqsave(&vha->gnl.fcports_lock, flags); + + INIT_LIST_HEAD(&h); + fcport = tf = NULL; +@@ -653,12 +658,16 @@ qla24xx_async_gnl_sp_done(void *s, int res) + + list_for_each_entry_safe(fcport, tf, &h, gnl_entry) { + list_del_init(&fcport->gnl_entry); ++ spin_lock(&vha->hw->tgt.sess_lock); + fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); ++ spin_unlock(&vha->hw->tgt.sess_lock); + ea.fcport = fcport; + + qla2x00_fcport_event_handler(vha, &ea); + } ++ spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags); + ++ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); + /* create new fcport if fw has knowledge of new sessions */ + for (i = 0; i < n; i++) { + port_id_t id; +@@ -710,18 +719,21 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport) + ql_dbg(ql_dbg_disc, vha, 0x20d9, + "Async-gnlist WWPN %8phC \n", fcport->port_name); + +- spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); ++ spin_lock_irqsave(&vha->gnl.fcports_lock, flags); ++ if (!list_empty(&fcport->gnl_entry)) { ++ spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags); ++ rval = QLA_SUCCESS; ++ goto done; ++ } ++ ++ spin_lock(&vha->hw->tgt.sess_lock); + fcport->disc_state = DSC_GNL; + fcport->last_rscn_gen = fcport->rscn_gen; + fcport->last_login_gen = fcport->login_gen; ++ spin_unlock(&vha->hw->tgt.sess_lock); + + list_add_tail(&fcport->gnl_entry, &vha->gnl.fcports); +- if (vha->gnl.sent) { +- spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); +- return QLA_SUCCESS; +- } +- vha->gnl.sent = 1; +- spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); ++ spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags); + + sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); + if (!sp) +@@ -1049,6 +1061,7 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) + fc_port_t *fcport = ea->fcport; + struct port_database_24xx *pd; + struct srb *sp = ea->sp; ++ uint8_t ls; + + pd = (struct port_database_24xx *)sp->u.iocb_cmd.u.mbx.in; + +@@ -1061,7 +1074,12 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) + if (fcport->disc_state == DSC_DELETE_PEND) + return; + +- switch (pd->current_login_state) { ++ if (fcport->fc4f_nvme) ++ ls = pd->current_login_state >> 4; ++ else ++ ls = pd->current_login_state & 0xf; ++ ++ switch (ls) { + case PDS_PRLI_COMPLETE: + __qla24xx_parse_gpdb(vha, fcport, pd); + break; +@@ -1151,8 +1169,9 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) + if (fcport->scan_state != QLA_FCPORT_FOUND) + return 0; + +- if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) || +- (fcport->fw_login_state == DSC_LS_PRLI_PEND)) ++ if ((fcport->loop_id != FC_NO_LOOP_ID) && ++ ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) || ++ (fcport->fw_login_state == DSC_LS_PRLI_PEND))) + return 0; + + if (fcport->fw_login_state == DSC_LS_PLOGI_COMP) { +@@ -1527,6 +1546,7 @@ qla24xx_abort_sp_done(void *ptr, int res) + srb_t *sp = ptr; + struct srb_iocb *abt = &sp->u.iocb_cmd; + ++ del_timer(&sp->u.iocb_cmd.timer); + complete(&abt->u.abt.comp); + } + +@@ -1791,6 +1811,7 @@ qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport, + qla2x00_mark_device_lost(vha, fcport, 1, 0); + qlt_logo_completion_handler(fcport, data[0]); + fcport->login_gen++; ++ fcport->flags &= ~FCF_ASYNC_ACTIVE; + return; + } + +@@ -1798,6 +1819,7 @@ void + qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, + uint16_t *data) + { ++ fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); + if (data[0] == MBS_COMMAND_COMPLETE) { + qla2x00_update_fcport(vha, fcport); + +@@ -1805,7 +1827,6 @@ qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, + } + + /* Retry login. */ +- fcport->flags &= ~FCF_ASYNC_SENT; + if (data[1] & QLA_LOGIO_LOGIN_RETRIED) + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + else +diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c +index afcb5567..285911e 100644 +--- a/drivers/scsi/qla2xxx/qla_os.c ++++ b/drivers/scsi/qla2xxx/qla_os.c +@@ -4577,6 +4577,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, + + spin_lock_init(&vha->work_lock); + spin_lock_init(&vha->cmd_list_lock); ++ spin_lock_init(&vha->gnl.fcports_lock); + init_waitqueue_head(&vha->fcport_waitQ); + init_waitqueue_head(&vha->vref_waitq); + +@@ -4806,9 +4807,12 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) + fcport->d_id = e->u.new_sess.id; + fcport->flags |= FCF_FABRIC_DEVICE; + fcport->fw_login_state = DSC_LS_PLOGI_PEND; +- if (e->u.new_sess.fc4_type == FC4_TYPE_FCP_SCSI) ++ if (e->u.new_sess.fc4_type == FC4_TYPE_FCP_SCSI) { + fcport->fc4_type = FC4_TYPE_FCP_SCSI; +- ++ } else if (e->u.new_sess.fc4_type == FC4_TYPE_NVME) { ++ fcport->fc4_type = FC4_TYPE_OTHER; ++ fcport->fc4f_nvme = FC4_TYPE_NVME; ++ } + memcpy(fcport->port_name, e->u.new_sess.port_name, + WWN_SIZE); + } else { +@@ -4877,6 +4881,8 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) + } + qlt_plogi_ack_unref(vha, pla); + } else { ++ fc_port_t *dfcp = NULL; ++ + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); + tfcp = qla2x00_find_fcport_by_nportid(vha, + &e->u.new_sess.id, 1); +@@ -4899,11 +4905,13 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) + default: + fcport->login_pause = 1; + tfcp->conflict = fcport; +- qlt_schedule_sess_for_deletion(tfcp); ++ dfcp = tfcp; + break; + } + } + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); ++ if (dfcp) ++ qlt_schedule_sess_for_deletion(tfcp); + + wwn = wwn_to_u64(fcport->node_name); + +diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c +index 896b2d8..b49ac85 100644 +--- a/drivers/scsi/qla2xxx/qla_target.c ++++ b/drivers/scsi/qla2xxx/qla_target.c +@@ -1224,10 +1224,10 @@ static void qla24xx_chk_fcp_state(struct fc_port *sess) + } + } + +-/* ha->tgt.sess_lock supposed to be held on entry */ + void qlt_schedule_sess_for_deletion(struct fc_port *sess) + { + struct qla_tgt *tgt = sess->tgt; ++ struct qla_hw_data *ha = sess->vha->hw; + unsigned long flags; + + if (sess->disc_state == DSC_DELETE_PEND) +@@ -1244,16 +1244,16 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess) + return; + } + ++ spin_lock_irqsave(&ha->tgt.sess_lock, flags); + if (sess->deleted == QLA_SESS_DELETED) + sess->logout_on_delete = 0; + +- spin_lock_irqsave(&sess->vha->work_lock, flags); + if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) { +- spin_unlock_irqrestore(&sess->vha->work_lock, flags); ++ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + return; + } + sess->deleted = QLA_SESS_DELETION_IN_PROGRESS; +- spin_unlock_irqrestore(&sess->vha->work_lock, flags); ++ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + + sess->disc_state = DSC_DELETE_PEND; + +@@ -1262,13 +1262,10 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess) + ql_dbg(ql_dbg_tgt, sess->vha, 0xe001, + "Scheduling sess %p for deletion\n", sess); + +- /* use cancel to push work element through before re-queue */ +- cancel_work_sync(&sess->del_work); + INIT_WORK(&sess->del_work, qla24xx_delete_sess_fn); +- queue_work(sess->vha->hw->wq, &sess->del_work); ++ WARN_ON(!queue_work(sess->vha->hw->wq, &sess->del_work)); + } + +-/* ha->tgt.sess_lock supposed to be held on entry */ + static void qlt_clear_tgt_db(struct qla_tgt *tgt) + { + struct fc_port *sess; +@@ -1451,8 +1448,8 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen) + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf008, "qla_tgt_fc_port_deleted %p", sess); + + sess->local = 1; +- qlt_schedule_sess_for_deletion(sess); + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); ++ qlt_schedule_sess_for_deletion(sess); + } + + static inline int test_tgt_sess_count(struct qla_tgt *tgt) +@@ -1512,10 +1509,8 @@ int qlt_stop_phase1(struct qla_tgt *tgt) + * Lock is needed, because we still can get an incoming packet. + */ + mutex_lock(&vha->vha_tgt.tgt_mutex); +- spin_lock_irqsave(&ha->tgt.sess_lock, flags); + tgt->tgt_stop = 1; + qlt_clear_tgt_db(tgt); +- spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + mutex_unlock(&vha->vha_tgt.tgt_mutex); + mutex_unlock(&qla_tgt_mutex); + +diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c +index d042915..ca53a5f 100644 +--- a/drivers/scsi/scsi_error.c ++++ b/drivers/scsi/scsi_error.c +@@ -223,7 +223,8 @@ static void scsi_eh_reset(struct scsi_cmnd *scmd) + + static void scsi_eh_inc_host_failed(struct rcu_head *head) + { +- struct Scsi_Host *shost = container_of(head, typeof(*shost), rcu); ++ struct scsi_cmnd *scmd = container_of(head, typeof(*scmd), rcu); ++ struct Scsi_Host *shost = scmd->device->host; + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); +@@ -259,7 +260,7 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd) + * Ensure that all tasks observe the host state change before the + * host_failed change. + */ +- call_rcu(&shost->rcu, scsi_eh_inc_host_failed); ++ call_rcu(&scmd->rcu, scsi_eh_inc_host_failed); + } + + /** +diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c +index a86df9c..c84f931 100644 +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -671,6 +671,7 @@ static bool scsi_end_request(struct request *req, blk_status_t error, + if (!blk_rq_is_scsi(req)) { + WARN_ON_ONCE(!(cmd->flags & SCMD_INITIALIZED)); + cmd->flags &= ~SCMD_INITIALIZED; ++ destroy_rcu_head(&cmd->rcu); + } + + if (req->mq_ctx) { +@@ -720,6 +721,8 @@ static blk_status_t __scsi_error_from_host_byte(struct scsi_cmnd *cmd, + int result) + { + switch (host_byte(result)) { ++ case DID_OK: ++ return BLK_STS_OK; + case DID_TRANSPORT_FAILFAST: + return BLK_STS_TRANSPORT; + case DID_TARGET_FAILURE: +@@ -1151,6 +1154,7 @@ static void scsi_initialize_rq(struct request *rq) + struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); + + scsi_req_init(&cmd->req); ++ init_rcu_head(&cmd->rcu); + cmd->jiffies_at_alloc = jiffies; + cmd->retries = 0; + } +diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c +index 6be5ab3..8c51d62 100644 +--- a/drivers/scsi/storvsc_drv.c ++++ b/drivers/scsi/storvsc_drv.c +@@ -1311,7 +1311,8 @@ static int storvsc_do_io(struct hv_device *device, + */ + cpumask_and(&alloced_mask, &stor_device->alloced_cpus, + cpumask_of_node(cpu_to_node(q_num))); +- for_each_cpu(tgt_cpu, &alloced_mask) { ++ for_each_cpu_wrap(tgt_cpu, &alloced_mask, ++ outgoing_channel->target_cpu + 1) { + if (tgt_cpu != outgoing_channel->target_cpu) { + outgoing_channel = + stor_device->stor_chns[tgt_cpu]; +diff --git a/drivers/video/fbdev/sbuslib.c b/drivers/video/fbdev/sbuslib.c +index af6fc97..a436d44 100644 +--- a/drivers/video/fbdev/sbuslib.c ++++ b/drivers/video/fbdev/sbuslib.c +@@ -122,7 +122,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, + unsigned char __user *ured; + unsigned char __user *ugreen; + unsigned char __user *ublue; +- int index, count, i; ++ unsigned int index, count, i; + + if (get_user(index, &c->index) || + __get_user(count, &c->count) || +@@ -161,7 +161,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, + unsigned char __user *ugreen; + unsigned char __user *ublue; + struct fb_cmap *cmap = &info->cmap; +- int index, count, i; ++ unsigned int index, count, i; + u8 red, green, blue; + + if (get_user(index, &c->index) || +diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c +index eb30f3e..71458f4 100644 +--- a/drivers/virtio/virtio_ring.c ++++ b/drivers/virtio/virtio_ring.c +@@ -428,8 +428,6 @@ static inline int virtqueue_add(struct virtqueue *_vq, + i = virtio16_to_cpu(_vq->vdev, vq->vring.desc[i].next); + } + +- vq->vq.num_free += total_sg; +- + if (indirect) + kfree(desc); + +diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c +index e0678c1..3a33c53 100644 +--- a/drivers/watchdog/f71808e_wdt.c ++++ b/drivers/watchdog/f71808e_wdt.c +@@ -566,7 +566,8 @@ static ssize_t watchdog_write(struct file *file, const char __user *buf, + char c; + if (get_user(c, buf + i)) + return -EFAULT; +- expect_close = (c == 'V'); ++ if (c == 'V') ++ expect_close = true; + } + + /* Properly order writes across fork()ed processes */ +diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c +index f1f00df..b0a1580 100644 +--- a/drivers/watchdog/hpwdt.c ++++ b/drivers/watchdog/hpwdt.c +@@ -28,16 +28,7 @@ + #include + #include + #include +-#ifdef CONFIG_HPWDT_NMI_DECODING +-#include +-#include +-#include +-#include +-#include +-#include +-#endif /* CONFIG_HPWDT_NMI_DECODING */ + #include +-#include + + #define HPWDT_VERSION "1.4.0" + #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) +@@ -48,6 +39,9 @@ + static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */ + static unsigned int reload; /* the computed soft_margin */ + static bool nowayout = WATCHDOG_NOWAYOUT; ++#ifdef CONFIG_HPWDT_NMI_DECODING ++static unsigned int allow_kdump = 1; ++#endif + static char expect_release; + static unsigned long hpwdt_is_open; + +@@ -63,373 +57,6 @@ static const struct pci_device_id hpwdt_devices[] = { + }; + MODULE_DEVICE_TABLE(pci, hpwdt_devices); + +-#ifdef CONFIG_HPWDT_NMI_DECODING +-#define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */ +-#define CRU_BIOS_SIGNATURE_VALUE 0x55524324 +-#define PCI_BIOS32_PARAGRAPH_LEN 16 +-#define PCI_ROM_BASE1 0x000F0000 +-#define ROM_SIZE 0x10000 +- +-struct bios32_service_dir { +- u32 signature; +- u32 entry_point; +- u8 revision; +- u8 length; +- u8 checksum; +- u8 reserved[5]; +-}; +- +-/* type 212 */ +-struct smbios_cru64_info { +- u8 type; +- u8 byte_length; +- u16 handle; +- u32 signature; +- u64 physical_address; +- u32 double_length; +- u32 double_offset; +-}; +-#define SMBIOS_CRU64_INFORMATION 212 +- +-/* type 219 */ +-struct smbios_proliant_info { +- u8 type; +- u8 byte_length; +- u16 handle; +- u32 power_features; +- u32 omega_features; +- u32 reserved; +- u32 misc_features; +-}; +-#define SMBIOS_ICRU_INFORMATION 219 +- +- +-struct cmn_registers { +- union { +- struct { +- u8 ral; +- u8 rah; +- u16 rea2; +- }; +- u32 reax; +- } u1; +- union { +- struct { +- u8 rbl; +- u8 rbh; +- u8 reb2l; +- u8 reb2h; +- }; +- u32 rebx; +- } u2; +- union { +- struct { +- u8 rcl; +- u8 rch; +- u16 rec2; +- }; +- u32 recx; +- } u3; +- union { +- struct { +- u8 rdl; +- u8 rdh; +- u16 red2; +- }; +- u32 redx; +- } u4; +- +- u32 resi; +- u32 redi; +- u16 rds; +- u16 res; +- u32 reflags; +-} __attribute__((packed)); +- +-static unsigned int hpwdt_nmi_decoding; +-static unsigned int allow_kdump = 1; +-static unsigned int is_icru; +-static unsigned int is_uefi; +-static DEFINE_SPINLOCK(rom_lock); +-static void *cru_rom_addr; +-static struct cmn_registers cmn_regs; +- +-extern asmlinkage void asminline_call(struct cmn_registers *pi86Regs, +- unsigned long *pRomEntry); +- +-#ifdef CONFIG_X86_32 +-/* --32 Bit Bios------------------------------------------------------------ */ +- +-#define HPWDT_ARCH 32 +- +-asm(".text \n\t" +- ".align 4 \n\t" +- ".globl asminline_call \n" +- "asminline_call: \n\t" +- "pushl %ebp \n\t" +- "movl %esp, %ebp \n\t" +- "pusha \n\t" +- "pushf \n\t" +- "push %es \n\t" +- "push %ds \n\t" +- "pop %es \n\t" +- "movl 8(%ebp),%eax \n\t" +- "movl 4(%eax),%ebx \n\t" +- "movl 8(%eax),%ecx \n\t" +- "movl 12(%eax),%edx \n\t" +- "movl 16(%eax),%esi \n\t" +- "movl 20(%eax),%edi \n\t" +- "movl (%eax),%eax \n\t" +- "push %cs \n\t" +- "call *12(%ebp) \n\t" +- "pushf \n\t" +- "pushl %eax \n\t" +- "movl 8(%ebp),%eax \n\t" +- "movl %ebx,4(%eax) \n\t" +- "movl %ecx,8(%eax) \n\t" +- "movl %edx,12(%eax) \n\t" +- "movl %esi,16(%eax) \n\t" +- "movl %edi,20(%eax) \n\t" +- "movw %ds,24(%eax) \n\t" +- "movw %es,26(%eax) \n\t" +- "popl %ebx \n\t" +- "movl %ebx,(%eax) \n\t" +- "popl %ebx \n\t" +- "movl %ebx,28(%eax) \n\t" +- "pop %es \n\t" +- "popf \n\t" +- "popa \n\t" +- "leave \n\t" +- "ret \n\t" +- ".previous"); +- +- +-/* +- * cru_detect +- * +- * Routine Description: +- * This function uses the 32-bit BIOS Service Directory record to +- * search for a $CRU record. +- * +- * Return Value: +- * 0 : SUCCESS +- * <0 : FAILURE +- */ +-static int cru_detect(unsigned long map_entry, +- unsigned long map_offset) +-{ +- void *bios32_map; +- unsigned long *bios32_entrypoint; +- unsigned long cru_physical_address; +- unsigned long cru_length; +- unsigned long physical_bios_base = 0; +- unsigned long physical_bios_offset = 0; +- int retval = -ENODEV; +- +- bios32_map = ioremap(map_entry, (2 * PAGE_SIZE)); +- +- if (bios32_map == NULL) +- return -ENODEV; +- +- bios32_entrypoint = bios32_map + map_offset; +- +- cmn_regs.u1.reax = CRU_BIOS_SIGNATURE_VALUE; +- +- set_memory_x((unsigned long)bios32_map, 2); +- asminline_call(&cmn_regs, bios32_entrypoint); +- +- if (cmn_regs.u1.ral != 0) { +- pr_warn("Call succeeded but with an error: 0x%x\n", +- cmn_regs.u1.ral); +- } else { +- physical_bios_base = cmn_regs.u2.rebx; +- physical_bios_offset = cmn_regs.u4.redx; +- cru_length = cmn_regs.u3.recx; +- cru_physical_address = +- physical_bios_base + physical_bios_offset; +- +- /* If the values look OK, then map it in. */ +- if ((physical_bios_base + physical_bios_offset)) { +- cru_rom_addr = +- ioremap(cru_physical_address, cru_length); +- if (cru_rom_addr) { +- set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK, +- (cru_length + PAGE_SIZE - 1) >> PAGE_SHIFT); +- retval = 0; +- } +- } +- +- pr_debug("CRU Base Address: 0x%lx\n", physical_bios_base); +- pr_debug("CRU Offset Address: 0x%lx\n", physical_bios_offset); +- pr_debug("CRU Length: 0x%lx\n", cru_length); +- pr_debug("CRU Mapped Address: %p\n", &cru_rom_addr); +- } +- iounmap(bios32_map); +- return retval; +-} +- +-/* +- * bios_checksum +- */ +-static int bios_checksum(const char __iomem *ptr, int len) +-{ +- char sum = 0; +- int i; +- +- /* +- * calculate checksum of size bytes. This should add up +- * to zero if we have a valid header. +- */ +- for (i = 0; i < len; i++) +- sum += ptr[i]; +- +- return ((sum == 0) && (len > 0)); +-} +- +-/* +- * bios32_present +- * +- * Routine Description: +- * This function finds the 32-bit BIOS Service Directory +- * +- * Return Value: +- * 0 : SUCCESS +- * <0 : FAILURE +- */ +-static int bios32_present(const char __iomem *p) +-{ +- struct bios32_service_dir *bios_32_ptr; +- int length; +- unsigned long map_entry, map_offset; +- +- bios_32_ptr = (struct bios32_service_dir *) p; +- +- /* +- * Search for signature by checking equal to the swizzled value +- * instead of calling another routine to perform a strcmp. +- */ +- if (bios_32_ptr->signature == PCI_BIOS32_SD_VALUE) { +- length = bios_32_ptr->length * PCI_BIOS32_PARAGRAPH_LEN; +- if (bios_checksum(p, length)) { +- /* +- * According to the spec, we're looking for the +- * first 4KB-aligned address below the entrypoint +- * listed in the header. The Service Directory code +- * is guaranteed to occupy no more than 2 4KB pages. +- */ +- map_entry = bios_32_ptr->entry_point & ~(PAGE_SIZE - 1); +- map_offset = bios_32_ptr->entry_point - map_entry; +- +- return cru_detect(map_entry, map_offset); +- } +- } +- return -ENODEV; +-} +- +-static int detect_cru_service(void) +-{ +- char __iomem *p, *q; +- int rc = -1; +- +- /* +- * Search from 0x0f0000 through 0x0fffff, inclusive. +- */ +- p = ioremap(PCI_ROM_BASE1, ROM_SIZE); +- if (p == NULL) +- return -ENOMEM; +- +- for (q = p; q < p + ROM_SIZE; q += 16) { +- rc = bios32_present(q); +- if (!rc) +- break; +- } +- iounmap(p); +- return rc; +-} +-/* ------------------------------------------------------------------------- */ +-#endif /* CONFIG_X86_32 */ +-#ifdef CONFIG_X86_64 +-/* --64 Bit Bios------------------------------------------------------------ */ +- +-#define HPWDT_ARCH 64 +- +-asm(".text \n\t" +- ".align 4 \n\t" +- ".globl asminline_call \n\t" +- ".type asminline_call, @function \n\t" +- "asminline_call: \n\t" +- FRAME_BEGIN +- "pushq %rax \n\t" +- "pushq %rbx \n\t" +- "pushq %rdx \n\t" +- "pushq %r12 \n\t" +- "pushq %r9 \n\t" +- "movq %rsi, %r12 \n\t" +- "movq %rdi, %r9 \n\t" +- "movl 4(%r9),%ebx \n\t" +- "movl 8(%r9),%ecx \n\t" +- "movl 12(%r9),%edx \n\t" +- "movl 16(%r9),%esi \n\t" +- "movl 20(%r9),%edi \n\t" +- "movl (%r9),%eax \n\t" +- "call *%r12 \n\t" +- "pushfq \n\t" +- "popq %r12 \n\t" +- "movl %eax, (%r9) \n\t" +- "movl %ebx, 4(%r9) \n\t" +- "movl %ecx, 8(%r9) \n\t" +- "movl %edx, 12(%r9) \n\t" +- "movl %esi, 16(%r9) \n\t" +- "movl %edi, 20(%r9) \n\t" +- "movq %r12, %rax \n\t" +- "movl %eax, 28(%r9) \n\t" +- "popq %r9 \n\t" +- "popq %r12 \n\t" +- "popq %rdx \n\t" +- "popq %rbx \n\t" +- "popq %rax \n\t" +- FRAME_END +- "ret \n\t" +- ".previous"); +- +-/* +- * dmi_find_cru +- * +- * Routine Description: +- * This function checks whether or not a SMBIOS/DMI record is +- * the 64bit CRU info or not +- */ +-static void dmi_find_cru(const struct dmi_header *dm, void *dummy) +-{ +- struct smbios_cru64_info *smbios_cru64_ptr; +- unsigned long cru_physical_address; +- +- if (dm->type == SMBIOS_CRU64_INFORMATION) { +- smbios_cru64_ptr = (struct smbios_cru64_info *) dm; +- if (smbios_cru64_ptr->signature == CRU_BIOS_SIGNATURE_VALUE) { +- cru_physical_address = +- smbios_cru64_ptr->physical_address + +- smbios_cru64_ptr->double_offset; +- cru_rom_addr = ioremap(cru_physical_address, +- smbios_cru64_ptr->double_length); +- set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK, +- smbios_cru64_ptr->double_length >> PAGE_SHIFT); +- } +- } +-} +- +-static int detect_cru_service(void) +-{ +- cru_rom_addr = NULL; +- +- dmi_walk(dmi_find_cru, NULL); +- +- /* if cru_rom_addr has been set then we found a CRU service */ +- return ((cru_rom_addr != NULL) ? 0 : -ENODEV); +-} +-/* ------------------------------------------------------------------------- */ +-#endif /* CONFIG_X86_64 */ +-#endif /* CONFIG_HPWDT_NMI_DECODING */ + + /* + * Watchdog operations +@@ -486,30 +113,12 @@ static int hpwdt_my_nmi(void) + */ + static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) + { +- unsigned long rom_pl; +- static int die_nmi_called; +- +- if (!hpwdt_nmi_decoding) +- return NMI_DONE; +- + if ((ulReason == NMI_UNKNOWN) && !hpwdt_my_nmi()) + return NMI_DONE; + +- spin_lock_irqsave(&rom_lock, rom_pl); +- if (!die_nmi_called && !is_icru && !is_uefi) +- asminline_call(&cmn_regs, cru_rom_addr); +- die_nmi_called = 1; +- spin_unlock_irqrestore(&rom_lock, rom_pl); +- + if (allow_kdump) + hpwdt_stop(); + +- if (!is_icru && !is_uefi) { +- if (cmn_regs.u1.ral == 0) { +- nmi_panic(regs, "An NMI occurred, but unable to determine source.\n"); +- return NMI_HANDLED; +- } +- } + nmi_panic(regs, "An NMI occurred. Depending on your system the reason " + "for the NMI is logged in any one of the following " + "resources:\n" +@@ -675,84 +284,11 @@ static struct miscdevice hpwdt_miscdev = { + * Init & Exit + */ + +-#ifdef CONFIG_HPWDT_NMI_DECODING +-#ifdef CONFIG_X86_LOCAL_APIC +-static void hpwdt_check_nmi_decoding(struct pci_dev *dev) +-{ +- /* +- * If nmi_watchdog is turned off then we can turn on +- * our nmi decoding capability. +- */ +- hpwdt_nmi_decoding = 1; +-} +-#else +-static void hpwdt_check_nmi_decoding(struct pci_dev *dev) +-{ +- dev_warn(&dev->dev, "NMI decoding is disabled. " +- "Your kernel does not support a NMI Watchdog.\n"); +-} +-#endif /* CONFIG_X86_LOCAL_APIC */ +- +-/* +- * dmi_find_icru +- * +- * Routine Description: +- * This function checks whether or not we are on an iCRU-based server. +- * This check is independent of architecture and needs to be made for +- * any ProLiant system. +- */ +-static void dmi_find_icru(const struct dmi_header *dm, void *dummy) +-{ +- struct smbios_proliant_info *smbios_proliant_ptr; +- +- if (dm->type == SMBIOS_ICRU_INFORMATION) { +- smbios_proliant_ptr = (struct smbios_proliant_info *) dm; +- if (smbios_proliant_ptr->misc_features & 0x01) +- is_icru = 1; +- if (smbios_proliant_ptr->misc_features & 0x1400) +- is_uefi = 1; +- } +-} + + static int hpwdt_init_nmi_decoding(struct pci_dev *dev) + { ++#ifdef CONFIG_HPWDT_NMI_DECODING + int retval; +- +- /* +- * On typical CRU-based systems we need to map that service in +- * the BIOS. For 32 bit Operating Systems we need to go through +- * the 32 Bit BIOS Service Directory. For 64 bit Operating +- * Systems we get that service through SMBIOS. +- * +- * On systems that support the new iCRU service all we need to +- * do is call dmi_walk to get the supported flag value and skip +- * the old cru detect code. +- */ +- dmi_walk(dmi_find_icru, NULL); +- if (!is_icru && !is_uefi) { +- +- /* +- * We need to map the ROM to get the CRU service. +- * For 32 bit Operating Systems we need to go through the 32 Bit +- * BIOS Service Directory +- * For 64 bit Operating Systems we get that service through SMBIOS. +- */ +- retval = detect_cru_service(); +- if (retval < 0) { +- dev_warn(&dev->dev, +- "Unable to detect the %d Bit CRU Service.\n", +- HPWDT_ARCH); +- return retval; +- } +- +- /* +- * We know this is the only CRU call we need to make so lets keep as +- * few instructions as possible once the NMI comes in. +- */ +- cmn_regs.u1.rah = 0x0D; +- cmn_regs.u1.ral = 0x02; +- } +- + /* + * Only one function can register for NMI_UNKNOWN + */ +@@ -780,45 +316,26 @@ static int hpwdt_init_nmi_decoding(struct pci_dev *dev) + dev_warn(&dev->dev, + "Unable to register a die notifier (err=%d).\n", + retval); +- if (cru_rom_addr) +- iounmap(cru_rom_addr); + return retval; ++#endif /* CONFIG_HPWDT_NMI_DECODING */ ++ return 0; + } + + static void hpwdt_exit_nmi_decoding(void) + { ++#ifdef CONFIG_HPWDT_NMI_DECODING + unregister_nmi_handler(NMI_UNKNOWN, "hpwdt"); + unregister_nmi_handler(NMI_SERR, "hpwdt"); + unregister_nmi_handler(NMI_IO_CHECK, "hpwdt"); +- if (cru_rom_addr) +- iounmap(cru_rom_addr); +-} +-#else /* !CONFIG_HPWDT_NMI_DECODING */ +-static void hpwdt_check_nmi_decoding(struct pci_dev *dev) +-{ +-} +- +-static int hpwdt_init_nmi_decoding(struct pci_dev *dev) +-{ +- return 0; ++#endif + } + +-static void hpwdt_exit_nmi_decoding(void) +-{ +-} +-#endif /* CONFIG_HPWDT_NMI_DECODING */ +- + static int hpwdt_init_one(struct pci_dev *dev, + const struct pci_device_id *ent) + { + int retval; + + /* +- * Check if we can do NMI decoding or not +- */ +- hpwdt_check_nmi_decoding(dev); +- +- /* + * First let's find out if we are on an iLO2+ server. We will + * not run on a legacy ASM box. + * So we only support the G5 ProLiant servers and higher. +@@ -922,6 +439,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + #ifdef CONFIG_HPWDT_NMI_DECODING + module_param(allow_kdump, int, 0); + MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs"); +-#endif /* !CONFIG_HPWDT_NMI_DECODING */ ++#endif /* CONFIG_HPWDT_NMI_DECODING */ + + module_pci_driver(hpwdt_driver); +diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c +index 316c2eb..e8bd988 100644 +--- a/drivers/watchdog/sbsa_gwdt.c ++++ b/drivers/watchdog/sbsa_gwdt.c +@@ -50,6 +50,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -159,7 +160,7 @@ static unsigned int sbsa_gwdt_get_timeleft(struct watchdog_device *wdd) + !(readl(gwdt->control_base + SBSA_GWDT_WCS) & SBSA_GWDT_WCS_WS0)) + timeleft += readl(gwdt->control_base + SBSA_GWDT_WOR); + +- timeleft += readq(gwdt->control_base + SBSA_GWDT_WCV) - ++ timeleft += lo_hi_readq(gwdt->control_base + SBSA_GWDT_WCV) - + arch_counter_get_cntvct(); + + do_div(timeleft, gwdt->clk); +diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c +index 74888ca..ec9eb4f 100644 +--- a/drivers/xen/xenbus/xenbus_probe.c ++++ b/drivers/xen/xenbus/xenbus_probe.c +@@ -466,8 +466,11 @@ int xenbus_probe_node(struct xen_bus_type *bus, + + /* Register with generic device framework. */ + err = device_register(&xendev->dev); +- if (err) ++ if (err) { ++ put_device(&xendev->dev); ++ xendev = NULL; + goto fail; ++ } + + return 0; + fail: +diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c +index 86d6a44..51f940e 100644 +--- a/fs/gfs2/bmap.c ++++ b/fs/gfs2/bmap.c +@@ -807,9 +807,6 @@ int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, + iomap->length = hole_size(inode, lblock, &mp); + else + iomap->length = size - pos; +- } else { +- if (height <= ip->i_height) +- iomap->length = hole_size(inode, lblock, &mp); + } + goto out_release; + } +diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c +index 8c10b05..621c517 100644 +--- a/fs/nfs/direct.c ++++ b/fs/nfs/direct.c +@@ -86,10 +86,10 @@ struct nfs_direct_req { + struct nfs_direct_mirror mirrors[NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX]; + int mirror_count; + ++ loff_t io_start; /* Start offset for I/O */ + ssize_t count, /* bytes actually processed */ + max_count, /* max expected count */ + bytes_left, /* bytes left to be sent */ +- io_start, /* start of IO */ + error; /* any reported error */ + struct completion completion; /* wait for i/o completion */ + +diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c +index c13e826..ee723aa 100644 +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -292,8 +292,11 @@ pnfs_detach_layout_hdr(struct pnfs_layout_hdr *lo) + void + pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo) + { +- struct inode *inode = lo->plh_inode; ++ struct inode *inode; + ++ if (!lo) ++ return; ++ inode = lo->plh_inode; + pnfs_layoutreturn_before_put_layout_hdr(lo); + + if (refcount_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) { +@@ -1241,10 +1244,12 @@ bool pnfs_roc(struct inode *ino, + spin_lock(&ino->i_lock); + lo = nfsi->layout; + if (!lo || !pnfs_layout_is_valid(lo) || +- test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) ++ test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) { ++ lo = NULL; + goto out_noroc; ++ } ++ pnfs_get_layout_hdr(lo); + if (test_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) { +- pnfs_get_layout_hdr(lo); + spin_unlock(&ino->i_lock); + wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN, + TASK_UNINTERRUPTIBLE); +@@ -1312,10 +1317,12 @@ bool pnfs_roc(struct inode *ino, + struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld; + if (ld->prepare_layoutreturn) + ld->prepare_layoutreturn(args); ++ pnfs_put_layout_hdr(lo); + return true; + } + if (layoutreturn) + pnfs_send_layoutreturn(lo, &stateid, iomode, true); ++ pnfs_put_layout_hdr(lo); + return false; + } + +diff --git a/fs/nfs/write.c b/fs/nfs/write.c +index 7428a66..e7d8cea 100644 +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -1876,40 +1876,43 @@ int nfs_generic_commit_list(struct inode *inode, struct list_head *head, + return status; + } + +-int nfs_commit_inode(struct inode *inode, int how) ++static int __nfs_commit_inode(struct inode *inode, int how, ++ struct writeback_control *wbc) + { + LIST_HEAD(head); + struct nfs_commit_info cinfo; + int may_wait = how & FLUSH_SYNC; +- int error = 0; +- int res; ++ int ret, nscan; + + nfs_init_cinfo_from_inode(&cinfo, inode); + nfs_commit_begin(cinfo.mds); +- res = nfs_scan_commit(inode, &head, &cinfo); +- if (res) +- error = nfs_generic_commit_list(inode, &head, how, &cinfo); ++ for (;;) { ++ ret = nscan = nfs_scan_commit(inode, &head, &cinfo); ++ if (ret <= 0) ++ break; ++ ret = nfs_generic_commit_list(inode, &head, how, &cinfo); ++ if (ret < 0) ++ break; ++ ret = 0; ++ if (wbc && wbc->sync_mode == WB_SYNC_NONE) { ++ if (nscan < wbc->nr_to_write) ++ wbc->nr_to_write -= nscan; ++ else ++ wbc->nr_to_write = 0; ++ } ++ if (nscan < INT_MAX) ++ break; ++ cond_resched(); ++ } + nfs_commit_end(cinfo.mds); +- if (res == 0) +- return res; +- if (error < 0) +- goto out_error; +- if (!may_wait) +- goto out_mark_dirty; +- error = wait_on_commit(cinfo.mds); +- if (error < 0) +- return error; +- return res; +-out_error: +- res = error; +- /* Note: If we exit without ensuring that the commit is complete, +- * we must mark the inode as dirty. Otherwise, future calls to +- * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure +- * that the data is on the disk. +- */ +-out_mark_dirty: +- __mark_inode_dirty(inode, I_DIRTY_DATASYNC); +- return res; ++ if (ret || !may_wait) ++ return ret; ++ return wait_on_commit(cinfo.mds); ++} ++ ++int nfs_commit_inode(struct inode *inode, int how) ++{ ++ return __nfs_commit_inode(inode, how, NULL); + } + EXPORT_SYMBOL_GPL(nfs_commit_inode); + +@@ -1919,11 +1922,11 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) + int flags = FLUSH_SYNC; + int ret = 0; + +- /* no commits means nothing needs to be done */ +- if (!atomic_long_read(&nfsi->commit_info.ncommit)) +- return ret; +- + if (wbc->sync_mode == WB_SYNC_NONE) { ++ /* no commits means nothing needs to be done */ ++ if (!atomic_long_read(&nfsi->commit_info.ncommit)) ++ goto check_requests_outstanding; ++ + /* Don't commit yet if this is a non-blocking flush and there + * are a lot of outstanding writes for this mapping. + */ +@@ -1934,16 +1937,16 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) + flags = 0; + } + +- ret = nfs_commit_inode(inode, flags); +- if (ret >= 0) { +- if (wbc->sync_mode == WB_SYNC_NONE) { +- if (ret < wbc->nr_to_write) +- wbc->nr_to_write -= ret; +- else +- wbc->nr_to_write = 0; +- } +- return 0; +- } ++ ret = __nfs_commit_inode(inode, flags, wbc); ++ if (!ret) { ++ if (flags & FLUSH_SYNC) ++ return 0; ++ } else if (atomic_long_read(&nfsi->commit_info.ncommit)) ++ goto out_mark_dirty; ++ ++check_requests_outstanding: ++ if (!atomic_read(&nfsi->commit_info.rpcs_out)) ++ return ret; + out_mark_dirty: + __mark_inode_dirty(inode, I_DIRTY_DATASYNC); + return ret; +diff --git a/fs/overlayfs/Kconfig b/fs/overlayfs/Kconfig +index 406e72d..ce6ff5a 100644 +--- a/fs/overlayfs/Kconfig ++++ b/fs/overlayfs/Kconfig +@@ -24,6 +24,8 @@ config OVERLAY_FS_REDIRECT_DIR + an overlay which has redirects on a kernel that doesn't support this + feature will have unexpected results. + ++ If unsure, say N. ++ + config OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW + bool "Overlayfs: follow redirects even if redirects are turned off" + default y +@@ -32,8 +34,13 @@ config OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW + Disable this to get a possibly more secure configuration, but that + might not be backward compatible with previous kernels. + ++ If backward compatibility is not an issue, then it is safe and ++ recommended to say N here. ++ + For more information, see Documentation/filesystems/overlayfs.txt + ++ If unsure, say Y. ++ + config OVERLAY_FS_INDEX + bool "Overlayfs: turn on inodes index feature by default" + depends on OVERLAY_FS +@@ -51,6 +58,8 @@ config OVERLAY_FS_INDEX + That is, mounting an overlay which has an inodes index on a kernel + that doesn't support this feature will have unexpected results. + ++ If unsure, say N. ++ + config OVERLAY_FS_NFS_EXPORT + bool "Overlayfs: turn on NFS export feature by default" + depends on OVERLAY_FS +@@ -72,3 +81,8 @@ config OVERLAY_FS_NFS_EXPORT + Note, that the NFS export feature is not backward compatible. + That is, mounting an overlay which has a full index on a kernel + that doesn't support this feature will have unexpected results. ++ ++ Most users should say N here and enable this feature on a case-by- ++ case basis with the "nfs_export=on" mount option. ++ ++ Say N unless you fully understand the consequences. +diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c +index bb94ce9..87bd414 100644 +--- a/fs/overlayfs/export.c ++++ b/fs/overlayfs/export.c +@@ -19,6 +19,142 @@ + #include + #include "overlayfs.h" + ++static int ovl_encode_maybe_copy_up(struct dentry *dentry) ++{ ++ int err; ++ ++ if (ovl_dentry_upper(dentry)) ++ return 0; ++ ++ err = ovl_want_write(dentry); ++ if (!err) { ++ err = ovl_copy_up(dentry); ++ ovl_drop_write(dentry); ++ } ++ ++ if (err) { ++ pr_warn_ratelimited("overlayfs: failed to copy up on encode (%pd2, err=%i)\n", ++ dentry, err); ++ } ++ ++ return err; ++} ++ ++/* ++ * Before encoding a non-upper directory file handle from real layer N, we need ++ * to check if it will be possible to reconnect an overlay dentry from the real ++ * lower decoded dentry. This is done by following the overlay ancestry up to a ++ * "layer N connected" ancestor and verifying that all parents along the way are ++ * "layer N connectable". If an ancestor that is NOT "layer N connectable" is ++ * found, we need to copy up an ancestor, which is "layer N connectable", thus ++ * making that ancestor "layer N connected". For example: ++ * ++ * layer 1: /a ++ * layer 2: /a/b/c ++ * ++ * The overlay dentry /a is NOT "layer 2 connectable", because if dir /a is ++ * copied up and renamed, upper dir /a will be indexed by lower dir /a from ++ * layer 1. The dir /a from layer 2 will never be indexed, so the algorithm (*) ++ * in ovl_lookup_real_ancestor() will not be able to lookup a connected overlay ++ * dentry from the connected lower dentry /a/b/c. ++ * ++ * To avoid this problem on decode time, we need to copy up an ancestor of ++ * /a/b/c, which is "layer 2 connectable", on encode time. That ancestor is ++ * /a/b. After copy up (and index) of /a/b, it will become "layer 2 connected" ++ * and when the time comes to decode the file handle from lower dentry /a/b/c, ++ * ovl_lookup_real_ancestor() will find the indexed ancestor /a/b and decoding ++ * a connected overlay dentry will be accomplished. ++ * ++ * (*) the algorithm in ovl_lookup_real_ancestor() can be improved to lookup an ++ * entry /a in the lower layers above layer N and find the indexed dir /a from ++ * layer 1. If that improvement is made, then the check for "layer N connected" ++ * will need to verify there are no redirects in lower layers above N. In the ++ * example above, /a will be "layer 2 connectable". However, if layer 2 dir /a ++ * is a target of a layer 1 redirect, then /a will NOT be "layer 2 connectable": ++ * ++ * layer 1: /A (redirect = /a) ++ * layer 2: /a/b/c ++ */ ++ ++/* Return the lowest layer for encoding a connectable file handle */ ++static int ovl_connectable_layer(struct dentry *dentry) ++{ ++ struct ovl_entry *oe = OVL_E(dentry); ++ ++ /* We can get overlay root from root of any layer */ ++ if (dentry == dentry->d_sb->s_root) ++ return oe->numlower; ++ ++ /* ++ * If it's an unindexed merge dir, then it's not connectable with any ++ * lower layer ++ */ ++ if (ovl_dentry_upper(dentry) && ++ !ovl_test_flag(OVL_INDEX, d_inode(dentry))) ++ return 0; ++ ++ /* We can get upper/overlay path from indexed/lower dentry */ ++ return oe->lowerstack[0].layer->idx; ++} ++ ++/* ++ * @dentry is "connected" if all ancestors up to root or a "connected" ancestor ++ * have the same uppermost lower layer as the origin's layer. We may need to ++ * copy up a "connectable" ancestor to make it "connected". A "connected" dentry ++ * cannot become non "connected", so cache positive result in dentry flags. ++ * ++ * Return the connected origin layer or < 0 on error. ++ */ ++static int ovl_connect_layer(struct dentry *dentry) ++{ ++ struct dentry *next, *parent = NULL; ++ int origin_layer; ++ int err = 0; ++ ++ if (WARN_ON(dentry == dentry->d_sb->s_root) || ++ WARN_ON(!ovl_dentry_lower(dentry))) ++ return -EIO; ++ ++ origin_layer = OVL_E(dentry)->lowerstack[0].layer->idx; ++ if (ovl_dentry_test_flag(OVL_E_CONNECTED, dentry)) ++ return origin_layer; ++ ++ /* Find the topmost origin layer connectable ancestor of @dentry */ ++ next = dget(dentry); ++ for (;;) { ++ parent = dget_parent(next); ++ if (WARN_ON(parent == next)) { ++ err = -EIO; ++ break; ++ } ++ ++ /* ++ * If @parent is not origin layer connectable, then copy up ++ * @next which is origin layer connectable and we are done. ++ */ ++ if (ovl_connectable_layer(parent) < origin_layer) { ++ err = ovl_encode_maybe_copy_up(next); ++ break; ++ } ++ ++ /* If @parent is connected or indexed we are done */ ++ if (ovl_dentry_test_flag(OVL_E_CONNECTED, parent) || ++ ovl_test_flag(OVL_INDEX, d_inode(parent))) ++ break; ++ ++ dput(next); ++ next = parent; ++ } ++ ++ dput(parent); ++ dput(next); ++ ++ if (!err) ++ ovl_dentry_set_flag(OVL_E_CONNECTED, dentry); ++ ++ return err ?: origin_layer; ++} ++ + /* + * We only need to encode origin if there is a chance that the same object was + * encoded pre copy up and then we need to stay consistent with the same +@@ -41,73 +177,59 @@ + * L = lower file handle + * + * (*) Connecting an overlay dir from real lower dentry is not always +- * possible when there are redirects in lower layers. To mitigate this case, +- * we copy up the lower dir first and then encode an upper dir file handle. ++ * possible when there are redirects in lower layers and non-indexed merge dirs. ++ * To mitigate those case, we may copy up the lower dir ancestor before encode ++ * a lower dir file handle. ++ * ++ * Return 0 for upper file handle, > 0 for lower file handle or < 0 on error. + */ +-static bool ovl_should_encode_origin(struct dentry *dentry) ++static int ovl_check_encode_origin(struct dentry *dentry) + { + struct ovl_fs *ofs = dentry->d_sb->s_fs_info; + ++ /* Upper file handle for pure upper */ + if (!ovl_dentry_lower(dentry)) +- return false; ++ return 0; + + /* +- * Decoding a merge dir, whose origin's parent is under a redirected +- * lower dir is not always possible. As a simple aproximation, we do +- * not encode lower dir file handles when overlay has multiple lower +- * layers and origin is below the topmost lower layer. ++ * Upper file handle for non-indexed upper. + * +- * TODO: copy up only the parent that is under redirected lower. ++ * Root is never indexed, so if there's an upper layer, encode upper for ++ * root. + */ +- if (d_is_dir(dentry) && ofs->upper_mnt && +- OVL_E(dentry)->lowerstack[0].layer->idx > 1) +- return false; +- +- /* Decoding a non-indexed upper from origin is not implemented */ + if (ovl_dentry_upper(dentry) && + !ovl_test_flag(OVL_INDEX, d_inode(dentry))) +- return false; +- +- return true; +-} +- +-static int ovl_encode_maybe_copy_up(struct dentry *dentry) +-{ +- int err; +- +- if (ovl_dentry_upper(dentry)) + return 0; + +- err = ovl_want_write(dentry); +- if (err) +- return err; +- +- err = ovl_copy_up(dentry); ++ /* ++ * Decoding a merge dir, whose origin's ancestor is under a redirected ++ * lower dir or under a non-indexed upper is not always possible. ++ * ovl_connect_layer() will try to make origin's layer "connected" by ++ * copying up a "connectable" ancestor. ++ */ ++ if (d_is_dir(dentry) && ofs->upper_mnt) ++ return ovl_connect_layer(dentry); + +- ovl_drop_write(dentry); +- return err; ++ /* Lower file handle for indexed and non-upper dir/non-dir */ ++ return 1; + } + + static int ovl_d_to_fh(struct dentry *dentry, char *buf, int buflen) + { +- struct dentry *origin = ovl_dentry_lower(dentry); + struct ovl_fh *fh = NULL; +- int err; ++ int err, enc_lower; + + /* +- * If we should not encode a lower dir file handle, copy up and encode +- * an upper dir file handle. ++ * Check if we should encode a lower or upper file handle and maybe ++ * copy up an ancestor to make lower file handle connectable. + */ +- if (!ovl_should_encode_origin(dentry)) { +- err = ovl_encode_maybe_copy_up(dentry); +- if (err) +- goto fail; +- +- origin = NULL; +- } ++ err = enc_lower = ovl_check_encode_origin(dentry); ++ if (enc_lower < 0) ++ goto fail; + +- /* Encode an upper or origin file handle */ +- fh = ovl_encode_fh(origin ?: ovl_dentry_upper(dentry), !origin); ++ /* Encode an upper or lower file handle */ ++ fh = ovl_encode_fh(enc_lower ? ovl_dentry_lower(dentry) : ++ ovl_dentry_upper(dentry), !enc_lower); + err = PTR_ERR(fh); + if (IS_ERR(fh)) + goto fail; +@@ -355,8 +477,8 @@ static struct dentry *ovl_lookup_real_inode(struct super_block *sb, + dput(upper); + } + +- if (!this) +- return NULL; ++ if (IS_ERR_OR_NULL(this)) ++ return this; + + if (WARN_ON(ovl_dentry_real_at(this, layer->idx) != real)) { + dput(this); +@@ -498,7 +620,7 @@ static struct dentry *ovl_lookup_real(struct super_block *sb, + if (err == -ECHILD) { + this = ovl_lookup_real_ancestor(sb, real, + layer); +- err = IS_ERR(this) ? PTR_ERR(this) : 0; ++ err = PTR_ERR_OR_ZERO(this); + } + if (!err) { + dput(connected); +diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c +index fcd97b7..3b1bd46 100644 +--- a/fs/overlayfs/inode.c ++++ b/fs/overlayfs/inode.c +@@ -669,38 +669,59 @@ struct inode *ovl_lookup_inode(struct super_block *sb, struct dentry *real, + return inode; + } + ++/* ++ * Does overlay inode need to be hashed by lower inode? ++ */ ++static bool ovl_hash_bylower(struct super_block *sb, struct dentry *upper, ++ struct dentry *lower, struct dentry *index) ++{ ++ struct ovl_fs *ofs = sb->s_fs_info; ++ ++ /* No, if pure upper */ ++ if (!lower) ++ return false; ++ ++ /* Yes, if already indexed */ ++ if (index) ++ return true; ++ ++ /* Yes, if won't be copied up */ ++ if (!ofs->upper_mnt) ++ return true; ++ ++ /* No, if lower hardlink is or will be broken on copy up */ ++ if ((upper || !ovl_indexdir(sb)) && ++ !d_is_dir(lower) && d_inode(lower)->i_nlink > 1) ++ return false; ++ ++ /* No, if non-indexed upper with NFS export */ ++ if (sb->s_export_op && upper) ++ return false; ++ ++ /* Otherwise, hash by lower inode for fsnotify */ ++ return true; ++} ++ + struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry, + struct dentry *lowerdentry, struct dentry *index, + unsigned int numlower) + { +- struct ovl_fs *ofs = sb->s_fs_info; + struct inode *realinode = upperdentry ? d_inode(upperdentry) : NULL; + struct inode *inode; +- /* Already indexed or could be indexed on copy up? */ +- bool indexed = (index || (ovl_indexdir(sb) && !upperdentry)); +- struct dentry *origin = indexed ? lowerdentry : NULL; ++ bool bylower = ovl_hash_bylower(sb, upperdentry, lowerdentry, index); + bool is_dir; + +- if (WARN_ON(upperdentry && indexed && !lowerdentry)) +- return ERR_PTR(-EIO); +- + if (!realinode) + realinode = d_inode(lowerdentry); + + /* +- * Copy up origin (lower) may exist for non-indexed non-dir upper, but +- * we must not use lower as hash key in that case. +- * Hash non-dir that is or could be indexed by origin inode. +- * Hash dir that is or could be merged by origin inode. +- * Hash pure upper and non-indexed non-dir by upper inode. +- * Hash non-indexed dir by upper inode for NFS export. ++ * Copy up origin (lower) may exist for non-indexed upper, but we must ++ * not use lower as hash key if this is a broken hardlink. + */ + is_dir = S_ISDIR(realinode->i_mode); +- if (is_dir && (indexed || !sb->s_export_op || !ofs->upper_mnt)) +- origin = lowerdentry; +- +- if (upperdentry || origin) { +- struct inode *key = d_inode(origin ?: upperdentry); ++ if (upperdentry || bylower) { ++ struct inode *key = d_inode(bylower ? lowerdentry : ++ upperdentry); + unsigned int nlink = is_dir ? 1 : realinode->i_nlink; + + inode = iget5_locked(sb, (unsigned long) key, +@@ -728,6 +749,7 @@ struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry, + nlink = ovl_get_nlink(lowerdentry, upperdentry, nlink); + set_nlink(inode, nlink); + } else { ++ /* Lower hardlink that will be broken on copy up */ + inode = new_inode(sb); + if (!inode) + goto out_nomem; +diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c +index de3e6da..70fcfcc 100644 +--- a/fs/overlayfs/namei.c ++++ b/fs/overlayfs/namei.c +@@ -913,9 +913,6 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, + stack[ctr].layer = lower.layer; + ctr++; + +- if (d.stop) +- break; +- + /* + * Following redirects can have security consequences: it's like + * a symlink into the lower layer without the permission checks. +@@ -933,6 +930,9 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, + goto out_put; + } + ++ if (d.stop) ++ break; ++ + if (d.redirect && d.redirect[0] == '/' && poe != roe) { + poe = roe; + /* Find the current layer on the root dentry */ +diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h +index 0df25a9..225ff11 100644 +--- a/fs/overlayfs/overlayfs.h ++++ b/fs/overlayfs/overlayfs.h +@@ -40,6 +40,7 @@ enum ovl_inode_flag { + enum ovl_entry_flag { + OVL_E_UPPER_ALIAS, + OVL_E_OPAQUE, ++ OVL_E_CONNECTED, + }; + + /* +diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c +index 9ee37c7..7c24619 100644 +--- a/fs/overlayfs/super.c ++++ b/fs/overlayfs/super.c +@@ -1359,6 +1359,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) + + /* Root is always merge -> can have whiteouts */ + ovl_set_flag(OVL_WHITEOUTS, d_inode(root_dentry)); ++ ovl_dentry_set_flag(OVL_E_CONNECTED, root_dentry); + ovl_inode_init(d_inode(root_dentry), upperpath.dentry, + ovl_dentry_lower(root_dentry)); + +diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c +index 66e1edb..046469f 100644 +--- a/fs/xfs/xfs_iomap.c ++++ b/fs/xfs/xfs_iomap.c +@@ -955,15 +955,29 @@ static inline bool imap_needs_alloc(struct inode *inode, + (IS_DAX(inode) && imap->br_state == XFS_EXT_UNWRITTEN); + } + ++static inline bool needs_cow_for_zeroing(struct xfs_bmbt_irec *imap, int nimaps) ++{ ++ return nimaps && ++ imap->br_startblock != HOLESTARTBLOCK && ++ imap->br_state != XFS_EXT_UNWRITTEN; ++} ++ + static inline bool need_excl_ilock(struct xfs_inode *ip, unsigned flags) + { + /* +- * COW writes will allocate delalloc space, so we need to make sure +- * to take the lock exclusively here. ++ * COW writes may allocate delalloc space or convert unwritten COW ++ * extents, so we need to make sure to take the lock exclusively here. + */ + if (xfs_is_reflink_inode(ip) && (flags & (IOMAP_WRITE | IOMAP_ZERO))) + return true; +- if ((flags & IOMAP_DIRECT) && (flags & IOMAP_WRITE)) ++ ++ /* ++ * Extents not yet cached requires exclusive access, don't block. ++ * This is an opencoded xfs_ilock_data_map_shared() to cater for the ++ * non-blocking behaviour. ++ */ ++ if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE && ++ !(ip->i_df.if_flags & XFS_IFEXTENTS)) + return true; + return false; + } +@@ -993,16 +1007,18 @@ xfs_file_iomap_begin( + return xfs_file_iomap_begin_delay(inode, offset, length, iomap); + } + +- if (need_excl_ilock(ip, flags)) { ++ if (need_excl_ilock(ip, flags)) + lockmode = XFS_ILOCK_EXCL; +- xfs_ilock(ip, XFS_ILOCK_EXCL); +- } else { +- lockmode = xfs_ilock_data_map_shared(ip); +- } ++ else ++ lockmode = XFS_ILOCK_SHARED; + +- if ((flags & IOMAP_NOWAIT) && !(ip->i_df.if_flags & XFS_IFEXTENTS)) { +- error = -EAGAIN; +- goto out_unlock; ++ if (flags & IOMAP_NOWAIT) { ++ if (!(ip->i_df.if_flags & XFS_IFEXTENTS)) ++ return -EAGAIN; ++ if (!xfs_ilock_nowait(ip, lockmode)) ++ return -EAGAIN; ++ } else { ++ xfs_ilock(ip, lockmode); + } + + ASSERT(offset <= mp->m_super->s_maxbytes); +@@ -1024,7 +1040,9 @@ xfs_file_iomap_begin( + goto out_unlock; + } + +- if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { ++ if (xfs_is_reflink_inode(ip) && ++ ((flags & IOMAP_WRITE) || ++ ((flags & IOMAP_ZERO) && needs_cow_for_zeroing(&imap, nimaps)))) { + if (flags & IOMAP_DIRECT) { + /* + * A reflinked inode will result in CoW alloc. +diff --git a/include/linux/compat.h b/include/linux/compat.h +index 8a96438..16c3027 100644 +--- a/include/linux/compat.h ++++ b/include/linux/compat.h +@@ -17,6 +17,7 @@ + #include + #include + #include /* for aio_context_t */ ++#include + #include + + #include +@@ -229,13 +230,13 @@ typedef struct compat_siginfo { + short int _addr_lsb; /* Valid LSB of the reported address. */ + /* used when si_code=SEGV_BNDERR */ + struct { +- short _dummy_bnd; ++ compat_uptr_t _dummy_bnd; + compat_uptr_t _lower; + compat_uptr_t _upper; + } _addr_bnd; + /* used when si_code=SEGV_PKUERR */ + struct { +- short _dummy_pkey; ++ compat_uptr_t _dummy_pkey; + u32 _pkey; + } _addr_pkey; + }; +@@ -550,8 +551,29 @@ asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, + asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp); + + extern int get_compat_sigset(sigset_t *set, const compat_sigset_t __user *compat); +-extern int put_compat_sigset(compat_sigset_t __user *compat, +- const sigset_t *set, unsigned int size); ++ ++/* ++ * Defined inline such that size can be compile time constant, which avoids ++ * CONFIG_HARDENED_USERCOPY complaining about copies from task_struct ++ */ ++static inline int ++put_compat_sigset(compat_sigset_t __user *compat, const sigset_t *set, ++ unsigned int size) ++{ ++ /* size <= sizeof(compat_sigset_t) <= sizeof(sigset_t) */ ++#ifdef __BIG_ENDIAN ++ compat_sigset_t v; ++ switch (_NSIG_WORDS) { ++ case 4: v.sig[7] = (set->sig[3] >> 32); v.sig[6] = set->sig[3]; ++ case 3: v.sig[5] = (set->sig[2] >> 32); v.sig[4] = set->sig[2]; ++ case 2: v.sig[3] = (set->sig[1] >> 32); v.sig[2] = set->sig[1]; ++ case 1: v.sig[1] = (set->sig[0] >> 32); v.sig[0] = set->sig[0]; ++ } ++ return copy_to_user(compat, &v, size) ? -EFAULT : 0; ++#else ++ return copy_to_user(compat, set, size) ? -EFAULT : 0; ++#endif ++} + + asmlinkage long compat_sys_migrate_pages(compat_pid_t pid, + compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes, +diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h +index 88865e0..091033a 100644 +--- a/include/linux/of_pci.h ++++ b/include/linux/of_pci.h +@@ -13,7 +13,6 @@ struct device_node; + struct device_node *of_pci_find_child_device(struct device_node *parent, + unsigned int devfn); + int of_pci_get_devfn(struct device_node *np); +-int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin); + int of_pci_parse_bus_range(struct device_node *node, struct resource *res); + int of_get_pci_domain_nr(struct device_node *node); + int of_pci_get_max_link_speed(struct device_node *node); +@@ -34,12 +33,6 @@ static inline int of_pci_get_devfn(struct device_node *np) + } + + static inline int +-of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin) +-{ +- return 0; +-} +- +-static inline int + of_pci_parse_bus_range(struct device_node *node, struct resource *res) + { + return -EINVAL; +@@ -67,6 +60,16 @@ of_pci_get_max_link_speed(struct device_node *node) + static inline void of_pci_check_probe_only(void) { } + #endif + ++#if IS_ENABLED(CONFIG_OF_IRQ) ++int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin); ++#else ++static inline int ++of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ return 0; ++} ++#endif ++ + #if defined(CONFIG_OF_ADDRESS) + int of_pci_get_host_bridge_resources(struct device_node *dev, + unsigned char busno, unsigned char bus_max, +diff --git a/include/linux/phy.h b/include/linux/phy.h +index 5a0c3e5..d706953 100644 +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -924,6 +924,7 @@ void phy_device_remove(struct phy_device *phydev); + int phy_init_hw(struct phy_device *phydev); + int phy_suspend(struct phy_device *phydev); + int phy_resume(struct phy_device *phydev); ++int __phy_resume(struct phy_device *phydev); + int phy_loopback(struct phy_device *phydev, bool enable); + struct phy_device *phy_attach(struct net_device *dev, const char *bus_id, + phy_interface_t interface); +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index c1e66bd..ddf77cf 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -3285,8 +3285,7 @@ int skb_zerocopy(struct sk_buff *to, struct sk_buff *from, + void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len); + int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen); + void skb_scrub_packet(struct sk_buff *skb, bool xnet); +-unsigned int skb_gso_transport_seglen(const struct sk_buff *skb); +-bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu); ++bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu); + bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len); + struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); + struct sk_buff *skb_vlan_untag(struct sk_buff *skb); +@@ -4104,38 +4103,6 @@ static inline bool skb_head_is_locked(const struct sk_buff *skb) + return !skb->head_frag || skb_cloned(skb); + } + +-/** +- * skb_gso_network_seglen - Return length of individual segments of a gso packet +- * +- * @skb: GSO skb +- * +- * skb_gso_network_seglen is used to determine the real size of the +- * individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP). +- * +- * The MAC/L2 header is not accounted for. +- */ +-static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb) +-{ +- unsigned int hdr_len = skb_transport_header(skb) - +- skb_network_header(skb); +- return hdr_len + skb_gso_transport_seglen(skb); +-} +- +-/** +- * skb_gso_mac_seglen - Return length of individual segments of a gso packet +- * +- * @skb: GSO skb +- * +- * skb_gso_mac_seglen is used to determine the real size of the +- * individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4 +- * headers (TCP/UDP). +- */ +-static inline unsigned int skb_gso_mac_seglen(const struct sk_buff *skb) +-{ +- unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb); +- return hdr_len + skb_gso_transport_seglen(skb); +-} +- + /* Local Checksum Offload. + * Compute outer checksum based on the assumption that the + * inner checksum will be offloaded later. +diff --git a/include/net/devlink.h b/include/net/devlink.h +index 6545b03..4de35ed 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -257,6 +257,18 @@ struct devlink_resource_size_params { + enum devlink_resource_unit unit; + }; + ++static inline void ++devlink_resource_size_params_init(struct devlink_resource_size_params *size_params, ++ u64 size_min, u64 size_max, ++ u64 size_granularity, ++ enum devlink_resource_unit unit) ++{ ++ size_params->size_min = size_min; ++ size_params->size_max = size_max; ++ size_params->size_granularity = size_granularity; ++ size_params->unit = unit; ++} ++ + /** + * struct devlink_resource - devlink resource + * @name: name of the resource +@@ -278,7 +290,7 @@ struct devlink_resource { + u64 size_new; + bool size_valid; + struct devlink_resource *parent; +- struct devlink_resource_size_params *size_params; ++ struct devlink_resource_size_params size_params; + struct list_head list; + struct list_head resource_list; + const struct devlink_resource_ops *resource_ops; +@@ -402,7 +414,7 @@ int devlink_resource_register(struct devlink *devlink, + u64 resource_size, + u64 resource_id, + u64 parent_resource_id, +- struct devlink_resource_size_params *size_params, ++ const struct devlink_resource_size_params *size_params, + const struct devlink_resource_ops *resource_ops); + void devlink_resources_unregister(struct devlink *devlink, + struct devlink_resource *resource); +@@ -556,7 +568,7 @@ devlink_resource_register(struct devlink *devlink, + u64 resource_size, + u64 resource_id, + u64 parent_resource_id, +- struct devlink_resource_size_params *size_params, ++ const struct devlink_resource_size_params *size_params, + const struct devlink_resource_ops *resource_ops) + { + return 0; +diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h +index d8d4a90..2280b23 100644 +--- a/include/scsi/scsi_cmnd.h ++++ b/include/scsi/scsi_cmnd.h +@@ -68,6 +68,9 @@ struct scsi_cmnd { + struct list_head list; /* scsi_cmnd participates in queue lists */ + struct list_head eh_entry; /* entry for the host eh_cmd_q */ + struct delayed_work abort_work; ++ ++ struct rcu_head rcu; ++ + int eh_eflags; /* Used by error handlr */ + + /* +diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h +index 1a1df0d..a8b7bf8 100644 +--- a/include/scsi/scsi_host.h ++++ b/include/scsi/scsi_host.h +@@ -571,8 +571,6 @@ struct Scsi_Host { + struct blk_mq_tag_set tag_set; + }; + +- struct rcu_head rcu; +- + atomic_t host_busy; /* commands actually active on low-level */ + atomic_t host_blocked; + +diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h +index 85dc965..99c902e 100644 +--- a/include/uapi/asm-generic/siginfo.h ++++ b/include/uapi/asm-generic/siginfo.h +@@ -102,13 +102,13 @@ typedef struct siginfo { + short _addr_lsb; /* LSB of the reported address */ + /* used when si_code=SEGV_BNDERR */ + struct { +- short _dummy_bnd; ++ void *_dummy_bnd; + void __user *_lower; + void __user *_upper; + } _addr_bnd; + /* used when si_code=SEGV_PKUERR */ + struct { +- short _dummy_pkey; ++ void *_dummy_pkey; + __u32 _pkey; + } _addr_pkey; + }; +diff --git a/include/uapi/misc/ocxl.h b/include/uapi/misc/ocxl.h +index 4b0b0b7..0af83d8 100644 +--- a/include/uapi/misc/ocxl.h ++++ b/include/uapi/misc/ocxl.h +@@ -32,6 +32,22 @@ struct ocxl_ioctl_attach { + __u64 reserved3; + }; + ++struct ocxl_ioctl_metadata { ++ __u16 version; // struct version, always backwards compatible ++ ++ // Version 0 fields ++ __u8 afu_version_major; ++ __u8 afu_version_minor; ++ __u32 pasid; // PASID assigned to the current context ++ ++ __u64 pp_mmio_size; // Per PASID MMIO size ++ __u64 global_mmio_size; ++ ++ // End version 0 fields ++ ++ __u64 reserved[13]; // Total of 16*u64 ++}; ++ + struct ocxl_ioctl_irq_fd { + __u64 irq_offset; + __s32 eventfd; +@@ -45,5 +61,6 @@ struct ocxl_ioctl_irq_fd { + #define OCXL_IOCTL_IRQ_ALLOC _IOR(OCXL_MAGIC, 0x11, __u64) + #define OCXL_IOCTL_IRQ_FREE _IOW(OCXL_MAGIC, 0x12, __u64) + #define OCXL_IOCTL_IRQ_SET_FD _IOW(OCXL_MAGIC, 0x13, struct ocxl_ioctl_irq_fd) ++#define OCXL_IOCTL_GET_METADATA _IOR(OCXL_MAGIC, 0x14, struct ocxl_ioctl_metadata) + + #endif /* _UAPI_MISC_OCXL_H */ +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 5fb69a8..c6eff10 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -1356,6 +1356,13 @@ static bool is_ctx_reg(struct bpf_verifier_env *env, int regno) + return reg->type == PTR_TO_CTX; + } + ++static bool is_pkt_reg(struct bpf_verifier_env *env, int regno) ++{ ++ const struct bpf_reg_state *reg = cur_regs(env) + regno; ++ ++ return type_is_pkt_pointer(reg->type); ++} ++ + static int check_pkt_ptr_alignment(struct bpf_verifier_env *env, + const struct bpf_reg_state *reg, + int off, int size, bool strict) +@@ -1416,10 +1423,10 @@ static int check_generic_ptr_alignment(struct bpf_verifier_env *env, + } + + static int check_ptr_alignment(struct bpf_verifier_env *env, +- const struct bpf_reg_state *reg, +- int off, int size) ++ const struct bpf_reg_state *reg, int off, ++ int size, bool strict_alignment_once) + { +- bool strict = env->strict_alignment; ++ bool strict = env->strict_alignment || strict_alignment_once; + const char *pointer_desc = ""; + + switch (reg->type) { +@@ -1576,9 +1583,9 @@ static void coerce_reg_to_size(struct bpf_reg_state *reg, int size) + * if t==write && value_regno==-1, some unknown value is stored into memory + * if t==read && value_regno==-1, don't care what we read from memory + */ +-static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regno, int off, +- int bpf_size, enum bpf_access_type t, +- int value_regno) ++static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regno, ++ int off, int bpf_size, enum bpf_access_type t, ++ int value_regno, bool strict_alignment_once) + { + struct bpf_reg_state *regs = cur_regs(env); + struct bpf_reg_state *reg = regs + regno; +@@ -1590,7 +1597,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn + return size; + + /* alignment checks will add in reg->off themselves */ +- err = check_ptr_alignment(env, reg, off, size); ++ err = check_ptr_alignment(env, reg, off, size, strict_alignment_once); + if (err) + return err; + +@@ -1735,21 +1742,23 @@ static int check_xadd(struct bpf_verifier_env *env, int insn_idx, struct bpf_ins + return -EACCES; + } + +- if (is_ctx_reg(env, insn->dst_reg)) { +- verbose(env, "BPF_XADD stores into R%d context is not allowed\n", +- insn->dst_reg); ++ if (is_ctx_reg(env, insn->dst_reg) || ++ is_pkt_reg(env, insn->dst_reg)) { ++ verbose(env, "BPF_XADD stores into R%d %s is not allowed\n", ++ insn->dst_reg, is_ctx_reg(env, insn->dst_reg) ? ++ "context" : "packet"); + return -EACCES; + } + + /* check whether atomic_add can read the memory */ + err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, +- BPF_SIZE(insn->code), BPF_READ, -1); ++ BPF_SIZE(insn->code), BPF_READ, -1, true); + if (err) + return err; + + /* check whether atomic_add can write into the same memory */ + return check_mem_access(env, insn_idx, insn->dst_reg, insn->off, +- BPF_SIZE(insn->code), BPF_WRITE, -1); ++ BPF_SIZE(insn->code), BPF_WRITE, -1, true); + } + + /* when register 'regno' is passed into function that will read 'access_size' +@@ -2388,7 +2397,8 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn + * is inferred from register state. + */ + for (i = 0; i < meta.access_size; i++) { +- err = check_mem_access(env, insn_idx, meta.regno, i, BPF_B, BPF_WRITE, -1); ++ err = check_mem_access(env, insn_idx, meta.regno, i, BPF_B, ++ BPF_WRITE, -1, false); + if (err) + return err; + } +@@ -4632,7 +4642,7 @@ static int do_check(struct bpf_verifier_env *env) + */ + err = check_mem_access(env, insn_idx, insn->src_reg, insn->off, + BPF_SIZE(insn->code), BPF_READ, +- insn->dst_reg); ++ insn->dst_reg, false); + if (err) + return err; + +@@ -4684,7 +4694,7 @@ static int do_check(struct bpf_verifier_env *env) + /* check that memory (dst_reg + off) is writeable */ + err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, + BPF_SIZE(insn->code), BPF_WRITE, +- insn->src_reg); ++ insn->src_reg, false); + if (err) + return err; + +@@ -4719,7 +4729,7 @@ static int do_check(struct bpf_verifier_env *env) + /* check that memory (dst_reg + off) is writeable */ + err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, + BPF_SIZE(insn->code), BPF_WRITE, +- -1); ++ -1, false); + if (err) + return err; + +diff --git a/kernel/compat.c b/kernel/compat.c +index 3247fe7..3f5fa89 100644 +--- a/kernel/compat.c ++++ b/kernel/compat.c +@@ -488,25 +488,6 @@ get_compat_sigset(sigset_t *set, const compat_sigset_t __user *compat) + } + EXPORT_SYMBOL_GPL(get_compat_sigset); + +-int +-put_compat_sigset(compat_sigset_t __user *compat, const sigset_t *set, +- unsigned int size) +-{ +- /* size <= sizeof(compat_sigset_t) <= sizeof(sigset_t) */ +-#ifdef __BIG_ENDIAN +- compat_sigset_t v; +- switch (_NSIG_WORDS) { +- case 4: v.sig[7] = (set->sig[3] >> 32); v.sig[6] = set->sig[3]; +- case 3: v.sig[5] = (set->sig[2] >> 32); v.sig[4] = set->sig[2]; +- case 2: v.sig[3] = (set->sig[1] >> 32); v.sig[2] = set->sig[1]; +- case 1: v.sig[1] = (set->sig[0] >> 32); v.sig[0] = set->sig[0]; +- } +- return copy_to_user(compat, &v, size) ? -EFAULT : 0; +-#else +- return copy_to_user(compat, set, size) ? -EFAULT : 0; +-#endif +-} +- + #ifdef CONFIG_NUMA + COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages, + compat_uptr_t __user *, pages32, +diff --git a/kernel/events/core.c b/kernel/events/core.c +index 96db9ae..4b83847 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -2246,7 +2246,7 @@ static void ctx_resched(struct perf_cpu_context *cpuctx, + struct perf_event_context *task_ctx, + enum event_type_t event_type) + { +- enum event_type_t ctx_event_type = event_type & EVENT_ALL; ++ enum event_type_t ctx_event_type; + bool cpu_event = !!(event_type & EVENT_CPU); + + /* +@@ -2256,6 +2256,8 @@ static void ctx_resched(struct perf_cpu_context *cpuctx, + if (event_type & EVENT_PINNED) + event_type |= EVENT_FLEXIBLE; + ++ ctx_event_type = event_type & EVENT_ALL; ++ + perf_pmu_disable(cpuctx->ctx.pmu); + if (task_ctx) + task_ctx_sched_out(cpuctx, task_ctx, event_type); +diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c +index 65cc0cb..940633c 100644 +--- a/kernel/locking/rtmutex.c ++++ b/kernel/locking/rtmutex.c +@@ -1616,11 +1616,12 @@ bool __sched __rt_mutex_futex_unlock(struct rt_mutex *lock, + void __sched rt_mutex_futex_unlock(struct rt_mutex *lock) + { + DEFINE_WAKE_Q(wake_q); ++ unsigned long flags; + bool postunlock; + +- raw_spin_lock_irq(&lock->wait_lock); ++ raw_spin_lock_irqsave(&lock->wait_lock, flags); + postunlock = __rt_mutex_futex_unlock(lock, &wake_q); +- raw_spin_unlock_irq(&lock->wait_lock); ++ raw_spin_unlock_irqrestore(&lock->wait_lock, flags); + + if (postunlock) + rt_mutex_postunlock(&wake_q); +diff --git a/kernel/panic.c b/kernel/panic.c +index 2cfef40..4b794f1 100644 +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -640,7 +640,7 @@ device_initcall(register_warn_debugfs); + */ + __visible void __stack_chk_fail(void) + { +- panic("stack-protector: Kernel stack is corrupted in: %p\n", ++ panic("stack-protector: Kernel stack is corrupted in: %pB\n", + __builtin_return_address(0)); + } + EXPORT_SYMBOL(__stack_chk_fail); +diff --git a/lib/bug.c b/lib/bug.c +index c1b0fad..1077366 100644 +--- a/lib/bug.c ++++ b/lib/bug.c +@@ -150,6 +150,8 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) + return BUG_TRAP_TYPE_NONE; + + bug = find_bug(bugaddr); ++ if (!bug) ++ return BUG_TRAP_TYPE_NONE; + + file = NULL; + line = 0; +@@ -191,7 +193,7 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) + if (file) + pr_crit("kernel BUG at %s:%u!\n", file, line); + else +- pr_crit("Kernel BUG at %p [verbose debug info unavailable]\n", ++ pr_crit("Kernel BUG at %pB [verbose debug info unavailable]\n", + (void *)bugaddr); + + return BUG_TRAP_TYPE_BUG; +diff --git a/lib/test_bpf.c b/lib/test_bpf.c +index b4e2234..2efb213 100644 +--- a/lib/test_bpf.c ++++ b/lib/test_bpf.c +@@ -24,10 +24,11 @@ + #include + #include + #include ++#include + + /* General test specific settings */ + #define MAX_SUBTESTS 3 +-#define MAX_TESTRUNS 10000 ++#define MAX_TESTRUNS 1000 + #define MAX_DATA 128 + #define MAX_INSNS 512 + #define MAX_K 0xffffFFFF +@@ -6582,6 +6583,7 @@ static __init int test_bpf(void) + struct bpf_prog *fp; + int err; + ++ cond_resched(); + if (exclude_test(i)) + continue; + +diff --git a/lib/test_kmod.c b/lib/test_kmod.c +index e372b97..0e5b7a6 100644 +--- a/lib/test_kmod.c ++++ b/lib/test_kmod.c +@@ -1141,7 +1141,7 @@ static struct kmod_test_device *register_test_dev_kmod(void) + mutex_lock(®_dev_mutex); + + /* int should suffice for number of devices, test for wrap */ +- if (unlikely(num_test_devs + 1) < 0) { ++ if (num_test_devs + 1 == INT_MAX) { + pr_err("reached limit of number of test devices\n"); + goto out; + } +diff --git a/mm/gup.c b/mm/gup.c +index 1b46e6e..6afae32 100644 +--- a/mm/gup.c ++++ b/mm/gup.c +@@ -516,7 +516,7 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma, + } + + if (ret & VM_FAULT_RETRY) { +- if (nonblocking) ++ if (nonblocking && !(fault_flags & FAULT_FLAG_RETRY_NOWAIT)) + *nonblocking = 0; + return -EBUSY; + } +@@ -890,7 +890,10 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk, + break; + } + if (*locked) { +- /* VM_FAULT_RETRY didn't trigger */ ++ /* ++ * VM_FAULT_RETRY didn't trigger or it was a ++ * FOLL_NOWAIT. ++ */ + if (!pages_done) + pages_done = ret; + break; +diff --git a/mm/hugetlb.c b/mm/hugetlb.c +index 7c204e3..a963f20 100644 +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -1583,7 +1583,7 @@ static struct page *alloc_surplus_huge_page(struct hstate *h, gfp_t gfp_mask, + page = NULL; + } else { + h->surplus_huge_pages++; +- h->nr_huge_pages_node[page_to_nid(page)]++; ++ h->surplus_huge_pages_node[page_to_nid(page)]++; + } + + out_unlock: +diff --git a/mm/memblock.c b/mm/memblock.c +index 5a9ca2a..b6ba6b7 100644 +--- a/mm/memblock.c ++++ b/mm/memblock.c +@@ -1107,7 +1107,7 @@ unsigned long __init_memblock memblock_next_valid_pfn(unsigned long pfn, + struct memblock_type *type = &memblock.memory; + unsigned int right = type->cnt; + unsigned int mid, left = 0; +- phys_addr_t addr = PFN_PHYS(pfn + 1); ++ phys_addr_t addr = PFN_PHYS(++pfn); + + do { + mid = (right + left) / 2; +@@ -1118,15 +1118,15 @@ unsigned long __init_memblock memblock_next_valid_pfn(unsigned long pfn, + type->regions[mid].size)) + left = mid + 1; + else { +- /* addr is within the region, so pfn + 1 is valid */ +- return min(pfn + 1, max_pfn); ++ /* addr is within the region, so pfn is valid */ ++ return pfn; + } + } while (left < right); + + if (right == type->cnt) +- return max_pfn; ++ return -1UL; + else +- return min(PHYS_PFN(type->regions[right].base), max_pfn); ++ return PHYS_PFN(type->regions[right].base); + } + + /** +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index cb41672..3d974cb 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -5359,9 +5359,14 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone, + /* + * Skip to the pfn preceding the next valid one (or + * end_pfn), such that we hit a valid pfn (or end_pfn) +- * on our next iteration of the loop. ++ * on our next iteration of the loop. Note that it needs ++ * to be pageblock aligned even when the region itself ++ * is not. move_freepages_block() can shift ahead of ++ * the valid region but still depends on correct page ++ * metadata. + */ +- pfn = memblock_next_valid_pfn(pfn, end_pfn) - 1; ++ pfn = (memblock_next_valid_pfn(pfn, end_pfn) & ++ ~(pageblock_nr_pages-1)) - 1; + #endif + continue; + } +diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c +index 79e3263..99abead 100644 +--- a/net/batman-adv/bat_iv_ogm.c ++++ b/net/batman-adv/bat_iv_ogm.c +@@ -157,7 +157,7 @@ static void batadv_iv_ogm_orig_free(struct batadv_orig_node *orig_node) + * Return: 0 on success, a negative error code otherwise. + */ + static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node, +- int max_if_num) ++ unsigned int max_if_num) + { + void *data_ptr; + size_t old_size; +@@ -201,7 +201,8 @@ static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node, + */ + static void + batadv_iv_ogm_drop_bcast_own_entry(struct batadv_orig_node *orig_node, +- int max_if_num, int del_if_num) ++ unsigned int max_if_num, ++ unsigned int del_if_num) + { + size_t chunk_size; + size_t if_offset; +@@ -239,7 +240,8 @@ batadv_iv_ogm_drop_bcast_own_entry(struct batadv_orig_node *orig_node, + */ + static void + batadv_iv_ogm_drop_bcast_own_sum_entry(struct batadv_orig_node *orig_node, +- int max_if_num, int del_if_num) ++ unsigned int max_if_num, ++ unsigned int del_if_num) + { + size_t if_offset; + void *data_ptr; +@@ -276,7 +278,8 @@ batadv_iv_ogm_drop_bcast_own_sum_entry(struct batadv_orig_node *orig_node, + * Return: 0 on success, a negative error code otherwise. + */ + static int batadv_iv_ogm_orig_del_if(struct batadv_orig_node *orig_node, +- int max_if_num, int del_if_num) ++ unsigned int max_if_num, ++ unsigned int del_if_num) + { + spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); + +@@ -311,7 +314,8 @@ static struct batadv_orig_node * + batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr) + { + struct batadv_orig_node *orig_node; +- int size, hash_added; ++ int hash_added; ++ size_t size; + + orig_node = batadv_orig_hash_find(bat_priv, addr); + if (orig_node) +@@ -893,7 +897,7 @@ batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface) + u32 i; + size_t word_index; + u8 *w; +- int if_num; ++ unsigned int if_num; + + for (i = 0; i < hash->size; i++) { + head = &hash->table[i]; +@@ -1023,7 +1027,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, + struct batadv_neigh_node *tmp_neigh_node = NULL; + struct batadv_neigh_node *router = NULL; + struct batadv_orig_node *orig_node_tmp; +- int if_num; ++ unsigned int if_num; + u8 sum_orig, sum_neigh; + u8 *neigh_addr; + u8 tq_avg; +@@ -1182,7 +1186,7 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, + u8 total_count; + u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; + unsigned int neigh_rq_inv_cube, neigh_rq_max_cube; +- int if_num; ++ unsigned int if_num; + unsigned int tq_asym_penalty, inv_asym_penalty; + unsigned int combined_tq; + unsigned int tq_iface_penalty; +@@ -1702,9 +1706,9 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset, + + if (is_my_orig) { + unsigned long *word; +- int offset; ++ size_t offset; + s32 bit_pos; +- s16 if_num; ++ unsigned int if_num; + u8 *weight; + + orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv, +@@ -2729,7 +2733,7 @@ static int batadv_iv_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_neigh_ifinfo *router_ifinfo = NULL; + struct batadv_neigh_node *router; + struct batadv_gw_node *curr_gw; +- int ret = -EINVAL; ++ int ret = 0; + void *hdr; + + router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); +diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c +index 27e165a..c74f813 100644 +--- a/net/batman-adv/bat_v.c ++++ b/net/batman-adv/bat_v.c +@@ -928,7 +928,7 @@ static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq, + struct batadv_neigh_ifinfo *router_ifinfo = NULL; + struct batadv_neigh_node *router; + struct batadv_gw_node *curr_gw; +- int ret = -EINVAL; ++ int ret = 0; + void *hdr; + + router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); +diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c +index fad4785..b1a0837 100644 +--- a/net/batman-adv/bridge_loop_avoidance.c ++++ b/net/batman-adv/bridge_loop_avoidance.c +@@ -2161,22 +2161,25 @@ batadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, + { + struct batadv_bla_claim *claim; + int idx = 0; ++ int ret = 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(claim, head, hash_entry) { + if (idx++ < *idx_skip) + continue; +- if (batadv_bla_claim_dump_entry(msg, portid, seq, +- primary_if, claim)) { ++ ++ ret = batadv_bla_claim_dump_entry(msg, portid, seq, ++ primary_if, claim); ++ if (ret) { + *idx_skip = idx - 1; + goto unlock; + } + } + +- *idx_skip = idx; ++ *idx_skip = 0; + unlock: + rcu_read_unlock(); +- return 0; ++ return ret; + } + + /** +@@ -2391,22 +2394,25 @@ batadv_bla_backbone_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, + { + struct batadv_bla_backbone_gw *backbone_gw; + int idx = 0; ++ int ret = 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) { + if (idx++ < *idx_skip) + continue; +- if (batadv_bla_backbone_dump_entry(msg, portid, seq, +- primary_if, backbone_gw)) { ++ ++ ret = batadv_bla_backbone_dump_entry(msg, portid, seq, ++ primary_if, backbone_gw); ++ if (ret) { + *idx_skip = idx - 1; + goto unlock; + } + } + +- *idx_skip = idx; ++ *idx_skip = 0; + unlock: + rcu_read_unlock(); +- return 0; ++ return ret; + } + + /** +diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c +index 22dde42..5afe641 100644 +--- a/net/batman-adv/fragmentation.c ++++ b/net/batman-adv/fragmentation.c +@@ -288,7 +288,8 @@ batadv_frag_merge_packets(struct hlist_head *chain) + /* Move the existing MAC header to just before the payload. (Override + * the fragment header.) + */ +- skb_pull_rcsum(skb_out, hdr_size); ++ skb_pull(skb_out, hdr_size); ++ skb_out->ip_summed = CHECKSUM_NONE; + memmove(skb_out->data - ETH_HLEN, skb_mac_header(skb_out), ETH_HLEN); + skb_set_mac_header(skb_out, -ETH_HLEN); + skb_reset_network_header(skb_out); +diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c +index 5f186bf..68b54a3 100644 +--- a/net/batman-adv/hard-interface.c ++++ b/net/batman-adv/hard-interface.c +@@ -763,6 +763,11 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, + hard_iface->soft_iface = soft_iface; + bat_priv = netdev_priv(hard_iface->soft_iface); + ++ if (bat_priv->num_ifaces >= UINT_MAX) { ++ ret = -ENOSPC; ++ goto err_dev; ++ } ++ + ret = netdev_master_upper_dev_link(hard_iface->net_dev, + soft_iface, NULL, NULL, NULL); + if (ret) +@@ -876,7 +881,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, + batadv_hardif_recalc_extra_skbroom(hard_iface->soft_iface); + + /* nobody uses this interface anymore */ +- if (!bat_priv->num_ifaces) { ++ if (bat_priv->num_ifaces == 0) { + batadv_gw_check_client_stop(bat_priv); + + if (autodel == BATADV_IF_CLEANUP_AUTO) +@@ -912,7 +917,7 @@ batadv_hardif_add_interface(struct net_device *net_dev) + if (ret) + goto free_if; + +- hard_iface->if_num = -1; ++ hard_iface->if_num = 0; + hard_iface->net_dev = net_dev; + hard_iface->soft_iface = NULL; + hard_iface->if_status = BATADV_IF_NOT_IN_USE; +diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c +index 58a7d92..7478242 100644 +--- a/net/batman-adv/originator.c ++++ b/net/batman-adv/originator.c +@@ -1569,7 +1569,7 @@ int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb) + * Return: 0 on success or negative error number in case of failure + */ + int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, +- int max_if_num) ++ unsigned int max_if_num) + { + struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); + struct batadv_algo_ops *bao = bat_priv->algo_ops; +@@ -1611,7 +1611,7 @@ int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, + * Return: 0 on success or negative error number in case of failure + */ + int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, +- int max_if_num) ++ unsigned int max_if_num) + { + struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); + struct batadv_hashtable *hash = bat_priv->orig_hash; +diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h +index 8e543a3..15d896b 100644 +--- a/net/batman-adv/originator.h ++++ b/net/batman-adv/originator.h +@@ -73,9 +73,9 @@ int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); + int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb); + int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset); + int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, +- int max_if_num); ++ unsigned int max_if_num); + int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, +- int max_if_num); ++ unsigned int max_if_num); + struct batadv_orig_node_vlan * + batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node, + unsigned short vid); +diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c +index 900c5ce..367a81f 100644 +--- a/net/batman-adv/soft-interface.c ++++ b/net/batman-adv/soft-interface.c +@@ -459,13 +459,7 @@ void batadv_interface_rx(struct net_device *soft_iface, + + /* skb->dev & skb->pkt_type are set here */ + skb->protocol = eth_type_trans(skb, soft_iface); +- +- /* should not be necessary anymore as we use skb_pull_rcsum() +- * TODO: please verify this and remove this TODO +- * -- Dec 21st 2009, Simon Wunderlich +- */ +- +- /* skb->ip_summed = CHECKSUM_UNNECESSARY; */ ++ skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); + + batadv_inc_counter(bat_priv, BATADV_CNT_RX); + batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES, +diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h +index bb15784..a5aa6d6 100644 +--- a/net/batman-adv/types.h ++++ b/net/batman-adv/types.h +@@ -167,7 +167,7 @@ struct batadv_hard_iface { + struct list_head list; + + /** @if_num: identificator of the interface */ +- s16 if_num; ++ unsigned int if_num; + + /** @if_status: status of the interface for batman-adv */ + char if_status; +@@ -1596,7 +1596,7 @@ struct batadv_priv { + atomic_t batman_queue_left; + + /** @num_ifaces: number of interfaces assigned to this mesh interface */ +- char num_ifaces; ++ unsigned int num_ifaces; + + /** @mesh_obj: kobject for sysfs mesh subdirectory */ + struct kobject *mesh_obj; +@@ -2186,15 +2186,16 @@ struct batadv_algo_orig_ops { + * orig_node due to a new hard-interface being added into the mesh + * (optional) + */ +- int (*add_if)(struct batadv_orig_node *orig_node, int max_if_num); ++ int (*add_if)(struct batadv_orig_node *orig_node, ++ unsigned int max_if_num); + + /** + * @del_if: ask the routing algorithm to apply the needed changes to the + * orig_node due to an hard-interface being removed from the mesh + * (optional) + */ +- int (*del_if)(struct batadv_orig_node *orig_node, int max_if_num, +- int del_if_num); ++ int (*del_if)(struct batadv_orig_node *orig_node, ++ unsigned int max_if_num, unsigned int del_if_num); + + #ifdef CONFIG_BATMAN_ADV_DEBUGFS + /** @print: print the originator table (optional) */ +diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c +index 27f1d4f..9b16eaf 100644 +--- a/net/bridge/br_netfilter_hooks.c ++++ b/net/bridge/br_netfilter_hooks.c +@@ -214,7 +214,7 @@ static int br_validate_ipv4(struct net *net, struct sk_buff *skb) + + iph = ip_hdr(skb); + if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) +- goto inhdr_error; ++ goto csum_error; + + len = ntohs(iph->tot_len); + if (skb->len < len) { +@@ -236,6 +236,8 @@ static int br_validate_ipv4(struct net *net, struct sk_buff *skb) + */ + return 0; + ++csum_error: ++ __IP_INC_STATS(net, IPSTATS_MIB_CSUMERRORS); + inhdr_error: + __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS); + drop: +diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c +index 5193527..9896f49 100644 +--- a/net/bridge/br_vlan.c ++++ b/net/bridge/br_vlan.c +@@ -168,6 +168,8 @@ static struct net_bridge_vlan *br_vlan_get_master(struct net_bridge *br, u16 vid + masterv = br_vlan_find(vg, vid); + if (WARN_ON(!masterv)) + return NULL; ++ refcount_set(&masterv->refcnt, 1); ++ return masterv; + } + refcount_inc(&masterv->refcnt); + +diff --git a/net/bridge/netfilter/ebt_among.c b/net/bridge/netfilter/ebt_among.c +index ce7152a..c5afb42 100644 +--- a/net/bridge/netfilter/ebt_among.c ++++ b/net/bridge/netfilter/ebt_among.c +@@ -172,18 +172,35 @@ ebt_among_mt(const struct sk_buff *skb, struct xt_action_param *par) + return true; + } + ++static bool poolsize_invalid(const struct ebt_mac_wormhash *w) ++{ ++ return w && w->poolsize >= (INT_MAX / sizeof(struct ebt_mac_wormhash_tuple)); ++} ++ + static int ebt_among_mt_check(const struct xt_mtchk_param *par) + { + const struct ebt_among_info *info = par->matchinfo; + const struct ebt_entry_match *em = + container_of(par->matchinfo, const struct ebt_entry_match, data); +- int expected_length = sizeof(struct ebt_among_info); ++ unsigned int expected_length = sizeof(struct ebt_among_info); + const struct ebt_mac_wormhash *wh_dst, *wh_src; + int err; + ++ if (expected_length > em->match_size) ++ return -EINVAL; ++ + wh_dst = ebt_among_wh_dst(info); +- wh_src = ebt_among_wh_src(info); ++ if (poolsize_invalid(wh_dst)) ++ return -EINVAL; ++ + expected_length += ebt_mac_wormhash_size(wh_dst); ++ if (expected_length > em->match_size) ++ return -EINVAL; ++ ++ wh_src = ebt_among_wh_src(info); ++ if (poolsize_invalid(wh_src)) ++ return -EINVAL; ++ + expected_length += ebt_mac_wormhash_size(wh_src); + + if (em->match_size != EBT_ALIGN(expected_length)) { +diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c +index 02c4b40..254ef9f 100644 +--- a/net/bridge/netfilter/ebtables.c ++++ b/net/bridge/netfilter/ebtables.c +@@ -1641,7 +1641,8 @@ static int compat_match_to_user(struct ebt_entry_match *m, void __user **dstptr, + int off = ebt_compat_match_offset(match, m->match_size); + compat_uint_t msize = m->match_size - off; + +- BUG_ON(off >= m->match_size); ++ if (WARN_ON(off >= m->match_size)) ++ return -EINVAL; + + if (copy_to_user(cm->u.name, match->name, + strlen(match->name) + 1) || put_user(msize, &cm->match_size)) +@@ -1671,7 +1672,8 @@ static int compat_target_to_user(struct ebt_entry_target *t, + int off = xt_compat_target_offset(target); + compat_uint_t tsize = t->target_size - off; + +- BUG_ON(off >= t->target_size); ++ if (WARN_ON(off >= t->target_size)) ++ return -EINVAL; + + if (copy_to_user(cm->u.name, target->name, + strlen(target->name) + 1) || put_user(tsize, &cm->match_size)) +@@ -1902,7 +1904,8 @@ static int ebt_buf_add(struct ebt_entries_buf_state *state, + if (state->buf_kern_start == NULL) + goto count_only; + +- BUG_ON(state->buf_kern_offset + sz > state->buf_kern_len); ++ if (WARN_ON(state->buf_kern_offset + sz > state->buf_kern_len)) ++ return -EINVAL; + + memcpy(state->buf_kern_start + state->buf_kern_offset, data, sz); + +@@ -1915,7 +1918,8 @@ static int ebt_buf_add_pad(struct ebt_entries_buf_state *state, unsigned int sz) + { + char *b = state->buf_kern_start; + +- BUG_ON(b && state->buf_kern_offset > state->buf_kern_len); ++ if (WARN_ON(b && state->buf_kern_offset > state->buf_kern_len)) ++ return -EINVAL; + + if (b != NULL && sz > 0) + memset(b + state->buf_kern_offset, 0, sz); +@@ -1992,8 +1996,10 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, + pad = XT_ALIGN(size_kern) - size_kern; + + if (pad > 0 && dst) { +- BUG_ON(state->buf_kern_len <= pad); +- BUG_ON(state->buf_kern_offset - (match_size + off) + size_kern > state->buf_kern_len - pad); ++ if (WARN_ON(state->buf_kern_len <= pad)) ++ return -EINVAL; ++ if (WARN_ON(state->buf_kern_offset - (match_size + off) + size_kern > state->buf_kern_len - pad)) ++ return -EINVAL; + memset(dst + size_kern, 0, pad); + } + return off + match_size; +@@ -2043,7 +2049,8 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32, + if (ret < 0) + return ret; + +- BUG_ON(ret < match32->match_size); ++ if (WARN_ON(ret < match32->match_size)) ++ return -EINVAL; + growth += ret - match32->match_size; + growth += ebt_compat_entry_padsize(); + +@@ -2053,7 +2060,9 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32, + if (match_kern) + match_kern->match_size = ret; + +- WARN_ON(type == EBT_COMPAT_TARGET && size_left); ++ if (WARN_ON(type == EBT_COMPAT_TARGET && size_left)) ++ return -EINVAL; ++ + match32 = (struct compat_ebt_entry_mwt *) buf; + } + +@@ -2109,6 +2118,15 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, + * + * offsets are relative to beginning of struct ebt_entry (i.e., 0). + */ ++ for (i = 0; i < 4 ; ++i) { ++ if (offsets[i] >= *total) ++ return -EINVAL; ++ if (i == 0) ++ continue; ++ if (offsets[i-1] > offsets[i]) ++ return -EINVAL; ++ } ++ + for (i = 0, j = 1 ; j < 4 ; j++, i++) { + struct compat_ebt_entry_mwt *match32; + unsigned int size; +@@ -2140,7 +2158,8 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, + + startoff = state->buf_user_offset - startoff; + +- BUG_ON(*total < startoff); ++ if (WARN_ON(*total < startoff)) ++ return -EINVAL; + *total -= startoff; + return 0; + } +@@ -2267,7 +2286,8 @@ static int compat_do_replace(struct net *net, void __user *user, + state.buf_kern_len = size64; + + ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state); +- BUG_ON(ret < 0); /* parses same data again */ ++ if (WARN_ON(ret < 0)) ++ goto out_unlock; + + vfree(entries_tmp); + tmp.entries_size = size64; +diff --git a/net/core/dev.c b/net/core/dev.c +index d4362be..2cedf52 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -6396,6 +6396,7 @@ static int __netdev_upper_dev_link(struct net_device *dev, + .linking = true, + .upper_info = upper_info, + }; ++ struct net_device *master_dev; + int ret = 0; + + ASSERT_RTNL(); +@@ -6407,11 +6408,14 @@ static int __netdev_upper_dev_link(struct net_device *dev, + if (netdev_has_upper_dev(upper_dev, dev)) + return -EBUSY; + +- if (netdev_has_upper_dev(dev, upper_dev)) +- return -EEXIST; +- +- if (master && netdev_master_upper_dev_get(dev)) +- return -EBUSY; ++ if (!master) { ++ if (netdev_has_upper_dev(dev, upper_dev)) ++ return -EEXIST; ++ } else { ++ master_dev = netdev_master_upper_dev_get(dev); ++ if (master_dev) ++ return master_dev == upper_dev ? -EEXIST : -EBUSY; ++ } + + ret = call_netdevice_notifiers_info(NETDEV_PRECHANGEUPPER, + &changeupper_info.info); +diff --git a/net/core/devlink.c b/net/core/devlink.c +index 18d385e..2f2307d9 100644 +--- a/net/core/devlink.c ++++ b/net/core/devlink.c +@@ -1695,10 +1695,11 @@ static int devlink_dpipe_table_put(struct sk_buff *skb, + goto nla_put_failure; + + if (table->resource_valid) { +- nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID, +- table->resource_id, DEVLINK_ATTR_PAD); +- nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS, +- table->resource_units, DEVLINK_ATTR_PAD); ++ if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID, ++ table->resource_id, DEVLINK_ATTR_PAD) || ++ nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS, ++ table->resource_units, DEVLINK_ATTR_PAD)) ++ goto nla_put_failure; + } + if (devlink_dpipe_matches_put(table, skb)) + goto nla_put_failure; +@@ -2332,7 +2333,7 @@ devlink_resource_validate_children(struct devlink_resource *resource) + list_for_each_entry(child_resource, &resource->resource_list, list) + parts_size += child_resource->size_new; + +- if (parts_size > resource->size) ++ if (parts_size > resource->size_new) + size_valid = false; + out: + resource->size_valid = size_valid; +@@ -2372,20 +2373,22 @@ static int devlink_nl_cmd_resource_set(struct sk_buff *skb, + return 0; + } + +-static void ++static int + devlink_resource_size_params_put(struct devlink_resource *resource, + struct sk_buff *skb) + { + struct devlink_resource_size_params *size_params; + +- size_params = resource->size_params; +- nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN, +- size_params->size_granularity, DEVLINK_ATTR_PAD); +- nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX, +- size_params->size_max, DEVLINK_ATTR_PAD); +- nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN, +- size_params->size_min, DEVLINK_ATTR_PAD); +- nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit); ++ size_params = &resource->size_params; ++ if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN, ++ size_params->size_granularity, DEVLINK_ATTR_PAD) || ++ nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX, ++ size_params->size_max, DEVLINK_ATTR_PAD) || ++ nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN, ++ size_params->size_min, DEVLINK_ATTR_PAD) || ++ nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit)) ++ return -EMSGSIZE; ++ return 0; + } + + static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb, +@@ -2409,10 +2412,12 @@ static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb, + nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW, + resource->size_new, DEVLINK_ATTR_PAD); + if (resource->resource_ops && resource->resource_ops->occ_get) +- nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC, +- resource->resource_ops->occ_get(devlink), +- DEVLINK_ATTR_PAD); +- devlink_resource_size_params_put(resource, skb); ++ if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC, ++ resource->resource_ops->occ_get(devlink), ++ DEVLINK_ATTR_PAD)) ++ goto nla_put_failure; ++ if (devlink_resource_size_params_put(resource, skb)) ++ goto nla_put_failure; + if (list_empty(&resource->resource_list)) + goto out; + +@@ -3151,7 +3156,7 @@ int devlink_resource_register(struct devlink *devlink, + u64 resource_size, + u64 resource_id, + u64 parent_resource_id, +- struct devlink_resource_size_params *size_params, ++ const struct devlink_resource_size_params *size_params, + const struct devlink_resource_ops *resource_ops) + { + struct devlink_resource *resource; +@@ -3194,7 +3199,8 @@ int devlink_resource_register(struct devlink *devlink, + resource->id = resource_id; + resource->resource_ops = resource_ops; + resource->size_valid = true; +- resource->size_params = size_params; ++ memcpy(&resource->size_params, size_params, ++ sizeof(resource->size_params)); + INIT_LIST_HEAD(&resource->resource_list); + list_add_tail(&resource->list, resource_list); + out: +diff --git a/net/core/ethtool.c b/net/core/ethtool.c +index 494e6a5..3f89c76 100644 +--- a/net/core/ethtool.c ++++ b/net/core/ethtool.c +@@ -2520,11 +2520,14 @@ static int set_phy_tunable(struct net_device *dev, void __user *useraddr) + static int ethtool_get_fecparam(struct net_device *dev, void __user *useraddr) + { + struct ethtool_fecparam fecparam = { ETHTOOL_GFECPARAM }; ++ int rc; + + if (!dev->ethtool_ops->get_fecparam) + return -EOPNOTSUPP; + +- dev->ethtool_ops->get_fecparam(dev, &fecparam); ++ rc = dev->ethtool_ops->get_fecparam(dev, &fecparam); ++ if (rc) ++ return rc; + + if (copy_to_user(useraddr, &fecparam, sizeof(fecparam))) + return -EFAULT; +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 09bd89c..0bb0d88 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -4891,7 +4891,7 @@ EXPORT_SYMBOL_GPL(skb_scrub_packet); + * + * The MAC/L2 or network (IP, IPv6) headers are not accounted for. + */ +-unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) ++static unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) + { + const struct skb_shared_info *shinfo = skb_shinfo(skb); + unsigned int thlen = 0; +@@ -4913,7 +4913,40 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) + */ + return thlen + shinfo->gso_size; + } +-EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); ++ ++/** ++ * skb_gso_network_seglen - Return length of individual segments of a gso packet ++ * ++ * @skb: GSO skb ++ * ++ * skb_gso_network_seglen is used to determine the real size of the ++ * individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP). ++ * ++ * The MAC/L2 header is not accounted for. ++ */ ++static unsigned int skb_gso_network_seglen(const struct sk_buff *skb) ++{ ++ unsigned int hdr_len = skb_transport_header(skb) - ++ skb_network_header(skb); ++ ++ return hdr_len + skb_gso_transport_seglen(skb); ++} ++ ++/** ++ * skb_gso_mac_seglen - Return length of individual segments of a gso packet ++ * ++ * @skb: GSO skb ++ * ++ * skb_gso_mac_seglen is used to determine the real size of the ++ * individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4 ++ * headers (TCP/UDP). ++ */ ++static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb) ++{ ++ unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb); ++ ++ return hdr_len + skb_gso_transport_seglen(skb); ++} + + /** + * skb_gso_size_check - check the skb size, considering GSO_BY_FRAGS +@@ -4955,19 +4988,20 @@ static inline bool skb_gso_size_check(const struct sk_buff *skb, + } + + /** +- * skb_gso_validate_mtu - Return in case such skb fits a given MTU ++ * skb_gso_validate_network_len - Will a split GSO skb fit into a given MTU? + * + * @skb: GSO skb + * @mtu: MTU to validate against + * +- * skb_gso_validate_mtu validates if a given skb will fit a wanted MTU +- * once split. ++ * skb_gso_validate_network_len validates if a given skb will fit a ++ * wanted MTU once split. It considers L3 headers, L4 headers, and the ++ * payload. + */ +-bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu) ++bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu) + { + return skb_gso_size_check(skb, skb_gso_network_seglen(skb), mtu); + } +-EXPORT_SYMBOL_GPL(skb_gso_validate_mtu); ++EXPORT_SYMBOL_GPL(skb_gso_validate_network_len); + + /** + * skb_gso_validate_mac_len - Will a split GSO skb fit in a given length? +diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c +index 2dd21c3..b54b948 100644 +--- a/net/ipv4/ip_forward.c ++++ b/net/ipv4/ip_forward.c +@@ -55,7 +55,7 @@ static bool ip_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) + if (skb->ignore_df) + return false; + +- if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) + return false; + + return true; +diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c +index 45d97e9..0901de4 100644 +--- a/net/ipv4/ip_gre.c ++++ b/net/ipv4/ip_gre.c +@@ -970,9 +970,6 @@ static void __gre_tunnel_init(struct net_device *dev) + + t_hlen = tunnel->hlen + sizeof(struct iphdr); + +- dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; +- dev->mtu = ETH_DATA_LEN - t_hlen - 4; +- + dev->features |= GRE_FEATURES; + dev->hw_features |= GRE_FEATURES; + +@@ -1290,8 +1287,6 @@ static int erspan_tunnel_init(struct net_device *dev) + erspan_hdr_len(tunnel->erspan_ver); + t_hlen = tunnel->hlen + sizeof(struct iphdr); + +- dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; +- dev->mtu = ETH_DATA_LEN - t_hlen - 4; + dev->features |= GRE_FEATURES; + dev->hw_features |= GRE_FEATURES; + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +index e8e675b..66340ab 100644 +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -248,7 +248,7 @@ static int ip_finish_output_gso(struct net *net, struct sock *sk, + + /* common case: seglen is <= mtu + */ +- if (skb_gso_validate_mtu(skb, mtu)) ++ if (skb_gso_validate_network_len(skb, mtu)) + return ip_finish_output2(net, sk, skb); + + /* Slowpath - GSO segment length exceeds the egress MTU. +diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c +index d786a84..6d21068 100644 +--- a/net/ipv4/ip_tunnel.c ++++ b/net/ipv4/ip_tunnel.c +@@ -710,16 +710,9 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, + } + } + +- if (tunnel->fwmark) { +- init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, +- tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link, +- tunnel->fwmark); +- } +- else { +- init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, +- tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link, +- skb->mark); +- } ++ init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, ++ tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link, ++ tunnel->fwmark); + + if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0) + goto tx_error; +diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c +index 4b02ab3..8a8ae61 100644 +--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c ++++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c +@@ -232,7 +232,6 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i, + c->hash_mode = i->hash_mode; + c->hash_initval = i->hash_initval; + refcount_set(&c->refcount, 1); +- refcount_set(&c->entries, 1); + + spin_lock_bh(&cn->lock); + if (__clusterip_config_find(net, ip)) { +@@ -263,8 +262,10 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i, + + c->notifier.notifier_call = clusterip_netdev_event; + err = register_netdevice_notifier(&c->notifier); +- if (!err) ++ if (!err) { ++ refcount_set(&c->entries, 1); + return c; ++ } + + #ifdef CONFIG_PROC_FS + proc_remove(c->pde); +@@ -273,7 +274,7 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i, + spin_lock_bh(&cn->lock); + list_del_rcu(&c->list); + spin_unlock_bh(&cn->lock); +- kfree(c); ++ clusterip_config_put(c); + + return ERR_PTR(err); + } +@@ -496,12 +497,15 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) + return PTR_ERR(config); + } + } +- cipinfo->config = config; + + ret = nf_ct_netns_get(par->net, par->family); +- if (ret < 0) ++ if (ret < 0) { + pr_info("cannot load conntrack support for proto=%u\n", + par->family); ++ clusterip_config_entry_put(par->net, config); ++ clusterip_config_put(config); ++ return ret; ++ } + + if (!par->net->xt.clusterip_deprecated_warning) { + pr_info("ipt_CLUSTERIP is deprecated and it will removed soon, " +@@ -509,6 +513,7 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) + par->net->xt.clusterip_deprecated_warning = true; + } + ++ cipinfo->config = config; + return ret; + } + +diff --git a/net/ipv4/netfilter/nf_flow_table_ipv4.c b/net/ipv4/netfilter/nf_flow_table_ipv4.c +index 25d2975..0cd46bf 100644 +--- a/net/ipv4/netfilter/nf_flow_table_ipv4.c ++++ b/net/ipv4/netfilter/nf_flow_table_ipv4.c +@@ -111,6 +111,7 @@ static int nf_flow_dnat_ip(const struct flow_offload *flow, struct sk_buff *skb, + default: + return -1; + } ++ csum_replace4(&iph->check, addr, new_addr); + + return nf_flow_nat_ip_l4proto(skb, iph, thoff, addr, new_addr); + } +@@ -185,7 +186,7 @@ static bool __nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) + if ((ip_hdr(skb)->frag_off & htons(IP_DF)) == 0) + return false; + +- if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) + return false; + + return true; +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index a4f44d8..860b3fd 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -128,10 +128,11 @@ static int ip_rt_redirect_silence __read_mostly = ((HZ / 50) << (9 + 1)); + static int ip_rt_error_cost __read_mostly = HZ; + static int ip_rt_error_burst __read_mostly = 5 * HZ; + static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ; +-static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; ++static u32 ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; + static int ip_rt_min_advmss __read_mostly = 256; + + static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT; ++ + /* + * Interface to generic destination cache. + */ +@@ -930,14 +931,23 @@ void ip_rt_send_redirect(struct sk_buff *skb) + + static int ip_error(struct sk_buff *skb) + { +- struct in_device *in_dev = __in_dev_get_rcu(skb->dev); + struct rtable *rt = skb_rtable(skb); ++ struct net_device *dev = skb->dev; ++ struct in_device *in_dev; + struct inet_peer *peer; + unsigned long now; + struct net *net; + bool send; + int code; + ++ if (netif_is_l3_master(skb->dev)) { ++ dev = __dev_get_by_index(dev_net(skb->dev), IPCB(skb)->iif); ++ if (!dev) ++ goto out; ++ } ++ ++ in_dev = __in_dev_get_rcu(dev); ++ + /* IP on this device is disabled. */ + if (!in_dev) + goto out; +@@ -2818,6 +2828,7 @@ void ip_rt_multicast_event(struct in_device *in_dev) + static int ip_rt_gc_interval __read_mostly = 60 * HZ; + static int ip_rt_gc_min_interval __read_mostly = HZ / 2; + static int ip_rt_gc_elasticity __read_mostly = 8; ++static int ip_min_valid_pmtu __read_mostly = IPV4_MIN_MTU; + + static int ipv4_sysctl_rtcache_flush(struct ctl_table *__ctl, int write, + void __user *buffer, +@@ -2933,7 +2944,8 @@ static struct ctl_table ipv4_route_table[] = { + .data = &ip_rt_min_pmtu, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = proc_dointvec, ++ .proc_handler = proc_dointvec_minmax, ++ .extra1 = &ip_min_valid_pmtu, + }, + { + .procname = "min_adv_mss", +diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c +index 7c84357..faddf4f 100644 +--- a/net/ipv4/tcp_illinois.c ++++ b/net/ipv4/tcp_illinois.c +@@ -6,7 +6,7 @@ + * The algorithm is described in: + * "TCP-Illinois: A Loss and Delay-Based Congestion Control Algorithm + * for High-Speed Networks" +- * http://www.ifp.illinois.edu/~srikant/Papers/liubassri06perf.pdf ++ * http://tamerbasar.csl.illinois.edu/LiuBasarSrikantPerfEvalArtJun2008.pdf + * + * Implemented from description in paper and ns-2 simulation. + * Copyright (C) 2007 Stephen Hemminger +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 575d3c1..9a1b3c1 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1971,11 +1971,6 @@ void tcp_enter_loss(struct sock *sk) + /* F-RTO RFC5682 sec 3.1 step 1: retransmit SND.UNA if no previous + * loss recovery is underway except recurring timeout(s) on + * the same SND.UNA (sec 3.2). Disable F-RTO on path MTU probing +- * +- * In theory F-RTO can be used repeatedly during loss recovery. +- * In practice this interacts badly with broken middle-boxes that +- * falsely raise the receive window, which results in repeated +- * timeouts and stop-and-go behavior. + */ + tp->frto = net->ipv4.sysctl_tcp_frto && + (new_recovery || icsk->icsk_retransmits) && +@@ -2631,18 +2626,14 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack, + tcp_try_undo_loss(sk, false)) + return; + +- /* The ACK (s)acks some never-retransmitted data meaning not all +- * the data packets before the timeout were lost. Therefore we +- * undo the congestion window and state. This is essentially +- * the operation in F-RTO (RFC5682 section 3.1 step 3.b). Since +- * a retransmitted skb is permantly marked, we can apply such an +- * operation even if F-RTO was not used. +- */ +- if ((flag & FLAG_ORIG_SACK_ACKED) && +- tcp_try_undo_loss(sk, tp->undo_marker)) +- return; +- + if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */ ++ /* Step 3.b. A timeout is spurious if not all data are ++ * lost, i.e., never-retransmitted data are (s)acked. ++ */ ++ if ((flag & FLAG_ORIG_SACK_ACKED) && ++ tcp_try_undo_loss(sk, true)) ++ return; ++ + if (after(tp->snd_nxt, tp->high_seq)) { + if (flag & FLAG_DATA_SACKED || is_dupack) + tp->frto = 0; /* Step 3.a. loss was real */ +@@ -4001,6 +3992,7 @@ void tcp_reset(struct sock *sk) + /* This barrier is coupled with smp_rmb() in tcp_poll() */ + smp_wmb(); + ++ tcp_write_queue_purge(sk); + tcp_done(sk); + + if (!sock_flag(sk, SOCK_DEAD)) +diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c +index 94b8702..be980c1 100644 +--- a/net/ipv4/xfrm4_output.c ++++ b/net/ipv4/xfrm4_output.c +@@ -30,7 +30,8 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb) + + mtu = dst_mtu(skb_dst(skb)); + if ((!skb_is_gso(skb) && skb->len > mtu) || +- (skb_is_gso(skb) && skb_gso_network_seglen(skb) > ip_skb_dst_mtu(skb->sk, skb))) { ++ (skb_is_gso(skb) && ++ !skb_gso_validate_network_len(skb, ip_skb_dst_mtu(skb->sk, skb)))) { + skb->protocol = htons(ETH_P_IP); + + if (skb->sk) +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index 997c7f1..a8a9195 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -412,7 +412,7 @@ static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) + if (skb->ignore_df) + return false; + +- if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) + return false; + + return true; +diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c +index 4b15fe9..6e0f21e 100644 +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -1982,14 +1982,14 @@ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev, + { + struct net *net = dev_net(dev); + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); +- struct ip6_tnl *nt, *t; + struct ip_tunnel_encap ipencap; ++ struct ip6_tnl *nt, *t; ++ int err; + + nt = netdev_priv(dev); + + if (ip6_tnl_netlink_encap_parms(data, &ipencap)) { +- int err = ip6_tnl_encap_setup(nt, &ipencap); +- ++ err = ip6_tnl_encap_setup(nt, &ipencap); + if (err < 0) + return err; + } +@@ -2005,7 +2005,11 @@ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev, + return -EEXIST; + } + +- return ip6_tnl_create2(dev); ++ err = ip6_tnl_create2(dev); ++ if (!err && tb[IFLA_MTU]) ++ ip6_tnl_change_mtu(dev, nla_get_u32(tb[IFLA_MTU])); ++ ++ return err; + } + + static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[], +diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c +index d95ceca..531d695 100644 +--- a/net/ipv6/netfilter.c ++++ b/net/ipv6/netfilter.c +@@ -21,18 +21,19 @@ + int ip6_route_me_harder(struct net *net, struct sk_buff *skb) + { + const struct ipv6hdr *iph = ipv6_hdr(skb); ++ struct sock *sk = sk_to_full_sk(skb->sk); + unsigned int hh_len; + struct dst_entry *dst; + struct flowi6 fl6 = { +- .flowi6_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0, ++ .flowi6_oif = sk ? sk->sk_bound_dev_if : 0, + .flowi6_mark = skb->mark, +- .flowi6_uid = sock_net_uid(net, skb->sk), ++ .flowi6_uid = sock_net_uid(net, sk), + .daddr = iph->daddr, + .saddr = iph->saddr, + }; + int err; + +- dst = ip6_route_output(net, skb->sk, &fl6); ++ dst = ip6_route_output(net, sk, &fl6); + err = dst->error; + if (err) { + IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); +@@ -50,7 +51,7 @@ int ip6_route_me_harder(struct net *net, struct sk_buff *skb) + if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && + xfrm_decode_session(skb, flowi6_to_flowi(&fl6), AF_INET6) == 0) { + skb_dst_set(skb, NULL); +- dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), skb->sk, 0); ++ dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0); + if (IS_ERR(dst)) + return PTR_ERR(dst); + skb_dst_set(skb, dst); +diff --git a/net/ipv6/netfilter/ip6t_rpfilter.c b/net/ipv6/netfilter/ip6t_rpfilter.c +index 94deb69..91ed25a 100644 +--- a/net/ipv6/netfilter/ip6t_rpfilter.c ++++ b/net/ipv6/netfilter/ip6t_rpfilter.c +@@ -48,10 +48,6 @@ static bool rpfilter_lookup_reverse6(struct net *net, const struct sk_buff *skb, + } + + fl6.flowi6_mark = flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0; +- if ((flags & XT_RPFILTER_LOOSE) == 0) { +- fl6.flowi6_oif = dev->ifindex; +- lookup_flags |= RT6_LOOKUP_F_IFACE; +- } + + rt = (void *) ip6_route_lookup(net, &fl6, lookup_flags); + if (rt->dst.error) +diff --git a/net/ipv6/netfilter/nf_flow_table_ipv6.c b/net/ipv6/netfilter/nf_flow_table_ipv6.c +index d346705..207cb35 100644 +--- a/net/ipv6/netfilter/nf_flow_table_ipv6.c ++++ b/net/ipv6/netfilter/nf_flow_table_ipv6.c +@@ -178,7 +178,7 @@ static bool __nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) + if (skb->len <= mtu) + return false; + +- if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) + return false; + + return true; +diff --git a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c +index bed57ee..6b7f075 100644 +--- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c ++++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c +@@ -99,6 +99,10 @@ static bool nf_nat_ipv6_manip_pkt(struct sk_buff *skb, + !l4proto->manip_pkt(skb, &nf_nat_l3proto_ipv6, iphdroff, hdroff, + target, maniptype)) + return false; ++ ++ /* must reload, offset might have changed */ ++ ipv6h = (void *)skb->data + iphdroff; ++ + manip_addr: + if (maniptype == NF_NAT_MANIP_SRC) + ipv6h->saddr = target->src.u3.in6; +diff --git a/net/ipv6/netfilter/nft_fib_ipv6.c b/net/ipv6/netfilter/nft_fib_ipv6.c +index cc5174c..62fc84d 100644 +--- a/net/ipv6/netfilter/nft_fib_ipv6.c ++++ b/net/ipv6/netfilter/nft_fib_ipv6.c +@@ -180,7 +180,6 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs, + } + + *dest = 0; +- again: + rt = (void *)ip6_route_lookup(nft_net(pkt), &fl6, lookup_flags); + if (rt->dst.error) + goto put_rt_err; +@@ -189,15 +188,8 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs, + if (rt->rt6i_flags & (RTF_REJECT | RTF_ANYCAST | RTF_LOCAL)) + goto put_rt_err; + +- if (oif && oif != rt->rt6i_idev->dev) { +- /* multipath route? Try again with F_IFACE */ +- if ((lookup_flags & RT6_LOOKUP_F_IFACE) == 0) { +- lookup_flags |= RT6_LOOKUP_F_IFACE; +- fl6.flowi6_oif = oif->ifindex; +- ip6_rt_put(rt); +- goto again; +- } +- } ++ if (oif && oif != rt->rt6i_idev->dev) ++ goto put_rt_err; + + switch (priv->result) { + case NFT_FIB_RESULT_OIF: +diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c +index 3a1775a..0195598 100644 +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -1578,6 +1578,13 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev, + if (err < 0) + return err; + ++ if (tb[IFLA_MTU]) { ++ u32 mtu = nla_get_u32(tb[IFLA_MTU]); ++ ++ if (mtu >= IPV6_MIN_MTU && mtu <= 0xFFF8 - dev->hard_header_len) ++ dev->mtu = mtu; ++ } ++ + #ifdef CONFIG_IPV6_SIT_6RD + if (ipip6_netlink_6rd_parms(data, &ip6rd)) + err = ipip6_tunnel_update_6rd(nt, &ip6rd); +diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c +index 8ae87d4..5959ce9 100644 +--- a/net/ipv6/xfrm6_output.c ++++ b/net/ipv6/xfrm6_output.c +@@ -82,7 +82,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb) + + if ((!skb_is_gso(skb) && skb->len > mtu) || + (skb_is_gso(skb) && +- skb_gso_network_seglen(skb) > ip6_skb_dst_mtu(skb))) { ++ !skb_gso_validate_network_len(skb, ip6_skb_dst_mtu(skb)))) { + skb->dev = dst->dev; + skb->protocol = htons(ETH_P_IPV6); + +diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c +index 194a748..83421c6 100644 +--- a/net/l2tp/l2tp_core.c ++++ b/net/l2tp/l2tp_core.c +@@ -136,51 +136,6 @@ l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id) + + } + +-/* Lookup the tunnel socket, possibly involving the fs code if the socket is +- * owned by userspace. A struct sock returned from this function must be +- * released using l2tp_tunnel_sock_put once you're done with it. +- */ +-static struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel) +-{ +- int err = 0; +- struct socket *sock = NULL; +- struct sock *sk = NULL; +- +- if (!tunnel) +- goto out; +- +- if (tunnel->fd >= 0) { +- /* Socket is owned by userspace, who might be in the process +- * of closing it. Look the socket up using the fd to ensure +- * consistency. +- */ +- sock = sockfd_lookup(tunnel->fd, &err); +- if (sock) +- sk = sock->sk; +- } else { +- /* Socket is owned by kernelspace */ +- sk = tunnel->sock; +- sock_hold(sk); +- } +- +-out: +- return sk; +-} +- +-/* Drop a reference to a tunnel socket obtained via. l2tp_tunnel_sock_put */ +-static void l2tp_tunnel_sock_put(struct sock *sk) +-{ +- struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); +- if (tunnel) { +- if (tunnel->fd >= 0) { +- /* Socket is owned by userspace */ +- sockfd_put(sk->sk_socket); +- } +- sock_put(sk); +- } +- sock_put(sk); +-} +- + /* Session hash list. + * The session_id SHOULD be random according to RFC2661, but several + * L2TP implementations (Cisco and Microsoft) use incrementing +@@ -193,6 +148,13 @@ l2tp_session_id_hash(struct l2tp_tunnel *tunnel, u32 session_id) + return &tunnel->session_hlist[hash_32(session_id, L2TP_HASH_BITS)]; + } + ++void l2tp_tunnel_free(struct l2tp_tunnel *tunnel) ++{ ++ sock_put(tunnel->sock); ++ /* the tunnel is freed in the socket destructor */ ++} ++EXPORT_SYMBOL(l2tp_tunnel_free); ++ + /* Lookup a tunnel. A new reference is held on the returned tunnel. */ + struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id) + { +@@ -345,13 +307,11 @@ int l2tp_session_register(struct l2tp_session *session, + } + + l2tp_tunnel_inc_refcount(tunnel); +- sock_hold(tunnel->sock); + hlist_add_head_rcu(&session->global_hlist, g_head); + + spin_unlock_bh(&pn->l2tp_session_hlist_lock); + } else { + l2tp_tunnel_inc_refcount(tunnel); +- sock_hold(tunnel->sock); + } + + hlist_add_head(&session->hlist, head); +@@ -969,7 +929,7 @@ int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) + { + struct l2tp_tunnel *tunnel; + +- tunnel = l2tp_sock_to_tunnel(sk); ++ tunnel = l2tp_tunnel(sk); + if (tunnel == NULL) + goto pass_up; + +@@ -977,13 +937,10 @@ int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) + tunnel->name, skb->len); + + if (l2tp_udp_recv_core(tunnel, skb, tunnel->recv_payload_hook)) +- goto pass_up_put; ++ goto pass_up; + +- sock_put(sk); + return 0; + +-pass_up_put: +- sock_put(sk); + pass_up: + return 1; + } +@@ -1207,14 +1164,12 @@ EXPORT_SYMBOL_GPL(l2tp_xmit_skb); + static void l2tp_tunnel_destruct(struct sock *sk) + { + struct l2tp_tunnel *tunnel = l2tp_tunnel(sk); +- struct l2tp_net *pn; + + if (tunnel == NULL) + goto end; + + l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: closing...\n", tunnel->name); + +- + /* Disable udp encapsulation */ + switch (tunnel->encap) { + case L2TP_ENCAPTYPE_UDP: +@@ -1231,18 +1186,11 @@ static void l2tp_tunnel_destruct(struct sock *sk) + sk->sk_destruct = tunnel->old_sk_destruct; + sk->sk_user_data = NULL; + +- /* Remove the tunnel struct from the tunnel list */ +- pn = l2tp_pernet(tunnel->l2tp_net); +- spin_lock_bh(&pn->l2tp_tunnel_list_lock); +- list_del_rcu(&tunnel->list); +- spin_unlock_bh(&pn->l2tp_tunnel_list_lock); +- +- tunnel->sock = NULL; +- l2tp_tunnel_dec_refcount(tunnel); +- + /* Call the original destructor */ + if (sk->sk_destruct) + (*sk->sk_destruct)(sk); ++ ++ kfree_rcu(tunnel, rcu); + end: + return; + } +@@ -1303,49 +1251,43 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_closeall); + /* Tunnel socket destroy hook for UDP encapsulation */ + static void l2tp_udp_encap_destroy(struct sock *sk) + { +- struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); +- if (tunnel) { +- l2tp_tunnel_closeall(tunnel); +- sock_put(sk); +- } ++ struct l2tp_tunnel *tunnel = l2tp_tunnel(sk); ++ ++ if (tunnel) ++ l2tp_tunnel_delete(tunnel); + } + + /* Workqueue tunnel deletion function */ + static void l2tp_tunnel_del_work(struct work_struct *work) + { +- struct l2tp_tunnel *tunnel = NULL; +- struct socket *sock = NULL; +- struct sock *sk = NULL; +- +- tunnel = container_of(work, struct l2tp_tunnel, del_work); ++ struct l2tp_tunnel *tunnel = container_of(work, struct l2tp_tunnel, ++ del_work); ++ struct sock *sk = tunnel->sock; ++ struct socket *sock = sk->sk_socket; ++ struct l2tp_net *pn; + + l2tp_tunnel_closeall(tunnel); + +- sk = l2tp_tunnel_sock_lookup(tunnel); +- if (!sk) +- goto out; +- +- sock = sk->sk_socket; +- +- /* If the tunnel socket was created by userspace, then go through the +- * inet layer to shut the socket down, and let userspace close it. +- * Otherwise, if we created the socket directly within the kernel, use ++ /* If the tunnel socket was created within the kernel, use + * the sk API to release it here. +- * In either case the tunnel resources are freed in the socket +- * destructor when the tunnel socket goes away. + */ +- if (tunnel->fd >= 0) { +- if (sock) +- inet_shutdown(sock, 2); +- } else { ++ if (tunnel->fd < 0) { + if (sock) { + kernel_sock_shutdown(sock, SHUT_RDWR); + sock_release(sock); + } + } + +- l2tp_tunnel_sock_put(sk); +-out: ++ /* Remove the tunnel struct from the tunnel list */ ++ pn = l2tp_pernet(tunnel->l2tp_net); ++ spin_lock_bh(&pn->l2tp_tunnel_list_lock); ++ list_del_rcu(&tunnel->list); ++ spin_unlock_bh(&pn->l2tp_tunnel_list_lock); ++ ++ /* drop initial ref */ ++ l2tp_tunnel_dec_refcount(tunnel); ++ ++ /* drop workqueue ref */ + l2tp_tunnel_dec_refcount(tunnel); + } + +@@ -1598,13 +1540,22 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 + sk->sk_user_data = tunnel; + } + ++ /* Bump the reference count. The tunnel context is deleted ++ * only when this drops to zero. A reference is also held on ++ * the tunnel socket to ensure that it is not released while ++ * the tunnel is extant. Must be done before sk_destruct is ++ * set. ++ */ ++ refcount_set(&tunnel->ref_count, 1); ++ sock_hold(sk); ++ tunnel->sock = sk; ++ tunnel->fd = fd; ++ + /* Hook on the tunnel socket destructor so that we can cleanup + * if the tunnel socket goes away. + */ + tunnel->old_sk_destruct = sk->sk_destruct; + sk->sk_destruct = &l2tp_tunnel_destruct; +- tunnel->sock = sk; +- tunnel->fd = fd; + lockdep_set_class_and_name(&sk->sk_lock.slock, &l2tp_socket_class, "l2tp_sock"); + + sk->sk_allocation = GFP_ATOMIC; +@@ -1614,11 +1565,6 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 + + /* Add tunnel to our list */ + INIT_LIST_HEAD(&tunnel->list); +- +- /* Bump the reference count. The tunnel context is deleted +- * only when this drops to zero. Must be done before list insertion +- */ +- refcount_set(&tunnel->ref_count, 1); + spin_lock_bh(&pn->l2tp_tunnel_list_lock); + list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list); + spin_unlock_bh(&pn->l2tp_tunnel_list_lock); +@@ -1659,8 +1605,6 @@ void l2tp_session_free(struct l2tp_session *session) + + if (tunnel) { + BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC); +- sock_put(tunnel->sock); +- session->tunnel = NULL; + l2tp_tunnel_dec_refcount(tunnel); + } + +diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h +index 9bbee90..a1aa955 100644 +--- a/net/l2tp/l2tp_core.h ++++ b/net/l2tp/l2tp_core.h +@@ -214,27 +214,8 @@ static inline void *l2tp_session_priv(struct l2tp_session *session) + return &session->priv[0]; + } + +-static inline struct l2tp_tunnel *l2tp_sock_to_tunnel(struct sock *sk) +-{ +- struct l2tp_tunnel *tunnel; +- +- if (sk == NULL) +- return NULL; +- +- sock_hold(sk); +- tunnel = (struct l2tp_tunnel *)(sk->sk_user_data); +- if (tunnel == NULL) { +- sock_put(sk); +- goto out; +- } +- +- BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC); +- +-out: +- return tunnel; +-} +- + struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id); ++void l2tp_tunnel_free(struct l2tp_tunnel *tunnel); + + struct l2tp_session *l2tp_session_get(const struct net *net, + struct l2tp_tunnel *tunnel, +@@ -283,7 +264,7 @@ static inline void l2tp_tunnel_inc_refcount(struct l2tp_tunnel *tunnel) + static inline void l2tp_tunnel_dec_refcount(struct l2tp_tunnel *tunnel) + { + if (refcount_dec_and_test(&tunnel->ref_count)) +- kfree_rcu(tunnel, rcu); ++ l2tp_tunnel_free(tunnel); + } + + /* Session reference counts. Incremented when code obtains a reference +diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c +index ff61124..3428fba 100644 +--- a/net/l2tp/l2tp_ip.c ++++ b/net/l2tp/l2tp_ip.c +@@ -234,17 +234,13 @@ static void l2tp_ip_close(struct sock *sk, long timeout) + static void l2tp_ip_destroy_sock(struct sock *sk) + { + struct sk_buff *skb; +- struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); ++ struct l2tp_tunnel *tunnel = sk->sk_user_data; + + while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) + kfree_skb(skb); + +- if (tunnel) { +- l2tp_tunnel_closeall(tunnel); +- sock_put(sk); +- } +- +- sk_refcnt_debug_dec(sk); ++ if (tunnel) ++ l2tp_tunnel_delete(tunnel); + } + + static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) +diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c +index 1923446..6f009ea 100644 +--- a/net/l2tp/l2tp_ip6.c ++++ b/net/l2tp/l2tp_ip6.c +@@ -248,16 +248,14 @@ static void l2tp_ip6_close(struct sock *sk, long timeout) + + static void l2tp_ip6_destroy_sock(struct sock *sk) + { +- struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); ++ struct l2tp_tunnel *tunnel = sk->sk_user_data; + + lock_sock(sk); + ip6_flush_pending_frames(sk); + release_sock(sk); + +- if (tunnel) { +- l2tp_tunnel_closeall(tunnel); +- sock_put(sk); +- } ++ if (tunnel) ++ l2tp_tunnel_delete(tunnel); + + inet6_destroy_sock(sk); + } +diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c +index 59f246d..3b02f24 100644 +--- a/net/l2tp/l2tp_ppp.c ++++ b/net/l2tp/l2tp_ppp.c +@@ -416,20 +416,28 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) + * Session (and tunnel control) socket create/destroy. + *****************************************************************************/ + ++static void pppol2tp_put_sk(struct rcu_head *head) ++{ ++ struct pppol2tp_session *ps; ++ ++ ps = container_of(head, typeof(*ps), rcu); ++ sock_put(ps->__sk); ++} ++ + /* Called by l2tp_core when a session socket is being closed. + */ + static void pppol2tp_session_close(struct l2tp_session *session) + { +- struct sock *sk; +- +- BUG_ON(session->magic != L2TP_SESSION_MAGIC); ++ struct pppol2tp_session *ps; + +- sk = pppol2tp_session_get_sock(session); +- if (sk) { +- if (sk->sk_socket) +- inet_shutdown(sk->sk_socket, SEND_SHUTDOWN); +- sock_put(sk); +- } ++ ps = l2tp_session_priv(session); ++ mutex_lock(&ps->sk_lock); ++ ps->__sk = rcu_dereference_protected(ps->sk, ++ lockdep_is_held(&ps->sk_lock)); ++ RCU_INIT_POINTER(ps->sk, NULL); ++ if (ps->__sk) ++ call_rcu(&ps->rcu, pppol2tp_put_sk); ++ mutex_unlock(&ps->sk_lock); + } + + /* Really kill the session socket. (Called from sock_put() if +@@ -449,14 +457,6 @@ static void pppol2tp_session_destruct(struct sock *sk) + } + } + +-static void pppol2tp_put_sk(struct rcu_head *head) +-{ +- struct pppol2tp_session *ps; +- +- ps = container_of(head, typeof(*ps), rcu); +- sock_put(ps->__sk); +-} +- + /* Called when the PPPoX socket (session) is closed. + */ + static int pppol2tp_release(struct socket *sock) +@@ -480,26 +480,17 @@ static int pppol2tp_release(struct socket *sock) + sock_orphan(sk); + sock->sk = NULL; + ++ /* If the socket is associated with a session, ++ * l2tp_session_delete will call pppol2tp_session_close which ++ * will drop the session's ref on the socket. ++ */ + session = pppol2tp_sock_to_session(sk); +- +- if (session != NULL) { +- struct pppol2tp_session *ps; +- ++ if (session) { + l2tp_session_delete(session); +- +- ps = l2tp_session_priv(session); +- mutex_lock(&ps->sk_lock); +- ps->__sk = rcu_dereference_protected(ps->sk, +- lockdep_is_held(&ps->sk_lock)); +- RCU_INIT_POINTER(ps->sk, NULL); +- mutex_unlock(&ps->sk_lock); +- call_rcu(&ps->rcu, pppol2tp_put_sk); +- +- /* Rely on the sock_put() call at the end of the function for +- * dropping the reference held by pppol2tp_sock_to_session(). +- * The last reference will be dropped by pppol2tp_put_sk(). +- */ ++ /* drop the ref obtained by pppol2tp_sock_to_session */ ++ sock_put(sk); + } ++ + release_sock(sk); + + /* This will delete the session context via +@@ -796,6 +787,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, + + out_no_ppp: + /* This is how we get the session context from the socket. */ ++ sock_hold(sk); + sk->sk_user_data = session; + rcu_assign_pointer(ps->sk, sk); + mutex_unlock(&ps->sk_lock); +diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c +index fd58061..56fe16b 100644 +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -3921,7 +3921,7 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, + if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FROMDS | + IEEE80211_FCTL_TODS)) != + fast_rx->expected_ds_bits) +- goto drop; ++ return false; + + /* assign the key to drop unencrypted frames (later) + * and strip the IV/MIC if necessary +diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c +index 25904af..6972250 100644 +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3574,6 +3574,14 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb, + if (!IS_ERR_OR_NULL(sta)) { + struct ieee80211_fast_tx *fast_tx; + ++ /* We need a bit of data queued to build aggregates properly, so ++ * instruct the TCP stack to allow more than a single ms of data ++ * to be queued in the stack. The value is a bit-shift of 1 ++ * second, so 8 is ~4ms of queued data. Only affects local TCP ++ * sockets. ++ */ ++ sk_pacing_shift_update(skb->sk, 8); ++ + fast_tx = rcu_dereference(sta->fast_tx); + + if (fast_tx && +diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c +index e545a3c..7a4de6d 100644 +--- a/net/mpls/af_mpls.c ++++ b/net/mpls/af_mpls.c +@@ -122,7 +122,7 @@ bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) + if (skb->len <= mtu) + return false; + +- if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) + return false; + + return true; +diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c +index 3e17d32..58d5d05 100644 +--- a/net/netfilter/ipvs/ip_vs_ftp.c ++++ b/net/netfilter/ipvs/ip_vs_ftp.c +@@ -260,7 +260,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, + buf_len = strlen(buf); + + ct = nf_ct_get(skb, &ctinfo); +- if (ct && (ct->status & IPS_NAT_MASK)) { ++ if (ct) { + bool mangled; + + /* If mangling fails this function will return 0 +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 8b9fe30..558593e 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -5037,9 +5037,9 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk, + { + const struct nfgenmsg *nfmsg = nlmsg_data(nlh); + const struct nf_flowtable_type *type; ++ struct nft_flowtable *flowtable, *ft; + u8 genmask = nft_genmask_next(net); + int family = nfmsg->nfgen_family; +- struct nft_flowtable *flowtable; + struct nft_table *table; + struct nft_ctx ctx; + int err, i, k; +@@ -5099,6 +5099,22 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk, + goto err3; + + for (i = 0; i < flowtable->ops_len; i++) { ++ if (!flowtable->ops[i].dev) ++ continue; ++ ++ list_for_each_entry(ft, &table->flowtables, list) { ++ for (k = 0; k < ft->ops_len; k++) { ++ if (!ft->ops[k].dev) ++ continue; ++ ++ if (flowtable->ops[i].dev == ft->ops[k].dev && ++ flowtable->ops[i].pf == ft->ops[k].pf) { ++ err = -EBUSY; ++ goto err4; ++ } ++ } ++ } ++ + err = nf_register_net_hook(net, &flowtable->ops[i]); + if (err < 0) + goto err4; +@@ -5120,7 +5136,7 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk, + i = flowtable->ops_len; + err4: + for (k = i - 1; k >= 0; k--) +- nf_unregister_net_hook(net, &flowtable->ops[i]); ++ nf_unregister_net_hook(net, &flowtable->ops[k]); + + kfree(flowtable->ops); + err3: +@@ -5145,6 +5161,11 @@ static int nf_tables_delflowtable(struct net *net, struct sock *nlsk, + struct nft_table *table; + struct nft_ctx ctx; + ++ if (!nla[NFTA_FLOWTABLE_TABLE] || ++ (!nla[NFTA_FLOWTABLE_NAME] && ++ !nla[NFTA_FLOWTABLE_HANDLE])) ++ return -EINVAL; ++ + table = nf_tables_table_lookup(net, nla[NFTA_FLOWTABLE_TABLE], + family, genmask); + if (IS_ERR(table)) +diff --git a/net/qrtr/smd.c b/net/qrtr/smd.c +index 50615d5..9cf089b 100644 +--- a/net/qrtr/smd.c ++++ b/net/qrtr/smd.c +@@ -114,5 +114,6 @@ static struct rpmsg_driver qcom_smd_qrtr_driver = { + + module_rpmsg_driver(qcom_smd_qrtr_driver); + ++MODULE_ALIAS("rpmsg:IPCRTR"); + MODULE_DESCRIPTION("Qualcomm IPC-Router SMD interface driver"); + MODULE_LICENSE("GPL v2"); +diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c +index c061d6e..2257118 100644 +--- a/net/rds/tcp_listen.c ++++ b/net/rds/tcp_listen.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2006 Oracle. All rights reserved. ++ * Copyright (c) 2006, 2018 Oracle. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU +@@ -142,12 +142,20 @@ int rds_tcp_accept_one(struct socket *sock) + if (ret) + goto out; + +- new_sock->type = sock->type; +- new_sock->ops = sock->ops; + ret = sock->ops->accept(sock, new_sock, O_NONBLOCK, true); + if (ret < 0) + goto out; + ++ /* sock_create_lite() does not get a hold on the owner module so we ++ * need to do it here. Note that sock_release() uses sock->ops to ++ * determine if it needs to decrement the reference count. So set ++ * sock->ops after calling accept() in case that fails. And there's ++ * no need to do try_module_get() as the listener should have a hold ++ * already. ++ */ ++ new_sock->ops = sock->ops; ++ __module_get(new_sock->ops->owner); ++ + ret = rds_tcp_keepalive(new_sock); + if (ret < 0) + goto out; +diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c +index 229172d..03225a8 100644 +--- a/net/sched/sch_tbf.c ++++ b/net/sched/sch_tbf.c +@@ -188,7 +188,8 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch, + int ret; + + if (qdisc_pkt_len(skb) > q->max_size) { +- if (skb_is_gso(skb) && skb_gso_mac_seglen(skb) <= q->max_size) ++ if (skb_is_gso(skb) && ++ skb_gso_validate_mac_len(skb, q->max_size)) + return tbf_segment(skb, sch, to_free); + return qdisc_drop(skb, sch, to_free); + } +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index da1a5cd..8cc9783 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -1406,8 +1406,10 @@ static int smc_create(struct net *net, struct socket *sock, int protocol, + smc->use_fallback = false; /* assume rdma capability first */ + rc = sock_create_kern(net, PF_INET, SOCK_STREAM, + IPPROTO_TCP, &smc->clcsock); +- if (rc) ++ if (rc) { + sk_common_release(sk); ++ goto out; ++ } + smc->sk.sk_sndbuf = max(smc->clcsock->sk->sk_sndbuf, SMC_BUF_MIN_SIZE); + smc->sk.sk_rcvbuf = max(smc->clcsock->sk->sk_rcvbuf, SMC_BUF_MIN_SIZE); + +diff --git a/net/smc/smc_cdc.c b/net/smc/smc_cdc.c +index 3cd086e..b42395d 100644 +--- a/net/smc/smc_cdc.c ++++ b/net/smc/smc_cdc.c +@@ -269,7 +269,7 @@ static void smc_cdc_rx_handler(struct ib_wc *wc, void *buf) + + if (wc->byte_len < offsetof(struct smc_cdc_msg, reserved)) + return; /* short message */ +- if (cdc->len != sizeof(*cdc)) ++ if (cdc->len != SMC_WR_TX_SIZE) + return; /* invalid message */ + smc_cdc_msg_recv(cdc, link, wc->wr_id); + } +diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c +index 2424c71..645dd22 100644 +--- a/net/smc/smc_core.c ++++ b/net/smc/smc_core.c +@@ -177,6 +177,7 @@ static int smc_lgr_create(struct smc_sock *smc, __be32 peer_in_addr, + + lnk = &lgr->lnk[SMC_SINGLE_LINK]; + /* initialize link */ ++ lnk->link_id = SMC_SINGLE_LINK; + lnk->smcibdev = smcibdev; + lnk->ibport = ibport; + lnk->path_mtu = smcibdev->pattr[ibport - 1].active_mtu; +@@ -465,7 +466,7 @@ int smc_conn_create(struct smc_sock *smc, __be32 peer_in_addr, + rc = smc_link_determine_gid(conn->lgr); + } + conn->local_tx_ctrl.common.type = SMC_CDC_MSG_TYPE; +- conn->local_tx_ctrl.len = sizeof(struct smc_cdc_msg); ++ conn->local_tx_ctrl.len = SMC_WR_TX_SIZE; + #ifndef KERNEL_HAS_ATOMIC64 + spin_lock_init(&conn->acurs_lock); + #endif +diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c +index 92fe4cc..b4aa4fc 100644 +--- a/net/smc/smc_llc.c ++++ b/net/smc/smc_llc.c +@@ -92,7 +92,7 @@ int smc_llc_send_confirm_link(struct smc_link *link, u8 mac[], + memcpy(confllc->sender_mac, mac, ETH_ALEN); + memcpy(confllc->sender_gid, gid, SMC_GID_SIZE); + hton24(confllc->sender_qp_num, link->roce_qp->qp_num); +- /* confllc->link_num = SMC_SINGLE_LINK; already done by memset above */ ++ confllc->link_num = link->link_id; + memcpy(confllc->link_uid, lgr->id, SMC_LGR_ID_SIZE); + confllc->max_links = SMC_LINKS_PER_LGR_MAX; + /* send llc message */ +diff --git a/net/tipc/group.c b/net/tipc/group.c +index 122162a..04e516d 100644 +--- a/net/tipc/group.c ++++ b/net/tipc/group.c +@@ -189,6 +189,7 @@ struct tipc_group *tipc_group_create(struct net *net, u32 portid, + grp->loopback = mreq->flags & TIPC_GROUP_LOOPBACK; + grp->events = mreq->flags & TIPC_GROUP_MEMBER_EVTS; + grp->open = group_is_open; ++ *grp->open = false; + filter |= global ? TIPC_SUB_CLUSTER_SCOPE : TIPC_SUB_NODE_SCOPE; + if (tipc_topsrv_kern_subscr(net, portid, type, 0, ~0, + filter, &grp->subid)) +diff --git a/net/tipc/socket.c b/net/tipc/socket.c +index b0323ec..7dfa9fc 100644 +--- a/net/tipc/socket.c ++++ b/net/tipc/socket.c +@@ -473,6 +473,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock, + sk->sk_write_space = tipc_write_space; + sk->sk_destruct = tipc_sock_destruct; + tsk->conn_timeout = CONN_TIMEOUT_DEFAULT; ++ tsk->group_is_open = true; + atomic_set(&tsk->dupl_rcvcnt, 0); + + /* Start out with safe limits until we receive an advertised window */ +diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c +index e9b4b53..d824d54 100644 +--- a/net/tls/tls_main.c ++++ b/net/tls/tls_main.c +@@ -46,16 +46,26 @@ MODULE_DESCRIPTION("Transport Layer Security Support"); + MODULE_LICENSE("Dual BSD/GPL"); + + enum { ++ TLSV4, ++ TLSV6, ++ TLS_NUM_PROTS, ++}; ++ ++enum { + TLS_BASE_TX, + TLS_SW_TX, + TLS_NUM_CONFIG, + }; + +-static struct proto tls_prots[TLS_NUM_CONFIG]; ++static struct proto *saved_tcpv6_prot; ++static DEFINE_MUTEX(tcpv6_prot_mutex); ++static struct proto tls_prots[TLS_NUM_PROTS][TLS_NUM_CONFIG]; + + static inline void update_sk_prot(struct sock *sk, struct tls_context *ctx) + { +- sk->sk_prot = &tls_prots[ctx->tx_conf]; ++ int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4; ++ ++ sk->sk_prot = &tls_prots[ip_ver][ctx->tx_conf]; + } + + int wait_on_pending_writer(struct sock *sk, long *timeo) +@@ -453,8 +463,21 @@ static int tls_setsockopt(struct sock *sk, int level, int optname, + return do_tls_setsockopt(sk, optname, optval, optlen); + } + ++static void build_protos(struct proto *prot, struct proto *base) ++{ ++ prot[TLS_BASE_TX] = *base; ++ prot[TLS_BASE_TX].setsockopt = tls_setsockopt; ++ prot[TLS_BASE_TX].getsockopt = tls_getsockopt; ++ prot[TLS_BASE_TX].close = tls_sk_proto_close; ++ ++ prot[TLS_SW_TX] = prot[TLS_BASE_TX]; ++ prot[TLS_SW_TX].sendmsg = tls_sw_sendmsg; ++ prot[TLS_SW_TX].sendpage = tls_sw_sendpage; ++} ++ + static int tls_init(struct sock *sk) + { ++ int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4; + struct inet_connection_sock *icsk = inet_csk(sk); + struct tls_context *ctx; + int rc = 0; +@@ -479,6 +502,17 @@ static int tls_init(struct sock *sk) + ctx->getsockopt = sk->sk_prot->getsockopt; + ctx->sk_proto_close = sk->sk_prot->close; + ++ /* Build IPv6 TLS whenever the address of tcpv6_prot changes */ ++ if (ip_ver == TLSV6 && ++ unlikely(sk->sk_prot != smp_load_acquire(&saved_tcpv6_prot))) { ++ mutex_lock(&tcpv6_prot_mutex); ++ if (likely(sk->sk_prot != saved_tcpv6_prot)) { ++ build_protos(tls_prots[TLSV6], sk->sk_prot); ++ smp_store_release(&saved_tcpv6_prot, sk->sk_prot); ++ } ++ mutex_unlock(&tcpv6_prot_mutex); ++ } ++ + ctx->tx_conf = TLS_BASE_TX; + update_sk_prot(sk, ctx); + out: +@@ -493,21 +527,9 @@ static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = { + .init = tls_init, + }; + +-static void build_protos(struct proto *prot, struct proto *base) +-{ +- prot[TLS_BASE_TX] = *base; +- prot[TLS_BASE_TX].setsockopt = tls_setsockopt; +- prot[TLS_BASE_TX].getsockopt = tls_getsockopt; +- prot[TLS_BASE_TX].close = tls_sk_proto_close; +- +- prot[TLS_SW_TX] = prot[TLS_BASE_TX]; +- prot[TLS_SW_TX].sendmsg = tls_sw_sendmsg; +- prot[TLS_SW_TX].sendpage = tls_sw_sendpage; +-} +- + static int __init tls_register(void) + { +- build_protos(tls_prots, &tcp_prot); ++ build_protos(tls_prots[TLSV4], &tcp_prot); + + tcp_register_ulp(&tcp_tls_ulp_ops); + +diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig +index 1abcc4f..4172204 100644 +--- a/net/wireless/Kconfig ++++ b/net/wireless/Kconfig +@@ -34,9 +34,10 @@ config CFG80211 + + When built as a module it will be called cfg80211. + ++if CFG80211 ++ + config NL80211_TESTMODE + bool "nl80211 testmode command" +- depends on CFG80211 + help + The nl80211 testmode command helps implementing things like + factory calibration or validation tools for wireless chips. +@@ -51,7 +52,6 @@ config NL80211_TESTMODE + + config CFG80211_DEVELOPER_WARNINGS + bool "enable developer warnings" +- depends on CFG80211 + default n + help + This option enables some additional warnings that help +@@ -68,7 +68,7 @@ config CFG80211_DEVELOPER_WARNINGS + + config CFG80211_CERTIFICATION_ONUS + bool "cfg80211 certification onus" +- depends on CFG80211 && EXPERT ++ depends on EXPERT + default n + ---help--- + You should disable this option unless you are both capable +@@ -159,7 +159,6 @@ config CFG80211_REG_RELAX_NO_IR + + config CFG80211_DEFAULT_PS + bool "enable powersave by default" +- depends on CFG80211 + default y + help + This option enables powersave mode by default. +@@ -170,7 +169,6 @@ config CFG80211_DEFAULT_PS + + config CFG80211_DEBUGFS + bool "cfg80211 DebugFS entries" +- depends on CFG80211 + depends on DEBUG_FS + ---help--- + You can enable this if you want debugfs entries for cfg80211. +@@ -180,7 +178,6 @@ config CFG80211_DEBUGFS + config CFG80211_CRDA_SUPPORT + bool "support CRDA" if EXPERT + default y +- depends on CFG80211 + help + You should enable this option unless you know for sure you have no + need for it, for example when using internal regdb (above) or the +@@ -190,7 +187,6 @@ config CFG80211_CRDA_SUPPORT + + config CFG80211_WEXT + bool "cfg80211 wireless extensions compatibility" if !CFG80211_WEXT_EXPORT +- depends on CFG80211 + select WEXT_CORE + default y if CFG80211_WEXT_EXPORT + help +@@ -199,11 +195,12 @@ config CFG80211_WEXT + + config CFG80211_WEXT_EXPORT + bool +- depends on CFG80211 + help + Drivers should select this option if they require cfg80211's + wext compatibility symbols to be exported. + ++endif # CFG80211 ++ + config LIB80211 + tristate + default n +diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c +index 8e70291..e87d6c4 100644 +--- a/net/xfrm/xfrm_device.c ++++ b/net/xfrm/xfrm_device.c +@@ -217,7 +217,7 @@ bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x) + if (skb->len <= mtu) + goto ok; + +- if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) + goto ok; + } + +diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib +index 5589bae..a6f538b 100644 +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -297,11 +297,11 @@ cmd_dt_S_dtb= \ + echo '\#include '; \ + echo '.section .dtb.init.rodata,"a"'; \ + echo '.balign STRUCT_ALIGNMENT'; \ +- echo '.global __dtb_$(*F)_begin'; \ +- echo '__dtb_$(*F)_begin:'; \ ++ echo '.global __dtb_$(subst -,_,$(*F))_begin'; \ ++ echo '__dtb_$(subst -,_,$(*F))_begin:'; \ + echo '.incbin "$<" '; \ +- echo '__dtb_$(*F)_end:'; \ +- echo '.global __dtb_$(*F)_end'; \ ++ echo '__dtb_$(subst -,_,$(*F))_end:'; \ ++ echo '.global __dtb_$(subst -,_,$(*F))_end'; \ + echo '.balign STRUCT_ALIGNMENT'; \ + ) > $@ + +diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c +index fa3d39b6..449b68c 100644 +--- a/scripts/basic/fixdep.c ++++ b/scripts/basic/fixdep.c +@@ -93,14 +93,6 @@ + * (Note: it'd be easy to port over the complete mkdep state machine, + * but I don't think the added complexity is worth it) + */ +-/* +- * Note 2: if somebody writes HELLO_CONFIG_BOOM in a file, it will depend onto +- * CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not +- * fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as +- * UML_CONFIG_BOOM, to avoid conflicts with /usr/include/linux/autoconf.h, +- * through arch/um/include/uml-config.h; this fixdep "bug" makes sure that +- * those files will have correct dependencies. +- */ + + #include + #include +@@ -233,8 +225,13 @@ static int str_ends_with(const char *s, int slen, const char *sub) + static void parse_config_file(const char *p) + { + const char *q, *r; ++ const char *start = p; + + while ((p = strstr(p, "CONFIG_"))) { ++ if (p > start && (isalnum(p[-1]) || p[-1] == '_')) { ++ p += 7; ++ continue; ++ } + p += 7; + q = p; + while (*q && (isalnum(*q) || *q == '_')) +@@ -286,8 +283,6 @@ static int is_ignored_file(const char *s, int len) + { + return str_ends_with(s, len, "include/generated/autoconf.h") || + str_ends_with(s, len, "include/generated/autoksyms.h") || +- str_ends_with(s, len, "arch/um/include/uml-config.h") || +- str_ends_with(s, len, "include/linux/kconfig.h") || + str_ends_with(s, len, ".ver"); + } + +diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter +index 94b6648..d84a567 100755 +--- a/scripts/bloat-o-meter ++++ b/scripts/bloat-o-meter +@@ -15,7 +15,7 @@ signal(SIGPIPE, SIG_DFL) + if len(sys.argv) < 3: + sys.stderr.write("usage: %s [option] file1 file2\n" % sys.argv[0]) + sys.stderr.write("The options are:\n") +- sys.stderr.write("-c cateogrize output based on symbole type\n") ++ sys.stderr.write("-c categorize output based on symbol type\n") + sys.stderr.write("-d Show delta of Data Section\n") + sys.stderr.write("-t Show delta of text Section\n") + sys.exit(-1) +diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c +index 04d4db4..918338d 100644 +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -910,7 +910,8 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop) + static int snd_seq_client_enqueue_event(struct snd_seq_client *client, + struct snd_seq_event *event, + struct file *file, int blocking, +- int atomic, int hop) ++ int atomic, int hop, ++ struct mutex *mutexp) + { + struct snd_seq_event_cell *cell; + int err; +@@ -948,7 +949,8 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client, + return -ENXIO; /* queue is not allocated */ + + /* allocate an event cell */ +- err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, file); ++ err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, ++ file, mutexp); + if (err < 0) + return err; + +@@ -1017,12 +1019,11 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, + return -ENXIO; + + /* allocate the pool now if the pool is not allocated yet */ ++ mutex_lock(&client->ioctl_mutex); + if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) { +- mutex_lock(&client->ioctl_mutex); + err = snd_seq_pool_init(client->pool); +- mutex_unlock(&client->ioctl_mutex); + if (err < 0) +- return -ENOMEM; ++ goto out; + } + + /* only process whole events */ +@@ -1073,7 +1074,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, + /* ok, enqueue it */ + err = snd_seq_client_enqueue_event(client, &event, file, + !(file->f_flags & O_NONBLOCK), +- 0, 0); ++ 0, 0, &client->ioctl_mutex); + if (err < 0) + break; + +@@ -1084,6 +1085,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, + written += len; + } + ++ out: ++ mutex_unlock(&client->ioctl_mutex); + return written ? written : err; + } + +@@ -1838,9 +1841,11 @@ static int snd_seq_ioctl_set_client_pool(struct snd_seq_client *client, + (! snd_seq_write_pool_allocated(client) || + info->output_pool != client->pool->size)) { + if (snd_seq_write_pool_allocated(client)) { ++ /* is the pool in use? */ ++ if (atomic_read(&client->pool->counter)) ++ return -EBUSY; + /* remove all existing cells */ + snd_seq_pool_mark_closing(client->pool); +- snd_seq_queue_client_leave_cells(client->number); + snd_seq_pool_done(client->pool); + } + client->pool->size = info->output_pool; +@@ -2260,7 +2265,8 @@ static int kernel_client_enqueue(int client, struct snd_seq_event *ev, + if (! cptr->accept_output) + result = -EPERM; + else /* send it */ +- result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, atomic, hop); ++ result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, ++ atomic, hop, NULL); + + snd_seq_client_unlock(cptr); + return result; +diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c +index a8c2822..72c0302 100644 +--- a/sound/core/seq/seq_fifo.c ++++ b/sound/core/seq/seq_fifo.c +@@ -125,7 +125,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, + return -EINVAL; + + snd_use_lock_use(&f->use_lock); +- err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL); /* always non-blocking */ ++ err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL, NULL); /* always non-blocking */ + if (err < 0) { + if ((err == -ENOMEM) || (err == -EAGAIN)) + atomic_inc(&f->overflow); +diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c +index f763682..ab1112e9 100644 +--- a/sound/core/seq/seq_memory.c ++++ b/sound/core/seq/seq_memory.c +@@ -220,7 +220,8 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell) + */ + static int snd_seq_cell_alloc(struct snd_seq_pool *pool, + struct snd_seq_event_cell **cellp, +- int nonblock, struct file *file) ++ int nonblock, struct file *file, ++ struct mutex *mutexp) + { + struct snd_seq_event_cell *cell; + unsigned long flags; +@@ -244,7 +245,11 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool, + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&pool->output_sleep, &wait); + spin_unlock_irq(&pool->lock); ++ if (mutexp) ++ mutex_unlock(mutexp); + schedule(); ++ if (mutexp) ++ mutex_lock(mutexp); + spin_lock_irq(&pool->lock); + remove_wait_queue(&pool->output_sleep, &wait); + /* interrupted? */ +@@ -287,7 +292,7 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool, + */ + int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, + struct snd_seq_event_cell **cellp, int nonblock, +- struct file *file) ++ struct file *file, struct mutex *mutexp) + { + int ncells, err; + unsigned int extlen; +@@ -304,7 +309,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, + if (ncells >= pool->total_elements) + return -ENOMEM; + +- err = snd_seq_cell_alloc(pool, &cell, nonblock, file); ++ err = snd_seq_cell_alloc(pool, &cell, nonblock, file, mutexp); + if (err < 0) + return err; + +@@ -330,7 +335,8 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, + int size = sizeof(struct snd_seq_event); + if (len < size) + size = len; +- err = snd_seq_cell_alloc(pool, &tmp, nonblock, file); ++ err = snd_seq_cell_alloc(pool, &tmp, nonblock, file, ++ mutexp); + if (err < 0) + goto __error; + if (cell->event.data.ext.ptr == NULL) +diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h +index 32f959c..3abe306 100644 +--- a/sound/core/seq/seq_memory.h ++++ b/sound/core/seq/seq_memory.h +@@ -66,7 +66,8 @@ struct snd_seq_pool { + void snd_seq_cell_free(struct snd_seq_event_cell *cell); + + int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, +- struct snd_seq_event_cell **cellp, int nonblock, struct file *file); ++ struct snd_seq_event_cell **cellp, int nonblock, ++ struct file *file, struct mutex *mutexp); + + /* return number of unused (free) cells */ + static inline int snd_seq_unused_cells(struct snd_seq_pool *pool) +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index 37e1cf8..5b4dbce 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -957,6 +957,8 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { + SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC), + SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC), + SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK), ++ SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK), ++ SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), + SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), + SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO), +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index b9c93fa..9af301c 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -5274,6 +5274,16 @@ static void alc298_fixup_speaker_volume(struct hda_codec *codec, + } + } + ++/* disable DAC3 (0x06) selection on NID 0x17 as it has no volume amp control */ ++static void alc295_fixup_disable_dac3(struct hda_codec *codec, ++ const struct hda_fixup *fix, int action) ++{ ++ if (action == HDA_FIXUP_ACT_PRE_PROBE) { ++ hda_nid_t conn[2] = { 0x02, 0x03 }; ++ snd_hda_override_conn_list(codec, 0x17, 2, conn); ++ } ++} ++ + /* Hook to update amp GPIO4 for automute */ + static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec, + struct hda_jack_callback *jack) +@@ -5466,6 +5476,7 @@ enum { + ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, + ALC255_FIXUP_DELL_SPK_NOISE, + ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, ++ ALC295_FIXUP_DISABLE_DAC3, + ALC280_FIXUP_HP_HEADSET_MIC, + ALC221_FIXUP_HP_FRONT_MIC, + ALC292_FIXUP_TPT460, +@@ -5480,10 +5491,12 @@ enum { + ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE, + ALC233_FIXUP_LENOVO_MULTI_CODECS, + ALC294_FIXUP_LENOVO_MIC_LOCATION, ++ ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE, + ALC700_FIXUP_INTEL_REFERENCE, + ALC274_FIXUP_DELL_BIND_DACS, + ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, + ALC298_FIXUP_TPT470_DOCK, ++ ALC255_FIXUP_DUMMY_LINEOUT_VERB, + }; + + static const struct hda_fixup alc269_fixups[] = { +@@ -6198,6 +6211,10 @@ static const struct hda_fixup alc269_fixups[] = { + .chained = true, + .chain_id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE, + }, ++ [ALC295_FIXUP_DISABLE_DAC3] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc295_fixup_disable_dac3, ++ }, + [ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { +@@ -6283,6 +6300,18 @@ static const struct hda_fixup alc269_fixups[] = { + { } + }, + }, ++ [ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE] = { ++ .type = HDA_FIXUP_PINS, ++ .v.pins = (const struct hda_pintbl[]) { ++ { 0x16, 0x0101102f }, /* Rear Headset HP */ ++ { 0x19, 0x02a1913c }, /* use as Front headset mic, without its own jack detect */ ++ { 0x1a, 0x01a19030 }, /* Rear Headset MIC */ ++ { 0x1b, 0x02011020 }, ++ { } ++ }, ++ .chained = true, ++ .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC ++ }, + [ALC700_FIXUP_INTEL_REFERENCE] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { +@@ -6319,6 +6348,15 @@ static const struct hda_fixup alc269_fixups[] = { + .chained = true, + .chain_id = ALC293_FIXUP_LENOVO_SPK_NOISE + }, ++ [ALC255_FIXUP_DUMMY_LINEOUT_VERB] = { ++ .type = HDA_FIXUP_PINS, ++ .v.pins = (const struct hda_pintbl[]) { ++ { 0x14, 0x0201101f }, ++ { } ++ }, ++ .chained = true, ++ .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE ++ }, + }; + + static const struct snd_pci_quirk alc269_fixup_tbl[] = { +@@ -6367,10 +6405,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE), + SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), + SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME), ++ SND_PCI_QUIRK(0x1028, 0x07b0, "Dell Precision 7520", ALC295_FIXUP_DISABLE_DAC3), + SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER), ++ SND_PCI_QUIRK(0x1028, 0x080c, "Dell WYSE", ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x082a, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), + SND_PCI_QUIRK(0x1028, 0x084b, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), + SND_PCI_QUIRK(0x1028, 0x084e, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), ++ SND_PCI_QUIRK(0x1028, 0x0873, "Dell Precision 3930", ALC255_FIXUP_DUMMY_LINEOUT_VERB), + SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), +@@ -6508,9 +6549,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x17aa, 0x2245, "Thinkpad T470", ALC298_FIXUP_TPT470_DOCK), + SND_PCI_QUIRK(0x17aa, 0x2246, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), + SND_PCI_QUIRK(0x17aa, 0x2247, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), ++ SND_PCI_QUIRK(0x17aa, 0x2249, "Thinkpad", ALC292_FIXUP_TPT460), + SND_PCI_QUIRK(0x17aa, 0x224b, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), + SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), + SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), ++ SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), + SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), + SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), +@@ -6872,7 +6915,7 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { + {0x12, 0x90a60120}, + {0x14, 0x90170110}, + {0x21, 0x0321101f}), +- SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, ++ SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, + {0x12, 0xb7a60130}, + {0x14, 0x90170110}, + {0x21, 0x04211020}), +diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h +index 0dfe4d3..f41079d 100644 +--- a/tools/arch/x86/include/asm/cpufeatures.h ++++ b/tools/arch/x86/include/asm/cpufeatures.h +@@ -213,6 +213,7 @@ + #define X86_FEATURE_SEV ( 7*32+20) /* AMD Secure Encrypted Virtualization */ + + #define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */ ++#define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* "" Use IBRS during runtime firmware calls */ + + /* Virtualization flags: Linux defined, word 8 */ + #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ +diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h +index 0fb5ef9..7b26d4b 100644 +--- a/tools/include/uapi/linux/kvm.h ++++ b/tools/include/uapi/linux/kvm.h +@@ -761,6 +761,7 @@ struct kvm_ppc_resize_hpt { + #define KVM_TRACE_PAUSE __KVM_DEPRECATED_MAIN_0x07 + #define KVM_TRACE_DISABLE __KVM_DEPRECATED_MAIN_0x08 + #define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2) ++#define KVM_GET_MSR_FEATURE_INDEX_LIST _IOWR(KVMIO, 0x0a, struct kvm_msr_list) + + /* + * Extension capability list. +@@ -934,6 +935,7 @@ struct kvm_ppc_resize_hpt { + #define KVM_CAP_S390_AIS_MIGRATION 150 + #define KVM_CAP_PPC_GET_CPU_CHAR 151 + #define KVM_CAP_S390_BPB 152 ++#define KVM_CAP_GET_MSR_FEATURES 153 + + #ifdef KVM_CAP_IRQ_ROUTING + +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index 46c1d23..92b6a2c 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -1116,42 +1116,29 @@ static int read_unwind_hints(struct objtool_file *file) + + static int read_retpoline_hints(struct objtool_file *file) + { +- struct section *sec, *relasec; ++ struct section *sec; + struct instruction *insn; + struct rela *rela; +- int i; + +- sec = find_section_by_name(file->elf, ".discard.retpoline_safe"); ++ sec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe"); + if (!sec) + return 0; + +- relasec = sec->rela; +- if (!relasec) { +- WARN("missing .rela.discard.retpoline_safe section"); +- return -1; +- } +- +- if (sec->len % sizeof(unsigned long)) { +- WARN("retpoline_safe size mismatch: %d %ld", sec->len, sizeof(unsigned long)); +- return -1; +- } +- +- for (i = 0; i < sec->len / sizeof(unsigned long); i++) { +- rela = find_rela_by_dest(sec, i * sizeof(unsigned long)); +- if (!rela) { +- WARN("can't find rela for retpoline_safe[%d]", i); ++ list_for_each_entry(rela, &sec->rela_list, list) { ++ if (rela->sym->type != STT_SECTION) { ++ WARN("unexpected relocation symbol type in %s", sec->name); + return -1; + } + + insn = find_insn(file, rela->sym->sec, rela->addend); + if (!insn) { +- WARN("can't find insn for retpoline_safe[%d]", i); ++ WARN("bad .discard.retpoline_safe entry"); + return -1; + } + + if (insn->type != INSN_JUMP_DYNAMIC && + insn->type != INSN_CALL_DYNAMIC) { +- WARN_FUNC("retpoline_safe hint not a indirect jump/call", ++ WARN_FUNC("retpoline_safe hint not an indirect jump/call", + insn->sec, insn->offset); + return -1; + } +diff --git a/tools/perf/Documentation/perf-kallsyms.txt b/tools/perf/Documentation/perf-kallsyms.txt +index 954ea9e..cf9f404 100644 +--- a/tools/perf/Documentation/perf-kallsyms.txt ++++ b/tools/perf/Documentation/perf-kallsyms.txt +@@ -8,7 +8,7 @@ perf-kallsyms - Searches running kernel for symbols + SYNOPSIS + -------- + [verse] +-'perf kallsyms symbol_name[,symbol_name...]' ++'perf kallsyms' [] symbol_name[,symbol_name...] + + DESCRIPTION + ----------- +diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c +index bf4ca74..a217623 100644 +--- a/tools/perf/builtin-record.c ++++ b/tools/perf/builtin-record.c +@@ -881,6 +881,15 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) + } + } + ++ /* ++ * If we have just single event and are sending data ++ * through pipe, we need to force the ids allocation, ++ * because we synthesize event name through the pipe ++ * and need the id for that. ++ */ ++ if (data->is_pipe && rec->evlist->nr_entries == 1) ++ rec->opts.sample_id = true; ++ + if (record__open(rec) != 0) { + err = -1; + goto out_child; +diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c +index 98bf9d3..54a4c15 100644 +--- a/tools/perf/builtin-stat.c ++++ b/tools/perf/builtin-stat.c +@@ -917,7 +917,7 @@ static void print_metric_csv(void *ctx, + char buf[64], *vals, *ends; + + if (unit == NULL || fmt == NULL) { +- fprintf(out, "%s%s%s%s", csv_sep, csv_sep, csv_sep, csv_sep); ++ fprintf(out, "%s%s", csv_sep, csv_sep); + return; + } + snprintf(buf, sizeof(buf), fmt, val); +diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c +index b7c823b..35ac016 100644 +--- a/tools/perf/builtin-top.c ++++ b/tools/perf/builtin-top.c +@@ -991,7 +991,7 @@ static int perf_top_overwrite_fallback(struct perf_top *top, + evlist__for_each_entry(evlist, counter) + counter->attr.write_backward = false; + opts->overwrite = false; +- ui__warning("fall back to non-overwrite mode\n"); ++ pr_debug2("fall back to non-overwrite mode\n"); + return 1; + } + +diff --git a/tools/perf/perf.h b/tools/perf/perf.h +index cfe4623..57b9b34 100644 +--- a/tools/perf/perf.h ++++ b/tools/perf/perf.h +@@ -61,6 +61,7 @@ struct record_opts { + bool tail_synthesize; + bool overwrite; + bool ignore_missing_thread; ++ bool sample_id; + unsigned int freq; + unsigned int mmap_pages; + unsigned int auxtrace_mmap_pages; +diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c +index 2864279..fbf927c 100644 +--- a/tools/perf/ui/browsers/annotate.c ++++ b/tools/perf/ui/browsers/annotate.c +@@ -327,7 +327,32 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) + if (!disasm_line__is_valid_jump(cursor, sym)) + return; + ++ /* ++ * This first was seen with a gcc function, _cpp_lex_token, that ++ * has the usual jumps: ++ * ++ * │1159e6c: ↓ jne 115aa32 <_cpp_lex_token@@Base+0xf92> ++ * ++ * I.e. jumps to a label inside that function (_cpp_lex_token), and ++ * those works, but also this kind: ++ * ++ * │1159e8b: ↓ jne c469be ++ * ++ * I.e. jumps to another function, outside _cpp_lex_token, which ++ * are not being correctly handled generating as a side effect references ++ * to ab->offset[] entries that are set to NULL, so to make this code ++ * more robust, check that here. ++ * ++ * A proper fix for will be put in place, looking at the function ++ * name right after the '<' token and probably treating this like a ++ * 'call' instruction. ++ */ + target = ab->offsets[cursor->ops.target.offset]; ++ if (target == NULL) { ++ ui_helpline__printf("WARN: jump target inconsistency, press 'o', ab->offsets[%#x] = NULL\n", ++ cursor->ops.target.offset); ++ return; ++ } + + bcursor = browser_line(&cursor->al); + btarget = browser_line(target); +diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c +index 9faf3b5..6470ea2 100644 +--- a/tools/perf/util/auxtrace.c ++++ b/tools/perf/util/auxtrace.c +@@ -60,6 +60,12 @@ + #include "sane_ctype.h" + #include "symbol/kallsyms.h" + ++static bool auxtrace__dont_decode(struct perf_session *session) ++{ ++ return !session->itrace_synth_opts || ++ session->itrace_synth_opts->dont_decode; ++} ++ + int auxtrace_mmap__mmap(struct auxtrace_mmap *mm, + struct auxtrace_mmap_params *mp, + void *userpg, int fd) +@@ -762,6 +768,9 @@ int auxtrace_queues__process_index(struct auxtrace_queues *queues, + size_t i; + int err; + ++ if (auxtrace__dont_decode(session)) ++ return 0; ++ + list_for_each_entry(auxtrace_index, &session->auxtrace_index, list) { + for (i = 0; i < auxtrace_index->nr; i++) { + ent = &auxtrace_index->entries[i]; +@@ -892,12 +901,6 @@ int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr, + return err; + } + +-static bool auxtrace__dont_decode(struct perf_session *session) +-{ +- return !session->itrace_synth_opts || +- session->itrace_synth_opts->dont_decode; +-} +- + int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_session *session) +diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c +index 1e97937..6f09e49 100644 +--- a/tools/perf/util/record.c ++++ b/tools/perf/util/record.c +@@ -137,6 +137,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, + struct perf_evsel *evsel; + bool use_sample_identifier = false; + bool use_comm_exec; ++ bool sample_id = opts->sample_id; + + /* + * Set the evsel leader links before we configure attributes, +@@ -163,8 +164,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, + * match the id. + */ + use_sample_identifier = perf_can_sample_identifier(); +- evlist__for_each_entry(evlist, evsel) +- perf_evsel__set_sample_id(evsel, use_sample_identifier); ++ sample_id = true; + } else if (evlist->nr_entries > 1) { + struct perf_evsel *first = perf_evlist__first(evlist); + +@@ -174,6 +174,10 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, + use_sample_identifier = perf_can_sample_identifier(); + break; + } ++ sample_id = true; ++ } ++ ++ if (sample_id) { + evlist__for_each_entry(evlist, evsel) + perf_evsel__set_sample_id(evsel, use_sample_identifier); + } +diff --git a/tools/perf/util/trigger.h b/tools/perf/util/trigger.h +index 370138e..88223bc 100644 +--- a/tools/perf/util/trigger.h ++++ b/tools/perf/util/trigger.h +@@ -12,7 +12,7 @@ + * States and transits: + * + * +- * OFF--(on)--> READY --(hit)--> HIT ++ * OFF--> ON --> READY --(hit)--> HIT + * ^ | + * | (ready) + * | | +@@ -27,8 +27,9 @@ struct trigger { + volatile enum { + TRIGGER_ERROR = -2, + TRIGGER_OFF = -1, +- TRIGGER_READY = 0, +- TRIGGER_HIT = 1, ++ TRIGGER_ON = 0, ++ TRIGGER_READY = 1, ++ TRIGGER_HIT = 2, + } state; + const char *name; + }; +@@ -50,7 +51,7 @@ static inline bool trigger_is_error(struct trigger *t) + static inline void trigger_on(struct trigger *t) + { + TRIGGER_WARN_ONCE(t, TRIGGER_OFF); +- t->state = TRIGGER_READY; ++ t->state = TRIGGER_ON; + } + + static inline void trigger_ready(struct trigger *t) +diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c +index c73592f..437c0b1 100644 +--- a/tools/testing/selftests/bpf/test_verifier.c ++++ b/tools/testing/selftests/bpf/test_verifier.c +@@ -11163,6 +11163,64 @@ static struct bpf_test tests[] = { + .result = REJECT, + .prog_type = BPF_PROG_TYPE_TRACEPOINT, + }, ++ { ++ "xadd/w check unaligned stack", ++ .insns = { ++ BPF_MOV64_IMM(BPF_REG_0, 1), ++ BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8), ++ BPF_STX_XADD(BPF_W, BPF_REG_10, BPF_REG_0, -7), ++ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8), ++ BPF_EXIT_INSN(), ++ }, ++ .result = REJECT, ++ .errstr = "misaligned stack access off", ++ .prog_type = BPF_PROG_TYPE_SCHED_CLS, ++ }, ++ { ++ "xadd/w check unaligned map", ++ .insns = { ++ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), ++ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), ++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), ++ BPF_LD_MAP_FD(BPF_REG_1, 0), ++ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, ++ BPF_FUNC_map_lookup_elem), ++ BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), ++ BPF_EXIT_INSN(), ++ BPF_MOV64_IMM(BPF_REG_1, 1), ++ BPF_STX_XADD(BPF_W, BPF_REG_0, BPF_REG_1, 3), ++ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 3), ++ BPF_EXIT_INSN(), ++ }, ++ .fixup_map1 = { 3 }, ++ .result = REJECT, ++ .errstr = "misaligned value access off", ++ .prog_type = BPF_PROG_TYPE_SCHED_CLS, ++ }, ++ { ++ "xadd/w check unaligned pkt", ++ .insns = { ++ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, ++ offsetof(struct xdp_md, data)), ++ BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, ++ offsetof(struct xdp_md, data_end)), ++ BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), ++ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), ++ BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 2), ++ BPF_MOV64_IMM(BPF_REG_0, 99), ++ BPF_JMP_IMM(BPF_JA, 0, 0, 6), ++ BPF_MOV64_IMM(BPF_REG_0, 1), ++ BPF_ST_MEM(BPF_W, BPF_REG_2, 0, 0), ++ BPF_ST_MEM(BPF_W, BPF_REG_2, 3, 0), ++ BPF_STX_XADD(BPF_W, BPF_REG_2, BPF_REG_0, 1), ++ BPF_STX_XADD(BPF_W, BPF_REG_2, BPF_REG_0, 2), ++ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 1), ++ BPF_EXIT_INSN(), ++ }, ++ .result = REJECT, ++ .errstr = "BPF_XADD stores into R2 packet", ++ .prog_type = BPF_PROG_TYPE_XDP, ++ }, + }; + + static int probe_filter_length(const struct bpf_insn *fp) +diff --git a/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile +index 183b468..686da51 100644 +--- a/tools/testing/selftests/memory-hotplug/Makefile ++++ b/tools/testing/selftests/memory-hotplug/Makefile +@@ -5,7 +5,8 @@ include ../lib.mk + + TEST_PROGS := mem-on-off-test.sh + override RUN_TESTS := @./mem-on-off-test.sh -r 2 && echo "selftests: memory-hotplug [PASS]" || echo "selftests: memory-hotplug [FAIL]" +-override EMIT_TESTS := echo "$(RUN_TESTS)" ++ ++override EMIT_TESTS := echo "$(subst @,,$(RUN_TESTS))" + + run_full_test: + @/bin/bash ./mem-on-off-test.sh && echo "memory-hotplug selftests: [PASS]" || echo "memory-hotplug selftests: [FAIL]" +diff --git a/tools/testing/selftests/powerpc/mm/subpage_prot.c b/tools/testing/selftests/powerpc/mm/subpage_prot.c +index 35ade74..3ae77ba 100644 +--- a/tools/testing/selftests/powerpc/mm/subpage_prot.c ++++ b/tools/testing/selftests/powerpc/mm/subpage_prot.c +@@ -135,6 +135,16 @@ static int run_test(void *addr, unsigned long size) + return 0; + } + ++static int syscall_available(void) ++{ ++ int rc; ++ ++ errno = 0; ++ rc = syscall(__NR_subpage_prot, 0, 0, 0); ++ ++ return rc == 0 || (errno != ENOENT && errno != ENOSYS); ++} ++ + int test_anon(void) + { + unsigned long align; +@@ -145,6 +155,8 @@ int test_anon(void) + void *mallocblock; + unsigned long mallocsize; + ++ SKIP_IF(!syscall_available()); ++ + if (getpagesize() != 0x10000) { + fprintf(stderr, "Kernel page size must be 64K!\n"); + return 1; +@@ -180,6 +192,8 @@ int test_file(void) + off_t filesize; + int fd; + ++ SKIP_IF(!syscall_available()); ++ + fd = open(file_name, O_RDWR); + if (fd == -1) { + perror("failed to open file"); +diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile +index a234539..5c72ff9 100644 +--- a/tools/testing/selftests/powerpc/tm/Makefile ++++ b/tools/testing/selftests/powerpc/tm/Makefile +@@ -16,7 +16,7 @@ $(OUTPUT)/tm-syscall: tm-syscall-asm.S + $(OUTPUT)/tm-syscall: CFLAGS += -I../../../../../usr/include + $(OUTPUT)/tm-tmspr: CFLAGS += -pthread + $(OUTPUT)/tm-vmx-unavail: CFLAGS += -pthread -m64 +-$(OUTPUT)/tm-resched-dscr: ../pmu/lib.o ++$(OUTPUT)/tm-resched-dscr: ../pmu/lib.c + $(OUTPUT)/tm-unavailable: CFLAGS += -O0 -pthread -m64 -Wno-error=uninitialized -mvsx + $(OUTPUT)/tm-trap: CFLAGS += -O0 -pthread -m64 + +diff --git a/tools/testing/selftests/powerpc/tm/tm-trap.c b/tools/testing/selftests/powerpc/tm/tm-trap.c +index 5d92c23..179d592 100644 +--- a/tools/testing/selftests/powerpc/tm/tm-trap.c ++++ b/tools/testing/selftests/powerpc/tm/tm-trap.c +@@ -255,6 +255,8 @@ int tm_trap_test(void) + + struct sigaction trap_sa; + ++ SKIP_IF(!have_htm()); ++ + trap_sa.sa_flags = SA_SIGINFO; + trap_sa.sa_sigaction = trap_signal_handler; + sigaction(SIGTRAP, &trap_sa, NULL); +diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json b/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json +index e3407505..90bba48 100644 +--- a/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json ++++ b/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json +@@ -315,7 +315,7 @@ + "cmdUnderTest": "$TC actions ls action skbmod", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbmod index 4", +- "matchPattern": "action order [0-9]*: skbmod pipe set etype 0x0031", ++ "matchPattern": "action order [0-9]*: skbmod pipe set etype 0x31", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbmod" +diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests +index d256189..22d5646 100755 +--- a/tools/testing/selftests/vm/run_vmtests ++++ b/tools/testing/selftests/vm/run_vmtests +@@ -2,25 +2,33 @@ + # SPDX-License-Identifier: GPL-2.0 + #please run as root + +-#we need 256M, below is the size in kB +-needmem=262144 + mnt=./huge + exitcode=0 + +-#get pagesize and freepages from /proc/meminfo ++#get huge pagesize and freepages from /proc/meminfo + while read name size unit; do + if [ "$name" = "HugePages_Free:" ]; then + freepgs=$size + fi + if [ "$name" = "Hugepagesize:" ]; then +- pgsize=$size ++ hpgsize_KB=$size + fi + done < /proc/meminfo + ++# Simple hugetlbfs tests have a hardcoded minimum requirement of ++# huge pages totaling 256MB (262144KB) in size. The userfaultfd ++# hugetlb test requires a minimum of 2 * nr_cpus huge pages. Take ++# both of these requirements into account and attempt to increase ++# number of huge pages available. ++nr_cpus=$(nproc) ++hpgsize_MB=$((hpgsize_KB / 1024)) ++half_ufd_size_MB=$((((nr_cpus * hpgsize_MB + 127) / 128) * 128)) ++needmem_KB=$((half_ufd_size_MB * 2 * 1024)) ++ + #set proper nr_hugepages +-if [ -n "$freepgs" ] && [ -n "$pgsize" ]; then ++if [ -n "$freepgs" ] && [ -n "$hpgsize_KB" ]; then + nr_hugepgs=`cat /proc/sys/vm/nr_hugepages` +- needpgs=`expr $needmem / $pgsize` ++ needpgs=$((needmem_KB / hpgsize_KB)) + tries=2 + while [ $tries -gt 0 ] && [ $freepgs -lt $needpgs ]; do + lackpgs=$(( $needpgs - $freepgs )) +@@ -107,8 +115,9 @@ fi + echo "---------------------------" + echo "running userfaultfd_hugetlb" + echo "---------------------------" +-# 256MB total huge pages == 128MB src and 128MB dst +-./userfaultfd hugetlb 128 32 $mnt/ufd_test_file ++# Test requires source and destination huge pages. Size of source ++# (half_ufd_size_MB) is passed as argument to test. ++./userfaultfd hugetlb $half_ufd_size_MB 32 $mnt/ufd_test_file + if [ $? -ne 0 ]; then + echo "[FAIL]" + exitcode=1 +diff --git a/tools/testing/selftests/x86/test_vsyscall.c b/tools/testing/selftests/x86/test_vsyscall.c +index be81621..0b4f1cc 100644 +--- a/tools/testing/selftests/x86/test_vsyscall.c ++++ b/tools/testing/selftests/x86/test_vsyscall.c +@@ -450,7 +450,7 @@ static void sigtrap(int sig, siginfo_t *info, void *ctx_void) + num_vsyscall_traps++; + } + +-static int test_native_vsyscall(void) ++static int test_emulation(void) + { + time_t tmp; + bool is_native; +@@ -458,7 +458,7 @@ static int test_native_vsyscall(void) + if (!vtime) + return 0; + +- printf("[RUN]\tchecking for native vsyscall\n"); ++ printf("[RUN]\tchecking that vsyscalls are emulated\n"); + sethandler(SIGTRAP, sigtrap, 0); + set_eflags(get_eflags() | X86_EFLAGS_TF); + vtime(&tmp); +@@ -474,11 +474,12 @@ static int test_native_vsyscall(void) + */ + is_native = (num_vsyscall_traps > 1); + +- printf("\tvsyscalls are %s (%d instructions in vsyscall page)\n", ++ printf("[%s]\tvsyscalls are %s (%d instructions in vsyscall page)\n", ++ (is_native ? "FAIL" : "OK"), + (is_native ? "native" : "emulated"), + (int)num_vsyscall_traps); + +- return 0; ++ return is_native; + } + #endif + +@@ -498,7 +499,7 @@ int main(int argc, char **argv) + nerrs += test_vsys_r(); + + #ifdef __x86_64__ +- nerrs += test_native_vsyscall(); ++ nerrs += test_emulation(); + #endif + + return nerrs ? 1 : 0; diff --git a/main.go b/main.go new file mode 100644 index 0000000..f62aa00 --- /dev/null +++ b/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "fmt" + "time" +) + +//timeTrack tracks the time it took to do things. +//It's a convenient method that you can use everywhere +//you feel like it +func timeTrack(start time.Time, name string) { + elapsed := time.Since(start) + fmt.Printf("%s took %s\n", name, elapsed) +} + +//main is the entry point of our go program. It defers +//the execution of timeTrack so we can know how long it +//took for the main to complete. +//It also calls the compute and output the returned struct +//to stdout. +func main() { + defer timeTrack(time.Now(), "compute diff") + fmt.Println(compute()) +} + +//compute parses the git diffs in ./diffs and returns +//a result struct that contains all the relevant informations +//about these diffs +// list of files in the diffs +// number of regions +// number of line added +// number of line deleted +// list of function calls seen in the diffs and their number of calls +func compute() *result { + + return nil +} diff --git a/result.go b/result.go new file mode 100644 index 0000000..7e78236 --- /dev/null +++ b/result.go @@ -0,0 +1,50 @@ +package main + +import ( + "bytes" + "strconv" +) + +//result contains an analysis of a set of commit +type result struct { + //The name of the files seen + files []string + //How many region we have (i.e. seperated by @@) + regions int + //How many line were added total + lineAdded int + //How many line were deleted totla + lineDeleted int + //How many times the function seen in the code are called. + functionCalls map[string]int +} + +//String returns the value of results as a formated string +func (r *result) String() string { + + var buffer bytes.Buffer + buffer.WriteString("Files: \n") + for _, file := range r.files { + buffer.WriteString(" -") + buffer.WriteString(file) + buffer.WriteString("\n") + } + r.appendIntValueToBuffer(r.regions, "Regions", &buffer) + r.appendIntValueToBuffer(r.lineAdded, "LA", &buffer) + r.appendIntValueToBuffer(r.lineDeleted, "LD", &buffer) + + buffer.WriteString("Functions calls: \n") + for key, value := range r.functionCalls { + r.appendIntValueToBuffer(value, key, &buffer) + } + + return buffer.String() +} + +//appendIntValueToBuffer appends int value to a bytes buffer +func (r result) appendIntValueToBuffer(value int, label string, buffer *bytes.Buffer) { + buffer.WriteString(label) + buffer.WriteString(" : ") + buffer.WriteString(strconv.Itoa(value)) + buffer.WriteString("\n") +}